“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第16篇文章,点击检查活动详情”

讲完UART设备之后,咱们现已了解RT-Thread I/O 设备模型了,回头看看底子的 PIN 设备。

前语

咱们学习一个 MCU 的最底子的 GPIO 口,也便是 PIN 设备模型,咱们还没有讲过,至于原因之前也说了,由于 PIN 设备的操作函数与咱们介绍的 I/O 设备模型的通用函数名称不太对应,关于新手来说先将 PIN 设备可能会让人难以了解。

所以前面的文章咱们先讲了 UART 设备模型,从源码剖析了一下 UART 设备的规划思路,从设备驱动层,和设备驱动结构层再到 I/O 设备管理层,最后到应用层,咱们都理过一遍。

有了前面的经验,本文咱们就来学习了解 RT-Thread PIN设备 。

本 RT-Thread 专栏记载的开发环境:

RT-Thread记载(一、RT-Thread 版本、RT-Thread Studio开发环境 及 配合CubeMX开发快速上手)

RT-Thread记载(二、RT-Thread内核发动流程 — 发动文件和源码剖析)

RT-Thread 设备篇系列博文链接:

RT-Thread记载(十、全面认识 RT-Thread I/O 设备模型)

RT-Thread记载(十一、I/O 设备模型之UART设备 — 源码解析)

RT-Thread记载(十二、I/O 设备模型之UART设备 — 运用测验)

一、PIN 设备模型解析

一向提到 PIN 设备有点特别,和咱们讲 I/O 设备模型时分的设备感觉有一点区其他,那么究竟怎么个特别法?咱们仍是需求具体来剖析一下:

1.1 初识 GPIO 操作函数

咱们仍是从上层的 I/O 设备管理层来开始,看看 PIN 设备管理层供给的拜访 GPIO 的接口有哪些:

函数 描绘 函数原型
rt_pin_get() 获取引脚编号 rt_base_t rt_pin_get(const char *name) 还有一种办法获取引脚编号
rt_pin_mode() 设置引脚形式 void rt_pin_mode(rt_base_t pin, rt_base_t mode);
rt_pin_write() 设置引脚电平 void rt_pin_write(rt_base_t pin, rt_base_t value)
rt_pin_read() 读取引脚电平 int rt_pin_read(rt_base_t pin)
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_pin_irq_enable() 使能引脚中止 rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled)
rt_pin_detach_irq() 脱离引脚中止回调函数 rt_err_t rt_pin_detach_irq(rt_int32_t pin)

咱们能够发现,上面的 PIN 设备管理接口的操作函数,与咱们将的通用的函数完全不相同,如下图:

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

这也是为什么咱们将设备示例的时分没有先讲 PIN 设备的原因,怕许多小伙伴刚开始不了解,那么为什么会这样呢?

1.2 PIN 设备结构

咱们经过前面的 UART 设备的剖析,现已知道了设备的底子的结构了,首先咱们来看一下 上一篇文章讲到的 UART 设备结构:

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

关于 PIN 设备来说,结构总结如下图表:

硬件 PIN 设备驱动层 drv_gpio.c PIN 设备驱动结构层操作函数 pin.c I/O 设备管理层 device.c 应用程序
硬件 stm32_pin_write rt_pin_write() rt_device_write在官方介绍中,并没有运用这个接口函数介绍,可是也能够运用 应用程序
硬件 stm32_pin_attach_irq() rt_pin_attach_irq() 应用程序
注册阐明 rt_hw_pin_init() rt_device_pin_register rt_device_register

<3 前面一向说 PIN 设备有点特别,那只不过是由于官方阐明中 应用程序调用的不是 I/O 设备管理层的接口函数,而是直接调用的 PIN 设备驱动结构层的接口函数:

(下图中的阐明有点短缺,实际上其实也能够直接运用 device.c 中的接口对 PIN 设备进行操控的,这个咱们后边会阐明)

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

知道了这一点的话,其实咱们都不需求进行过多的剖析,具体的进程剖析能够检查前面几篇博文,咱们这儿只需求对 PIN 设备驱动结构层 和 设备驱动层的接口简略的了解一下,究竟 GPIO 的操作仍是很简略的。

1.3 PIN 设备驱动结构层

