講完UART設(shè)備之后,我們已經(jīng)熟悉RT-Thread I/O 設(shè)備模型了,回頭看看基本的 PIN 設(shè)備。
目錄
前言
一、PIN 設(shè)備模型解析
1.1 初識 GPIO 操作函數(shù)
1.2 PIN 設(shè)備框架
1.3 PIN 設(shè)備驅(qū)動(dòng)框架層
實(shí)現(xiàn)的函數(shù)
PIN 設(shè)備控制塊
注冊函數(shù)
1.4 PIN 設(shè)備驅(qū)動(dòng)層
實(shí)現(xiàn)的函數(shù)
初始化函數(shù)
☆引腳定義☆
二、PIN 設(shè)備操作函數(shù)
2.1 獲取 PIN 索引號方法
2.2 操作函數(shù)
2.2.1 設(shè)置 GPIO 模式
2.2.2 設(shè)置/ 讀取 GPIO 電平
2.2.3 綁定/脫離中斷回調(diào)函數(shù)
2.2.4 使能中斷
三、PIN 設(shè)備示例
結(jié)語
前言
我們學(xué)習(xí)一個(gè) MCU 的最基本的 GPIO 口,也就是 PIN 設(shè)備模型,我們還沒有講過,至于原因之前也說了,因?yàn)?PIN 設(shè)備的操作函數(shù)與我們介紹的 I/O 設(shè)備模型的通用函數(shù)名稱不太對應(yīng),對于新手來說先將 PIN 設(shè)備可能會(huì)讓人難以理解。
所以前面的文章我們先講了 UART 設(shè)備模型,從源碼分析了一下 UART 設(shè)備的設(shè)計(jì)思路,從設(shè)備驅(qū)動(dòng)層,和設(shè)備驅(qū)動(dòng)框架層再到 I/O 設(shè)備管理層,最后到應(yīng)用層,我們都理過一遍。
有了前面的經(jīng)驗(yàn),本文我們就來學(xué)習(xí)了解 RT-Thread PIN設(shè)備 。
??
本 RT-Thread 專欄記錄的開發(fā)環(huán)境:
RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發(fā)環(huán)境 及 配合CubeMX開發(fā)快速上手)
RT-Thread記錄(二、RT-Thread內(nèi)核啟動(dòng)流程 — 啟動(dòng)文件和源碼分析)
??
RT-Thread 設(shè)備篇系列博文鏈接:
RT-Thread記錄(十、全面認(rèn)識 RT-Thread I/O 設(shè)備模型)
RT-Thread記錄(十一、I/O 設(shè)備模型之UART設(shè)備 — 源碼解析)
RT-Thread記錄(十二、I/O 設(shè)備模型之UART設(shè)備 — 使用測試)
一、PIN 設(shè)備模型解析
一直說到 PIN 設(shè)備有點(diǎn)特殊,和我們講 I/O 設(shè)備模型時(shí)候的設(shè)備感覺有一點(diǎn)區(qū)別的,那么到底怎么個(gè)特殊法?我們還是需要具體來分析一下:
1.1 初識 GPIO 操作函數(shù)
我們還是從上層的 I/O 設(shè)備管理層來開始,看看 PIN 設(shè)備管理層提供的訪問 GPIO 的接口有哪些:
我們可以發(fā)現(xiàn),上面的 PIN 設(shè)備管理接口的操作函數(shù),與我們將的通用的函數(shù)完全不一樣,如下圖:
這也是為什么我們將設(shè)備示例的時(shí)候沒有先講 PIN 設(shè)備的原因,怕很多小伙伴剛開始不理解,那么為什么會(huì)這樣呢?
1.2 PIN 設(shè)備框架
我們通過前面的 UART 設(shè)備的分析,已經(jīng)知道了設(shè)備的基本的框架了,首先我們來看一下 上一篇文章講到的 UART 設(shè)備框架:
對于 PIN 設(shè)備來說,框架總結(jié)如下圖表:
?? 前面一直說 PIN 設(shè)備有點(diǎn)特別,那只不過是因?yàn)楣俜秸f明中 應(yīng)用程序調(diào)用的不是 I/O 設(shè)備管理層的接口函數(shù),而是直接調(diào)用的 PIN 設(shè)備驅(qū)動(dòng)框架層的接口函數(shù):
知道了這一點(diǎn)的話,其實(shí)我們都不需要進(jìn)行過多的分析,具體的過程分析可以查看前面幾篇博文,我們這里只需要對 PIN 設(shè)備驅(qū)動(dòng)框架層 和 設(shè)備驅(qū)動(dòng)層的接口簡單的了解一下,畢竟 GPIO 的操作還是很簡單的。
1.3 PIN 設(shè)備驅(qū)動(dòng)框架層
通過上面的說明,我們知道 PIN 設(shè)備的使用是直接調(diào)用的 設(shè)備驅(qū)動(dòng)框架層的接口,所以我們來看看 PIN 設(shè)備驅(qū)動(dòng)框架層的文件(pin.c
)有哪些函數(shù)接口:
實(shí)現(xiàn)的函數(shù)
//私有的
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)
//可調(diào)用的
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);
挑一個(gè)函數(shù)簡單看看:
/* 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);
}
函數(shù)先斷言判斷_hw_pin.ops這個(gè)結(jié)構(gòu)體是否有效,有效的情況下就設(shè)置引腳的模式。
第一個(gè)參數(shù)是引腳的索引號(這個(gè)在我們下面講解 PIN 設(shè)備驅(qū)動(dòng)層的時(shí)候會(huì)有說明什么是索引號),
第二個(gè)參數(shù)是引腳模式(具體的模式我們也會(huì)再下面講解GPIO 設(shè)置時(shí)候統(tǒng)一說明)。
PIN 設(shè)備控制塊
在 RT-Thread 中 PIN 設(shè)備作為一個(gè)對象,那么肯定有他的對象控制塊,和我們前面學(xué)習(xí)的所有的對象一樣,在pin.h
中有 PIN 設(shè)備的對象結(jié)構(gòu)體:
/* 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);
};
?? PIN 設(shè)備的訪問函數(shù)都是在 PIN 設(shè)備控制塊中的結(jié)構(gòu)體成員 ops
中實(shí)現(xiàn)的,也是通過這個(gè)結(jié)構(gòu)體成員與 底層驅(qū)動(dòng)層關(guān)聯(lián)起來 —— 在設(shè)備驅(qū)動(dòng)層定義rt_pin_ops
類型的變量,實(shí)現(xiàn)這些操作函數(shù)。
注冊函數(shù)
在 PIN設(shè)備初始化的時(shí)候,rt_hw_pin_init()
會(huì)調(diào)用 rt_device_pin_register
函數(shù)進(jìn)行 PIN 設(shè)備的初始化。
PIN 設(shè)備注冊函數(shù),使用這個(gè)注冊函數(shù),可以綁定底層驅(qū)動(dòng)層的函數(shù),也同時(shí)將設(shè)備接口提供給上層 I/O 設(shè)備管理層:
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 設(shè)備不需要
_hw_pin.parent.open = RT_NULL; //
_hw_pin.parent.close = RT_NULL; //
_hw_pin.parent.read = _pin_read; //* 把設(shè)備的read操作綁定在pin.c的_pin_read函數(shù) */
_hw_pin.parent.write = _pin_write; //同上
_hw_pin.parent.control = _pin_control; //同上
#endif
/*
把drv_gpio.c所實(shí)現(xiàn)的_stm32_pin_ops綁定在_hw_pin.ops上
因?yàn)?PIN 設(shè)備驅(qū)動(dòng)層使用的注冊函數(shù)為:
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
/* 將其注冊進(jìn)device設(shè)備框架中 */
*/
rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
return 0;
}
在注冊函數(shù)中:_hw_pin.ops = ops;
這個(gè)操作就把設(shè)備驅(qū)動(dòng)層實(shí)現(xiàn)的硬件操作函數(shù)給關(guān)聯(lián)到了 設(shè)備驅(qū)動(dòng)框架層。
官方說明的 PIN 設(shè)備訪問的接口就是在 設(shè)備驅(qū)動(dòng)框架層 提供的函數(shù)接口。
但是我們看到:
_hw_pin.parent.read = _pin_read; //把設(shè)備的read操作綁定在pin.c的_pin_read函數(shù)
_hw_pin.parent.write = _pin_write;
_hw_pin.parent.control = _pin_control;
這說明我們不僅可以使用 rt_pin_read
獲取 PIN 設(shè)備的值,還可以使用 rt_device_read
獲取 PIN 設(shè)備的值?。?!
?? 在 RT-Thread 的 PIN 設(shè)備模型中, rt_pin_read
函數(shù)和 rt_device_read
函數(shù)效果一樣。
1.4 PIN 設(shè)備驅(qū)動(dòng)層
PIN 設(shè)備驅(qū)動(dòng)層,直接與硬件打交道的層面,對于我們使用的 STM32 來說,里面的很多操作我們應(yīng)該都不會(huì)陌生,我們也簡單了解下里面的函數(shù),主要的目的在于實(shí)現(xiàn) PIN 設(shè)備控制塊中 rt_pin_ops
成員中的幾個(gè)函數(shù):
實(shí)現(xiàn)的函數(shù)
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)
/*一個(gè)重要的結(jié)構(gòu)體*/
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)
...//一系列的外部中斷函數(shù)
...
int rt_hw_pin_init(void)
我們簡單來看一個(gè)函數(shù),根本不需要過多的解釋:
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);
}
初始化函數(shù)
初始化函數(shù)雖然重要,但是簡單,看一下就能明白,首先就是熟悉的 GPIO 時(shí)鐘初始化,
然后就是調(diào)用設(shè)備注冊函數(shù),設(shè)備名稱 pin ,也是在這里定義的,如果改成其他的,在 shell 工具中使用 list_device 就會(huì)顯示其他的名稱了。
第二個(gè)參數(shù),就是將設(shè)備驅(qū)動(dòng)層中實(shí)現(xiàn)的對硬件的操作函數(shù)關(guān)聯(lián)到 PIN 設(shè)備驅(qū)動(dòng)框架層以供應(yīng)用程序使用用。
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);
}
☆引腳定義☆
在驅(qū)動(dòng)文件中,關(guān)于 GPIO 引腳的定義方式(STM32為例),我們有必要說明一下。
與 UART 不同的是,GPIO 配置簡單能夠更直接關(guān)聯(lián)硬件,所以 HAL 庫并沒有為 GPIO 提供句柄結(jié)構(gòu)體描述,在 HAL 庫中描述 GPIO 使用了兩個(gè)參數(shù):GPIO_TypeDef* GPIOx和GPIO_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 中,其定義了一個(gè)結(jié)構(gòu)體 pin_index
,通過一個(gè)變量即可描述一個(gè) GPIO,如下:
/* STM32 GPIO driver */
struct pin_index
{
int index;
GPIO_TypeDef *gpio;
uint32_t pin;
};
針對這個(gè)結(jié)構(gòu)體,驅(qū)動(dòng)程序中給了一些補(bǔ)充的操作:
/*
相當(dāng)于結(jié)構(gòu)體pin_index以宏定義的形式被初始化
用C語言字符串連接定義引腳信息
index 引腳的索引號,用戶可自行定義的驅(qū)動(dòng)程序定義的引腳編號
gpio 相當(dāng)于HAL庫中的GPIO_TypeDef
gpio_index 相當(dāng)于HAL庫中的GPIO_Pin
例如宏__STM32_PIN(0, A, 0) 就表示結(jié)構(gòu)體內(nèi)容為 {0, GPIOA, GPIO_PIN_0}
*/
#define __STM32_PIN(index, gpio, gpio_index) \
{ \
index, GPIO##gpio, GPIO_PIN_##gpio_index \
}
//保留未使用的宏定義,有些IO口未使用,使用這個(gè)宏定義
#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語言連接符,其功能是在帶參數(shù)的宏定義中將兩個(gè)子串(token)聯(lián)接起來,從而形成一個(gè)新的子串,例如宏__STM32_PIN(0, A, 0)
就表示結(jié)構(gòu)體內(nèi)容為 {0, GPIOA, GPIO_PIN_0}
,就等于定義了一個(gè)pin_index
結(jié)構(gòu)體。
然后宏定義__STM32_PIN_RESERVE
:
預(yù)留的IO樓,有些IO口未使用,使用這個(gè)宏定義
接下來的結(jié)構(gòu)體數(shù)組pins
:
pins
為pin_index
結(jié)構(gòu)體類型的數(shù)組,RT-Thread 使用 pins
數(shù)組對 所有的 GPIO 引腳進(jìn)行初始化定義。
這樣就相當(dāng)于芯片上所支持的 IO 口都進(jìn)行了初始化定義,每一個(gè) GPIO 都有了一個(gè)對應(yīng)的索引號index。
在 RT-Thread 提供的 PIN 設(shè)備操作函數(shù)中void rt_pin_mode(rt_base_t pin, rt_base_t mode);, 他的第一個(gè)參數(shù)也不是類似 PIN設(shè)備控制塊之類的數(shù)據(jù)結(jié)構(gòu),而是一個(gè)引腳索引號,就是對應(yīng)的上面這個(gè)index。
引腳中斷的分析和 引腳定義類似,可自行查看代碼,這里就不過多說明。
二、PIN 設(shè)備操作函數(shù)
文章開頭我們雖然已經(jīng)認(rèn)識過 PIN 設(shè)備的操作函數(shù),但是我們沒有對函數(shù)參數(shù)可取值做說明,學(xué)習(xí) API 的使用還是老樣子,直接放函數(shù)原型然后看注釋。
2.1 獲取 PIN 索引號方法
在我們使用某個(gè) GPIO 的時(shí)候,第一步要做的就是獲取 GPIO 的索引號,即上文說到的index
。因?yàn)閷?PIN 設(shè)備的訪問操作都是通過這個(gè)索引號進(jìn)行的。
在 RT-Thread 中,提供了 3種方式獲取 PIN 設(shè)備索引號:
方法一: 使用函數(shù)rt_pin_get()
:
在 pin.c
文件中提供了一個(gè)函數(shù):
rt_base_t rt_pin_get(const char *name)
里面的參數(shù)為一個(gè)名字,那么這個(gè)名字是什么呢?在函數(shù)申明有注釋:
對于STM32而言,使用示例如下:
//獲取索引號
pin_number = rt_pin_get("PA.9"); // pin_number 就是索引號
//設(shè)置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)
對于STM32而言,使用示例如下:
//獲取索引號
#define LED0_PIN GET_PIN(B, 9)
//LED0 點(diǎn)亮或者熄滅
#define LED0(n) (n ? rt_pin_write(LED0_PIN, PIN_HIGH) : rt_pin_write(LED0_PIN, PIN_LOW))
方法三: 查看驅(qū)動(dòng)文件drv_gpio.c
:
上面講解 PIN 設(shè)備驅(qū)動(dòng)層的時(shí)候說到過,所有的 GPIO 對應(yīng)的索引號都會(huì)在驅(qū)動(dòng)文件中定義,直接查看文件使用索引號就可以:
對于STM32而言,使用示例如下:
//對應(yīng)驅(qū)動(dòng)文件,下面的代碼含義就是 設(shè)置 PA0 的模式為 PIN_MODE_INPUT_PULLUP
rt_pin_mode(0, PIN_MODE_INPUT_PULLUP);
說明,查看驅(qū)動(dòng)文件的方式并不直觀。
2.2 操作函數(shù)
操作函數(shù)說明老樣子
2.2.1 設(shè)置 GPIO 模式
/*
參數(shù) 描述
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 設(shè)置/ 讀取 GPIO 電平
設(shè)置引腳電平:
/*
參數(shù) 描述
pin 引腳編號
value 電平邏輯值,
value 取值:
PIN_LOW 低電平,
PIN_HIGH 高電平
*/
void rt_pin_write(rt_base_t pin, rt_base_t value);
讀取引腳電平:
/*
參數(shù) 描述
pin 引腳編號
返回
PIN_LOW 低電平
PIN_HIGH 高電平
*/
int rt_pin_read(rt_base_t pin);
2.2.3 綁定/脫離中斷回調(diào)函數(shù)
綁定中斷回調(diào)函數(shù):
/*
參數(shù) 描述
pin 引腳編號
mode 中斷觸發(fā)模式
hdr 中斷回調(diào)函數(shù),用戶需要自行定義這個(gè)函數(shù)
args 中斷回調(diào)函數(shù)的參數(shù),不需要時(shí)設(shè)置為 RT_NULL
返回 ——
RT_EOK 綁定成功
錯(cuò)誤碼 綁定失敗
其中 mode 可選參數(shù):
#define PIN_IRQ_MODE_RISING 0x00 上升沿觸發(fā)
#define PIN_IRQ_MODE_FALLING 0x01 下降沿觸發(fā)
#define PIN_IRQ_MODE_RISING_FALLING 0x02 邊沿觸發(fā)(上升沿和下降沿都觸發(fā))
#define PIN_IRQ_MODE_HIGH_LEVEL 0x03 高電平觸發(fā)
#define PIN_IRQ_MODE_LOW_LEVEL 0x04 低電平觸發(fā)
*/
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
void (*hdr)(void *args), void *args);
脫離中斷回調(diào)函數(shù):
/*
參數(shù) 描述
pin 引腳編號
返回 ——
RT_EOK 脫離成功
錯(cuò)誤碼 脫離失敗
*/
rt_err_t rt_pin_detach_irq(rt_int32_t pin);
說明:引腳脫離了中斷回調(diào)函數(shù)以后,中斷并沒有關(guān)閉,還可以調(diào)用綁定中斷回調(diào)函數(shù)再次綁定其他回調(diào)函數(shù)。
2.2.4 使能中斷
綁定好引腳中斷回調(diào)函數(shù)后需要使用下面的函數(shù)使能引腳中斷:
/*
參數(shù) 描述
pin 引腳編號
enabled 狀態(tài)
返回 ——
RT_EOK 使能成功
錯(cuò)誤碼 使能失敗
enabled 可取 2 種值之一:
PIN_IRQ_ENABLE (開啟)
PIN_IRQ_DISABLE (關(guān)閉)
*/
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled);
三、PIN 設(shè)備示例
只要明白了PIN 設(shè)備模型原理,使用起來還是很簡單的,我們先看一下原理圖:
程序如下,測試OK,太簡單所以沒有什么好說的:
...
//添加這兩個(gè)頭文件
#include
#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); //去抖動(dòng)
if(key1_read == 0){
rt_kprintf("key1 kicked..\r\n");
}
while(key1_read == 0){rt_thread_mdelay(10);//去抖動(dòng)
}
}
rt_thread_mdelay(1);
}
}
int main(void)
{
MX_USART1_UART_Init();
// MX_GPIO_Init(); //使用設(shè)備模型不需要初始化這個(gè)
/*配置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默認(rèn)狀態(tài)*/
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);
/* 如果獲得線程控制塊,啟動(dòng)這個(gè)線程 */
if (key1_thread != RT_NULL)
rt_thread_startup(key1_thread);
...//后面省略
結(jié)語
本文我們詳細(xì)的分析了 RT-Thread I/O 設(shè)備模型之PIN設(shè)備,最終看來,使用 PIN 設(shè)備模型操作還是特別的簡單的。
其實(shí)關(guān)鍵的部分還是在于理解 PIN 設(shè)備模型的原理,理解了以后使用起來也更加的得心應(yīng)手。
GPIO設(shè)備雖然簡單,但是文章寫下來也1W多字了,即便以前對 PIN 設(shè)備有點(diǎn)模糊,只要看了本文,相信大家肯定有撥云見日的感覺!
希望大家多多支持!本文就到這里,謝謝!
審核編輯:湯梓紅
-
GPIO
+關(guān)注
關(guān)注
16文章
1175瀏覽量
51515 -
PIN
+關(guān)注
關(guān)注
1文章
302瀏覽量
23973 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1239瀏覽量
39442
發(fā)布評論請先 登錄
相關(guān)推薦
評論