简要分析Thread的通用GPIO设备驱动

EDA/IC设计

1048人已加入

描述

1 本文的目的和结构

1.1 本文的目的 和背景

为了给用户提供操作GPIO的通用API,方便应用程序开发,RT-Thread中引入了通用GPIO设备驱动。并提供类似Arduino风格的API用于操作GPIO,如设置GPIO模式和输出电平、读取GPIO输入电平、配置GPIO外部中断。本文说明了如何使用RT-Thread的通用GPIO设备驱动。

1.2 本文的结构

本文首先描述了RT-Thread 通用GPIO设备驱动的基本情况,接下来给出了在正点原子STM32F4探索者开发板上验证的代码示例,最后详细描述了通用GPIO设备驱动API的参数取值和注意事项。

2 问题阐述

RT-Thread提供了一套简单的I/O设备管理框架,它把I/O设备分成了三层进行处理:应用层、I/O设备管理层、硬件驱动层。应用程序通过RT-Thread的设备操作接口获得正确的设备驱动,然后通过这个设备驱动与底层I/O硬件设备进行数据(或控制)交互。RT-Thread提供给上层应用的是一个抽象的设备操作接口,给下层设备提供的是底层驱动框架。对于通用GPIO设备,应用程序既可以通过设备操作接口访问,又可以直接通过通用GPIO设备驱动来访问。一般来说,我们都是使用第二种方式,那么如何在RT-Thread中使用通用GPIO设备驱动从而操作GPIO呢?

图A. 1 RT-Thread设备管理框架

3 问题的解决

本文基于正点原子STM32F4探索者开发板,给出了通用GPIO设备的具体应用示例代码,包含管脚输入、输出和外部中断的使用方法。由于RT-Thread上层应用API的通用性,因此这些代码不局限于具体的硬件平台,用户可以轻松将它移植到其它平台上。

正点原子 STM32F4 探索者开发板使用的MCU是 STM32F407ZET6,板载2颗LED和4个独立按键。LED分别连接到MCU的GPIOF9、GPIOF10,KEY0按键连接到GPIOE4,KEY1按键连接到GPIOE3,KEY2按键连接到GPIOE2,WK_UP按键连接到GPIOA0,2颗LED均为低电平点亮,独立按键KEY0、KEY1、KEY2按下为低电平;WK_UP按下为高电平。

图A. 2 实验用正点原子开发板

 

3.1 准备和配置工程

1. 下载 RT-Thread 源码 https://github.com/RT-Thread/rt-thread

2. 进入 rt-threadspstm32f4xx-HAL 目录,在 env 命令行中输入menuconfig,进入配置界面,使用 menuconfig 工具(学习如何使用)配置工程。

1) 在menuconfig配置界面依次选择RT-Thread Components ---》 Device Drivers ---》 Using generic GPIO device drivers,如图所示:

图A. 3 menuconfig中开启GPIO驱动

2) 输入scons --target=mdk5 -s

命令生成mdk5工程。将本应用笔记附带的main.c替换掉bsp中的main.c,如图所示:

图A. 4 加入测试代码

3) 编译,下载程序,在终端输入list_device命令可以看到pin device、类型是Miscellaneous Device就说明通用GPIO设备驱动添加成功了。

图A. 5 查看pin设备

下面是3个通用GPIO设备驱动API应用示例,分别是:GPIO输出、GPIO输入、GPIO外部中断,这些代码在正点原子STM32F4探索者开发板上验证通过。

3.2 GPIO输出配置

示例1:配置GPIO为输出,点亮LED。根据原理图,GPIOF9连接到了板载红色LED,丝印为DS0;GPIOF10连接到了板载绿色LED,丝印为DS1。GPIOF9输出低电平则点亮DS0,GPIOF9输出高电平则DS0不亮;GPIOF10输出低电平则点亮DS1,GPIOF10输出高电平则DS1不亮。

STM32F4

图A. 6 LED原理图

#define LED0 21 //PF9--21,在 drv_gpio.c 文件 pin_index pins[]中查到 PF9 编号为 21

#define LED1 22 //PF10--21,在 drv_gpio.c 文件 pin_index pins[]中查到 PF10 编号为 22

void led_thread_entry(void* parameter)

{

//设置管脚为输出模式

rt_pin_mode(LED0, PIN_MODE_OUTPUT);

//设置管脚为输出模式

rt_pin_mode(LED1, PIN_MODE_OUTPUT);

while (1)

{

//输出低电平,LED0 亮

rt_pin_write(LED0, PIN_LOW);

//输出低电平,LED1 亮

rt_pin_write(LED1, PIN_LOW);

//挂起 500ms

rt_thread_delay(rt_tick_from_millisecond(500));

//输出高电平,LED0 灭

rt_pin_write(LED0, PIN_HIGH);

//输出高电平,LED1 灭

rt_pin_write(LED1, PIN_HIGH);

//挂起 500ms

rt_thread_delay(rt_tick_from_millisecond(500));

}

}

在线程入口函数led_thread_entry里首先调用rt_pin_mode设置管脚模式为输出模式,然后就进入while(1)循环,间隔500ms调用rt_pin_write来改变GPIO输出电平。

下面是创建线程的代码:

rt_thread_t tid;//线程句柄

/* 创建led线程 */

tid = rt_thread_create(“led”,

led_thread_entry,

RT_NULL,

1024,

3,

10);

/* 创建成功则启动线程 */

if (tid != RT_NULL)

rt_thread_startup(tid);

