Schwertlilien
As a recoder: notes and ideas.

嵌入式上机实验1

实验一

一、实验目的

  • 熟悉Proteus硬件仿真环境
  • 掌握使用Keil uVision5进行STM32程序开发
  • 掌握Proteus和Keil联调的方法

二、实验环境

OS:Windows11

软件:Keil uVision5,Proteus

三、实验内容及实验原理

根据实验原理图配置对应的GPIO口,实现下述功能:

根据按键状态来控制LED灯亮灭状态,每个按键控制一个LED灯,LED灯初始状态为亮,按键按下时对应LED灯灭,按键抬起时对应LED灯亮。

根据按键状态来控制LED灯的闪烁方式,没有按键按下时三个LED灯都亮,第一个按键按下时三个LED灯同步周期性慢速闪烁,第二个按键按下时三个LED灯同步周期性快速闪烁,第三个按键按下时三个LED灯跑马灯方式闪烁

(1)使能APB2总线上使用引脚所属的GPIO端口的时钟

老师已经在工程中配置好了电源电路,因此直接开始配置时钟电路。如果没有稳定的时钟信号,即使接入电源,也无法正常工作。STM32F103通常选用8MHZ的外部晶振,因此该工程也是采用的该频率的外部晶振,使能GPIOA,GPIOB,USARTA1。

GPIOB使用引脚PB7~12用于连接LED的电路。GPIOA用于USART模块实现双向通信,任何USART双向通信至少需要2个引脚:接受数据输入(RX)和发送数据输出(TX):

  • RX: 接受数据串行输入,使用引脚PA9,连接虚拟串口输出框。

  • TX: 发送数据输出,使用引脚PA10。

1
2
3
4
5
//Enable GPIOA's and GPIOB's Clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//Enable USART1's Clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
(2)通过GPIO_InitTypeDef结构体变量配置GPIO引脚

设置引脚PB7-9为推挽输出,与LED灯相连,控制LED灯的亮灭;设置引脚PB10-12为上拉输入,来接受按钮的输入信号。再将PB7-9复位,设置为低电平,实施LED灯初始为未点亮状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//设置推挽输出的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//设置上拉输入的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//将指定引脚复位
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
GPIO_ResetBits(GPIOB, GPIO_Pin_8);
GPIO_ResetBits(GPIOB, GPIO_Pin_9);
(3)操作该引脚完成相应的功能

首先完成功能一:要求是按下按键时LED灯灭。因此可以将其写为非负判断:若不存在输入值,那么将对应的引脚置位,使得LED灯亮;若存在输入值(即按下了按键),则将对应的引脚复位,使得LED灯灭。

1
2
3
4
5
6
7
8
9
//功能1:LED灯初始为亮,只有按下按键使得灯灭。
if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)) GPIO_SetBits(GPIOB, GPIO_Pin_7);
else GPIO_ResetBits(GPIOB, GPIO_Pin_7);

if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11))GPIO_SetBits(GPIOB, GPIO_Pin_8);
else GPIO_ResetBits(GPIOB, GPIO_Pin_8);

if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)) GPIO_SetBits(GPIOB, GPIO_Pin_9);
else GPIO_ResetBits(GPIOB, GPIO_Pin_9);

再完成功能二:根据按键状态来控制LED灯的闪烁方式,没有按键按下时三个LED灯都亮,第一个按键按下时三个LED灯同步周期性慢速闪烁,第二个按键按下时三个LED灯同步周期性快速闪烁,第三个按键按下时三个LED灯跑马灯方式闪烁。编写代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int i; 
//第一个按键按下时三个LED灯同步周期性慢速闪烁
if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)){
for(i = 0; i < 1000000; i++);
GPIO_SetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);
for(i = 0; i < 1000000; i++);
GPIO_ResetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);
printf("SLOW LIGHT\r\n");
}else GPIO_ResetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);
//第二个按键按下时三个LED灯同步周期性快速闪烁
if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)){
for(i = 0; i < 300000; i++);
GPIO_SetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);
for(i = 0; i < 300000; i++);
GPIO_ResetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);
printf("FAST LIGHT\r\n");
}else GPIO_ResetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);
//第三个按键按下时三个LED灯跑马灯方式闪烁
if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)){
for(i = 0; i < 100000; i++) {
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
GPIO_SetBits(GPIOB, GPIO_Pin_8|GPIO_Pin_9);
}
for(i = 0; i < 100000; i++){
GPIO_ResetBits(GPIOB, GPIO_Pin_8);
GPIO_SetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_9);
}
for(i = 0; i < 100000; i++){
GPIO_ResetBits(GPIOB, GPIO_Pin_9);
GPIO_SetBits(GPIOB, GPIO_Pin_7|GPIO_Pin_8);
}
printf("CIRCULATION LIGHT\r\n");
}else GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);

四、实验结果及其分析

使用C语言中的#if与#endif完成分支编译。对于功能二的实现,需要长按某按钮实现。此处选择的快速约是慢速的三倍左右。

具体结果见视频。

五、心得体会与建议

通过本次实验,我在PC上安装了嵌入式学习的软件:Keil和Proteus,并对其基本操作进行了了解。针对老师给出的实验内容,对要求实现的功能进行了C语言代码的编写。并通过Keil进行编译运行,再在Proteus的硬件仿真环境下进行结果验证。

在调试的过程中,会遇到一定的问题:比如写出的printf函数中使用了换行的转义字符,但是在显示上并没有换行。在Keil上未成功编译就急忙打开Proteus想要验证,但是导致Proteus未响应最后只能退出。

但是经过这次实验,我对这两个软件的联调也有了一定的认识,操作上熟练了一些。

搜索
匹配结果数:
未搜索到匹配的文章。