目录

1、PIN设备说明

2、PIN设备的初始化及注册

3、PIN设备的操作

3.1 获取管脚编号的实现

3.1.1使用API

3.1.2使用宏定义

3.1.3查看驱动文件

3.2 设置引脚模式

3.3 输出控制

3.4 输入获取

3.5 中断回调的绑定

3.6 中断回调的解绑

3.7 中断的使能和禁用

3.8 中断回调函数的实现


1、PIN设备说明

rtthread通过pin.c和pin.h两个文件进行pin设备的管理。通过pin.h中的结构体rt_device_pin进行pin设备的定义,pin设备继承自设备基类rt_device,rt_device继承自rt_object基类,继承关系如下

PIN设备通过结构体的定义实现了对rt_device设备基类的继承,结构体中的成员rt_pin_ops来实现pin设备的具体操作实现。

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);
};

2、PIN设备的初始化及注册

启动阶段rtthread会根据是否进行了RT_USING_PIN定义,在hw_board_init函数中进行pin设备的初始化,在rt_hw-pin_init函数中首先进行了时钟的初始化,最终调用函数rt_device_pin_register来实现STM32的IO和pin设备的关联及设备的挂载。

/*
进行PIN设备的结构体定义
*/
static struct rt_device_pin _hw_pin;    int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{/*PIN设备的父设备,设备基类的类型进行定义,定义为RT_Device_Class_Miscellaneous,杂类*/_hw_pin.parent.type         = RT_Device_Class_Miscellaneous;/*收发回调函数为空*/_hw_pin.parent.rx_indicate  = RT_NULL;_hw_pin.parent.tx_complete  = RT_NULL;/*设备基类的初始化灯相关函数指针赋值。*/
#ifdef RT_USING_DEVICE_OPS_hw_pin.parent.ops          = &pin_ops;
#else_hw_pin.parent.init         = RT_NULL;_hw_pin.parent.open         = RT_NULL;_hw_pin.parent.close        = RT_NULL;_hw_pin.parent.read         = _pin_read;_hw_pin.parent.write        = _pin_write;_hw_pin.parent.control      = _pin_control;
#endif/*PIN设备ops,即STM32的具体实现方式进行赋值。*/_hw_pin.ops                 = ops;_hw_pin.parent.user_data    = user_data;/*设备注册*//* register a character device */rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);return 0;
}

rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL)中参数_stm32_pin_ops为rt_pin_ops,具体定义内容如下,实现了GPIO的模式配置,输入输出控制,中断控制和管脚查找等功能在STM32下得具体实现方式函数指针的定义。

const static struct rt_pin_ops _stm32_pin_ops =
{stm32_pin_mode,stm32_pin_write,stm32_pin_read,stm32_pin_attach_irq,stm32_pin_dettach_irq,stm32_pin_irq_enable,stm32_pin_get,
};

3、PIN设备的操作

PIN设备对外提供如下接口函数

函数 描述
rt_pin_get() 获取引脚编号
rt_pin_mode() 设置引脚模式
rt_pin_write() 设置引脚电平
rt_pin_read() 读取引脚电平
rt_pin_attach_irq() 绑定引脚中断回调函数
rt_pin_irq_enable() 使能引脚中断
rt_pin_detach_irq() 脱离引脚中断回调函数

3.1 获取管脚编号的实现

RT-Thread 提供的引脚编号需要和芯片的引脚号区分开来,它们并不是同一个概念,引脚编号由 PIN 设备驱动程序定义,和具体的芯片相关。管脚序号是后续其他输入输出中断函数实现的一个重要参数。STM32的驱动中对GPIOA(0-15)到GPIOx(0-15)进行了按顺序的编号操作。

RTT官方文档描述针对STM32的GPIO驱动drv_gpio.c中针对管脚编号提供了三种方式进行实现:

3.1.1使用API

此处需要注意

旧版本的drv_gpio.c文件在_stm32_pin_ops 中并没有定义函数stm32_pin_get,的实现,所以旧版本的驱动无法使用API获取到管脚编号。新建工程时,系统使用的驱动任为旧版本的

