STM32点亮LED灯
文章目录
一、使用寄存器点亮LED灯
1. 新建一个工程文件,并将启动文件 startup_stm32f10x_hd.s 引入到 Source Group 中。
引入的启动文件根据自己的 stm32 定,此处引入的启动文件支持的是 stm32F1系列;
文件所在位置:Libraries —> CMSIS —> CM3 —> DeviceSupport —> ST —> STM32F10x —> startup —> arm;
2. 新建 main.c, 写入一下内容:
int main(void)
{
//打开GPIOB的时钟
*(unsigned int *)0x40021018 |= (1 << 3);
//配置IO口为输出
*(unsigned int *)0x40010C00 |= (1 << (4*0));
// 控制 ODR 寄存器
*(unsigned int *)0x40010C0C &= ~(1 << 0); //(unsigned int *)将0x40010C0C强制转换为地址,前面再加指针进行指针的赋值操作
}
void SystemInit(void)
{
//函数外定义SystemInt(), 骗过编译器不报错
}
3. 程序的说明
-
定义一个 SystemInit 空函数的目的是为了骗过编译器;因为在启动文件中引入了 SystemInit 函数 (如图一),而我们此处在此处没有引入 stm32f10x.h 的固件库,所以应在 main 文件中定义一个空函数,不然将会报如下错误 (如图二)
图一 图二 -
配置端口输出数据寄存器(GPIOx_ODR)
由上图可知,要想 LED 灯PB0 亮,即将 PB0 对应的 GPIOB_ODR 置0,也就是将GPIOB_ODR0置0。
由上图可知,GPIOB_ODR地址 = 0x40010C00(GPIOB初始地址) + 0x0C(偏移地址) = 0x40010C0C
由上图知,将 GPIOB_ODR第0位置0,所以代码为:
*(unsigned int *)0x40010C0C &= ~(1 << 0);// 控制 ODR 寄存器
-
配置 PB0 的 IO 口为输出 (配置低寄存器GPIOB_CRL)
因为 stm32 的 IO 口可以输出或者输入,默认情况下为输入,如上图所示。
由上图可知,GPIOB_CRL地址 = 0x40010C00(GPIOB初始地址) + 0x00(偏移地址) = 0x40010C00
由上图,选择配置 GPIOB_CRL第四位为0001,所以代码如下:
*(unsigned int *)0x40010C00 |= (1 << (4*0));//配置IO口为输出
-
位情况下,时钟处于关闭状态,需要打开 GPIOB 的时钟,否则将不会工作;
由上图可知道,应打开 **APB2 外设时钟使能寄存器(RCC_APB2ENR) **
由上图可知,RCC_APB2ENR地址 = 0x40021000(RCC初始地址) + 0x18(偏移地址) = 0x40021018
由上图可知,要打开 GPIOB 的时钟,需将 RCC_APB2ENR 的第三位置1,所以代码应如下:
*(unsigned int *)0x40021018 |= (1 << 3); //打开GPIOB的时钟
二、使用固件库点亮LED灯
1. 新建一个工程文件,配置并引入固件库,具体操作这里将不会细诉 (此处引入的固件库版本为STM32F10x_StdPeriph_Lib_V3.5.0)
2. 由寄存器点亮 LED 灯可知,点亮 LED 灯大致应有如下步骤:
- 开启 GPIO 的端口时钟
- 选择要具体控制的 IO 口,即 pin
- 选择 IO 口输出的速率,即 speed
- 选择 IO 口输出的模式,即 mode
- 输出高/低电平
3. 新建 main.c, 写入一下内容:
#include "stm32f10x.h"
//定义宏,提高程序的可移植性
#define LED_GPIO_PIN GPIO_Pin_0
#define LED_GPIO_PORT GPIOB
#define LED_GPIO_CLK RCC_APB2Periph_GPIOB
void LED_GPIO_Config(void)
{
//定义GPIO_InitTypeDef结构体
GPIO_InitTypeDef GPIO_InitStruct;
//开启时钟
RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);
//端口配置
GPIO_InitStruct.GPIO_Pin = LED_GPIO_PIN; //配置位(I/O口)
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //配置输出速度
//GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) 参数一:端口,参数二:GPIO_InitTypeDef结构体指针
GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct); //初始化GPIO
//点亮LED
GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN);
//熄灭LED
//GPIO_SetBits(LED_G_GPIO_PORT, LED_G_GPIO_PIN);
}
int main(void)
{
// 程序来到 main 函数之前,启动文件:statup_stm32f10x_hd.s 已经调用
// SystemInit()函数把系统时钟初始化成 72MHZ
// SystemInit()在 system_stm32f10x.c 中定义
// 如果用户想修改系统时钟,可自行编写程序修改
LED_GPIO_Config();
}
C语言的标准中变量必须在函数或者块的开始部分进行 声明/定义,而不像C++中是可以在任意位置定义变量,否则将会出现如下错误。
4. 程序的说明
-
RCC_APB2PeriphClockCmd(RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) 控制 APB2 时钟函数 :
-
GPIO_InitTypeDef 将端口配置的 pin, speed,mode封装成结构体,同样 speed,mode被分别封装成枚举(enum) GPIOSpeed_TypeDef,GPIOMode_TypeDef
typedef 的作用是给已知的数据类型命名别名
-
GPIO_Init(GPIO_TypeDef GPIOx, GPIO_InitTypeDef GPIO_InitStruct)** 把配置好的端口参数写到 CRL 或者 CRH 这两个寄存器中。
-
GPIO_ResetBits(GPIO_TypeDef GPIOx, uint16_t GPIO_Pin)* 设置指定的数据端口(置0),*GPIO_SetBits(GPIO_TypeDef GPIOx, uint16_t GPIO_Pin) **清除指定的数据端口(置1)。
下一篇: vue-cli中安装方法(图文详细步骤)