大部分的嵌入式系统都包括一些I/O设备,例如仪器上的数据显示屏、工业设备上的串口通信、数据采集设备上模拟数据采样、用于保存数据的Flash/SD卡以及网络设备上的以太网接口等,都是嵌入式系统中容易找到的I/O设备例子。
本专栏主要是分享RT-Thread是如何对不同的I/O设备进行管理的。读完本专栏,我们会了解到如何从宏观角度去管理I/O设备,为我们在编写代码时有一个参考的管理模型,从而提高我们代码的复用性、降低耦合性,从而实现换硬件不动软件的目标。.
1、《设备与驱动:I/O设备模型》
2、《设备与驱动:UART设备》
3、《设备与驱动:PIN设备》
4、《设备与驱动:ADC设备》
5、《设备与驱动:DAC设备》
6、《设备与驱动:CAN设备》
7、《设备与驱动:I2C设备》
8、《设备与驱动:PWM设备》
9、《设备与驱动:SPI设备》
目录
一、引脚简介
芯片上的引脚一般分为4类:电源、时钟、控制与I/O,I/O口在使用模式上又分为General Purpose Input Output(通用输入/输出),简称GPIO,与功能复用I/O(如SPI/I2C/UART等)。
大多数MCU的引脚都不止一个功能。不同引脚内部结构不一样,拥有的功能也不一样。可以通过不同的配置切换引脚的实际功能。通用I/O主要特性如下:
1)可编程控制中断
中断触发模式可配置,一般有5种,如下图所示:
2)输入输出模式可控制
输出模式一般包括:推挽、开漏、上拉、下拉。引脚为输出模式时,可以通过配置引脚输出的电平状态为高电平或低电平来控制连接的外围设备。
输入模式一般包括:浮空、上拉、下拉、模拟。引脚为输入模式时,可以读取引脚电平状态,即高电平或低电平。
二、访问PIN设备
应用程序可通过相关设备管理接口来访问GPIO。
2.1、获取引脚编号
RT-Thread提供的引脚编号需要和芯片的引脚号区分出来,它们并不是同一个概念,引脚编号由PIN设备驱动程序定义,和具体的芯片组相关。有三种方式可以获取引脚编号:API接口获取、宏定义或者查看PIN驱动文件。
2.1.1、使用API
通过相关接口函数获取引脚编号。
2.1.2、使用宏定义
通过BSP可以使用相关宏定义获取引脚编号。
2.1.3、查看驱动文件
通过查阅文件确认引脚编号,该文件里由一个数组存放了每个PIN脚对应的编号信息。如下述代码所示:
static const rt_uint16_t pins[] =
{
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN(2, A, 15),
__STM32_PIN(3, B, 5),
__STM32_PIN(4, B, 8),
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN(8, A, 14),
__STM32_PIN(9, B, 6),
... ...
}
以__STM32_PIN(2, A, 15)为例,表示PA15,2表示芯片引脚编号。
2.2、设置引脚模式
引脚在使用前需要先设置好输入或者输出模式。
2.3、设置引脚电平
通过相关API接口配置PIN脚的电平。
2.4、读取引脚电平
通过相关API接口读取PIN脚的电平。
2.5、绑定引脚中断回调函数
若要使用到引脚的终端功能,可以使用相关函数将某个引脚配置为某种终端触发模式并绑定一个中断回调函数到对应的引脚,当引脚中断发生时,就会执行回调函数。
2.6、使能引脚中断
绑定好引脚终端回调函数后需要调用相关函数使能引脚中断。
三、PIN设备使用示例
/*
* 程序清单:这是一个 PIN 设备使用例程
* 例程导出了 pin_beep_sample 命令到控制终端
* 命令调用格式:pin_beep_sample
* 程序功能:通过按键控制蜂鸣器对应引脚的电平状态控制蜂鸣器
*/
#include <rtthread.h>
#include <rtdevice.h>
/* 引脚编号,通过查看设备驱动文件drv_gpio.c确定 */
#ifndef BEEP_PIN_NUM
#define BEEP_PIN_NUM 35 /* PB0 */
#endif
#ifndef KEY0_PIN_NUM
#define KEY0_PIN_NUM 55 /* PD8 */
#endif
#ifndef KEY1_PIN_NUM
#define KEY1_PIN_NUM 56 /* PD9 */
#endif
void beep_on(void *args)
{
rt_kprintf("turn on beep!\n");
rt_pin_write(BEEP_PIN_NUM, PIN_HIGH);
}
void beep_off(void *args)
{
rt_kprintf("turn off beep!\n");
rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
}
static void pin_beep_sample(void)
{
/* 蜂鸣器引脚为输出模式 */
rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
/* 默认低电平 */
rt_pin_write(BEEP_PIN_NUM, PIN_LOW);
/* 按键0引脚为输入模式 */
rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
/* 绑定中断,下降沿模式,回调函数名为beep_on */
rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
/* 使能中断 */
rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);
/* 按键1引脚为输入模式 */
rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
/* 绑定中断,下降沿模式,回调函数名为beep_off */
rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, beep_off, RT_NULL);
/* 使能中断 */
rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(pin_beep_sample, pin beep sample);