野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 9771|回复: 6

[STM32入门篇]第十二 十三课 GPIO输入输出控制 课后作业

[复制链接]
发表于 2022-7-17 13:10:43 | 显示全部楼层 |阅读模式
本帖最后由 GCT 于 2022-7-17 23:28 编辑

入门第十二课《GPIO输出—使用固件库点亮LED》 第十三课《GPIO输入—按键检测》 课后作业汇总

    入门篇 第十二课题目:

    野火论坛202207171047282486..png


    之前几节课讲的都是从寄存器方式“进化”到库函数方式的过程,如何自己创建库。

    ST官方也有它自己的库,对于不同型号开发板、不同内核外设文件都写进了库中,可以说很完备。

    在对于寄存器方式有了一个基本了解以后,是时候使用官方的库效率更高地进行开发了。


    按照课上讲的步骤创建了一个库函数开发模板,不得不承认创建过程比寄存器方式略微复杂,需要导入很多官方文件。

    创建方式步骤可以看火良大大的第十一课《新建工程—固件库版本》

    野火论坛202207171127191207..png

    开发者自己创建的文件都放在User文件夹里


    仍然是熟悉的点LED灯,在User文件夹创建一个文件夹led,里面创建两个文件:bsp_led.c & bsp_led.h

    (BSP:Board Support Package 板级支持包 由开发者编写,只兼容特定开发板)

    bsp_led.c:定义初始化函数。

    bsp_led.h:对于硬件的宏定义(提高可移植性)、其他宏定义、bsp_led.c中函数的申明。


    在 bsp_led.c 创建一个函数用来初始化时钟、一个函数用来初始化GPIO:

    野火论坛202207171203527781..png

    野火论坛202207171204435848..png

    里面使用的函数、结构体、参数的定义都可以在官方库对应的.c/.h文件里找到

    比如 野火论坛202207171206377864..png

    的定义就在 stm32f10x_rcc.c 中能找到定义:

    野火论坛202207171207217223..png

    输出模式的定义(stm32f10x_gpio.h)

    野火论坛202207171209439069..png

    怎么知道外设有多少函数?

    方法1.查找官方手册(英文 固件库自带 野火论坛202207171211495092..png

    方法2.看固件库文件的函数申明部分(推荐)


    stm32f10x_gpio.h包含了全部的gpio函数申明:

    野火论坛202207171215246833..png

    每个函数的定义、用什么参量、什么作用可以在stm32f10x_gpio.c找到

    野火论坛202207171219209937..png


    根据官方函数定义的注释,RCC时钟使能的参数:

    野火论坛202207171221368095..png

    时钟使能函数编写:

    野火论坛202207171222077428..png

    CLK形参意为RCC寄存器要使能相应外设所要操作的寄存器位,定义也在rcc的头文件。

    官方已经写好每一位对应什么,与参考手册一致。

    野火论坛202207171226084877..png

   

    初始化GPIO函数编写(参数:GPIO端口号(GPIO类型地址)、引脚号):

    初始化内容和之前写的完全一致:定义新的初始化结构体型,确定引脚=PIN、输出模式=推挽输出、输出速度=50MHz,初始化相应GPIO。

    野火论坛202207171229089881..png


    为了便于移植,在头文件里定义了引脚别名:

    野火论坛202207171254271685..png


    如果使用setbits和resetbits函数控制LED的开和关,如果不看参考手册无法得知用哪个开LED哪个关LED,可读性还是不够高。

    火良大大教了一招,用宏定义来定义一个新的函数,通过形参的状态量判断使用哪个setbit函数。

    状态量定义为ON=True,OFF=False。

    野火论坛202207171255459570..png

    定义完以后LED()函数就可以使用了,参数:某颜色的LED、开/关,方便了很多。


    做了这么多准备工作以后,可以开始写main.c了

    头文件引用"stm32f10x.h"(上帝之手 总宏定义)和bsp_led.h(对于led的宏定义)

    野火论坛202207171306153295..png


    将控制灯的步骤封装整合到一个函数中,并加入延时:

    野火论坛202207171304365654..png


    流水灯完成(红->绿->蓝 交替)

    野火论坛202207171305293118..png


    实现代码:

bsp_led.c:

  1. //bsp: board support package 板级支持包
  2. #include "bsp_led.h"

  3. void GPIO_RCC_Config(int CLK)
  4. {
  5.     RCC_APB2PeriphClockCmd(CLK, ENABLE);
  6. }

  7. void GPIO_LED_Config(GPIO_TypeDef* PORT, int PIN)
  8. {
  9.     GPIO_InitTypeDef  GPIO_InitStruct;
  10.    
  11.     GPIO_InitStruct.GPIO_Pin = PIN;
  12.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  13.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  14.     GPIO_Init(PORT, &GPIO_InitStruct);
  15. }
复制代码


bsp_led.h:

  1. #ifndef __BSP_LED_H
  2. #define __BSP_LED_H

  3. #include "stm32f10x.h"

  4. #define LED_Red          GPIO_Pin_5
  5. #define LED_Green        GPIO_Pin_0
  6. #define LED_Blue         GPIO_Pin_1
  7. #define LED_GPIO_PORT    GPIOB
  8. #define LED_GPIO_CLK     RCC_APB2Periph_GPIOB

  9. #define ON  1
  10. #define OFF 0

  11. // \C语言 里面叫续行符,后面不能有任何东西
  12. #define LED(color,stat) if(stat)\
  13.                             GPIO_ResetBits(LED_GPIO_PORT, color);\
  14.                         else GPIO_SetBits(LED_GPIO_PORT, color);

  15. void GPIO_RCC_Config(int CLK);
  16. void GPIO_LED_Config(GPIO_TypeDef* PORT, int PIN);

  17. #endif /*__BSP_LED_H*/
复制代码


main.c:

  1. #include "stm32f10x.h"   // 相当于51单片机中的  #include <reg51.h>
  2. #include "bsp_led.h"

  3. void LED_Blink(int LED_Color);
  4. void delay( uint32_t count);

  5. int main(void)
  6. {
  7.     // 来到这里的时候,系统的时钟已经被配置成72M。
  8.     GPIO_RCC_Config(LED_GPIO_CLK);
  9.     while(1)
  10.     {
  11.         LED_Blink(LED_Red);
  12.         LED_Blink(LED_Green);
  13.         LED_Blink(LED_Blue);
  14.     }
  15. }
  16. void LED_Blink(int LED_Color)
  17. {
  18.     GPIO_LED_Config(LED_GPIO_PORT, LED_Color);
  19.     LED(LED_Color, ON);
  20.     delay(0xFFFFFF);
  21.     LED(LED_Color, OFF);
  22.     //delay(0xFFFFFF);
  23. }
  24. void delay( uint32_t count)
  25. {
  26.     for(;count!=0;count--);
  27. }
复制代码


      第十三课题目:
       野火论坛202207171606167326..png



      在User文件夹再创建一个文件夹key,里面创建两个文件:bsp_key.c & bsp_key.h

    bsp_key.c:定义初始化函数,按键检测函数。

    bsp_key.h:对于硬件的宏定义(提高可移植性)bsp_key.c中函数的申明。


    如图为按键的原理图:

    野火论坛202207171631564041..png

    可知 按钮1 使用GPIOA 0号引脚;按钮2 使用GPIOC 13号引脚。

   

    和bsp_led.c的中的初始化相同,bsp_key也需要一个初始化函数配置输入

    野火论坛202207171743523422..png

    内容:定义新的初始化结构体类型,确定引脚=PIN、输入模式=浮空输入,初始化相应GPIO。

    按键时钟使能直接用led定义的时钟使能函数即可,不用再定义一个了。

    野火论坛202207171751599195..png


    还需定义一个函数用于检测按键

    野火论坛202207171750121456..png

    其中GPIO_ReadInputDataBit用来读取输入时输入寄存器对应位状态

    野火论坛202207171814148489..png

    先判断是否按下(寄存器对应的位为1),如果条件成立进入循环。循环的作用是判断是否松手,只有松手才跳出循环。


    返回值KEY_ON、KET_OFF的宏定义:

    野火论坛202207172258436869..png

    对于按键端口引脚的宏定义和函数的声明:

    按键1和按键2使用不同的GPIO端口,所以时钟也不同。

    野火论坛202207172302159658..png

   

    led的程序大体上不需要改变,头文件需要增加一个宏定义的函数定义:

    野火论坛202207172310587121..png

    异或是为了让相应位的状态一直取反,因为异或1会一直改变那一个位。

    其他的部分和上面的点亮LED灯部分一致

    野火论坛202207172318167281..png

    野火论坛202207172318363365..png

    这里唯一有区别的地方就是初始化LED函数最后加了一个SetBits()。

    因为指南针开发板的LED灯是置0有效,初始化以后的值就是0,所以一开始灯是亮的,需要把它关掉。

   

    主函数的初始化部分

    野火论坛202207172323378618..png

    使用|来控制多个引脚,这样就不用重复写相同的函数了

    野火论坛202207172324257943..png

    使用按键检测函数判断状态是否为开,然后执行先前定义的led状态切换。


    最终代码:

bsp_led.c

  1. #include "bsp_led.h"

  2. void GPIO_RCC_Config(int CLK)
  3. {
  4.     RCC_APB2PeriphClockCmd(CLK, ENABLE);
  5. }

  6. void GPIO_LED_Config(GPIO_TypeDef* PORT, int PIN)
  7. {
  8.     GPIO_InitTypeDef  GPIO_InitStruct;
  9.    
  10.     GPIO_InitStruct.GPIO_Pin = PIN;
  11.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  12.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  13.     GPIO_Init(PORT, &GPIO_InitStruct);
  14.    
  15.     GPIO_SetBits(PORT, PIN);
  16. }
复制代码

bsp_led.h

  1. #ifndef __BSP_LED_H
  2. #define __BSP_LED_H

  3. #include "stm32f10x.h"

  4. #define LED_Red          GPIO_Pin_5
  5. #define LED_Green        GPIO_Pin_0
  6. #define LED_Blue         GPIO_Pin_1
  7. #define LED_GPIO_PORT    GPIOB
  8. #define LED_GPIO_CLK     RCC_APB2Periph_GPIOB

  9. //^= 异或运算符 与1异或改变 与0异或不变
  10. #define LED_TOGGLE(color) {LED_GPIO_PORT->ODR ^=color;}

  11. void GPIO_RCC_Config(int CLK);
  12. void GPIO_LED_Config(GPIO_TypeDef* PORT, int PIN);

  13. #endif /*__BSP_LED_H*/
复制代码

bsp_key.c

  1. #include "bsp_key.h"


  2. void GPIO_KEY_Config(GPIO_TypeDef* PORT, int PIN)
  3. {
  4.     GPIO_InitTypeDef  GPIO_InitStruct;
  5.    
  6.     GPIO_InitStruct.GPIO_Pin = PIN;
  7.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  8.    
  9.     GPIO_Init(PORT, &GPIO_InitStruct);
  10. }

  11. uint8_t KEY_Scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
  12. {
  13.     if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==KEY_ON)
  14.     {
  15.         //松手检测
  16.         while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==KEY_ON);
  17.         return KEY_ON;
  18.     }
  19.     else
  20.         return KEY_OFF;
  21. }
