前言:在裸机开发和FreeRTOS开发过程中,我们使用的GPIO操作函数都是由stm32库函数提供,如GPIO_SetBits()、GPIO_Init()、GPIO结构体对端口进行初始化--模式、速度、管脚号等操作,但是是在RTT中它也为我们封装了很多函数使用,我们既可以使用它提供给我们的函数也可以使用HAL库提供的函数
RTT提供6个函数供我们使用
rt_base_t rt_pin_get(const char *name); void rt_pin_mode(rt_base_t pin, rt_base_t mode); void rt_pin_write(rt_base_t pin, rt_base_t value); int rt_pin_read(rt_base_t pin); rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args); rt_err_t rt_pin_detach_irq(rt_int32_t pin); rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled);
1:rt_pin_mode()
设置引脚模式,引脚在使用前需要设置好输入还是输出模式
注意:引脚编号和芯片的引脚号区分开来,他们不是同一个概念,引脚编号由PIN设备驱动程序定义,和芯片相关
模式共5种:输入、输出、上拉输入、下拉输入、开漏输出
#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 /* RT-Thread Hardware PIN APIs */ 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); } FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_mode, pinMode, set hardware pin mode); 注意这里的pin是引脚编号,并不是芯片端口号,一个芯片的端口号对应得编号在drv_gpio.c中 static const struct pin_index pins[] = { #if defined(GPIOA) __STM32_PIN(0 , A, 0 ), __STM32_PIN(1 , A, 1 ), __STM32_PIN(2 , A, 2 ), __STM32_PIN(3 , A, 3 ), __STM32_PIN(4 , A, 4 ), __STM32_PIN(5 , A, 5 ), __STM32_PIN(6 , A, 6 ), __STM32_PIN(7 , A, 7 ), __STM32_PIN(8 , A, 8 ), 如果你想使用GPIOA.11的话,那么编号就是11了,但是我觉得这样写的方式不好,阅读性太差。使用#define LED0_PIN GET_PIN(A, 8)更好 __STM32_PIN(9 , A, 9 ), __STM32_PIN(10, A, 10), __STM32_PIN(11, A, 11), __STM32_PIN(12, A, 12), __STM32_PIN(13, A, 13), __STM32_PIN(14, A, 14), __STM32_PIN(15, A, 15), }
2:rt_pin_write()
设置引脚输出电平,高低电平
#define PIN_LOW 0x00 #define PIN_HIGH 0x01
void rt_pin_write(rt_base_t pin, rt_base_t value) { RT_ASSERT(_hw_pin.ops != RT_NULL); _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value); }
3:rt_pin_read()
读取某一个引脚的值
int rt_pin_read(rt_base_t pin) { RT_ASSERT(_hw_pin.ops != RT_NULL); return _hw_pin.ops->pin_read(&_hw_pin.parent, pin); } pin的获取 #define LED0_PIN GET_PIN(A, 8)--使用GET_PIN()获取,LED0_pin是我们使用的宏定义表示后面的GPIOA.8
4:rt_pin_attach_irq()
绑定引脚的中断回调函数,其实就是相当于EXTI
rt_err_t rt_pin_attach_irq(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 PIN_IRQ_MODE_RISING 0x00 #define PIN_IRQ_MODE_FALLING 0x01 #define PIN_IRQ_MODE_RISING_FALLING 0x02 #define PIN_IRQ_MODE_HIGH_LEVEL 0x03 #define PIN_IRQ_MODE_LOW_LEVEL 0x04
pin--引脚编号、、、mode--触发模式(上升沿、下降沿与stm32的exti是一样的)、、中断回调函数(中断函数自己写,不像stm32自己给我们提供)、中断函数的参数(一般不传递使用RT_NULL)、、、返回值绑定成功---RT_EOK
5: rt_pin_detach_irq()
脱离引脚的中断回调函数、、参数是pin--引脚编号
注意:引脚脱离了中断回调函数后,中断并没有关闭,还可以调用绑定中断回调函数。意思就是引脚走了,中断没有走,引脚可以以后继续绑定这个中断---添狗
rt_err_t rt_pin_detach_irq(rt_int32_t pin) { RT_ASSERT(_hw_pin.ops != RT_NULL); if(_hw_pin.ops->pin_detach_irq) { return _hw_pin.ops->pin_detach_irq(&_hw_pin.parent, pin); } return RT_ENOSYS; }
6:rt_pin_irq_enable()
第四点只是绑定了中断函数,但是还没有使能引脚中断,该函数作用就是开启引脚中断
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled) { RT_ASSERT(_hw_pin.ops != RT_NULL); if(_hw_pin.ops->pin_irq_enable) { return _hw_pin.ops->pin_irq_enable(&_hw_pin.parent, pin, enabled); } return RT_ENOSYS; } #define PIN_IRQ_DISABLE 0x00 #define PIN_IRQ_ENABLE 0x01
void KEY0_ISR(void * args)
{
rt_kprintf("enter key0_isr\r\n");
}
int main(void)
{
//引脚模式初始化
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(KEY0_PIN, PIN_MODE_INPUT_PULLUP);
//引脚电平初始化
rt_pin_write(LED0_PIN, PIN_LOW);
rt_pin_write(LED1_PIN, PIN_LOW);
//绑定引脚中断函数
rt_pin_attach_irq(KEY0_PIN, PIN_IRQ_MODE_FALLING, KEY0_ISR, RT_NULL);
//使能引脚中断
rt_pin_irq_enable(KEY0_PIN, ENABLE);
while(1);
return RT_EOK;
}