硬件:STM32F103ZET6、ST-LINK、usb轉(zhuǎn)串口工具、4個LED燈、1個蜂鳴器、4個1k電阻、2個按鍵、面包板、杜邦線
前言
在嵌入式系統(tǒng)中,GPIO是最常用的一種設(shè)備,在RT-Thread操作系統(tǒng)中,把GPIO命名為PIN設(shè)備。
一、PIN設(shè)備介紹
RT-Thread通過PIN設(shè)備對芯片的GPIO引腳進行管理,應(yīng)用程序可以通過其提供的一組PIN設(shè)備管理接口來操作GPIO,PIN設(shè)備管理接口如表所示
接口 | 描述 |
---|---|
rt_pin_get() | 獲取引腳編號 |
rt_pin_mode() | 設(shè)置引腳模式 |
rt_pin_write() | 設(shè)置引腳電平 |
rt_pin_read() | 讀取引腳電平 |
rt_pin_attach_irq() | 綁定引腳中斷回調(diào)函數(shù) |
rt_pin_irq_enable() | 使能引腳中斷 |
rt_pin_detach_irq() | 脫離引腳中斷回調(diào)函數(shù) |
1. 引腳編號獲取
引腳變化和芯片的引腳號不是同一概念。RT-Thread的PIN設(shè)備驅(qū)動程序把芯片的不同引腳賦予不同的編號,操作PIN設(shè)備時,需要使用引腳編號來指定對哪個引腳進行操作。
可通過三種方法獲得引腳編號:
(1)API法
利用rt_pin_get() 函數(shù)來獲取引腳編號,例如獲取PD9的引腳編號,則可以使用pin_number = rt_pin_get("PD.9")
(2)宏定義法
對于STM32芯片,可以使用GET_PIN(PORTx,PIN)獲取引腳編號,如硬件的PD9用于驅(qū)動LED_R_PIN,則可以把宏LED_R_PIN定義為相應(yīng)的引腳編號,如下: #define LED_R_PIN GET_PIN(D, 9)
(3)查看驅(qū)動文件
在drivers/drv_gpio.c中,pin[]數(shù)組定義了硬件平臺的GPIO引腳編號,通過查看該數(shù)組,得到引腳PD9的編號為57。
具體數(shù)組代碼如下:
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),
__STM32_PIN(18, B, 2),
__STM32_PIN(19, B, 3),
__STM32_PIN(20, B, 4),
__STM32_PIN(21, B, 5),
__STM32_PIN(22, B, 6),
__STM32_PIN(23, B, 7),
__STM32_PIN(24, B, 8),
__STM32_PIN(25, B, 9),
__STM32_PIN(26, B, 10),
__STM32_PIN(27, B, 11),
__STM32_PIN(28, B, 12),
__STM32_PIN(29, B, 13),
__STM32_PIN(30, B, 14),
__STM32_PIN(31, B, 15),
#if defined(GPIOC)
__STM32_PIN(32, C, 0),
__STM32_PIN(33, C, 1),
__STM32_PIN(34, C, 2),
__STM32_PIN(35, C, 3),
__STM32_PIN(36, C, 4),
__STM32_PIN(37, C, 5),
__STM32_PIN(38, C, 6),
__STM32_PIN(39, C, 7),
__STM32_PIN(40, C, 8),
__STM32_PIN(41, C, 9),
__STM32_PIN(42, C, 10),
__STM32_PIN(43, C, 11),
__STM32_PIN(44, C, 12),
__STM32_PIN(45, C, 13),
__STM32_PIN(46, C, 14),
__STM32_PIN(47, C, 15),
#if defined(GPIOD)
__STM32_PIN(48, D, 0),
__STM32_PIN(49, D, 1),
__STM32_PIN(50, D, 2),
__STM32_PIN(51, D, 3),
__STM32_PIN(52, D, 4),
__STM32_PIN(53, D, 5),
__STM32_PIN(54, D, 6),
__STM32_PIN(55, D, 7),
__STM32_PIN(56, D, 8),
__STM32_PIN(57, D, 9),
__STM32_PIN(58, D, 10),
__STM32_PIN(59, D, 11),
__STM32_PIN(60, D, 12),
__STM32_PIN(61, D, 13),
__STM32_PIN(62, D, 14),
__STM32_PIN(63, D, 15),
2. 設(shè)置引腳的輸入/輸出模式
宏定義 | 描述 |
---|---|
PIN_MODE_OUTPUT | 推挽輸出 |
PIN_MODE_OUTPUT_OD | 開漏輸出,硬件需要外接上拉電阻 |
PIN_MODE_INPUT | 輸入 |
PIN_MODE_INPUT_PULLUP | 上拉輸入,引腳懸空時為高電平 |
PIN_MODE_INPUT_PULLDOWN | 下拉輸入,引腳懸空時為低電平 |
引腳可通過以下函數(shù)設(shè)置輸入/輸出模式: |
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
pin:引腳編號
mode:輸入/輸出模式所對應(yīng)的宏
#define LED_R_PIN GET_PIN(D, 9)
rt_pin_mode(LED_R_PIN, PIN_MODE_OUTPUT);
3. 設(shè)置引腳的電平值
設(shè)置函數(shù)如下:void rt_pin_write(rt_base_t pin, rt_base_t value)
pin:引腳編號
value:高電平為PIN_HIGH;低電平為PIN_LOW
4. 讀取引腳的電平值
設(shè)置函數(shù)如下:int rt_pin_read(rt_base_t pin)
pin:引腳編號
返回值:高電平為PIN_HIGH;低電平為PIN_LOW
5. 綁定引腳中斷回調(diào)函數(shù)
引腳作為中斷輸入時,需要設(shè)置引腳的中斷觸發(fā)方式,引腳的中斷觸發(fā)模式有5種,RT-Thread中分別有5個宏與之對應(yīng),具體如下:
宏定義 | 描述 |
---|---|
PIN_IQR_MODE_RISING | 上升沿觸發(fā) |
PIN_IQR_MODE_FALLING | 下降沿觸發(fā) |
PIN_IQR_MODE_RISING_FALLING | 雙邊沿觸發(fā) |
PIN_IQR_MODE_HIGH_LEVEL | 高電平觸發(fā) |
PIN_IQR_MODE_LOW_LEVEL | 低電平觸發(fā) |
當(dāng)引腳產(chǎn)生中斷時,通過中斷回調(diào)函數(shù)響應(yīng)中斷。綁定中斷回調(diào)函數(shù)到引腳后,引腳有中斷發(fā)生,就會執(zhí)行對應(yīng)的中斷回調(diào)函數(shù)。
具體函數(shù)如下:rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args)
pin:引腳編號
mode:中斷觸發(fā)模式
hdr:中斷回調(diào)函數(shù)指針,用戶需要自定義這個函數(shù)
args:中斷回調(diào)函數(shù)的參數(shù),不需要設(shè)置時為RT_NULL
返回:綁定成功為RT_EOK;失敗產(chǎn)生錯誤碼
6. 脫離引腳中斷回調(diào)函數(shù)
如不希望響應(yīng)中斷,或者想更換中斷響應(yīng)函數(shù),則可以使用如下脫離引腳中斷回調(diào)函數(shù):rt_err_t rt_pin_detach_irq(rt_int32_t pin)
pin:引腳編號
返回:脫離成功為RT_EOK;失敗產(chǎn)生錯誤碼
7. 使能中斷
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled)
pin:引腳編號
enable:PIN_IRQ_ENABLE(開啟),PIN_IRQ_DISABLE(關(guān)閉)
返回:使能成功為RT_EOK;失敗產(chǎn)生錯誤碼
二、任務(wù)1:LED燈雙閃控制
1. 任務(wù)描述
控制LED1、LED2輪流閃爍。通過本任務(wù),學(xué)習(xí)PIN設(shè)備輸出功能的設(shè)置方法。
2. 代碼編寫
在項目的main.c文件中,編寫如下代碼:
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"
/* 定義左右轉(zhuǎn)向燈的控制引腳 */
#define LED_L_PIN GET_PIN(D, 8)
#define LED_R_PIN GET_PIN(D, 9)
int main(void)
{
/* 把引腳設(shè)置為推拉輸出模式 */
rt_pin_mode(LED_L_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(LED_R_PIN, PIN_MODE_OUTPUT);
while (1){
rt_pin_write(LED_L_PIN, PIN_HIGH);//滅左燈
rt_pin_write(LED_R_PIN, PIN_LOW);//亮右燈
rt_thread_mdelay(500);//延遲500毫秒
rt_pin_write(LED_L_PIN, PIN_LOW);//亮左燈
rt_pin_write(LED_R_PIN, PIN_HIGH);//滅右燈
rt_thread_mdelay(500);
}
return RT_EOK;
}
三、任務(wù)2:蜂鳴器控制(查詢法)
1. 任務(wù)描述
通過按鍵控制蜂鳴器的開關(guān)。當(dāng)按鍵按下時,蜂鳴器響起;當(dāng)按鍵松開時,蜂鳴器關(guān)閉。通過本任務(wù),學(xué)習(xí)PIN設(shè)備輸入功能的使用。
2. 代碼編寫
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"
/* 定義左右轉(zhuǎn)向燈的控制引腳 */
#define BEEP_PIN GET_PIN(A, 5)
#define KEY1_PIN GET_PIN(A, 0)
int main(void)
{
/* 把蜂鳴器引腳設(shè)置為推拉模式 */
rt_pin_mode(BEEP_PIN, PIN_MODE_OUTPUT);
/* 把按鍵引腳設(shè)置為上拉輸入模式 */
rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT_PULLUP);
while (1)
{
if(PIN_LOW==rt_pin_read(KEY1_PIN)){//按鍵按下
rt_thread_mdelay(20);//延時去抖
if(PIN_LOW==rt_pin_read(KEY1_PIN))
rt_pin_write(BEEP_PIN, PIN_LOW);//蜂鳴器響
}
else
rt_pin_write(BEEP_PIN, PIN_HIGH);//否則,蜂鳴器不響
rt_thread_mdelay(300);//每0.3秒進行一次按鍵掃描
}
return RT_EOK;
}
3. 測試
按下按鍵,蜂鳴器發(fā)聲,松開按鍵,停止發(fā)聲,但是經(jīng)過多次嘗試發(fā)現(xiàn),按鍵檢測成功率較低,所以需要利用中斷進行改進。
四、任務(wù)3:蜂鳴器控制(中斷回調(diào)法)
1. 任務(wù)描述
通過按鍵控制蜂鳴器的開關(guān)。當(dāng)按鍵按下時,蜂鳴器響起;當(dāng)按鍵松開時,蜂鳴器關(guān)閉。通過本任務(wù),掌握PIN設(shè)備中斷回調(diào)函數(shù)的使用方法。
2. 代碼編寫
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"
#define BEEP_PIN GET_PIN(A, 5) //定義蜂鳴器的控制引腳
#define KEY1_PIN GET_PIN(A, 0) //定義按鍵的控制引腳
/* 定義中斷回調(diào)函數(shù)實現(xiàn) */
void beep_on(void *args)
{
/* 判斷按鍵是否按下 */
if(PIN_LOW==rt_pin_read(KEY1_PIN))
{
/* 按鍵按下,驅(qū)動蜂鳴器響 */
rt_pin_write(BEEP_PIN, PIN_LOW);
/* 等待按鍵臺起 */
while(PIN_LOW==rt_pin_read(KEY1_PIN));
/* 關(guān)閉蜂鳴器 */
rt_pin_write(BEEP_PIN, PIN_HIGH);
}
}
int main(void)
{
rt_pin_mode(BEEP_PIN, PIN_MODE_OUTPUT); //把蜂鳴器引腳設(shè)置為推拉模式
rt_pin_write(BEEP_PIN, PIN_HIGH); //初始化蜂鳴器默認狀態(tài)為不響
/* 把按鍵引腳設(shè)置為上拉輸入模式 */
rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT_PULLUP);
/* 綁定中斷,下降沿觸發(fā)模式,回調(diào)函數(shù)名為beep_on */
rt_pin_attach_irq(KEY1_PIN, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
rt_pin_irq_enable(KEY1_PIN, PIN_IRQ_ENABLE); //使能中斷
return RT_EOK;
}
3. 測試
按下按鍵,蜂鳴器發(fā)聲,松開按鍵,停止發(fā)聲,經(jīng)過多次嘗試發(fā)現(xiàn),按鍵檢測成功率較高,所以中斷法比查詢法更具優(yōu)勢。
五、任務(wù)4:同時實現(xiàn)LED閃爍和按鍵控制喇叭
1. 任務(wù)描述
本任務(wù)功能為同時實現(xiàn)LED燈雙閃功能和按鍵控制蜂鳴器的功能,要求兩個功能不能相互影響,按鍵檢測靈敏度要高,即每次發(fā)生按鍵按下的事件,程序都能成功檢測該事件并開啟蜂鳴器。
2. 代碼編寫
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
/* 定義左右轉(zhuǎn)向燈的控制引腳 */
#define LED_L_PIN GET_PIN(D, 8)
#define LED_R_PIN GET_PIN(D, 9)
/* 定義蜂鳴器的控制引腳 */
#define BEEP_PIN GET_PIN(A, 5)
/* 定義按鍵的控制引腳 */
#define KEY1_PIN GET_PIN(A, 0)
/* 定義中斷回調(diào)函數(shù) */
void beep_on(void *args)
{
/* 判斷按鍵是否按下 */
if(PIN_LOW==rt_pin_read(KEY1_PIN))
{
rt_pin_write(BEEP_PIN, PIN_LOW); //按按鍵下,驅(qū)動蜂鳴器響
while(PIN_LOW==rt_pin_read(KEY1_PIN)); //等待按鍵臺起
rt_pin_write(BEEP_PIN, PIN_HIGH); //關(guān)閉蜂鳴器
}
}
int main(void)
{
/* 把LED燈引腳設(shè)置為輸出模式 */
rt_pin_mode(LED_L_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(LED_R_PIN, PIN_MODE_OUTPUT);
/* 把蜂鳴器引腳設(shè)置為推拉模式 */
rt_pin_mode(BEEP_PIN, PIN_MODE_OUTPUT);
/* 初始化蜂鳴器默認狀態(tài)為不響 */
rt_pin_write(BEEP_PIN, PIN_HIGH);
/* 把按鍵引腳設(shè)置為上拉輸入模式 */
rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT_PULLUP);
/* 綁定中斷,下降沿觸發(fā)模式,回調(diào)函數(shù)名為beep_on */
rt_pin_attach_irq(KEY1_PIN, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL);
rt_pin_irq_enable(KEY1_PIN, PIN_IRQ_ENABLE); // 使能中斷
while(1){
rt_pin_write(LED_L_PIN, PIN_HIGH);//亮左燈
rt_pin_write(LED_R_PIN, PIN_LOW);//滅右燈
rt_thread_mdelay(500);//延遲500毫秒
rt_pin_write(LED_L_PIN, PIN_LOW);//滅左燈
rt_pin_write(LED_R_PIN, PIN_HIGH);//亮右燈
rt_thread_mdelay(500);
}
return RT_EOK;
}
3. 測試
測試過程如下:
(1)系統(tǒng)啟動后,觀察左右轉(zhuǎn)向燈是否輪流閃爍;
(2)當(dāng)按下按鍵時,喇叭是否發(fā)出響聲;
(3)當(dāng)松開按鍵時,喇叭是否停止發(fā)出響聲;
(4)一直按住按鍵不松開,觀察燈的閃爍情況。
測試結(jié)果:
(1)系統(tǒng)啟動后,左右轉(zhuǎn)向燈輪流閃爍;
(2)當(dāng)按下按鍵時,喇叭發(fā)出響聲;
(3)當(dāng)松開按鍵時,喇叭停止發(fā)出響聲;
(4)一直按住按鍵不松開,喇叭發(fā)出響聲,燈停止閃爍。文章來源:http://www.zghlxwxcb.cn/news/detail-641625.html
總結(jié)
從任務(wù)4測試結(jié)果中,我們可以發(fā)現(xiàn),按鍵功能影響了閃燈的功能,說明兩個功能還是沒有很好地解耦,依然存在相互影響的情況。
出現(xiàn)這種情況,主要是由于中斷回調(diào)函數(shù)中存在需要長時間等待的代碼,當(dāng)按鍵一直按住不松開的時候,中斷回調(diào)函數(shù)由于一直停留在等待按鍵松開的地方而無法退出中斷處理。而中斷的優(yōu)先級又高于main()線程的優(yōu)先級,從而導(dǎo)致main()線程無法得到執(zhí)行。
通常,我們不應(yīng)該在中斷回調(diào)函數(shù)中進行長時間的處理,中斷回調(diào)函數(shù)應(yīng)該只做一些必要的快速處理操作,而把長時間的處理操作放到線程中實現(xiàn)。
關(guān)于線程和優(yōu)先級的概念,我們在下一節(jié)講述。文章來源地址http://www.zghlxwxcb.cn/news/detail-641625.html
到了這里,關(guān)于【STM32&RT-Thread零基礎(chǔ)入門】 3. PIN設(shè)備(GPIO)的使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!