引脚简介
芯片上的引脚一般分为4类:
电源、时钟、控制与I/O。
I/O在使用模式上又分为General Purpose Input Output(通用输入/输出),简称GPIO。与功能复用I/O(如SPI/I2C/UART)。
大多数MCU的引脚都不止一个功能。
不同引脚内部结构不一样,拥有的功能也不一样。可以通过不同的配置,切换引脚的实际功能。通用I/O口主要特性如下:
-
可编程控制中断:中断触发模式可配置,一般有下图所示5种中断触发模式:
-
输入输出模式可控制。
输出模式一般包括:推挽、开漏、上拉、下拉。引脚为输出模式时,可以通过配置引脚输出的电平状态控制连接的外围设备。
输入模式一般包括:浮空、上拉、下拉、模式。引脚为输入模式时,可以读取引脚的电平状态,即高电平或低电平。
访问PIN设备
应用程序可以通过提供的PIN设备管理接口来访问GPIO。
struct rt_device_pin
{
struct rt_device parent;
const struct rt_pin_ops *ops;
};
struct rt_pin_ops
{
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
int (*pin_read)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
rt_uint32_t mode, void (*hdr)(void *args), void *args);
rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
rt_base_t (*pin_get)(const char *name);
};
rt_base_t rt_pin_get(const char *name)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
RT_ASSDER(name[0] == 'P');
if(_hw_pin.ops->pin_get == RT_NULL)
return -RT_ENOSYS;
return _hw_pin.ops->pin_get(name);
}
RT-Thread提供的引脚编号和芯片的引脚号区分开来,它们并不是同一个概念,引脚编号由PIN设备驱动程序定义,和具体芯片相关。
有三种方式获取引脚编号:API接口获取、使用宏定义或者查看PIN驱动文件。
pin_number = rt_pin_get("PF.9");
#define LED0_PIN GET_PIN(F, 9)
设置引脚模式
引脚在使用前需要先设置好输入或者输出模式,通过如下函数完成:
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
}
#define PIN_MODE_OUTPUT 0x00 /* 输出 */
#define PIN_MODE_INPUT 0x01 /* 输入 */
#define PIN_MODE_INPUT_PULLUP 0x02 /* 上拉输入 */
#define PIN_MODE_INPUT_PULLDOWN 0x03 /* 下拉输入 */
#define PIN_MODE_OUTPUT_OD 0x04 /* 开漏输出 */
#define BEEP_PIN_NUM 35
int status;
rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT);
rt_pin_werite(BEEP_PIN_NUM, PIN_LOW);
status = rt_pin_read(BEEP_PIN_NUM);
绑定引脚中断回调函数
若要使用引脚的中断功能,可以使用如下函数将某个引脚配置为某种中断触发模式并绑定一个中断回调函数到对应引脚,当引脚中断发生时,就会执行回调函数:
rt_err_t rt_pin_attach_orq(rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
if(_hw_pin.ops->pin_attach_irq)
{
return _hw_pin.ops->pin_attach_irq(&_hw_pin.parent, pin, mode, hdr, args);
}
return -RT_ENOSYS;
}
#define KEY0_PIN_NUM 55
void beep_on(void *args)
{
rt_kprint("turn on beep");
rt_pin_write(BEEP_PIN_NUM, PIN_HIGH);
}
static void pin_beep_sample(void)
{
/* 按键0引脚为输入模式 */
rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
/* 绑定中断,下降沿模式 */
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);
}
使能引脚中断
绑定好引脚中断回调函数后使用下面的函数使能引脚中断:
rt_err_t rt_pin_irq_enable(re_base_t pin, rt_uint32_t enbaled);