gpio驱动所以需要更新,可以从gitee进行文件下载bsp/stm32/libraries/HAL_Drivers/drv_gpio.c · RT-Thread/rt-thread - Gitee.com。具体实现方式函数如下

/*根据输入字符串的端口号A-Z,转换为数值0-25根据输入字符串的管脚号0-15,转换为数值0-15将两者结合端口号为高位,管脚号为地位
*/
static rt_base_t stm32_pin_get(const char *name)
{rt_base_t pin = 0;int hw_port_num, hw_pin_num = 0;int i, name_len;name_len = rt_strlen(name);    if ((name_len < 4) || (name_len >= 6))          //进行字符串长度验证PA.0   PA.15  最短4,最长5{return -RT_EINVAL;}if ((name[0] != 'P') || (name[2] != '.'))      //字符串第一个必须为P   第三个必须为.{return -RT_EINVAL;}if ((name[1] >= 'A') && (name[1] <= 'Z'))      //端口范围在A-Z{hw_port_num = (int)(name[1] - 'A');        //端口编号计算,A-Z转换为0-25}else{return -RT_EINVAL;}for (i = 3; i < name_len; i++)                //根据字符串的第4个进行编号转换PA.0=0  PA.15 = 15{hw_pin_num *= 10;hw_pin_num += name[i] - '0';}pin = PIN_NUM(hw_port_num, hw_pin_num);        //进行最后引脚编号的处理return pin;
}

最终调用宏定义如下来进行引脚编号的获取

#define PIN_NUM(port, no) (((((port) & 0xFu) << 4) | ((no) & 0xFu)))

测算结果如下表,后续IO以此类推

name port no result name port no result
PA.0 0 0 0 PB.0 1 0 16
PA.1 0 1 1 PB.1 1 1 17
PA.2 0 2 2 PB.2 1 2 18
PA.3 0 3 3 PB.3 1 3 19
PA.4 0 4 4 PB.4 1 4 20
PA.5 0 5 5 PB.5 1 5 21
PA.6 0 6 6 PB.6 1 6 22
PA.7 0 7 7 PB.7 1 7 23
PA.8 0 8 8 PB.8 1 8 24
PA.9 0 9 9 PB.9 1 9 25
PA.10 0 10 10 PB.10 1 10 26
PA.11 0 11 11 PB.11 1 11 27
PA.12 0 12 12 PB.12 1 12 28
PA.13 0 13 13 PB.13 1 13 29
PA.14 0 14 14 PB.14 1 14 30
PA.15 0 15 15 PB.15 1 15 31

3.1.2使用宏定义

针对STM32,RTT提供了宏定义GET_PIN来进行管脚编号的获取,再未更新drv_gpio驱动前,该定义再drv_common.h中进行了定义,更新驱动后在drv_gpio.h中也进行了定义,两者定义相同。内容如下。


//drv_common.h中的宏定义
#define __STM32_PORT(port)  GPIO##port##_BASE
#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN)//drv_gpio.h中的宏定义
#define __STM32_PORT(port)  GPIO##port##_BASE#if defined(SOC_SERIES_STM32MP1)
#define GET_PIN(PORTx,PIN) (GPIO##PORTx == GPIOZ) ? (176 + PIN) : ((rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x1000UL) )) + PIN))
#else
#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN)
#endif

如上图,对GET_PIN宏定义进行了重复定义,可以看出drv_gpio.h中对宏定义进行了预编译,包含了STM32MP1的支持。

全局搜索GET_PIN的使用情况如下

board.h、drv_gpio.h和drv_usart.c中均进行了drv_common.h的包含。仅在drv_gpio.c文件中进行了drv_gpio.h的包含。所以我们可以将drv_gpio.h中关于GET_PIN的相关宏定义进行删除(不涉及STM32MP1的使用)。来保证宏定义的唯一性。

宏定义根据参数portx进行管脚端口的地址获取,将A-Z分别转换为0-25。参数PIN为端口下得具体IO。最终转换结果为端口序号*16+IO编号。与API转换结果相同。