复制代码

bsp_key.h

  1. #ifndef __BSP_KEY_H
  2. #define __BSP_KEY_H

  3. #include "stm32f10x.h"

  4. #define KEY_ON  1
  5. #define KEY_OFF 0

  6. #define KEY1_GPIO_PIN     GPIO_Pin_0
  7. #define KEY1_GPIO_PORT    GPIOA
  8. #define KEY1_GPIO_CLK     RCC_APB2Periph_GPIOA

  9. #define KEY2_GPIO_PIN     GPIO_Pin_13
  10. #define KEY2_GPIO_PORT    GPIOC
  11. #define KEY2_GPIO_CLK     RCC_APB2Periph_GPIOC

  12. void GPIO_KEY_Config(GPIO_TypeDef* PORT, int PIN);
  13. uint8_t KEY_Scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);

  14. #endif /*__BSP_KEY_H*/
复制代码

main.c

  1. #include "stm32f10x.h"   // 相当于51单片机中的  #include <reg51.h>
  2. #include "bsp_led.h"
  3. #include "bsp_key.h"

  4. int main(void)
  5. {
  6.     // 来到这里的时候,系统的时钟已经被配置成72M。
  7.     GPIO_RCC_Config(LED_GPIO_CLK|KEY1_GPIO_CLK|KEY2_GPIO_CLK);
  8.     GPIO_LED_Config(LED_GPIO_PORT,LED_Green|LED_Red);
  9.     GPIO_KEY_Config(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
  10.     GPIO_KEY_Config(KEY2_GPIO_PORT,KEY2_GPIO_PIN);
  11.     while(1)
  12.     {
  13.         if(KEY_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN) ==KEY_ON)
  14.             LED_TOGGLE(LED_Green);
  15.         if(KEY_Scan(KEY2_GPIO_PORT, KEY2_GPIO_PIN) ==KEY_ON)
  16.             LED_TOGGLE(LED_Red);
  17.     }
  18. }
