跑马灯实验
在前面五篇STM32学习笔记中,我们已经初步认识了STM32芯片,并且了解STM32的常用寄存器,介绍了STM32的GPIO模式,STM32工程文件,以及最终讲解了如何为STM32添加源文件和头文件的步骤。但是前面的知识只能说是理论和基础,但是非常重要,如果STM32的理论知识不扎实,会导致后续开发项目时,总感觉自己并没有学过STM32,就好像自己是一片浮萍一直飘在水上。所以我们在开发STM32的项目过程中,遇到需要学习一些理论知识时,一定要好好补充自己的理论知识,在实践中检验自己学习的效果是最好的。
GPIO简介
GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引 脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚,如型号为 STM32F103ZET6 型号的芯片有 GPIOA、GPIOB、 GPIOC、GPIOD、GPIOE、GPIOF 至 GPIOG 共 7组 GPIO,芯片一共 144 个引脚,其中 GPIO 就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能。
最基本的输出功能是由 STM32 控制引脚输出高、低电平,实现开关控制,如把 GPIO 引脚接入 到 LED 灯,那就可以控制 LED 灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或 三极管控制外部大功率电路的通断。
最基本的输入功能是检测外部输入电平,如把 GPIO 引脚连接到按键,通过电平高低区分按键是 否被按下。
在固件库中,GPIO 端口操作对应的库函数函数以及相关定义在文件 stm32f10x_gpio.h 和 stm32f10x_gpio.c 中。
跑马灯硬件连接
本章用到的硬件只有 LED(DS0 和 DS1)。其电路在 ALIENTEK 精英 STM32F103 开发板 上默认是已经连接好了的。DS0 接 PB5,DS1 接 PE5。所以在硬件上不需要动任何东西。因为LED发光二极管的阳极串联一个510欧姆的电阻与VCC3.3V电源相连。LED发光二极管的阴极与芯片的GPIO口相连。如果要控制发光二极管发光,则需要将GPIO输出的电平拉低,发光二极管就会由电流流过,电流流过时发光二极管就发光了。当两个GPIO输出的电平不断的拉高或者拉低就能实现了LED的闪烁或者跑马灯的效果了。
注意:510欧姆的电阻一共有两个作用:
- 起到上拉电阻的作用。
- 起到限流电阻的作用,防止流过发光二极管的电路过大而烧坏。
跑马灯程序设计
跑马灯实验我们主要用到的固件库文件是:
stm32f10x_gpio.c stm32f10x_gpio.h
stm32f10x_rcc.c stm32f10x_rcc.h
misc.c misc.h
stm32f10x_usart stm32f10x_usart.h
其中 stm32f10x_rcc.h 头文件在每个实验中都要引入,因为系统时钟配置函数以及相关的外设时 钟使能函数都在这个其源文件 stm32f10x_rcc.c 中。stm32f10x_usart.h 和 misc.h 头文件在我们 SYSTEM 文件夹中都需要使用到,所以每个实验都会引用。
跑马灯所要用到的库函数
1、一个GPIO初始化函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
/*作用:初始化一个或者多个IO口(同一组)的工作模式,输出类型,速度以及上下拉方式。也就是一组IO
口的4个配置寄存器。
*/
typedef struct
{
uint16_t GPIO_Pin;
//指定要配置的 GPIO 引脚。此参数可以是 @ref GPIO_pins_define的任何值
GPIOSpeed_TypeDef GPIO_Speed;
//指定所选引脚的速度。此参数可以是ref GPIOSpeed_TypeDef成员变量中的值
GPIOMode_TypeDef GPIO_Mode;
//指定选定引脚的工作模式。此参数可以是 GPIOMode_TypeDef成员变量中的值
}GPIO_InitTypeDef;
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
#define IS_GPIO_PIN(PIN) ((((PIN) & (uint16_t)0x00) == 0x00) && ((PIN) != (uint16_t)0x00))
#define IS_GET_GPIO_PIN(PIN) (((PIN) == GPIO_Pin_0) || \
((PIN) == GPIO_Pin_1) || \
((PIN) == GPIO_Pin_2) || \
((PIN) == GPIO_Pin_3) || \
((PIN) == GPIO_Pin_4) || \
((PIN) == GPIO_Pin_5) || \
((PIN) == GPIO_Pin_6) || \
((PIN) == GPIO_Pin_7) || \
((PIN) == GPIO_Pin_8) || \
((PIN) == GPIO_Pin_9) || \
((PIN) == GPIO_Pin_10) || \
((PIN) == GPIO_Pin_11) || \
((PIN) == GPIO_Pin_12) || \
((PIN) == GPIO_Pin_13) || \
((PIN) == GPIO_Pin_14) || \
((PIN) == GPIO_Pin_15))
在GPIO_InitTypeDef结构体中已经初始化了成员变量,所以在调用这个初始化函数的时候,我们首先需要对GPIO_InitTypeDef成员变量进行赋值。
但是在给GPIO_InitTypeDef的成员变量赋值时,赋值的内容需要满足对应结构体类型中的成员变量。
例如:GPIO_Mode的结构类型为GPIOMode_TypeDef,那么给它赋值的内容需要在下面这个结构体当中的成员变量中选择。
typedef enum
{
GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14,
GPIO_Mode_Out_PP = 0x10,
GPIO_Mode_AF_OD = 0x1C,
GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;
#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_AIN) || ((MODE) == GPIO_Mode_IN_FLOATING) || \
((MODE) == GPIO_Mode_IPD) || ((MODE) == GPIO_Mode_IPU) || \
((MODE) == GPIO_Mode_Out_OD) || ((MODE) == GPIO_Mode_Out_PP) || \
((MODE) == GPIO_Mode_AF_OD) || ((MODE) == GPIO_Mode_AF_PP))
GPIO_Speed的结构类型为GPIOSpeed_TypeDef,那么给它赋值的内容需要在下面这个结构体当中的成员变量中选择。
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
#define IS_GPIO_SPEED(SPEED) (((SPEED) == GPIO_Speed_10MHz) || ((SPEED) == GPIO_Speed_2MHz) || \
((SPEED) == GPIO_Speed_50MHz))
2、两个读取输入电平函数
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:读取某个GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
参数:1、GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
2、GPIO_Pin:指定要读取的端口位。
返回值:输入端口引脚值。
例如:
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输入电平
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
作用:读取某组GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
参数:GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
返回值:GPIO输入数据端口值。
例如:
GPIO_ReadOutputData(GPIOA);//读取GPIOA组中所有io口输出电平
3、两个读取输出电平函数
uint8_t GPIO_ReadOutputDataBit (GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:读取某个GPIO的输出电平。实际操作的是GPIO_ODR寄存器。
参数:1、GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
2、GPIO_Pin:指定要读取的端口位。
返回值:输出端口引脚值。
例如:
GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输出电平
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
作用:读取某组GPIO的输出电平。实际操作的是GPIO_ODR寄存器。
参数:GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
返回值:GPIO输入数据端口值。
例如:
GPIO_ReadOutputData(GPIOA);//读取GPIOA组中所有io口输出电平
4、四个设置输出电平函数
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:设置某个IO口输出为高电平(1)。实际操作BSRRL寄存器
参数:1、GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
2、GPIO_Pin:指定要写入的端口位。
返回值:无
例如:
GPIO_SetBits(GPIOA, GPIO_Pin_5);//将GPIOA.5的输出电平置为高电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:设置某个IO口输出为低电平(0)。实际操作的BSRRH寄存器。
参数:1、GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
2、GPIO_Pin:指定要写入的端口位
返回值:无
例如:
GPIO_ResetBits (GPIOA, GPIO_Pin_5);//将GPIOA.5的输出电平置为低电平
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
作用:设置或清除选定的数据端口位。
参数:1、GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
2、GPIO_Pin:指定要写入的端口位。
3、BitVal:指定要写入选定位的值。
此参数可以是BitAction枚举值之一:
typedef enum
{
Bit_RESET = 0, // Bit_RESET:清除端口引脚
Bit_SET // Bit_SET:设置端口引脚
}BitAction;
#define IS_GPIO_BIT_ACTION(ACTION) (((ACTION) == Bit_RESET) || ((ACTION) == Bit_SET))
返回值:无
例如:
GPIO_WriteBit(GPIOA, GPIO_Pin_5, Bit_RESET);// 清除GPIOA.5数据端口位。
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
作用:将数据写入指定的GPIO数据端口。
参数:1、GPIOx:其中x可以是(A..G)以选择GPIO外围设备。
2、PortVal:指定要写入端口输出数据寄存器的值。。
返回值:无
例如:
GPIO_Write(GPIOA,1);将数据“1”写入指定的GPIOA数据端口。
后面两个函数不常用,也是用来设置IO口输出电平。
跑马灯实验编写步骤:
1. 使能IO口时钟。调用函数RCC_AHB1PeriphClockCmd();
不同的外设调用的时钟使能函数可能不一样
2. 初始化 GPIO 口模式。调用GPIO_Init();把目标引脚为推挽输出模式;
3. 编写简单测试程序,控制 GPIO 引脚输出高、低电平。
跑马灯源文件和头文件中的代码
头文件中的代码:
#ifndef __LED_H
#define __LED_H
void LED_Init(void);//初始化
#endif
源文件中的代码:
#include "led.h"
//初始化PB5和PE5为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
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; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 端口配置, 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高
}
跑马灯实验中主函数里的代码
main.c里的代码:
#include "delay.h"
#include "led.h"
/**
*****************下面注视的代码是通过调用库函数来实现IO控制的方法*****************************************
int main(void)
{
delay_init(); //初始化延时函数
LED_Init(); //初始化LED端口
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_5); //LED0对应引脚GPIOB.5拉低,亮
GPIO_SetBits(GPIOE,GPIO_Pin_5); //LED1对应引脚GPIOE.5拉高,灭
delay_ms(300); //延时300ms
GPIO_SetBits(GPIOB,GPIO_Pin_5); //LED0对应引脚GPIOB.5拉高,灭 GPIO_ResetBits(GPIOE,GPIO_Pin_5); //LED1对应引脚GPIOE.5拉低,亮
delay_ms(300); //延时300ms
}
}
函数执行流程如下:
(1) 使用 GPIO_InitTypeDef 定义 GPIO 初始化结构体变量,以便下面用于存储 GPIO 配置。
(2) 调用库函数 RCC_APB2PeriphClockCmd 来使能 LED 灯的 GPIO 端口时钟,这个函数的调用和详细资料会在后面的一篇文章讲解。
(3) 向 GPIO 初始化结构体赋值,把引脚初始化成推挽输出模式。
(4) 使用以上初始化结构体的配置,调用 GPIO_Init 函数向寄存器写入参数,完成 GPIO 的初始化。文章来源:https://www.toymoban.com/news/detail-403253.html
(5)紧接着使用两个GPIO的库函数,分别为GPIO_SetBits()与GPIO_ResetBits(),在置低和置高之间延时一段时间,就实现了两个LED灯轮流转的实验目的。文章来源地址https://www.toymoban.com/news/detail-403253.html
到了这里,关于【STM32学习笔记】(6)—— 跑马灯实验详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!