STM32F103寄存器方式点亮LED流水灯
一、寄存器
1、什么是寄存器
寄存器(Register)是 CPU 中用于存储数据的单元。在运算器、控制器中,都需要有记忆功能的单元来保存从存储器中读取的数据,以及保存运算器生成的数据,这样的单元就是寄存器。简单来说,寄存器就是存放东西的一个空间器物。寄存器可能存放的是指令、数据或地址。
2、寄存器映射
给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
比方说我们找到0x4001 1010 这个单元地址,那么可以通过查阅相关资料了解到此单元具有GPIOC 端口置位/复位功能。因此为了更好区分此单元的功能和方便后续的程序开发,可以给这个单元取一个别名GPIOC_BSRR,那么这个GPIOC_BSRR 就是寄存器,并且这个寄存器地址就是0x4001 1010。这个过程就是寄存器映射。
二、LED流水灯设计
1、试验器材准备
STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿黄LED灯+杜邦线+usb转ttl(不限于这些)等。
2、GPIO端口的初始化
(1)、找到时钟是能寄存器映射基地址
想要配置时钟首先要访问其寄存器,找到其地址。
时钟控制的名字是RCC,属于ABH总线,如下图:
有数据手册可以知道复位和时钟控制RCC的地址范围是:0x4002 1000 - 0x400213FF
(2)、找到端口偏移地址和对应端口所在的位置
手册RCC_APB2ENR,位3是IOPB,名字是IO端口B时钟使能,就是我们想要的。把RCC_APB2ENR的位3赋值为1,就是开启GPIOB时钟。
(3)、使能对应端口时钟
`打开三个IO口的时钟需要将三个位都置
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
// 打开时钟
RCC_APB2ENR |= (1<<4); // 打开 GPIOC 时钟
RCC_APB2ENR |= (1<<3); // 打开 GPIOB 时钟
RCC_APB2ENR |= (1<<2); // 打开 GPIOA 时钟
2、输出端口寄存器配置
本次实验使用GPIOA-5、GPIOB-9、GPIOC-12 这3个引脚控制LED灯,GPIOA\GPIOB\GPIOC都是属于总线APB2控制的。
(1)、找到GPIO的地址
由图可见GPIOA,GOIOB,GPIOC的地址的范围
(2)、端口输入寄存器的地址偏移
还是查看数据手册
这里需要注意使用的寄存器是端口配置低寄存器还是端口配置高寄存器,两者的偏移地址是不相同的
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
GPIOB_CRH&= 0xffffff0f;
GPIOB_CRH|=0x00000020;
GPIOC_CRH &= 0x0fffffff;
GPIOC_CRH|=0x30000000;
GPIOA_CRL &= 0xfff0ffff;
GPIOA_CRL|=0x00010000;
(3) 、输入输出设置以及输出速率的设置
由于我们需要输出高低电平,所以设置为推挽输出,输出的速度设置为2MHZ
具体如下
GPIOB_CRH&= 0xffffff0f;
GPIOB_CRH|=0x00000020;
GPIOC_CRH &= 0x0fffffff;
GPIOC_CRH|=0x30000000;
GPIOA_CRL &= 0xfff0ffff;
GPIOA_CRL|=0x00010000;
三、 C语言实现
1、代码
关于如何创建一个新的项目就不在赘述,如有需求可以参考以下链接
link
具体代码如下
#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; //PA4低电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x1<<12; //PC12高电平
}
void B_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x0<<9; //PB9低电平
GPIOC_ODR=0x1<<12; //PC12高电平
}
void C_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x0<<12; //PC12低电平
}
int main(){
int p=1;
// 开启时钟
RCC_APB2ENR |= (1<<4); // 开启 GPIOC 时钟
RCC_APB2ENR |= (1<<3); // 开启 GPIOB 时钟
RCC_APB2ENR |= (1<<2); // 开启 GPIOA 时钟
// 设置 GPIO 为推挽输出
GPIOB_CRH&= 0xffffff0f; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出
GPIOC_CRH &= 0x0fffffff; //设置位 清零
GPIOC_CRH|=0x30000000; //PC12推挽输出
GPIOA_CRL &= 0xfff0ffff; //设置位 清零
GPIOA_CRL|=0x00010000; //PA4推挽输出
// 3个LED初始化为不亮(即高点位)
GPIOB_ODR |= (1<<9);
GPIOC_ODR |= (1<<12);
GPIOA_ODR |= (1<<4);
while(p){//永真循环,让代码一直执行
B_LED_LIGHT();
Delay_ms(1000000);
C_LED_LIGHT();
Delay_ms(1000000);
A_LED_LIGHT() ;
Delay_ms(1000000);
}
}
void SystemInit(){
//
}
这里需要注意的是芯片的类型选择,还有就是要引入启动文件
2、电路的连接
2.连接电路
根据设计的程序连接电路:
对于USB转TTL模块和stm32f103c8t6连接:
GND — GND
3v3 — 3v3
TXD — A10
RXD — A9
//这里的连接都相同
总电路:
红——B9
绿——C12
黄——A4
//这里需要根据自己的选择连线
需要了解一些面包板的用法可以自行查阅
3、程序烧入
点击此处
4、现象
四、参考
链接: link
链接: link