宏定义 PORTx 16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) ) PIN result
GET_PIN(A, 0) GPIOA_BASE D3_AHB1PERIPH_BASE + 0x0000UL 0 0 0
GET_PIN(A, 1) GPIOA_BASE D3_AHB1PERIPH_BASE + 0x0000UL 0 0 0
GET_PIN(A, 2) GPIOA_BASE D3_AHB1PERIPH_BASE + 0x0000UL 0 0 0
GET_PIN(A, 3) GPIOA_BASE D3_AHB1PERIPH_BASE + 0x0000UL 0 0 0
GET_PIN(B, 0) GPIOB_BASE D3_AHB1PERIPH_BASE + 0x0400UL 1 0 16
GET_PIN(B, 1) GPIOB_BASE D3_AHB1PERIPH_BASE + 0x0400UL 1 1 17
GET_PIN(B, 2) GPIOB_BASE D3_AHB1PERIPH_BASE + 0x0400UL 1 2 18

3.1.3查看驱动文件

旧版本的drv_gpio驱动提供了管脚与编号的对应定义,可以通过查看直接进行管脚序号的定义。

新版本驱动更新了管脚编号识别逻辑,不在提供该驱动文件查看的方式。

3.2 设置引脚模式

rtt通过rt_pin_mode进行管脚模式的配置

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);
}

最终调用的函数为pin设备类的ops下的pin_mode函数,在初始阶段该函数指针设置为了stm32_pin_mode,具体实现如下

/*1、管脚序号的识别通过宏定义#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin)))    转换为位信息#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu))             转换为0-15来进行序号识别   2、端口识别#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))来进行引脚编号到端口结构体地址的转换。3、最终调用库函数进行GPIO的配置。
*/
static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
{GPIO_InitTypeDef GPIO_InitStruct;//验证端口是否大于最大端口,是否合法if (PIN_PORT(pin) >= PIN_STPORT_MAX){return;}//配置端口IO为默认推挽输出,不上下拉,输出速度HIGHGPIO_InitStruct.Pin = PIN_STPIN(pin);GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;//根据实际传入参数的模式来进行配置if (mode == PIN_MODE_OUTPUT){/* output setting */GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;}else if (mode == PIN_MODE_INPUT){/* input setting: not pull. */GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;}else if (mode == PIN_MODE_INPUT_PULLUP){/* input setting: pull up. */GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;}else if (mode == PIN_MODE_INPUT_PULLDOWN){/* input setting: pull down. */GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLDOWN;}else if (mode == PIN_MODE_OUTPUT_OD){/* output setting: od. */GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_NOPULL;}//调用库函数进行初始化HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct);
}

3.3 输出控制

rtt通过rt_pin_write进行管脚模式的配置。

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);
}

最终调用的函数为pin设备类的ops下的pin_write函数,在初始阶段该函数指针设置为了stm32_pin_write,具体实现如下

/*1、管脚序号的识别通过宏定义#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin)))    转换为位信息#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu))             转换为0-15来进行序号识别   2、端口识别#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))来进行引脚编号到端口结构体地址的转换。3、最终调用库函数进行GPIO的配置。
*/
static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{GPIO_TypeDef *gpio_port;uint16_t gpio_pin;if (PIN_PORT(pin) < PIN_STPORT_MAX){//获取端口gpio_port = PIN_STPORT(pin);//获取IO编号gpio_pin = PIN_STPIN(pin);//库函数输出HAL_GPIO_WritePin(gpio_port, gpio_pin, (GPIO_PinState)value);}
}

3.4 输入获取

rtt通过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设备类的ops下的pin_read函数,在初始阶段该函数指针设置为了stm32_pin_read,具体实现如下

/*1、管脚序号的识别通过宏定义#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin)))    转换为位信息#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu))             转换为0-15来进行序号识别   2、端口识别#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))来进行引脚编号到端口结构体地址的转换。3、最终调用库函数进行GPIO的配置。
*/
static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
{GPIO_TypeDef *gpio_port;uint16_t gpio_pin;int value = PIN_LOW;if (PIN_PORT(pin) < PIN_STPORT_MAX){gpio_port = PIN_STPORT(pin);gpio_pin = PIN_STPIN(pin);value = HAL_GPIO_ReadPin(gpio_port, gpio_pin);}return value;
}

3.5 中断回调的绑定

rtt通过rt_pin_attach_irq进行中断回调的绑定。

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;
}