经过上面的阐明,咱们知道 PIN 设备的运用是直接调用的 设备驱动结构层的接口,所以咱们来看看 PIN 设备驱动结构层的文件(pin.c)有哪些函数接口:

完成的函数

//私有的
static struct rt_device_pin _hw_pin;
static rt_size_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
static rt_size_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
static rt_err_t  _pin_control(rt_device_t dev, int cmd, void *args)
//可调用的
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data);
/* Get pin number by name,such as PA.0,P0.12 */
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);

挑一个函数简略看看:

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

函数先断言判断_hw_pin.ops这个结构体是否有效,有效的情况下就设置引脚的形式。

第一个参数是引脚的索引号(这个在咱们下面解说 PIN 设备驱动层的时分会有阐明什么是索引号), 第二个参数是引脚形式(具体的形式咱们也会再下面解说GPIO 设置时分一致阐明)。

PIN 设备操控块

在 RT-Thread 中 PIN 设备作为一个目标,那么必定有他的目标操控块,和咱们前面学习的一切的目标相同,在pin.h中有 PIN 设备的目标结构体:

/* pin device and operations for RT-Thread */
struct rt_device_pin
{
    struct rt_device parent;  // rt_device 咱们前面讲过的,一切 device 的父类
    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);
    /* TODO: add GPIO interrupt */
    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);
};

<3 PIN 设备的拜访函数都是在 PIN 设备操控块中的结构体成员 ops 中完成的,也是经过这个结构体成员与 底层驱动层相关起来 —— 在设备驱动层界说rt_pin_ops类型的变量,完成这些操作函数。

注册函数

在 PIN设备初始化的时分,rt_hw_pin_init()会调用 rt_device_pin_register 函数进行 PIN 设备的初始化。

PIN 设备注册函数,运用这个注册函数,能够绑定底层驱动层的函数,也同时将设备接口供给给上层 I/O 设备管理层:

int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
    _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; //PIN 设备不需求
    _hw_pin.parent.open         = RT_NULL; //
    _hw_pin.parent.close        = RT_NULL; //
    _hw_pin.parent.read         = _pin_read; //* 把设备的read操作绑定在pin.c的_pin_read函数 */
    _hw_pin.parent.write        = _pin_write; //同上
    _hw_pin.parent.control      = _pin_control; //同上
#endif
	/* 
	把drv_gpio.c所完成的_stm32_pin_ops绑定在_hw_pin.ops上 
	由于 PIN 设备驱动层运用的注册函数为:
	rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
	*/
    _hw_pin.ops                 = ops;
    _hw_pin.parent.user_data    = user_data;
    /*
    register a character device
    /* 将其注册进device设备结构中 */ 
    */
    rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
    return 0;
}

在注册函数中:_hw_pin.ops = ops; 这个操作就把设备驱动层完成的硬件操作函数给相关到了 设备驱动结构层。

官方阐明的 PIN 设备拜访的接口便是在 设备驱动结构层 供给的函数接口。

可是咱们看到:

    _hw_pin.parent.read         = _pin_read; //把设备的read操作绑定在pin.c的_pin_read函数 
    _hw_pin.parent.write        = _pin_write;
    _hw_pin.parent.control      = _pin_control;

这阐明咱们不只能够运用 rt_pin_read 获取 PIN 设备的值,还能够运用 rt_device_read 获取 PIN 设备的值!!!

<3 在 RT-Thread 的 PIN 设备模型中, rt_pin_read 函数和 rt_device_read 函数效果相同。

1.4 PIN 设备驱动层

PIN 设备驱动层,直接与硬件打交道的层面,关于咱们运用的 STM32 来说,里边的许多操作咱们应该都不会陌生,咱们也简略了解下里边的函数,首要的目的在于完成 PIN 设备操控块中 rt_pin_ops 成员中的几个函数:

完成的函数

static const struct pin_index *get_pin(uint8_t pin)
static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
rt_inline rt_int32_t bit2bitno(rt_uint32_t bit)
rt_inline const struct pin_irq_map *get_pin_irq_map(uint32_t pinbit)
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)
static rt_err_t stm32_pin_dettach_irq(struct rt_device *device, rt_int32_t pin)
static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
                                     rt_uint32_t enabled)
