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不亮。
圖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應讀取到低電平。
圖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)
評論
查看更多