跑马灯实验 通过代码控制 ALIENTEK MiniSTM32 开发板上的两个 LED:DS0 和 DS1 交 替闪烁,实现类似跑马灯的效果 1.STM32 IO 口简介 2.硬件设计 3.软件设计
一. STM32 IO 简介
GPIO 端口操作对应的库函数函数以及相关定义在文件stm32f10x_gpio.h 和 stm32f10x_gpio.c 中。
STM32 的 IO 口 可以由软件配置成如下 8 种模式:
1、输入浮空
2、输入上拉
3、输入下拉
4、模拟输入
5、开漏输出
6、推挽输出
7、推挽式复用功能
8、开漏复用功能
STM32 的每个 IO 端口都有 7 个寄存器来控制。他们分别是:配置模式的 2 个 32 位的端口 配置寄存器 CRL 和 CRH;2 个 32 位的数据寄存器 IDR 和 ODR;1 个 32 位的置位/复位寄存器、BSRR;一个 16 位的复位寄存器 BRR;1 个 32 位的锁存寄存器 LCKR。
在固件库开发中,操作寄存器 CRH 和 CRL 来配置 IO 口的模式和速度是通过 GPIO 初始化 函数完成:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
这个函数有两个参数,第一个参数是用来指定 GPIO,取值范围为 GPIOA~GPIOG。第二个参数为初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。下面我们看看这个结 构体的定义。首先我们打开我们光盘的跑马灯实验,然后找到 FWLib 组下面的 stm32f10x_gpio.c文件,定位到 GPIO_Init 函数体处,双击入口参数类型 GPIO_InitTypeDef 后右键选择“Go to definition of …”可以查看结构体的定义:
typedef struct
{ uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
下面我们通过一个 GPIO 初始化实例来讲解这个结构体的成员变量的含义。通过初始化结构体初始化 GPIO 的常用格式是:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度 50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);//根据设定参数配置 GPIO
第三个参数是 IO 口速度设置,有三个可选值,在 MDK 中同样是通过枚举类型定义:
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
要想知道某个 IO 口的电平状态,你只要读这个寄存器,再看某个位的状态就可以了。使 用起来是比较简单的。
在固件库中操作 IDR 寄存器读取 IO 端口数据是通过 GPIO_ReadInputDataBit 函数实现的:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
BRR 寄存器是端口位清除寄存器。该寄存器的作用跟 BSRR 的高 16 位雷同,这里就不做 详细讲解。在 STM32 固件库中,通过 BSRR 和 BRR 寄存器设置 GPIO 端口输出是通过函数 GPIO_SetBits()和函数 GPIO_ResetBits()来完成的。
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
在多数情况下,我们都是采用这两个函数来设置 GPIO 端口的输入和输出状态。比如我们要设 置 GPIOB.5 输出 1,那么方法为:
GPIO_SetBits(GPIOB, GPIO_Pin_5);
二.硬件设计
本次跑马灯用到的硬件只有 LEDDS0和DS1)。DS0 接PA8,DS1接PD2。
硬件原理如下图所示:
三.软件设计
跑马灯实验我们主要用到的固件库文件是:
stm32f10x_gpio.c /stm32f10x_gpio.h
stm32f10x_rcc.c/stm32f10x_rcc.h
misc.c/ misc.h
stm32f10x_usart /stm32f10x_usart.h
led.c代码如下
#include "led.h" //初始化 PA8和 PD2为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|
RCC_APB2Periph_GPIOD, ENABLE); //使能PA,PD端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //LED0-->PA.8 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA.8
GPIO_SetBits(GPIOA,GPIO_Pin_8); //PA.8 输出高
保存led.c代码,然后我们按同样的方法,新建一个led.h文件,也保存在LED文件夹下面。
#ifndef __LED_H
#define __LED_H
#include "sys.h" //LED端口定义
#define LED0 PAout(8) // PA8
#define LED1 PDout(2) // PD2
void LED_Init(void);//初始化
#endif
这里使用的是位带操作来实现操作某个IO口的1个位的,关于位带操作前面第五章5.2.1已经有介绍,这里不再多说。这里我们来讲解一下,操作IO口输出高低电平的三种方法。通过位带操作PA8输出高低电平从而控制LED0的方法如下:
LED0=1; //通过位带操作控制 LED0的引脚 PA8输出高电平
LED0=0; //通过位带操作控制 LED0的引脚 PA8输出低电平
库函数操作就直接调用两个函数即可控制IO输出高低电平。我们也通过直接操作寄存器BRR和BSRR的方式来操作IO口输出高低电平,方法如下:
GPIOA->BRR=GPIO_Pin_8; //设置 GPIOA.8输出 1,等同 LED0=1;
GPIOA->BSRR=GPIO_Pin_8; //设置 GPIOA.8输出 0,等同 LED0=0;
main函数代码如下:
#include "led.h" #include "delay.h"
#include "sys.h" //ALIENTEK miniSTM32开发板实验 1 //跑马灯实验
int main(void)
{ delay_init(); //延时函数初始化
LED_Init(); //初始化与 LED连接的硬件接口
while(1)
{ LED0=0;
LED1=1;
delay_ms(500); //延时 500ms
LED0=1;
LED1=0;
delay_ms(500); //延时 500ms
}
}
最后我们编译工程显示如下表示零错误零警告
新手小白若有错误还请大佬讲解,以上就是我的个人理解。