/*一个重要的结构体*/
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,
};
rt_inline void pin_irq_hdr(int irqno)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
void EXTI0_IRQHandler(void)
...//一系列的外部中止函数
...
int rt_hw_pin_init(void)

咱们简略来看一个函数,底子不需求过多的解说:

static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{
    const struct pin_index *index;
    index = get_pin(pin);
    if (index == RT_NULL)
    {
        return;
    }
    HAL_GPIO_WritePin(index->gpio, index->pin, (GPIO_PinState)value);
}

初始化函数

初始化函数尽管重要,可是简略,看一下就能了解,首先便是了解的 GPIO 时钟初始化,

然后便是调用设备注册函数,设备名称 pin ,也是在这儿界说的,如果改成其他的,在 shell 东西中运用 list_device 就会显示其他的名称了。

第二个参数,便是将设备驱动层中完成的对硬件的操作函数相关到 PIN 设备驱动结构层以供应用程序运用用。

int rt_hw_pin_init(void)
{
#if defined(__HAL_RCC_GPIOA_CLK_ENABLE)
    __HAL_RCC_GPIOA_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOB_CLK_ENABLE)
    __HAL_RCC_GPIOB_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOC_CLK_ENABLE)
    __HAL_RCC_GPIOC_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOD_CLK_ENABLE)
    __HAL_RCC_GPIOD_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOE_CLK_ENABLE)
    __HAL_RCC_GPIOE_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOF_CLK_ENABLE)
    __HAL_RCC_GPIOF_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOG_CLK_ENABLE)
    #ifdef SOC_SERIES_STM32L4
        HAL_PWREx_EnableVddIO2();
    #endif
    __HAL_RCC_GPIOG_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOH_CLK_ENABLE)
    __HAL_RCC_GPIOH_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOI_CLK_ENABLE)
    __HAL_RCC_GPIOI_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOJ_CLK_ENABLE)
    __HAL_RCC_GPIOJ_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOK_CLK_ENABLE)
    __HAL_RCC_GPIOK_CLK_ENABLE();
#endif
    return rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
}

☆引脚界说☆

在驱动文件中,关于 GPIO 引脚的界说办法(STM32为例),咱们有必要阐明一下。

与 UART 不同的是,GPIO 装备简略能够更直接相关硬件,所以 HAL 库并没有为 GPIO 供给句柄结构体描绘,在 HAL 库中描绘 GPIO 运用了两个参数:GPIO_TypeDef* GPIOxGPIO_Pin,比如:

GPIO_PinState     HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void              HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
void              HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

而在 RT-Thread 中,其界说了一个结构体 pin_index,经过一个变量即可描绘一个 GPIO,如下:

/* STM32 GPIO driver */
struct pin_index
{
    int index;
    GPIO_TypeDef *gpio;
    uint32_t pin;
};

针对这个结构体,驱动程序中给了一些弥补的操作:

/*
相当于结构体pin_index以宏界说的形式被初始化
用C言语字符串连接界说引脚信息
index   	引脚的索引号,用户可自行界说的驱动程序界说的引脚编号
gpio   		相当于HAL库中的GPIO_TypeDef 
gpio_index 	相当于HAL库中的GPIO_Pin
例如宏__STM32_PIN(0, A, 0) 就表明结构体内容为 {0, GPIOA, GPIO_PIN_0}
*/
#define __STM32_PIN(index, gpio, gpio_index)                                \
    {                                                                       \
        index, GPIO##gpio, GPIO_PIN_##gpio_index                            \
    }
//保留未运用的宏界说,有些IO口未运用,运用这个宏界说
#define __STM32_PIN_RESERVE                                                 \
    {                                                                       \
        -1, 0, 0                                                            \
    }
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 ),
    __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),
#if defined(GPIOB)
    __STM32_PIN(16,  B, 0),
    __STM32_PIN(17,  B, 1),
 //后边省掉许多......

首先宏界说#define __STM32_PIN(index, gpio, gpio_index)

其间##为C言语连接符,其功用是在带参数的宏界说中将两个子串(token)联接起来,从而形成一个新的子串,例如宏__STM32_PIN(0, A, 0) 就表明结构体内容为 {0, GPIOA, GPIO_PIN_0},就等于界说了一个pin_index结构体。

