最近在看了一个项目之后发现自己对于底层配置这块不熟悉,浅浅了解了一下,此篇文章记录用STM32底层配置流水灯的操作方法。
共分为两步,使能时钟和配置LED端口
1、使能时钟
1.1 RCC寄存器地址(起始地址0x4002 3800):
1.2 RCC使能外设偏移地址(0x30):
地址:0x4002 3800 + 0x40 = 0x40023830
值:0000 0000 0000 0000 0000 0000 0010 0000
1.3 RCC使能相关代码
//APB1总线
//使能GPIOF的时钟
*(unsigned int *)0x40023830=0x00000020;
2、LED配置(PF9/PF10)
2.1 GPIOF地址分配
2.2 GPIOF端口模式配置(通用输出模式)
地址:0x4002 1400 + 0x00 = 0x40021400
值:0000 0000 0001 0100 0000 0000 0000 0000(0x00140000)
2.3 GPIO端口输出类型配置(输出推挽)
地址:0x4002 1400 + 0x04 = 0x40021404
值:0000 0000 0000 0000 0000 0110 0000 0000 (0x00000600)
2.4 GPIO 端口输出速度配置(低速)
地址:0x4002 1400 + 0x08 = 0x40021408
值:0x00000000
2.5 GPIO 端口上拉/下拉(下拉)
地址:0x4002 1400 + 0x0C = 0x4002140C
值:0000 0000 0010 1000 0000 0000 0000 0000(0x00280000)
2.6 LED配置相关代码
//GPIO 端口模式寄存器配置(通用输出模式)
*(unsigned int *)0x40021400=0x00140000;
//GPIO端口输出类型配置(推挽输出)
*(unsigned int *)0x40021404=0x00000600;
//GPIO 端口输出速度配置(低速)
*(unsigned int *)0x40021408=0x00000000;
//GPIO 端口上拉/下拉(下拉)
*(unsigned int *)0x4002140C=0x00280000;
3、点灯
3.1 GPIO端口输出数据寄存器ODR
亮:
LED0:0000 0000 0000 0000 0000 1101 0000 0000(0x0000FDFF)
LED1:0000 0000 0000 0000 0000 1011 0000 0000(0x0000FBFF)
灭:
LED0:0000 0000 0000 0000 1111 1111 1111 1111(0x0000FFFF)
LED1:0000 0000 0000 0000 1111 1111 1111 1111(0x0000FFFF)
3.2 流水灯相关代码
*(unsigned int *)0x40021414=0x0000FDFF; //turn on LED0
delay(1000000);
*(unsigned int *)0x40021414=0x0000FFFF; //turn off LED0
delay(1000000);
*(unsigned int *)0x40021414=0x0000FBFF; //turn on LED1
delay(1000000);
*(unsigned int *)0x40021414=0x0000FFFF; //turn off LED1
delay(1000000);
4 整体代码
void delay (unsigned int t)
{
while(t--);
}
int main( )
{
//APB1总线
//使能GPIOF的时钟
*(unsigned int *)0x40023830=0x00000020;
/**************端口配置(只配置推挽输出也行)**************/
//GPIO 端口模式寄存器配置(通用输出模式)
*(unsigned int *)0x40021400=0x00140000;
//GPIO端口输出类型配置(推挽输出)
*(unsigned int *)0x40021404=0x00000600;
//GPIO 端口输出速度配置(低速)
*(unsigned int *)0x40021408=0x00000000;
//GPIO 端口上拉/下拉(下拉)
*(unsigned int *)0x4002140C=0x00280000;
while(1)
{
*(unsigned int *)0x40021414=0x0000FDFF; //turn on LED0
delay(1000000);
*(unsigned int *)0x40021414=0x0000FFFF; //turn off LED0
delay(1000000);
*(unsigned int *)0x40021414=0x0000FBFF; //turn on LED1
delay(1000000);
*(unsigned int *)0x40021414=0x0000FFFF; //turn off LED1
delay(1000000);
}
}
5 踩过的一些坑
(给蠢蠢的自己一些警示)
1、APB1印象太深,一度以为是APB1的RCC配置,直到请教同学才发现应该是AHB1,而且二进制转十六进制的时候,把0000 0010B换算成了0x04 /(ㄒoㄒ)/~~
2、LED输出端口选择错误,用过端口上/下拉寄存器来点灯,是错误的。不管是上/下拉寄存器还是端口模式寄存器都是配置他们的工作模式,最后输出是多少,是GPIO 端口输出数据寄存器 (GPIOx_ODR)
3、虽然可以点亮灯,但是只能单灯闪烁,同学提示是端口重复配置,第二段的值把第一段覆盖了(此段代码PF9的值已改为最终正确的值)
//此段为错误代码❌
/********************PF9********************/
//GPIO 端口模式寄存器配置(通用输出模式)
*(unsigned int *)0x40021400=0x00140000;
//GPIO端口输出类型配置(推挽输出)
*(unsigned int *)0x40021404=0x00000600;
//GPIO 端口输出速度配置(低速)
*(unsigned int *)0x40021408=0x00000000;
//GPIO 端口上拉/下拉(下拉)
*(unsigned int *)0x4002140C=0x00280000;
/********************PF10********************/
//GPIO 端口模式寄存器配置(通用输出模式)
*(unsigned int *)0x40021400=0x00100000;
//GPIO端口输出类型配置(推挽输出)
*(unsigned int *)0x40021404=0x00000400;
//GPIO 端口输出速度配置(低速)
*(unsigned int *)0x40021408=0x00000000;
//GPIO 端口上拉/下拉(下拉)
*(unsigned int *)0x4002140C=0x00200000;