GPIO输出-----点灯(输出)和按键(输入)
来源:互联网 发布:淘宝如何变更主营类目 编辑:程序博客网 时间:2024/06/10 09:05
LED灯连接到STM32的GPIO引脚,可以通过控制低电平(0)点亮,高电平(1)熄灭。
编程要点
1).使能GPIO端口时钟
2).初始化GPIO目标引脚为推挽输出模式
3).编写简单的测试程序,控制GPIO引脚输出高、低电平
代码分析
1. LED灯引脚宏定义
将与硬件相关的部分使用宏来封装,这些定义存储在“led.h”文件中。
//R-红色#define LED1_GPIO_PORT GPIOB#define LED1_GPIO_CLK RCC_APB2Periph_GPIOB#define LED1_GPIO_PIN GPIO_Pin_5//G-绿色#define LED2_GPIO_PORT GPIOB#define LED2_GPIO_CLK RCC_APB2Periph_GPIOB#define LED2_GPIO_PIN GPIO_Pin_0// B-蓝色#define LED3_GPIO_PORT GPIOB#define LED3_GPIO_CLK RCC_APB2Periph_GPIOB#define LED3_GPIO_PIN GPIO_Pin_1
以上是用代码把控制LED的GPIO端口、引脚以及GPIO端口时钟封装起来。
注: GPIO 时钟宏“RCC_APB2Periph_GPIOB”是 STM32 标准库定义的 GPIO 端口时钟相关的宏,是用于指示寄存器位的。
一共32bit,4bit控制一个位,如果使能AFIO时钟即是((uint32_t)0x00000001),如果使能GPIOB时钟即是((uint32_t)0x00000008)。这也就是控制寄存器的位,用宏定义封装即是
#define RCC_APB2Periph_AFIO ((uint32_t)0x00000001)#define RCC_APB2Periph_GPIOA ((uint32_t)0x00000004)#define RCC_APB2Periph_GPIOB ((uint32_t)0x00000008)#define RCC_APB2Periph_GPIOC ((uint32_t)0x00000010)#define RCC_APB2Periph_GPIOD ((uint32_t)0x00000020)#define RCC_APB2Periph_GPIOE ((uint32_t)0x00000040)#define RCC_APB2Periph_GPIOF ((uint32_t)0x00000080)#define RCC_APB2Periph_GPIOG ((uint32_t)0x00000100)#define RCC_APB2Periph_ADC1 ((uint32_t)0x00000200)#define RCC_APB2Periph_ADC2 ((uint32_t)0x00000400)#define RCC_APB2Periph_TIM1 ((uint32_t)0x00000800)#define RCC_APB2Periph_SPI1 ((uint32_t)0x00001000)#define RCC_APB2Periph_TIM8 ((uint32_t)0x00002000)#define RCC_APB2Periph_USART1 ((uint32_t)0x00004000)#define RCC_APB2Periph_ADC3 ((uint32_t)0x00008000)#define RCC_APB2Periph_TIM15 ((uint32_t)0x00010000)#define RCC_APB2Periph_TIM16 ((uint32_t)0x00020000)#define RCC_APB2Periph_TIM17 ((uint32_t)0x00040000)#define RCC_APB2Periph_TIM9 ((uint32_t)0x00080000)#define RCC_APB2Periph_TIM10 ((uint32_t)0x00100000)#define RCC_APB2Periph_TIM11 ((uint32_t)0x00200000)
2.控制 LED灯亮灭状态的宏定义
/* 直接操作寄存器的方法控制 IO */#define digitalHi(p,i) {p->BSRR=i;} //输出为高电平#define digitalLo(p,i) {p->BRR=i;} //输出低电平#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态 /* 定义控制 IO 的宏 */#define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_GPIO_PIN)#define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_GPIO_PIN)#define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_GPIO_PIN)#define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_GPIO_PIN)#define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_GPIO_PIN)#define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_GPIO_PIN)#define LED3_TOGGLE digitalToggle(LED2_GPIO_PORT,LED3_GPIO_PIN)#define LED3_OFF digitalHi(LED2_GPIO_PORT,LED3_GPIO_PIN)#define LED3_ON digitalLo(LED2_GPIO_PORT,LED3_GPIO_PIN) /* 基本混色,后面高级用法使用 PWM 可混出全彩颜色,且效果更好 *///红#define LED_RED \LED1_ON;\LED2_OFF\LED3_OFF//绿#define LED_GREEN \LED1_OFF;\LED2_ON\LED3_OFF//蓝#define LED_BLUE \LED1_OFF;\LED2_OFF\LED3_ON//黄(红+绿)#define LED_YELLOW \LED1_ON;\LED2_ON\LED3_OFF//紫(红+蓝)#define LED_PURPLE \LED1_ON;\LED2_OFF\LED3_ON//青(绿+蓝)#define LED_CYAN \LED1_OFF;\LED2_ON\LED3_ON//白(红+绿+蓝)#define LED_WHITE \LED1_ON;\LED2_ON\LED3_ON//黑(全部关闭)#define LED_RGBOFF \LED1_OFF;\LED2_OFF\LED3_OFF
将用直接操作寄存器的方法控制IO口,控制 LED 亮灭的操作是直接向 BSRR、BRR 和 ODR 这三个寄存器写入控制指令来实现的,对 BSRR 写 1 输出高电平,对 BRR 写 1 输出低电平,对 ODR 寄存器某位进行异或操作可反转位的状态。再将其定义成IO口的宏(开、关、反转),基本混色代码中的“\”是 C 语言中的续行符语法,表示续行符的下一行与续行符所在的代码是同一行。代码中因为宏定义关键字“#define”只是对当前行有效,所以我们使用续行符来连接起来,以下的代码是等效的:
#define LED_YELLOW LED1_ON; LED2_ON; LED3_OFF
应用续行符的时候要注意,在“\”后面不能有任何字符(包括注释、空格),只能直接回车。
3. LED GPIO初始化函数
在“led.c”中编写LED灯的初始化函数
void LED_GPIO_Config(void){/*定义一个 GPIO_InitTypeDef 类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启 LED 相关的 GPIO 外设时钟*/RCC_APB2PeriphClockCmd( LED1_GPIO_CLK|LED2_GPIO_CLK|LED3_GPIO_CLK, ENABLE);/*选择要控制的 GPIO 引脚*/GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;/*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;/*设置引脚速率为 50MHz */GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*调用库函数,初始化 GPIO*/GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);/*选择要控制的 GPIO 引脚*/GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;/*调用库函数,初始化 GPIO*/GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);/*选择要控制的 GPIO 引脚*/GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;/*调用库函数,初始化 GPIOF*/GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);/* 关闭所有 led 灯 */GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);/* 关闭所有 led 灯 */GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);/* 关闭所有 led 灯 */GPIO_SetBits(LED3_GPIO_PORT, LED3_GPIO_PIN);}
函数执行流程如下:
(1) 使用GPIO_InitTypeDef定义 GPIO初始化结构体变量,以便下面用于存储GPIO配置。
(2) 调用库函数 RCC_APB2PeriphClockCmd 来使能 LED 灯的 GPIO端口时钟,在前面的章节中我们是直接向 RCC 寄存器赋值来使能时钟的,不如这样直观。该函数有两个输入参数,第一个参数用于指示要配置的时钟,如本例中的“RCC_ APB2Periph_GPIOB”,应用时我们使用“|”操作同时配置 3个 LED 灯的时钟;函数的第二个参数用于设置状态,可输入“Disable”关闭或“Enable”使能时钟。
(3) 向 GPIO 初始化结构体赋值,把引脚初始化成推挽输出模式,其中的 GPIO_Pin 使用宏“LEDx_GPIO_PIN”来赋值,使函数的实现方便移植。
(4) 使用以上初始化结构体的配置,调用 GPIO_Init 函数向寄存器写入参数,完成 GPIO 的初始化,这里的 GPIO 端口使用“LEDx_GPIO_PORT”宏来赋值,也是为了程序移植方便。
(5) 使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它 LED 灯使用的GPIO引脚。
(6) 使用宏控制 RGB灯默认关闭。
4. 主函数
#include "stm32f10x.h"#include "./led/bsp_led.h"#define SOFT_DELAY Delay(0x0FFFFF);void Delay(__IO u32 nCount);int main(void){/* LED 端口初始化 */LED_GPIO_Config(); while (1){LED1_ON; // 亮SOFT_DELAY;LED1_OFF; // 灭LED2_ON; // 亮SOFT_DELAY;LED2_OFF; // 灭LED3_ON; // 亮SOFT_DELAY;LED3_OFF; // 灭/*轮流显示 红绿蓝黄紫青白 颜色*/LED_RED;SOFT_DELAY;LED_GREEN;SOFT_DELAY;LED_BLUE;SOFT_DELAY;LED_YELLOW;SOFT_DELAY;LED_PURPLE;SOFT_DELAY;LED_CYAN;SOFT_DELAY;LED_WHITE;SOFT_DELAY;LED_RGBOFF;SOFT_DELAY;}}void Delay(__IO uint32_t nCount) //简单的延时函数{for (; nCount != 0; nCount--);}
点灯完毕
从按键原理图中可知,按键没被按下的时候GPIO输入的是低电平,当有按键按下,GPIO输入的是高电平。只要检测引脚的电平就能判断按键是否被按下。按键通过在点灯的基础上新建“bsp_key.c”及“bsp_key.h”文件。
注:此按键电路利用电容充放电的延时,消除了波纹,从而简化了软件的处理,软件只需要直接检测引脚的电平即可。
编程要点
- 使能 GPIO端口时钟;
- 初始化 GPIO 目标引脚为输入模式(浮空输入);
- 编写简单测试程序,检测按键的状态,实现按键控制 LED 灯。
代码分析
1. 按键引脚宏定义
// 引脚定义#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA#define KEY1_GPIO_PORT GPIOA#define KEY1_GPIO_PIN GPIO_Pin_0#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC#define KEY2_GPIO_PORT GPIOC#define KEY2_GPIO_PIN GPIO_Pin_13
2. 按键 GPIO初始化函数
void Key_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure; /*开启按键端口的时钟*/ RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);//选择按键的引脚GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN; // 设置按键的引脚为浮空输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//使用结构体初始化按键GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);//选择按键的引脚GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;//设置按键的引脚为浮空输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//使用结构体初始化按键GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);}
同为 GPIO的初始化函数,初始化的流程与“LED GPIO初始化函数”章节中的类似,主要区别是引脚的模式。函数执行流程如下:
(1) 使用GPIO_InitTypeDef定义 GPIO初始化结构体变量,以便下面用于存储GPIO配置。
(2) 调用库函数 RCC_APB2PeriphClockCmd 来使能按键的 GPIO 端口时钟,调用时我们使用“|”操作同时配置两个按键的时钟。
(3) 向 GPIO 初始化结构体赋值,把引脚初始化成浮空输入模式,其中的 GPIO_Pin 使用宏“KEYx_GPIO_PIN”来赋值,使函数的实现方便移植。由于引脚的默认电平受按键电路影响,所以设置成浮空输入。
(4) 使用以上初始化结构体的配置,调用 GPIO_Init 函数向寄存器写入参数,完成 GPIO 的初始化,这里的 GPIO 端口使用“KEYx_GPIO_PORT”宏来赋值,也是为了程序移植方便。
(5) 使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它按键检测时使用的GPIO引脚。
3. 检测按键的状态
#define KEY_ON 1 #define KEY_OFF 0 uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin) { /*检测是否有按键按下 */ if (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON ) { /*等待按键释放 */ while (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON); return KEY_ON; } else return KEY_OFF; }
在这里我们定义了一个 Key_Scan 函数用于扫描按键状态。GPIO 引脚的输入电平可通过 读 取 IDR 寄 存 器 对 应 的 数 据 位 来 感 知 , 而 STM32 标 准 库 提 供 了 库 函 数GPIO_ReadInputDataBit 来获取位状态,该函数输入 GPIO 端口及引脚号,函数返回该引脚的电平状态,高电平返回 1,低电平返回 0。Key_Scan 函数中以 GPIO_ReadInputDataBit 的返回值与自定义的宏“KEY_ON”对比,若检测到按键按下,则使用while循环持续检测按键状态,直到按键释放,按键释放后 Key_Scan函数返回一个“KEY_ON”值;若没有检测到按键按下,则函数直接返回“KEY_OFF”。若按键的硬件没有做消抖处理,需要在这个Key_Scan 函数中做软件滤波,防止波纹抖动引起误触发。
注:端口输入数据寄存器(GPIOx_IDR)(x=A…E)
4. 主函数
int main(void) { /* LED 端口初始化 */ LED_GPIO_Config(); /*初始化按键*/ Key_GPIO_Config(); /* 轮询按键状态,若按键按下则反转 LED */ while (1) { if ( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON ) { /*LED1 反转*/ LED1_TOGGLE; } if ( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON ) { /*LED2 反转*/ LED2_TOGGLE; } } }
代码中初始化 LED 灯及按键后,在 while函数里不断调用 Key_Scan函数,并判断其返回值,若返回值表示按键按下,则反转 LED 灯的状态。
按键结束。
LED初始化先设置一个结构体,开启时钟所有所需端口的时钟用“|”来连接,再给端口,引脚,输出模式赋值,将这些设置保存着结构体中,最后用赋值的内容初始化所需端口。设置完一个引脚的输出模式时,其他的如相同输出模式则不需重复设置,可以直接用结构体初始化所需端口即可。
按键初始化也是先设置一个结构体,开启时钟所有所需端口的时钟用“|”来链接,设置引脚和输入模式为浮空输入,使用结构体初始化按键。
好记性不如烂键盘。学路漫漫。学习野火STM32开发板中…………
- GPIO输出-----点灯(输出)和按键(输入)
- LPC2478 通用输入/输出口(GPIO)
- GPIO-输入/输出配置
- stm32 GPIO原理: 输入和输出控制
- STM32的GPIO口的输出:开漏输出和推挽输出(整理)
- STM32的GPIO口的输出:开漏输出和推挽输出 浮空输入
- arm11 Tiny6410 gpio驱动实现输入和输出
- 6410 gpio口输入和输出的理解
- 如何利用s3c2440的gpio实现数据输入和输出
- 树莓派3QT+wiringPI控制GPIO输入和输出
- 按键输入-GPIO输入
- Linux I/O(输入和输出)
- Python学习(一)----输入和输出
- 字符输入和输出(代码片段)
- (三)C++中的输入和输出
- python学习(3)输入和输出
- MapReduce深入理解输入和输出格式(2)-输入和输出完全总结
- stm8 GPIO按键输入
- Mac 10.9 自带apache2虚拟目录设置
- Servlet技术(四)--Servlet的服务方法抛出异常
- JSP九大内置对象
- js里面格式化日期
- hbase伪分布式的配置
- GPIO输出-----点灯(输出)和按键(输入)
- java接口不能实例化原因浅谈
- iOS中的感应器
- winform自动写入SQL数据库默认值方法
- Linux学习--gdb调试
- input输入框添加提示文字
- JQ返回php读取数据库的数据
- asp通过json调用webservice接口,并获取返回的xml数据及解析
- 将Web项目War包部署到Tomcat服务器基本步骤