然后宏界说__STM32_PIN_RESERVE

预留的IO楼,有些IO口未运用,运用这个宏界说

接下来的结构体数组pins

pinspin_index结构体类型的数组,RT-Thread 运用 pins 数组对 一切的 GPIO 引脚进行初始化界说。

这样就相当于芯片上所支撑的 IO 口都进行了初始化界说,每一个 GPIO 都有了一个对应的索引号index。 在 RT-Thread 供给的 PIN 设备操作函数中void rt_pin_mode(rt_base_t pin, rt_base_t mode);, 他的第一个参数也不是相似 PIN设备操控块之类的数据结构,而是一个引脚索引号,便是对应的上面这个index

引脚中止的剖析和 引脚界说相似,可自行检查代码,这儿就不过多阐明。

.

二、PIN 设备操作函数

文章开头咱们尽管现已认识过 PIN 设备的操作函数,可是咱们没有对函数参数可取值做阐明,学习 API 的运用仍是老样子,直接放函数原型然后看注释。

2.1 获取 PIN 索引号办法

在咱们运用某个 GPIO 的时分,第一步要做的便是获取 GPIO 的索引号,即上文提到的index。由于对 PIN 设备的拜访操作都是经过这个索引号进行的。

在 RT-Thread 中,供给了 3种办法获取 PIN 设备索引号:

办法一: 运用函数rt_pin_get()

pin.c 文件中供给了一个函数:

rt_base_t rt_pin_get(const char *name)

里边的参数为一个姓名,那么这个姓名是什么呢?在函数声明有注释:

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

关于STM32而言,运用示例如下:

//获取索引号
pin_number = rt_pin_get("PA.9"); // pin_number 便是索引号
//设置GPIO形式
rt_pin_mode(pin_number , PIN_MODE_INPUT_PULLUP);

办法二: 运用宏界说GET_PIN

drv_common.h文件中有宏界说,能够直接获取 GPIO 的索引号:

#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)

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

关于STM32而言,运用示例如下:

//获取索引号
#define LED0_PIN        GET_PIN(B,  9)
//LED0 点亮或者熄灭
#define LED0(n)	(n ? rt_pin_write(LED0_PIN, PIN_HIGH) : rt_pin_write(LED0_PIN, PIN_LOW))

办法三: 检查驱动文件drv_gpio.c

上面解说 PIN 设备驱动层的时分提到过,一切的 GPIO 对应的索引号都会在驱动文件中界说,直接检查文件运用索引号就能够:

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

关于STM32而言,运用示例如下:

//对应驱动文件,下面的代码含义便是 设置 PA0 的形式为 PIN_MODE_INPUT_PULLUP
rt_pin_mode(0, PIN_MODE_INPUT_PULLUP);

阐明,检查驱动文件的办法并不直观。

2.2 操作函数

操作函数阐明老样子

2.2.1 设置 GPIO 形式

/*
参数 	描绘
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         	 开漏输出
*/
void rt_pin_mode(rt_base_t pin, rt_base_t mode);

2.2.2 设置/ 读取 GPIO 电平

设置引脚电平:

/*
参数 	描绘
pin 	引脚编号
value 	电平逻辑值,
value 	取值:
PIN_LOW 低电平,
PIN_HIGH 高电平
*/
void rt_pin_write(rt_base_t pin, rt_base_t value);

读取引脚电平:

/*
参数 	描绘
pin 	引脚编号
回来 	
PIN_LOW 	低电平
PIN_HIGH 	高电平
*/
int  rt_pin_read(rt_base_t pin);

2.2.3 绑定/脱离中止回调函数

绑定中止回调函数:

/*
参数 	描绘
pin 	引脚编号
mode 	中止触发形式
hdr 	中止回调函数,用户需求自行界说这个函数
args 	中止回调函数的参数,不需求时设置为 RT_NULL
回来 	——
RT_EOK 	绑定成功
错误码 	绑定失利
其间 mode 可选参数:
#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      	低电平触发 
*/
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
                             void (*hdr)(void *args), void  *args);

脱离中止回调函数:

