STM32使用寄存器点灯实验
寄存器点灯实验
操作过程
使能IO口时钟配置寄存器RCC_APB2ENR
初始化IO口模式,配置寄存器GPIOx_CRH/CRL
操作IO口,输出高低电平,配置寄存器GPIOx_ODR或者BSRR/BRR。
APB2 外设时钟使能寄存器(RCC_APB2ENR)
在STM32中文参考手册6.3RCC寄存器描述的6.3.7小节可以看到该寄存器的使用说明
因为使用的是GPIOA端口组,所以使能IOPAEN位,该位置1则IO端口A时钟开启
端口配置低寄存器(GPIOx_CRL) (x=A…E)
在中文参考手册的8.2节可以找到GPIO寄存器相关配置寄存器的描述
因为开发板上的PA1连接到了LED灯,所以对CNF1和MODE1进行初始化,MODE1初始化为11,设置为输出模式,速度为50MHz,CNF1初始化为00,设置为通用推挽输出模式
因为没有用到更高的引脚位,所以端口配置高寄存器(GPIOx_CRH) 并不用配置
端口输出数据寄存器(GPIOx_ODR)
往ODR寄存器的ODR1位写入0,则PA1引脚输出低电平,LED灯被点亮
端口位设置/清除寄存器(GPIOx_BSRR) ,端口位清除寄存器(GPIOx_BRR)
也可以使用这两个寄存器,因为是PA1输出低电平LED灯才被点亮,所以这两个寄存器都有效
如果LED灯是引脚输出高电平才能被点亮,那就只有端口位设置/清除寄存器(GPIOx_BSRR)的设置功能才能输出高电平,BRR寄存器不行
程序
参照手册搭建好寄存器的工程模板后,新建LED.h和LED.c文件,开始编写代码
LED.h
在头文件中要添加函数声明,因为写了多种初始化方法,所以这些函数都要添加声明
#ifndef __LED_H__
#define __LED_H__
//宏定义,LED_Init_3,LED_Init_4
#define IOPAEN 0x01<<2
#define CNF1_AND_MODE1 ((u32)0x0F<<4)
#define OUT_MODE_PP ((u32)0x03<<4)
#define ODR1 ((u16)0x01<<1)
#define BSRR_BR1 ((u32)0x01<<17)
#define BRR_BR1 ((u16)0x01<<1)
void LED_Init_1(void);
void LED_Init_2(void);
void LED_Init_3(void);
void LED_Init_4(void);
#endif
LED.c
分别用三种不同的写法实现点亮LED灯,方法一是直接往寄存器写入十六进制,方法二是用移位的方法初始化寄存器,但这两种方法的数值第一眼看去不好理解,不看参考手册的话很难知道0xFFF4是初始化什么,(u16)0x01<<2也是一样
所以推荐使用第三种方法,用宏定义,先在LED.h头文件中定义好数值,然后使用时直接调用宏名即可,可以让人一眼就看出初始化的是哪个位
第四种方法是使用BSRR或BRR寄存器对PA1进行赋值,一样能使LED灯点亮
#include "LED.h"
#include "stm32f10x.h"
/**
* @name LED_Init_1
* @brief LED初始化-寄存器(写法1)
* @param None
* @retval None
*/
void LED_Init_1()
{
//初始化APB2上GPIOA的时钟
RCC->APB2ENR |= 0xFFF4;
//GPIOA端口配置低寄存器
//4 ~ 7配置的是PA1,所以先将这4位清零
GPIOA->CRL &= 0xFFFFFF0F;
//然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
GPIOA->CRL |= 0xFFFFFF3F;
//配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
GPIOA->ODR &= 0xFFFD;
}
/**
* @name LED_Init_2
* @brief LED初始化-寄存器(写法2)
* @param None
* @retval None
*/
void LED_Init_2()
{
//初始化APB2上GPIOA的时钟
RCC->APB2ENR |= ((u16)0x01<<2);
//GPIOA端口配置低寄存器
//4 ~ 7配置的是PA1,所以先将这4位清零
GPIOA->CRL &= ~((u32)0x0F<<4);
//然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
GPIOA->CRL |= ((u32)0x03<<4);
//配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
GPIOA->ODR &= ~((u16)0x01<<1);
}
/**
* @name LED_Init_3
* @brief LED初始化-寄存器(写法3)
* @param None
* @retval None
*/
void LED_Init_3()
{
//初始化APB2上GPIOA的时钟
RCC->APB2ENR |= IOPAEN;
//GPIOA端口配置低寄存器
//4 ~ 7配置的是PA1,所以先将这4位清零
GPIOA->CRL &= ~CNF1_AND_MODE1;
//然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
GPIOA->CRL |= OUT_MODE_PP;
//配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
GPIOA->ODR &= ~ODR1;
}
/**
* @name LED_Init_4
* @brief LED初始化-寄存器(测试BSRR寄存器和BRR寄存器)
* @param None
* @retval None
*/
void LED_Init_4()
{
//初始化APB2上GPIOA的时钟
RCC->APB2ENR |= IOPAEN;
//GPIOA端口配置低寄存器
//4 ~ 7配置的是PA1,所以先将这4位清零
GPIOA->CRL &= ~CNF1_AND_MODE1;
//然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
GPIOA->CRL |= OUT_MODE_PP;
//配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
//GPIOA->ODR &= ~ODR1;
//配置端口位设置/清除寄存器(GPIOx_BSRR) 31-16位置1则对应的ODR位清0,LED点亮
//GPIOA->BSRR |= BSRR_BR1;
//配置端口位清除寄存器(GPIOx_BRR) 15-0位置1则对应的ODR位清0,LED点亮
GPIOA->BRR |= BRR_BR1;
}
main.c
主函数中引入LED.h头文件后,直接调用LED初始化函数即可
#include "LED.h"
int main()
{
//LED_Init_1();
//LED_Init_2();
//LED_Init_3();
LED_Init_4();
while(1)
{
}
}