欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32点亮LED灯

程序员文章站 2022-06-09 08:25:53
...

一、使用寄存器点亮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 文件中定义一个空函数,不然将会报如下错误 (如图二)

    STM32点亮LED灯
    图一
    STM32点亮LED灯
    图二
  • 配置端口输出数据寄存器(GPIOx_ODR)

    STM32点亮LED灯

    由上图可知,要想 LED 灯PB0 亮,即将 PB0 对应的 GPIOB_ODR 置0,也就是将GPIOB_ODR0置0。

    STM32点亮LED灯

    由上图可知,GPIOB_ODR地址 = 0x40010C00(GPIOB初始地址) + 0x0C(偏移地址) = 0x40010C0C

    STM32点亮LED灯

    由上图知,将 GPIOB_ODR第0位置0,所以代码为:

     *(unsigned int *)0x40010C0C &= ~(1 << 0);// 控制 ODR 寄存器
  • 配置 PB0 的 IO 口为输出 (配置低寄存器GPIOB_CRL)

    STM32点亮LED灯

    因为 stm32 的 IO 口可以输出或者输入,默认情况下为输入,如上图所示。

    STM32点亮LED灯

    由上图可知,GPIOB_CRL地址 = 0x40010C00(GPIOB初始地址) + 0x00(偏移地址) = 0x40010C00

    STM32点亮LED灯

    由上图,选择配置 GPIOB_CRL第四位为0001,所以代码如下:

       *(unsigned int *)0x40010C00 |= (1 << (4*0));//配置IO口为输出
    
  • 位情况下,时钟处于关闭状态,需要打开 GPIOB 的时钟,否则将不会工作;

    STM32点亮LED灯

    由上图可知道,应打开 **APB2 外设时钟使能寄存器(RCC_APB2ENR) **

    STM32点亮LED灯

    由上图可知,RCC_APB2ENR地址 = 0x40021000(RCC初始地址) + 0x18(偏移地址) = 0x40021018

    STM32点亮LED灯

    由上图可知,要打开 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++中是可以在任意位置定义变量,否则将会出现如下错误。

STM32点亮LED灯
4. 程序的说明
  • RCC_APB2PeriphClockCmd(RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) 控制 APB2 时钟函数 :

    STM32点亮LED灯
  • GPIO_InitTypeDef 将端口配置的 pin, speed,mode封装成结构体,同样 speed,mode被分别封装成枚举(enum) GPIOSpeed_TypeDef,GPIOMode_TypeDef

    STM32点亮LED灯

    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)。