最终调用的函数为pin设备类的ops下的pin_attach_irq函数,在初始阶段该函数指针设置为了stm32_pin_attach_irq,具体实现如下

/*该函数不进行底层STM32的外部中断的实际操作。进行了pin设备的中断相关结构体赋值。
*/
static rt_err_t stm32_pin_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args)
{rt_base_t level;rt_int32_t irqindex = -1;//识别端口号是否正确if (PIN_PORT(pin) >= PIN_STPORT_MAX){return -RT_ENOSYS;}/*进行中断序号的识别1、通过管脚序号进行了中断序号的识别,首先通过PIN_STDPIN进行了位的转换2、通过函数bit2bitno实现了位序号的识别。3、实际可以通过PIN_NO来替代上述流程来进行识别*/irqindex = bit2bitno(PIN_STPIN(pin));/*判断中断序号是否合法*/if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map)){return RT_ENOSYS;}/*进行pin设备的中断模式和回调函数的赋值*/level = rt_hw_interrupt_disable();if (pin_irq_hdr_tab[irqindex].pin == pin &&pin_irq_hdr_tab[irqindex].hdr == hdr &&pin_irq_hdr_tab[irqindex].mode == mode &&pin_irq_hdr_tab[irqindex].args == args){rt_hw_interrupt_enable(level);return RT_EOK;}if (pin_irq_hdr_tab[irqindex].pin != -1){rt_hw_interrupt_enable(level);return RT_EBUSY;}pin_irq_hdr_tab[irqindex].pin = pin;pin_irq_hdr_tab[irqindex].hdr = hdr;pin_irq_hdr_tab[irqindex].mode = mode;pin_irq_hdr_tab[irqindex].args = args;rt_hw_interrupt_enable(level);return RT_EOK;
}

3.6 中断回调的解绑

rtt通过rt_pin_detach_irq进行管脚模式的配置。

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;
}

最终调用的函数为pin设备类的ops下的pin_detach_irq函数,在初始阶段该函数指针设置为了stm32_pin_dettach_irq,具体实现如下

static rt_err_t stm32_pin_dettach_irq(struct rt_device *device, rt_int32_t pin)
{rt_base_t level;rt_int32_t irqindex = -1;//识别输入端口是否合法if (PIN_PORT(pin) >= PIN_STPORT_MAX){return -RT_ENOSYS;}/*进行中断序号的识别1、通过管脚序号进行了中断序号的识别,首先通过PIN_STDPIN进行了位的转换2、通过函数bit2bitno实现了位序号的识别。3、实际可以通过PIN_NO来替代上述流程来进行识别*/irqindex = bit2bitno(PIN_STPIN(pin));/*判断中断序号是否合法*/if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map)){return RT_ENOSYS;}/*中断模式和中断管脚回调函数的复位*/level = rt_hw_interrupt_disable();if (pin_irq_hdr_tab[irqindex].pin == -1){rt_hw_interrupt_enable(level);return RT_EOK;}pin_irq_hdr_tab[irqindex].pin = -1;pin_irq_hdr_tab[irqindex].hdr = RT_NULL;pin_irq_hdr_tab[irqindex].mode = 0;pin_irq_hdr_tab[irqindex].args = RT_NULL;rt_hw_interrupt_enable(level);return RT_EOK;
}

3.7 中断的使能和禁用

rtt通过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;
}

最终调用的函数为pin设备类的ops下的pin_irq_enable函数,在初始阶段该函数指针设置为了stm32_pin_irq_enable,具体实现如下

