一、实验原理
1.寄存器
- 寄存器的功能是存储二进制数,可能存放的是指令、数据或地址。
- 如果需要读取数据,则要到寄存器所在的位置进行数据读取,称为访问寄存器。
- 不同的数据存放在不同的寄存器里,通过地址区分不同的寄存器。
2.通过查询数据手册找到某个寄存器的地址
STM32给不同的寄存器分配了不同的地址,在《STM32中文参考手册_V10》的第28页,有不同寄存器的地址范围。以下为读取PB3引脚的电平的步骤。
(1)找到GPIOB的基地址
查手册可以看到,GPIOB相关的寄存器,都住在0x4001 0C00到0x4001 0FFF范围内。
(2)找到端口输入寄存器的地址偏移
找到存储数据的单元,为0x4001 0C00+0x08 = 0x4001 0C08
(3)找到具体的屋子
PB3的数据位置在图中已经圈出。
3.操作寄存器点亮LED灯
(1)配置时钟使能
STM32默认的时钟是关闭的,这样做可以省电,我们需要使用的时候打开就可以了。 同样是查询数据手册,时钟控制的名称为RCC。 用之前我们使用过的寻找寄存器地址的方法来寻找RCC的地址,上图可以看到从0x40021000开始。 这里可以看到偏移地址为0x18,位2,位3,位4分别对应IO端口的A,B,C时钟使能。
//----------------APB2使能时钟寄存器 ---------------------
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
RCC_APB2ENR|=1<<2|1<<3|1<<4; //APB2-GPIOA、GPIOB、GPIOC外设时钟使能
(2)配置通用输出
控制LED需要输出高电平或是低电平,所以我们要配置为输出。 STM32中,用端口配置低寄存器(GPIOx_CRL)来配置引脚Px0-Px7, 用端口配置高寄存器(GPIOx_CRH)来配置引脚Px8-Px15。 本次实验采用通用推挽输出模式,最高输出时钟频率2Mhz。分别用到A5、B9、C14三个引脚。其中A5属于端口配置低寄存器偏移地址为0x00,B9,C14属于端口配置高寄存器偏移地址为0x04。 5号引脚,偏移地址0x00。 对应9号和13号引脚,偏移地址0x04 然后我们要找到GPIOA,GPIOB,GPIOC的基地址 配置寄存器,使用宏定义,基地址+偏移量
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
然后设置输出模式为推挽输出,输出速度为2Mhz
GPIOA_CRL&=0xFF0FFFFF;
GPIOA_CRL|=0x00200000;
GPIOB_CRH&=0xFFFFFF0F;
GPIOB_CRH|=0x00000020;
GPIOC_CRH&=0xFF0FFFFF;
GPIOC_CRH|=0x00200000;
二、用寄存器方式实现流水灯
1.流水灯的原理
本次实验使用3个灯来实现,亮灯状态用1表示,灭灯状态用0表示。 初始状态为0 0 0,即三个灯都不亮。 状态一为:1 0 0,即只有第一个灯亮 状态二为:0 1 0,即只有第二个灯亮 状态三为:0 0 1,即只有第三个灯亮 然后回到状态一,进行循环,达成实验效果。
2.用C语言来实现流水灯
代码如下,部分代码前文有过解释:
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
void SystemInit(void);
void Delay_ms(volatile unsigned int);
void A_LED_LIGHT(void);
void B_LED_LIGHT(void);
void C_LED_LIGHT(void);
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
void A_LED_LIGHT(){
GPIOA_ODR=0x0<<4;
GPIOB_ODR=0x1<<9;
GPIOC_ODR=0x1<<15;
}
void B_LED_LIGHT(){
GPIOA_ODR=0x1<<4;
GPIOB_ODR=0x0<<9;
GPIOC_ODR=0x1<<15;
}
void C_LED_LIGHT(){
GPIOA_ODR=0x1<<4;
GPIOB_ODR=0x1<<9;
GPIOC_ODR=0x0<<15;
}
int main(){
int j=100;
RCC_APB2ENR |= (1<<3);
RCC_APB2ENR |= (1<<4);
RCC_APB2ENR |= (1<<2);
GPIOB_CRH&= 0xffffff0f;
GPIOB_CRH|=0x00000020;
GPIOC_CRH &= 0x0fffffff;
GPIOC_CRH|=0x30000000;
GPIOA_CRL &= 0xfff0ffff;
GPIOA_CRL|=0x00010000;
GPIOB_ODR |= (1<<9);
GPIOC_ODR |= (1<<15);
GPIOA_ODR |= (1<<4);
while(j){
B_LED_LIGHT();
Delay_ms(1000);
C_LED_LIGHT();
Delay_ms(1000);
A_LED_LIGHT();
Delay_ms(1000);
}
}
void SystemInit(){
}
3.添加启动程序
操作如下图 上图的启动文件可以去官网下载,然后我们要让其生成HEX文件。
4.编译程序
生成的HEX文件在项目的根目录里面可以找到,然后我们打开FlyMcu
5.效果展示
.
6.观察GPIO端口的波形
(1)配置Debug
(2)启动调试
添加要观察的引脚 点击IN或OUT将GRID设置为1s,勾选后面圈中的两项 运行程序 观察波形 引脚为低电平的灯亮,高电平的灯不亮,高低电平转换周期(LED闪烁周期)为1s左右。
三、STM32CubeMX生成代码使用HAL库点亮流水灯
1.创建项目
(1)打开该软件,创建项目
(2)选择芯片,然后双击右边信息栏
(3)点击System Core,选择SYS,然后Debug选择Serial Wire
(4)配置时钟,选择上面的RCC
(5)设置引脚输出寄存器
这里我们选择PA4,PB9,PC15
(6)设置项目管理
(7)进入 Code Generator界面
(8)Open Project
(9)调到主函数,把以下代码粘贴到while循环中
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_RESET);
HAL_Delay(1000);
}
2.实验效果
实验的效果跟上文中寄存器方法点灯的效果是一样的,就不再放图了。
3.观察GPIO波形图
设置参照上文寄存器方法的仿真设置。 引脚为低电平的灯亮,高电平的灯不亮,高低电平转换周期(LED闪烁周期)为1s左右。
四、总结
(1)学习了使用寄存器方法进行编程实现流水灯。 (2)学习了安装 stm32CubeMX,用cubemx完成初始化过程,采用HAL库编程实现流水灯。 (3)了解了GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)。 (4)学习和理解了STM32F103系列芯片的地址映射和寄存器映射原理。
五、参考资料
https://blog.csdn.net/weixin_46129506/article/details/120780184 https://blog.csdn.net/geek_monkey/article/details/86291377
|