/*
参数 	描绘
pin 	引脚编号
回来 	——
RT_EOK 	脱离成功
错误码 	脱离失利
*/
rt_err_t rt_pin_detach_irq(rt_int32_t pin);

阐明:引脚脱离了中止回调函数今后,中止并没有封闭,还能够调用绑定中止回调函数再次绑定其他回调函数。

2.2.4 使能中止

绑定好引脚中止回调函数后需求运用下面的函数使能引脚中止:

/*
参数 	描绘
pin 		引脚编号
enabled 	状况
回来 	——
RT_EOK 	使能成功
错误码 	使能失利
enabled 	可取 2 种值之一:
PIN_IRQ_ENABLE	(开启)
PIN_IRQ_DISABLE	(封闭)
*/
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled);

三、PIN 设备示例

只需了解了PIN 设备模型原理,运用起来仍是很简略的,咱们先看一下原理图

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

程序如下,测验OK,太简略所以没有什么好说的:

...
//增加这两个头文件
#include <rtdevice.h>
#include "board.h"
...
static struct rt_thread led1_thread;    //led1线程
static char led1_thread_stack[256];
static rt_thread_t key1_thread = RT_NULL; //
#define LED1_PIN        GET_PIN(D,  9)
#define LED2_PIN        GET_PIN(D,  8)
#define KEY1_PIN        GET_PIN(D,  11)
#define KEY2_PIN        GET_PIN(D,  10)
#define key1_read   rt_pin_read(KEY1_PIN)
#define LED1_ON     rt_pin_write(LED1_PIN, PIN_LOW);
#define LED1_OFF    rt_pin_write(LED1_PIN, PIN_HIGH);
#define LED2_ON     rt_pin_write(LED2_PIN, PIN_LOW);
#define LED2_OFF    rt_pin_write(LED2_PIN, PIN_HIGH);
//#define LED0(n) (n ? rt_pin_write(LED0_PIN, PIN_HIGH) : rt_pin_write(LED0_PIN, PIN_LOW))
static void led1_thread_entry(void *par){
    while(1){
        LED1_ON;
        rt_thread_mdelay(1000);
        LED1_OFF;
        rt_thread_mdelay(1000);
    }
}
static void key1_thread_entry(void *par){
    while(1){
        if(key1_read == 0){
            rt_thread_mdelay(10); //去颤动
            if(key1_read == 0){
                rt_kprintf("key1 kicked..\r\n");
             }
             while(key1_read == 0){rt_thread_mdelay(10);//去颤动
            }
        }
        rt_thread_mdelay(1);
   }
}
int main(void)
{
    MX_USART1_UART_Init();
    //    MX_GPIO_Init();  //运用设备模型不需求初始化这个
    /*装备LED管脚为输出*/
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);
    /*装备按键为输入*/
    rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT);
    /*LED默许状况*/
    rt_pin_write(LED1_PIN, 1);
    rt_pin_write(LED2_PIN, 0);
	rt_err_t rst2;
    rst2 = rt_thread_init(&led1_thread,
                        "led1_blink ",
                        led1_thread_entry,
                        RT_NULL,
                        &led1_thread_stack[0],
                        sizeof(led1_thread_stack),
                        RT_THREAD_PRIORITY_MAX -1,
                        50);
    if(rst2 == RT_EOK){
        rt_thread_startup(&led1_thread);
    }
    key1_thread = rt_thread_create("key1_control",
                                key1_thread_entry,
                                RT_NULL,
                                512,
                                RT_THREAD_PRIORITY_MAX -2,
                                50);
        /* 如果取得线程操控块,发动这个线程 */
        if (key1_thread != RT_NULL)
            rt_thread_startup(key1_thread);
  ...//后边省掉

结语

本文咱们详细的剖析了 RT-Thread I/O 设备模型之PIN设备,终究看来,运用 PIN 设备模型操作仍是特其他简略的。

其实关键的部分仍是在于了解 PIN 设备模型的原理,了解了今后运用起来也更加的得心应手。

GPIO设备尽管简略,可是文章写下来也1W多字了,即使以前对 PIN 设备有点模糊,只需看了本文,信任我们必定有拨云见日的感觉!

期望我们多多支撑!本文就到这儿,谢谢!