复制代码



回复

使用道具 举报

发表于 2022-7-20 19:32:54 | 显示全部楼层
不错,向大佬看齐victory:
回复 支持 反对

使用道具 举报

发表于 2022-7-20 19:50:02 | 显示全部楼层
void LED_Blink(int LED_Color);
这里的话,LED_Color的类型是不是改成uint16_t,更合适些,毕竟最终取得是对应得寄存器。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-7-21 10:22:23 | 显示全部楼层
狂飙的蜗牛 发表于 2022-7-20 19:50
void LED_Blink(int LED_Color);
这里的话,LED_Color的类型是不是改成uint16_t,更合适些,毕竟最终取得 ...

野火论坛202207211021212653..png

野火论坛202207211022128941..png

确实,改成uint16_t 更严谨



回复 支持 反对

使用道具 举报

发表于 2022-7-21 11:23:45 | 显示全部楼层
大佬,能否给看一下这个编译的错误,卡了快1个小时了,求解决,蟹蟹
bsp_led.h.png bsp-led.c.png main.c.png
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-7-21 12:47:40 | 显示全部楼层
本帖最后由 GCT 于 2022-7-21 12:49 编辑
狂飙的蜗牛 发表于 2022-7-21 11:23
大佬,能否给看一下这个编译的错误,卡了快1个小时了,求解决,蟹蟹

...

是#define ON #define OFF 错了,后面的注释都没变绿。斜杠画反了
回复 支持 反对

使用道具 举报

发表于 2022-7-21 14:44:57 | 显示全部楼层
GCT 发表于 2022-7-21 12:47
是#define ON #define OFF 错了,后面的注释都没变绿。斜杠画反了

我擦,真没注意
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-12-24 07:00 , Processed in 0.055349 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表