
3.2 实现PIN设备的操作方法
1.操作方法原型
PIN设备的操作方法rt_pin_ops定义在PIN设备框架中,包含了和硬件相关的操作方法,其结构体原型如下:


(1)成员说明
1)pin_get:获取某个PIN的引脚编号。
2)pin_mode:将某个引脚初始化为对应的工作模式。
3)pin_write:设置某个引脚的输出电平。
4)pin_read:读取某个引脚的电平。
5)pin_attach_irq:中断操作,为某个引脚绑定一个中断回调函数,使能中断后,当中断到来时调用该函数。
6)pin_irq_enable:中断操作,开启或关闭中断。
7)pin_detach_irq:中断操作,脱离某个引脚的中断回调函数。
(2)引脚编号的作用
不同厂商对引脚的定义不相同,确定一个引脚所需的参数也不同,举例如下。
1)ST:引脚由PORT名和PIN名组成,PORT名为英文字母A~Z,PIN名为数字0~15,如PA0、PB5。如果使用STM32的HAL库来控制某一个引脚,需要提供如下类型的参数组合:(GPIO_TypeDef*GPIOx, uint16_t GPIO_Pin)。
2)NXP: LPC系列引脚名也是由PORT名和PIN名组成,但是PORT名由数字组成,如PIO0_0、PIO2_15。如果使用其提供的库函数来控制某一个引脚,需要提供的参数组合为(GPIO_Type*base, uint32_t port, uint32_t pin)。
若是在应用层直接使用各厂商提供的写法,则应用层代码不可能具有良好的通用性。为了使基于PIN设备驱动框架开发的应用代码兼容各个硬件平台,于是给每个引脚进行编号(0、1、2……),每个编号代表唯一一个引脚,这样基于PIN设备驱动框架开发的代码就有了良好的通用性。引脚编号可以直接使用MCU的引脚编号,也可以自定义一个引脚编号表,自定义编号表的编号顺序不一定和MCU引脚编号相同。
2.为设备定义操作方法
驱动开发者需要在驱动文件中实现这些操作方法。以STM32为例,首先使用struct rt_pin_ops实例化一个如下所示的结构,然后实现对应的函数。


3.pin_get:获取引脚编号
操作方法pin_get是用于获取某个PIN引脚编号的接口,其原型如下所示:

pin_get方法的参数及返回值如表3-1所示。
表3-1 pin_get方法的参数及返回值

注意,用户对PIN设备的操作主要是通过引脚编号,不同厂商为芯片引脚定义的名称不同,如ST的是PA0,NXP的是PIO0_0,在RT-Thread中,使用“.”作为PORT名与PIN名的分割,将它们统一为PA.0、P0.0。
驱动开发者在实现该操作方法时,需要根据传入的name参数,返回匹配的引脚编号数值。
我们来看一个获取引脚编号的示例,以下是STM32 PIN设备实现的pin_get接口的部分代码,我们可通过MCU引脚排列规律得出引脚编号。

4.pin_mode:设置引脚工作模式
操作方法pin_mode是用于设置引脚工作模式的接口,如上/下拉模式或输入/输出模式,其原型如下所示:

pin_mode方法的参数如表3-2所示。
表3-2 pin_mode方法的参数

其中,参数device表示PIN的设备句柄,因为PIN设备在实现时每一个引脚都会由引脚编号进行代替,所以device参数目前不再使用。
在表3-2中,mode的取值如下所示。驱动需要根据指定的模式对MCU的引脚进行相应的配置。驱动框架提供的模式有以下几种:

需要注意的是,mode参数会从应用层传入,驱动层需要根据以上mode的值完成对应的操作。
如下是设置引脚工作模式的示例,可根据上面的5种模式对引脚进行设置,即STM32 PIN驱动的pin_mode接口实现。

其他芯片的驱动可以参考如上代码完成pin_mode这个操作方法。
5.pin_write:设置引脚电平
操作方法pin_write是用于设置引脚的电平状态的接口,通过传入的引脚编号和引脚电平状态,对引脚进行设置,其原型如下所示:

pin_write方法的参数如表3-3所示。
表3-3 pin_write方法的参数

我们来看一个在STM32上实现pin_write接口的示例代码,首先根据引脚编号获取引脚编号映射表的索引,索引包含引脚的端口信息和引脚信息,之后调用库函数修改引脚电平状态。

6.pin_read:读取引脚电平
操作方法pin_read是用于读取引脚电平状态的接口,通过传入的引脚编号获取该引脚的状态,并将状态返回,其原型如下所示:

pin_read方法的参数及返回值如表3-4所示。
表3-4 pin_read方法的参数及返回值

我们来看一个在STM32上实现pin_read方法的示例,首先根据引脚编号获取引脚编号映射表的索引,索引包含引脚的端口信息和引脚信息,之后调用库函数读取引脚电平状态,最后返回该状态。


7.pin_attach_irq:引脚绑定中断
操作方法pin_attach_irq用于给某一个引脚绑定中断回调函数,该方法在实现时需要根据中断触发方式实现中断功能,触发方式有上升沿触发、下降沿触发等,还需绑定引脚中断回调函数,用于触发中断之后执行的动作,其原型如下所示:

pin_attach_irq方法的参数及返回值如表3-5所示。
表3-5 pin_attach_irq方法的参数及返回值

在表3-5中,引脚中断触发模式有5种宏定义值,若遇到芯片不支持的模式,在驱动中直接返回错误即可。

回调函数指针hdr需要被保存起来,例如保存在一张中断回调函数表中(方法不限于此),与引脚编号和中断触发模式等属性一一对应,待中断触发时,通过查表调用绑定的回调函数,完成中断的执行,以下是中断回调函数表。


除此之外,驱动开发人员需完成相应的中断处理函数。以CORTEX-M为例,若PA0引脚开启外部中断,并进行外部触发,则需实现如下类似代码:

下面以STM32 PIN为例讲解引脚绑定中断。
1)实现中断回调函数表(方法不限于此),如STM32最多有16条外部中断线,即最多可同时打开16个外部中断,所以中断回调函数表初始化如下所示:

2)STM32 PIN驱动pin_attach_irq接口的部分代码如下所示,首先根据pin引脚编号获取到中断回调函数表的索引,然后为回调表对应索引的元素赋值。

当使能中断,触发外部中断时,进入中断并调用回调函数。需要注意的是,进出中断时必须分别调用rt_interrupt_enter()和rt_interrupt_leave()。

8.pin_irq_enable:引脚中断使能控制
操作方法pin_irq_enable用于设置引脚的中断开关状态,其原型如下所示:

pin_irq_enable方法的参数及返回值如表3-6所示。
表3-6 pin_irq_enable方法的参数及返回值

来看一个引脚中断使能控制的示例,PIN驱动根据参数enabled开启或者关闭引脚中断。STM32 PIN驱动pin_irq_enable方法的部分代码如下所示。


9.pin_detach_irq:引脚脱离中断
操作方法pin_detach_irq是用于脱离引脚绑定的中断回调函数的接口,该方法根据传入的引脚编号,脱离该引脚已经绑定的中断回调函数,其原型如下所示:

pin_detach_irq方法的参数及返回值如表3-7所示。
表3-7 pin_detach_irq方法的参数及返回值

引脚脱离中断示例如下所示,PIN驱动根据参数引脚编号,重置对应的引脚中断回调函数表。STM32 PIN驱动的pin_detach_irq方法的部分代码如下所示。