编译、下载程序,我们将看到LED间隔500ms闪烁的现象。

3.3 GPIO输入配置

示例2:配置GPIOE3、GPIOE2为上拉输入,GPIOA0为下拉输入,检测按键信号。根据原理图,GPIOE3连接到按键KEY1,按键被按下时GPIOE3应读取到低电平,按键没有被按下时GPIOE3应读取到高电平;GPIOE2连接到按键KEY2,按键被按下时GPIOE2应读取到低电平,按键没有被按下时GPIOE2应读取到高电平;GPIOA0连接到按键WK_UP,按键被按下时GPIOA0应读取到高电平,按键没有被按下时GPIOA0应读取到低电平。

STM32F4
图A. 7 按键原理图

#define KEY1 2 //PE3--2,在 drv_gpio.c 文件 pin_index pins[]中查到 PE3 编号为 2

#define KEY2 1 //PE2--1,在 drv_gpio.c 文件 pin_index pins[]中查到 PE2 编号为 1

#define WK_UP 34 //PA0--34,在 drv_gpio.c 文件 pin_index pins[]中查到 PA0 编号为 34

void key_thread_entry(void* parameter)

{

//PE2、PE3设置上拉输入

rt_pin_mode(KEY1, PIN_MODE_INPUT_PULLUP);

rt_pin_mode(KEY2, PIN_MODE_INPUT_PULLUP);

//PA0设置为下拉输入

rt_pin_mode(WK_UP, PIN_MODE_INPUT_PULLDOWN);

while (1)

{

//检测到低电平,即按键1按下了

if (rt_pin_read(KEY1) == PIN_LOW)

{

rt_kprintf(“key1 pressed! ”);

}

//检测到低电平,即按键2按下了

if (rt_pin_read(KEY2) == PIN_LOW)

{

rt_kprintf(“key2 pressed! ”);

}

//检测到高电平,即按键wp按下了

if (rt_pin_read(WK_UP) == PIN_HIGH)

{

rt_kprintf(“WK_UP pressed! ”);

}

//挂起10ms

rt_thread_delay(rt_tick_from_millisecond(10));

}

}

在线程入口函数key_thread_entry里首先调用rt_pin_mode设置管脚GPIOE3为上拉输入模式。这样当用户按下按键KEY1时,GPIOE3读取到的电平是低电平;按键未被按下时,GPIOE3读取到的电平是高电平。然后进入while(1)循环,调用rt_pin_read读取管脚GPIOE3电平,如果读取到低电平则表示按键KEY1被按下,就在终端打印字符串“key1 pressed!”。每隔10ms检测一次按键输入情况。

下面是创建线程的代码:

rt_thread_t tid;

/* 创建key线程 */

tid = rt_thread_create(“key”,

key_thread_entry,

RT_NULL,

1024,

2,

10);

/* 创建成功则启动线程 */

if (tid != RT_NULL)

rt_thread_startup(tid);

编译、下载程序,我们按下开发板上的用户按键,终端将打印提示字符。

3.4 GPIO中断配置

示例3:配置GPIO为外部中断模式、下降沿触发,检测按键信号。根据原理图,GPIOE4连接到按键KEY0,按键被按下时MCU应探测到电平下降沿。

#define KEY0 3 //PE4--3,在gpio.c文件pin_index pins[]中查到PE4编号为3

void hdr_callback(void *args)//回调函数

{

char *a = args;//获取参数

rt_kprintf(“key0 down! %s ”,a);

}

void irq_thread_entry(void* parameter)

{

//上拉输入

rt_pin_mode(KEY0, PIN_MODE_INPUT_PULLUP);

//绑定中断,下降沿模式,回调函数名为hdr_callback

rt_pin_attach_irq(KEY0, PIN_IRQ_MODE_FALLING, hdr_callback, (void*)“callback

args”);

//使能中断

rt_pin_irq_enable(KEY0, PIN_IRQ_ENABLE);

}

在线程入口函数irq_thread_entry里首先调用rt_pin_attach_irq设置管脚GPIOE4为下降沿中断模式,并绑定了中断回调函数,还传入了字符串“callback args”。然后调用rt_pin_irq_enable使能中断,这样按键KEY0被按下时MCU会检测到电平下降沿,触发外部中断,在中断服务程序中会调用回调函数hdr_callback,在回调函数中打印传入的参数和提示信息。

下面是创建线程的代码:

rt_thread_t tid;//线程句柄

/* 创建irq线程 */

tid = rt_thread_create(“exirq”,

irq_thread_entry,

RT_NULL,

1024,

4,

10);

/* 创建成功则启动线程 */

if (tid != RT_NULL)

rt_thread_startup(tid);

编译、下载程序,我们按下按键KEY0,终端将打印提示字符。

3.5 I/O设备管理框架和通用GPIO设备联系

RT-Thread自动初始化功能依次调用rt_hw_pin_init ===》 rt_device_pin_register ===》 rt_device_register完成了GPIO硬件初始化。rt_device_register注册设备类型为RT_Device_Class_Miscellaneous,即杂类设备,从而我们就可以使用统一的API操作GPIO。

图A. 8 通用GPIO驱动和设备管理框架联系

更多关于I/O设备管理框架的说明,请参考《RT-Thread编程手册》第 6 章 I/O设备管理,在线查看地址:https://www.rt-thread.org/document/site/zh/1chapters/06-chapter_device/ 

4 参考

4.1 本文所有相关的API

要使用这些API需引用头文件

#include

4.1.1 API 列表(Summary)

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分