跑马灯实验

在前面五篇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欧姆的电阻一共有两个作用:

  1. 起到上拉电阻的作用。
  2. 起到限流电阻的作用,防止流过发光二极管的电路过大而烧坏。

跑马灯程序设计

跑马灯实验我们主要用到的固件库文件是:

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_Hvoid 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口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);     //根据设定参数初始化GPIOB.5GPIO_SetBits(GPIOB,GPIO_Pin_5);   //PB.5 输出高GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;    //LED1-->PE.5 端口配置, 推挽输出GPIO_Init(GPIOE, &GPIO_InitStructure);   //推挽输出 ,IO口速度为50MHzGPIO_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 的初始化。

      (5)紧接着使用两个GPIO的库函数,分别为GPIO_SetBits()与GPIO_ResetBits(),在置低和置高之间延时一段时间,就实现了两个LED灯轮流转的实验目的。

【STM32学习笔记】(6)—— 跑马灯实验详解相关推荐

  1. 【stm32】stm32学习笔记(江科大)-详解stm32获取Mpu6050陀螺仪和加速度

    目录 I2C 起始条件: 终止条件: 发送一个字节 接收一个字节 接收发送应答 代码 I2C I2C.C I2C.h Mpu6050 Mpu6050.c Mpu6050.h Mpu6050Reg.h ...

  2. JDBC学习笔记02【ResultSet类详解、JDBC登录案例练习、PreparedStatement类详解】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  3. 小猫爪:i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解

    i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解 1 前言 2 FlexCAN简介 2.1 MB(邮箱)系统 2.1.1 正常模式下 2.1.2 激活了CAN FD情况下 2. ...

  4. IP地址和子网划分学习笔记之《IP地址详解》

    在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. IP地址和子网划分学习笔记相关篇章: 1.I ...

  5. 我的学习笔记——CSS背景渐变(Gradients)详解

    我的学习笔记--CSS背景渐变(Gradients)详解 一.线性渐变(Linear Gradients) 1.语法 background-image: linear-gradient(directi ...

  6. IP地址和子网划分学习笔记之《子网划分详解》

    一,子网划分概述 IP地址和子网划分学习笔记相关篇章: 1.IP地址和子网划分学习笔记之<预备知识:进制计数> 2.IP地址和子网划分学习笔记之<IP地址详解> 3.IP地址和 ...

  7. Apollo星火计划学习笔记——Apollo决策规划技术详解及实现(以交通灯场景检测为例)

    文章目录 前言 1. Apollo决策技术详解 1.1 Planing模块运行机制 1.2 Apollo决策功能的设计与实现 1.2.1参考路径 Reference Line 1.2.2 交规决策 T ...

  8. 对联智能生成的原理(学习笔记附代码实现与详解)

    文章均从个人微信公众号" AI牛逼顿"转载,文末扫码,欢迎关注! 过年的脚步越来越近,是不是该给家里贴上一副对联呢?除了买买买,有没有想过自己动手写出一副对联?来吧,撸起袖子加油干 ...

  9. redis学习笔记(2)之redis主从详解

    redis主从详解 主从详解 主从配置 拓扑 原理 数据同步 概念 复制偏移量 复制积压缓冲区 主节点运行ID Psync命令 全量复制流程 部分复制流程 心跳 缓冲大小调节 读写分离 内容来源为六星 ...

  10. redis学习笔记(7)之redis哨兵详解

    redis哨兵详解 sentinel命令 客户端连接 素材代码 思路 实现过程 哨兵的切换实现原理 发布订阅基础 哨兵的实现原理 部署建议 需要关注的问题 代码流程 内容来源为六星教育,这里仅作为学习 ...

最新文章

  1. linux运维第二讲
  2. 附pdf下载 | 入门深度学习和GAN的几本书
  3. 《CUDA C编程权威指南》——3.4 避免分支分化
  4. Linux crontab 定时任务设置
  5. dataguard如何实现切换_深度干货 | 如何借助云原生搞定Oracle备份快速恢复?
  6. mysql5.7存储json_MySQL5.7的json数据格式的问题
  7. 给apm换一个软件源
  8. 太赞了!终于有人把怎么在IDEA中使用Java热部署插件JRebel讲清楚了...
  9. 1小时教你理解HTTP,TCP,UDP,Socket,WebSocket
  10. PgSQL · 特性分析 · 金融级同步多副本分级配置方法
  11. 关于HTTP缓存的故事
  12. 日历2021年日历表|2021年日历表打印版 Excel版
  13. gbdt算法_双色球最简单的算法
  14. 高分三号卫星(GF-3)简介
  15. 沃特世推出SELECT SERIES MRT多反射飞行时间质谱平台,树立高分辨质谱性能新标杆
  16. VC之获取计算机网卡mac地址
  17. linux系统如何安装bt5,BT5硬盘安装(多系统linux + win + BT5)
  18. 冰冻三尺非一日之寒-自学篇 浅谈个人学习方法(转载)
  19. 天津大学计算机学院李晨曦,【奋斗·青春】最美的不是牵手,而是携手一起读研——访保研至天津大学的情侣学霸许贤哲与李晨曦...
  20. test 4:假币问题

热门文章

  1. 关于ubantu安装cmake
  2. 利用人性做大闸蟹,给予客户特殊的身份优越感,思维决定财富!
  3. SiliconLab zigbee host移植到IPQ 807X平台
  4. python基础之模块
  5. linux表示一序列ip,linux 下查看硬件信息(mac,IP地址,硬盘型号,序列号等)
  6. Python3:批量读取excel百度分享链接保存到百度网盘
  7. 深圳app上架-2021年上半年android ios app上架价格一览
  8. MapReduce强化实验
  9. AEC、AGC、ANS是什么意思?
  10. 2018某二本的秋招流水帐