static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,rt_uint32_t enabled)
{const struct pin_irq_map *irqmap;rt_base_t level;rt_int32_t irqindex = -1;GPIO_InitTypeDef GPIO_InitStruct;//识别IO是否合法if (PIN_PORT(pin) >= PIN_STPORT_MAX){return -RT_ENOSYS;}//使能中断if (enabled == PIN_IRQ_ENABLE){//获取判断中断序号是否合法irqindex = bit2bitno(PIN_STPIN(pin));if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map)){return RT_ENOSYS;}level = rt_hw_interrupt_disable();if (pin_irq_hdr_tab[irqindex].pin == -1){rt_hw_interrupt_enable(level);return RT_ENOSYS;}//查表获取中断序号对应的内容irqmap = &pin_irq_map[irqindex];/*中断具体配置*/GPIO_InitStruct.Pin = PIN_STPIN(pin);GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;switch (pin_irq_hdr_tab[irqindex].mode){case PIN_IRQ_MODE_RISING:GPIO_InitStruct.Pull = GPIO_PULLDOWN;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;break;case PIN_IRQ_MODE_FALLING:GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;break;case PIN_IRQ_MODE_RISING_FALLING:GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;break;}HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct);//设置中断优先级HAL_NVIC_SetPriority(irqmap->irqno, 5, 0);HAL_NVIC_EnableIRQ(irqmap->irqno);pin_irq_enable_mask |= irqmap->pinbit;rt_hw_interrupt_enable(level);}//禁用中断else if (enabled == PIN_IRQ_DISABLE){irqmap = get_pin_irq_map(PIN_STPIN(pin));if (irqmap == RT_NULL){return RT_ENOSYS;}level = rt_hw_interrupt_disable();//复位管脚HAL_GPIO_DeInit(PIN_STPORT(pin), PIN_STPIN(pin));pin_irq_enable_mask &= ~irqmap->pinbit;
#if defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0)if ((irqmap->pinbit >= GPIO_PIN_0) && (irqmap->pinbit <= GPIO_PIN_1)){if (!(pin_irq_enable_mask & (GPIO_PIN_0 | GPIO_PIN_1))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else if ((irqmap->pinbit >= GPIO_PIN_2) && (irqmap->pinbit <= GPIO_PIN_3)){if (!(pin_irq_enable_mask & (GPIO_PIN_2 | GPIO_PIN_3))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else if ((irqmap->pinbit >= GPIO_PIN_4) && (irqmap->pinbit <= GPIO_PIN_15)){if (!(pin_irq_enable_mask & (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else{HAL_NVIC_DisableIRQ(irqmap->irqno);}
#elseif ((irqmap->pinbit >= GPIO_PIN_5) && (irqmap->pinbit <= GPIO_PIN_9)){if (!(pin_irq_enable_mask & (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else if ((irqmap->pinbit >= GPIO_PIN_10) && (irqmap->pinbit <= GPIO_PIN_15)){if (!(pin_irq_enable_mask & (GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else{HAL_NVIC_DisableIRQ(irqmap->irqno);}
#endifrt_hw_interrupt_enable(level);}else{return -RT_ENOSYS;}return RT_EOK;
}

3.8 中断回调函数的实现

在使能了外部中断后,STM32的底层在中断触发后会进行中断函数的调用如下函数。

  • EXTI0_IRQHandler~EXTI4_IRQHandler
  • EXTI9_5_IRQHandler
  • EXTI15_10_IRQHandler

函数内部调用为HAL_GPIO_EXTI_IRQHandler。在该函数内部最终调用了回调函数HAL_GPIO_EXTI_Callback来进行回调函数的实现。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{pin_irq_hdr(bit2bitno(GPIO_Pin));
}

如上回调函数调用了pin_irq_hdr进行了与pin设备所绑定的回调函数的关联。

rt_inline void pin_irq_hdr(int irqno)
{if (pin_irq_hdr_tab[irqno].hdr){pin_irq_hdr_tab[irqno].hdr(pin_irq_hdr_tab[irqno].args);}
}

