STM32点亮LED 寄存器方式
IO简介
1、每个IO可以自由编程,但是IO口寄存器必须按照32位字被访问。
2、每个IO端口都有7个寄存器来控制。
CRL 【0-7】端口配置寄存器 32位
CRH 【8-15】端口配置寄存器 32位
IDR 数据寄存器 32位 输入
ODR 数据寄存器 32位 输出
BSRR 置位/复位寄存器 32位
BRR 复位寄存器 16位
LCKR 锁存寄存器 32位
3、常用的IO端口寄存器 CRL CRH IDR ODR
4、CRL CRH控制每个IO口的模式及输出速率
(1)STM32的IO口可以由软件配置为8种模式:
输入浮空
输入上拉
输入下拉
模拟输入
开漏输出
推挽输出
推挽式复用功能
开漏复用功能
(2)端口配置低寄存器(GPIOx_CRL)(x = A..E)
偏移地址:0x00
复位值:0x4444 4444
(3)端口位配置
配置模式 |
| CNF1 | CNF0 | MODE1 | MODE0 | PxODR寄存器 |
通用输出
| 推挽输出 | 0 | 0 | 01 10 11 |
| 0或1 |
开漏输出 | 0 | 1 |
|
| 0或1 | |
复用功能输出
| 推挽 | 1 | 0 |
|
| 不使用 |
开漏 | 1 | 1 |
|
| 不使用 | |
输入
| 模拟输入 | 0 | 0 | 00 |
| 不使用 |
浮空输入 | 0 | 1 |
|
| 不使用 | |
下拉输入 | 1 | 0 |
|
| 0 | |
上拉输入 | 1 | 0 |
|
| 1 |
(4)输出模式
MODE[1:0] | 意义 |
00 | 保留 |
01 | 最大输出速率10MHz |
10 | 最大输出速率2MHz |
11 | 最大输出速率50MHz |
(5)端口配置高寄存器(GPIOx_CRH)(x = A..E)
偏移地址:0x04
复位值:0x4444 4444
CRH的作用和使用方法与CRL基本一致。
(6)端口输入数据寄存器(GPIOx_IDR)(x = A..E)
偏移地址:0x08
复位值:0x0000 XXXX
IDR是一个端口输入数据寄存器,只用了低16位。
IDR寄存器是一个只读寄存器,并且只能以16位的形式读出。
(7)端口输出数据寄存器(GPIOx_ODR)(x = A..E)
偏移地址:0xCH
复位值:0x0000 0000、
ODR是一个端口输出数据寄存器,只用了低16位。
ODR寄存器是一个可读写的寄存器。
从该寄存器读出来的数据可以判断当前IO口的输出状态。
向该寄存器写数据,可以控制某个IO口的输出电平。
注意:
在配置STM32外设的时候,任何时候都需要先使能该外设时钟。例如APB2ENR是APB2总线上的外设时钟使能寄存器。
Keil
1、工程创建(寄存器)
模板文件结构
└─OBJ └─project_template ├─CMSIS │ └─CM3 │ ├─CoreSupport │ │ core_cm3.c │ │ core_cm3.h │ │ │ └─DeviceSupport │ └─ST │ └─STM32F10x │ │ stm32f10x.h │ │ system_stm32f10x.c │ │ system_stm32f10x.h │ │ │ └─startup │ └─arm │ startup_stm32f10x_cl.s │ startup_stm32f10x_hd.s │ startup_stm32f10x_hd_vl.s │ startup_stm32f10x_ld.s │ startup_stm32f10x_ld_vl.s │ startup_stm32f10x_md.s │ startup_stm32f10x_md_vl.s │ startup_stm32f10x_xl.s │ ├─HARDWARE │ ├─inc │ └─src ├─lst ├─out ├─project └─user main.c stm32f10x_conf.h stm32f10x_it.c stm32f10x_it.h |
2、模板工程结构(寄存器)
3、寄存器编程技巧
寄存器编程的一般步骤:
(1)宏定义寄存器基地址 通过查看芯片数据手册获得
(2)宏定义寄存器地址 基地址+偏移量
(3)宏定义寄存器的指针类型 (*(unsigned int*)address)
(4)对寄存器指针进行赋值
点亮LED
1 原理图
LED连接特点:
8个LED灯共阳极,IO提供低电平时,LED灯亮
LED灯在CPU上的接口是PC端口,PC0-PC7
2 端口定义
第一步:宏定义PC端口的寄存器地址
端口PC的其实地址是 0x4001 1000
定义GPIO端口C的基地址: #define GPIOC_BASE_ADD 0x40011000
第二步:配置端口
LED灯只用到了GPIOC端口的0-7位,所以端口配置寄存器只需要查看地位的寄存器即可。
寄存器地址偏移量是:0x00
寄存器的地址可以定义为:
#define GPIOC_CRL_ADD (GPIOC_BASE_ADD + 0x00)
#define GPIOC_CRL (*(*unsigned int)GPIOC_CRL_ADD)
复位值是:0x4444 4444
GPIOC端口的CRL寄存器的初始化值可以为:
GPIOC_CRL = 0x44444444;
GPIOC端口的每个IO口都是有该寄存器的四位控制的。
CNF(2位):端口配置位
在这里我们需要将这两位配置为推挽输出即可:00
MODE(2位):端口模式位
在这里我们设置IO口的模式位输出模式,最大速度50MHz : 11
即每一个IO口的配置位值应该是:0x03
如果需要将GPIOC的0-7个IO口全配置好,而需要以下语句:
GPIOC_CRL = 0x33333333;
第三步:设置IO口的输出值
经过第二步,GPIOC端口的0-7位就配置好了。但是现在还不能是LED灯发光。需要LED灯发光,还要向ODR寄存器中设置好每个端口的数据。
LED灯只用到了GPIOC端口的0-7位,所以我们也就只需要将ODR寄存器的0-7位配置好就可以了。
ODR寄存的地址偏移是:0Ch
则定义ODR寄存器的地址为:
#define GPIOC_ODR_ADD (GPIOC_BASE_ADD + 0x0C);
#define GPIO_ODR (*(*unsigned int)GPIOC_ODR_ADD);
ODR的复位值是:0x0000 0000
则ODR寄存器的初始化值可以设置为:GPIO_ODR = 0x00;
如果我们需要不同的LED灯亮,则只需要就ODR寄存器中的相关位配置为0输出即可。
第四步:设置外设时钟
注意,进过上面的三步,我们将通用GPIO相关的设置都弄清楚了,但是现在还不能使得LED灯亮。因为,STM32的端口管理还需要涉及到相关的时钟设置的内容。
我们查询手册中的系统结构图可以看出,GPIOC是APB2总线上的外设。那么我们还需要将APB2总线时钟相关的参数设置好。
首先确认RCC时钟模块的寄存器基地址:
#define RCC_BASE_ADD 0x40021000
APB2外设使能时钟的寄存器地址偏移量为0x18
#define RCC_APB2ENR_ADD (RCC_BASE_ADD + 0x18)
#define RCC_APB2ENR (*(*unsigned int)RCC_APB2ENR_ADD)
需要外设的时钟打开,只需要将外设时钟使能寄存器的相关位设置为1即可。例如我们需要GPIOC的外设时钟使能,那我们只需要将RCC_APB2ENR的第4位设置为1;
RCC_APB2ENR = 0x00000010
3 源代码
//寄存器基地址
#define GPIOC_BASE_ADD 0x40011000
#define RCC_BASE_ADD0x40021000
//寄存器地址定义
#define GPIOC_CRL_ADD (GPIOC_BASE_ADD + 0x00)
#define GPIOC_ODR_ADD (GPIOC_BASE_ADD + 0x0C)
#define RCC_APB2ENR_ADD (RCC_BASE_ADD + 0x18)
//寄存器定义
#define GPIOC_CRL (*(unsigned int *)GPIOC_CRL_ADD)
#define GPIOC_ODR (*(unsigned int *)GPIOC_ODR_ADD)
#define RCC_APB2ENR (*(unsigned int *)RCC_APB2ENR_ADD)
//函数声明
void led_init(void);
void led_run(void);
void delay(void); //粗略延时
int main(void)
{
led_init();
//led初始化之后,LED应该是全亮状态
while(1)
{
led_run();
}
return 0;
}
void led_init()
{
RCC_APB2ENR = 0x00000010;
GPIOC_CRL &= 0x00;
PIOC_CRL |= 0x33333333;
GPIOC_ODR |= 0x00; //LED全亮
}
void led_run()
{
unsigned int i = 0;
GPIOC_ODR |= ~(0x00000001);
delay();
for(i = 0; i < 8; i++)
{
GPIOC_ODR <<= 1;
delay();
}
}
void delay()
{
unsigned int i,j;
for(i = 0;i<1000;i++)
{
for(j = 0;j<1000;j++);
}
}