引言:对于第一个实验跑马灯,就相当于代码界的打印“Holle word”,可以说非常重要和基础,理解了跑马灯实验,在后面的学习将非常有用。为此特意写下这篇文章来解释一下每个代码的作用,以及本人在理解时遇到的问题和解决思路。
1)实验平台:正点原子STM32mini开发板
2)摘自《正点原子STM32 不完全手册(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子
led.h头文件代码:
#ifndef _LED_H //如果没有定义led.h头文件
#define _LED_H //定义led.h头文件
#include "sys.h" //引入sys.h头文件
#define LED0 PAout(8) //使LED0等于PAout(8),后面用到LED0=1,则PAout(8)=1
#define LED1 PDout(2) //同理
void LED_Init(void); //自定义一个函数,用来初始化LED灯配置
#endif
led.c文件代码:
#include "led.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_Initure; //定义了一个结构体变量
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOD_CLK_ENABLE(); //开启GPIOD时钟
GPIO_Initure.Pin=GPIO_PIN_8; //PB8
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //配置PA8
GPIO_Initure.Pin=GPIO_PIN_2; //PD2
HAL_GPIO_Init(GPIOD,&GPIO_Initure); //配置PD2
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET); //PA8置1,默认初始化后灯灭
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET); //PD2置1,默认初始化后灯灭
}
下面解释一些重要的代码:
1.
GPIO_InitTypeDef GPIO_Initure; //创建一个GPIO_InitTypeDef结构体
解释:GPIO_InitTypeDef结构体的内容
typedef struct
{
uint32_t Pin; /*指定要配置的GPIO引脚。*/uint32_t Mode; /*指定选定接点的工作模式*/
uint32_t Pull; /*指定选定接点的上拉或下拉激活。*/
uint32_t Speed; /*指定选定接点的速度。*/
} GPIO_InitTypeDef;
2.
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOD_CLK_ENABLE(); //开启GPIOD时钟
对于这两个时钟是一定要开的,相当于小开关,只开有用的GPIO,无用的不开,这样可以节省芯片功耗。 因为用到了GPIOA和GPIOB,所以打开相应的GPIO串口时钟。
3.
GPIO_Initure.Pin=GPIO_PIN_8; //PB8
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //配置PA8
由于LED0和PA8串口相连,LED1和PD2串口相连,先定义串口PA8,或者先定义串口PD2都可以,在上述代码中先定义了串口PA8。
4.
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
这里介绍一下几个Mode(寄存器) 模式的选择:
GPIO_MODE_INPUT 浮空输入
GPIO_Mode_OUTPUT_OD 开漏输出
GPIO_Mode_OUTPUT_PP 推挽输出
GPIO_Mode_AF_OD 复用开漏输出
GPIO_Mode_AF_PP 复用推挽输出
LED灯使用的是推挽输出,推挽输出可以输出高低电平。
5.
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //配置PA8
此函数的原型为
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
GPIO_TypeDef为一个结构体
typedef struct
{
__IO uint32_t CRL; //端口配置寄存器
__IO uint32_t CRH; //端口配置高寄存器
__IO uint32_t IDR; //端口输入数据寄存器
__IO uint32_t ODR; //端口输出数据寄存器
__IO uint32_t BSRR; //端口位设置/清除寄存器
__IO uint32_t BRR; //端口位清除寄存器
__IO uint32_t LCKR; //端口配置锁定寄存器
} GPIO_TypeDef; //七种寄存器
GPIOx可以用来设置GPIOA或GPIOB等等,根据这两个结构体就可以把GPIO口给配置好。
同理因为LED 1与PD2相连,所以设置:
GPIO_Initure.Pin=GPIO_PIN_2; //PD2 把结构体的Pin设置为2.
HAL_GPIO_Init(GPIOD,&GPIO_Initure);
这样GPIO_Initure为PD2的串口设置。
6.
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET); //PA8置1,默认初始化后灯灭
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
GPIO写入函数。此函数前两个形参之前已经介绍过,第三个形参为一个结构体:
typedef enum
{
GPIO_PIN_RESET = 0u,
GPIO_PIN_SET
} GPIO_PinState; //枚举类型,第一个GPIO_PIN_RESET设置为0,则第二个自然为1.
main.c主函数的设置:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
int main(void)
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
delay_init(72); //初始化延时函数
LED_Init(); //初始化LED
while(1)
{
LED0=0; //LED0亮
LED1=1; //LED1灭
delay_ms(500);
LED0=1; //LED0灭
LED1=0; //LED1亮
delay_ms(500);
}
}
这样就可以完成一个跑马灯实验,大家还有什么不懂的欢迎评论。