2.1 rtthread pin设备详解相关推荐

  1. RT-Thread pin设备驱动代码结构剖析

    硬件测试平台:正点原子潘多拉STM32L4开发板 OS内核版本:4.0.0 注意:下面的示例代码是从原子提供的例程中摘录,因此可能与最新的RT-Thread源码有出入(因为RT-Thread源码在不断 ...

  2. RT-Thread Pin设备驱动API应用介绍

    概要 本文主要涉及Pin驱动相关的API接口的简要介绍及使用示例,有兴趣深入了解Pin驱动程序框架可参考:RT-Thread pin设备驱动代码结构剖析 PIN设备的操作方法 应用程序通过RT-Thr ...

  3. 如何用树莓派连接语音模块,红外模块来控制红外设备详解

    如何用树莓派连接语音模块,红外模块来控制红外设备详解 1.硬件设备 2.软件准备 3.解码 1.红外解码流程 1.连接红外设备(与TTL串口相连) 2.获取开关红外电器的码 4.我们使用树莓派如何和W ...

  4. OSI七层参考模型及其协议和各层设备详解

    引言 我们在学习计算机网络的时候,都会接触到网络的分层模型,那么,这个分层模型是怎么来的呢? 本次博客,张大帅比将写出自己对于这个网络分层模型的详细理解 分层模型的理解 a.为什么需要分层,分层的作用 ...

  5. 芯片读取设备详解+U盘芯片flash读取分析实录_一篇看够

    当我们在分析 IOT 设备,如智能摄像头.智能门锁.智能路由器等等产品时,采用传统的安全检测手段,如对 APP 的逆向.云端服务器的渗透测试.产品通信的抓包等方式可以获得部分的信息,但如果需要深入分析 ...

  6. 鸿蒙最新功能及承载设备详解:HarmonyOS 2及华为全场景新品发布会全纪录

    6月2日,华为联手CSDN直播了"HarmonyOS 2及华为全场景新品发布会",老猿全程观看直播,并进行了回看,力争将发布会的核心内容在本文中概要性地呈现. 一.一生万物 万物归 ...

  7. RT-Thread记录(十三、I/O 设备模型之PIN设备)

    讲完UART设备之后,我们已经熟悉RT-Thread I/O 设备模型了,回头看看基本的 PIN 设备. 目录 前言 一.PIN 设备模型解析 1.1 初识 GPIO 操作函数 1.2 PIN 设备框 ...

  8. RT-Thread学习笔记——PIN 设备

    前言 本文主要学习RT-Thread的设备驱动框架之PIN 设备,这里以及后面更新的博客内容将不会详细介绍I/O 设备模型,当学习PIN 设备以及其他设备需要对I/O 设备模型有所了解,请和我一样刚学 ...

  9. c++获取串口设备名称_RTThread PIN设备学习笔记

    前面我们学习了RTT的UART设备的使用,不得不说真的超级给力呀,不到100行秒杀任何MCU最原始的串口编程模式,不得不感叹RTT发展如此强大,文章链接: RT-Thread UART设备驱动框架初体 ...

最新文章

  1. HR问:“你能熬夜吗?”,你会如何回答?
  2. ORACLE 分区表 PARTITION table
  3. 数据可视化 -- Python
  4. flink streamGraph生成
  5. 自然语言处理项目之新闻主题分类Python实现
  6. linux纯文字界面,Linux入门 Part1: 使用控制台(1)-纯文本界面
  7. 中位数和顺序统计量(第9章)
  8. Pc端微信加群的测试用例
  9. cout输出精确小数点
  10. ubuntu安装cuda11.2
  11. vue省市区三级联动(行政区划代码)
  12. jQuery版本低引起的漏洞——CVE-2020-11022/CVE-2020-11023
  13. 分享一份软件测试面试指南
  14. 微信小程序python选择题_微信小程序头脑风暴2答题辅助
  15. 环保数采仪环境污染在线监控设备 上传监控平台
  16. 数据挖掘十大算法(九):朴素贝叶斯原理、实例与Python实现
  17. 微软数据中心将到南非!AWS也将要跟进
  18. 使用手机号登录、注册、重置密码
  19. 自定义输入矩阵,顺时针输出或顺时针旋转后输出
  20. 文案是否有违禁词查询

热门文章

  1. java使用sftp上传(文件)图片到服务器中
  2. 怎么在电脑上玩赛尔号星球大战手游 赛尔号星球大战模拟器玩法教程
  3. cutterman网盘免费下载
  4. USB2.0协议规范详解
  5. Xcode非ARC项目转ARC,ARC项目中支持非ARC也就是共存
  6. 基于改进NSGA-Ⅱ算法的开关磁阻电机再生制动优化控制方法
  7. 厄米特矩阵(Hermittan Matrix)
  8. 字节跳动或将强制实行1075工作制,加班需申请
  9. PDF如何编辑,怎么使用PDF裁剪页面工具
  10. 让数据分析极速统一,阿里云和StarRocks一起干了件大事