RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

RT-Thread記錄(十三、I/O 設備模型之PIN設備)

矜辰所致 ? 來源:矜辰所致 ? 作者:矜辰所致 ? 2022-07-03 11:28 ? 次閱讀
講完UART設備之后,我們已經熟悉RT-Thread I/O 設備模型了,回頭看看基本的 PIN 設備。

目錄

前言
一、PIN 設備模型解析

1.1 初識 GPIO 操作函數
1.2 PIN 設備框架
1.3 PIN 設備驅動框架層
實現的函數
PIN 設備控制塊
注冊函數
1.4 PIN 設備驅動層
實現的函數
初始化函數
☆引腳定義☆

二、PIN 設備操作函數

2.1 獲取 PIN 索引號方法
2.2 操作函數
2.2.1 設置 GPIO 模式
2.2.2 設置/ 讀取 GPIO 電平
2.2.3 綁定/脫離中斷回調函數
2.2.4 使能中斷

三、PIN 設備示例
結語

前言

我們學習一個 MCU 的最基本的 GPIO 口,也就是 PIN 設備模型,我們還沒有講過,至于原因之前也說了,因為 PIN 設備的操作函數與我們介紹的 I/O 設備模型的通用函數名稱不太對應,對于新手來說先將 PIN 設備可能會讓人難以理解。

所以前面的文章我們先講了 UART 設備模型,從源碼分析了一下 UART 設備的設計思路,從設備驅動層,和設備驅動框架層再到 I/O 設備管理層,最后到應用層,我們都理過一遍。

有了前面的經驗,本文我們就來學習了解 RT-Thread PIN設備 。

??
本 RT-Thread 專欄記錄的開發(fā)環(huán)境:
RT-Thread記錄(一、RT-Thread 版本、RT-Thread Studio開發(fā)環(huán)境 及 配合CubeMX開發(fā)快速上手)
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 設備模型時候的設備感覺有一點區(qū)別的,那么到底怎么個特殊法?我們還是需要具體來分析一下:

1.1 初識 GPIO 操作函數

我們還是從上層的 I/O 設備管理層來開始,看看 PIN 設備管理層提供的訪問 GPIO 的接口有哪些:

pYYBAGLBBGaAfgosAACZZOOWTtw817.png

我們可以發(fā)現,上面的 PIN 設備管理接口的操作函數,與我們將的通用的函數完全不一樣,如下圖:

poYBAGLBDNKAKt0UAADpLyfdVTw895.png

這也是為什么我們將設備示例的時候沒有先講 PIN 設備的原因,怕很多小伙伴剛開始不理解,那么為什么會這樣呢?

1.2 PIN 設備框架

我們通過前面的 UART 設備的分析,已經知道了設備的基本的框架了,首先我們來看一下 上一篇文章講到的 UART 設備框架:

pYYBAGLBDNKAEchAAAA9YW5nzGk886.png

對于 PIN 設備來說,框架總結如下圖表:

poYBAGLBBQGACEPDAABqy_G7O4w677.png

?? 前面一直說 PIN 設備有點特別,那只不過是因為官方說明中 應用程序調用的不是 I/O 設備管理層的接口函數,而是直接調用的 PIN 設備驅動框架層的接口函數:

poYBAGLBDNKAOpGzAABezVbtgKY007.png

知道了這一點的話,其實我們都不需要進行過多的分析,具體的過程分析可以查看前面幾篇博文,我們這里只需要對 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 設置時候統(tǒng)一說明)。

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

?? 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 設備的值?。?!

?? 在 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* 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 中,其定義了一個結構體 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)

里面的參數為一個名字,那么這個名字是什么呢?在函數申明有注釋:

pYYBAGLBDNKAbTv4AAAlQxeUzZo607.png

對于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)
poYBAGLBDNOAY0NbAABqpO8_U4w922.png

對于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 對應的索引號都會在驅動文件中定義,直接查看文件使用索引號就可以:

pYYBAGLBDNOAQjsyAABITiO5-lA818.png

對于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 	中斷觸發(fā)模式
hdr 	中斷回調函數,用戶需要自行定義這個函數
args 	中斷回調函數的參數,不需要時設置為 RT_NULL
返回 	——
RT_EOK 	綁定成功
錯誤碼 	綁定失敗

其中 mode 可選參數:
#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);

脫離中斷回調函數:

/*
參數 	描述
pin 	引腳編號
返回 	——
RT_EOK 	脫離成功
錯誤碼 	脫離失敗
*/
rt_err_t rt_pin_detach_irq(rt_int32_t pin);

說明:引腳脫離了中斷回調函數以后,中斷并沒有關閉,還可以調用綁定中斷回調函數再次綁定其他回調函數。

2.2.4 使能中斷

綁定好引腳中斷回調函數后需要使用下面的函數使能引腳中斷:

/*
參數 	描述
pin 		引腳編號
enabled 	狀態(tài)
返回 	——
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 設備模型原理,使用起來還是很簡單的,我們先看一下原理圖:

poYBAGLBDNOAEAFIAADjlJM65TU083.png

程序如下,測試OK,太簡單所以沒有什么好說的:

...
//添加這兩個頭文件
#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); //去抖動
            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默認狀態(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);

        /* 如果獲得線程控制塊,啟動這個線程 */
        if (key1_thread != RT_NULL)
            rt_thread_startup(key1_thread);
  
  ...//后面省略

結語

本文我們詳細的分析了 RT-Thread I/O 設備模型之PIN設備,最終看來,使用 PIN 設備模型操作還是特別的簡單的。

其實關鍵的部分還是在于理解 PIN 設備模型的原理,理解了以后使用起來也更加的得心應手。

GPIO設備雖然簡單,但是文章寫下來也1W多字了,即便以前對 PIN 設備有點模糊,只要看了本文,相信大家肯定有撥云見日的感覺!

希望大家多多支持!本文就到這里,謝謝!

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • GPIO
    +關注

    關注

    16

    文章

    1204

    瀏覽量

    52051
  • PIN
    PIN
    +關注

    關注

    1

    文章

    304

    瀏覽量

    24284
  • RT-Thread
    +關注

    關注

    31

    文章

    1285

    瀏覽量

    40081
收藏 人收藏

    評論

    相關推薦

    RT-Thread記錄(十、全面認識 I/O 設備模型

    學完 RT-Thread 內核,從本文開始熟悉了解 RT-Thread I/O 設備管理相關知識。
    的頭像 發(fā)表于 06-30 10:38 ?4156次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>記錄</b>(十、全面認識 <b class='flag-5'>I</b>/<b class='flag-5'>O</b> <b class='flag-5'>設備</b><b class='flag-5'>模型</b>)

    RT-Thread記錄(十一、UART設備—源碼解析)

    一文帶你深入理解 RT-Thread I/O 設備模型 — UART 設備源碼分析。
    的頭像 發(fā)表于 07-01 11:24 ?5466次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>記錄</b>(十一、UART<b class='flag-5'>設備</b>—源碼解析)

    RT-Thread記錄(十四、I/O 設備模型ADC設備

    我曾經考慮過把 RT-Thread 常用的設備都寫完,其實通過前面的《全面認識 RT-Thread I/O
    的頭像 發(fā)表于 07-04 12:28 ?4397次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>記錄</b>(十四、<b class='flag-5'>I</b>/<b class='flag-5'>O</b> <b class='flag-5'>設備</b><b class='flag-5'>模型</b><b class='flag-5'>之</b>ADC<b class='flag-5'>設備</b>)

    RT-Thread記錄(十二、UART設備—使用測試)

    從 UART 設備開始學會使用 RT-Thread I/O 設備模型
    的頭像 發(fā)表于 07-02 12:42 ?4994次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>記錄</b>(十二、UART<b class='flag-5'>設備</b>—使用測試)

    RT-Thread記錄(十五、I/O 設備模型SPI設備

    本文學習一下I/O 設備模型SPI設備使用,I/
    的頭像 發(fā)表于 07-04 15:46 ?3986次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>記錄</b>(十五、<b class='flag-5'>I</b>/<b class='flag-5'>O</b> <b class='flag-5'>設備</b><b class='flag-5'>模型</b><b class='flag-5'>之</b>SPI<b class='flag-5'>設備</b>)

    RT-Thread 的 IO 設備模型框架是由哪些部分組成的呢

    RT-ThreadI/O 設備模型框架是由哪些部分組成的呢?接下來由小編給大家詳細介紹一下。1、R
    發(fā)表于 03-11 18:17

    【原創(chuàng)精選】RT-Thread征文精選技術文章合集

    RT-Thread記錄(十二、UART設備—使用測試)RT-Thread記錄十三、
    發(fā)表于 07-26 14:56

    RT-Thread設備模型框架及創(chuàng)建注冊設備的實現

    RT-Thread設備模型框架及創(chuàng)建注冊設備的實現方式介紹如下:
    的頭像 發(fā)表于 05-28 10:38 ?2177次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>設備</b><b class='flag-5'>模型</b>框架及創(chuàng)建注冊<b class='flag-5'>設備</b>的實現

    RT-Thread文檔_I/O 設備模型

    RT-Thread文檔_I/O 設備模型
    發(fā)表于 02-22 18:31 ?0次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>I</b>/<b class='flag-5'>O</b> <b class='flag-5'>設備</b><b class='flag-5'>模型</b>

    RT-Thread文檔_PIN 設備

    RT-Thread文檔_PIN 設備
    發(fā)表于 02-22 18:33 ?0次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>PIN</b> <b class='flag-5'>設備</b>

    RT-Thread文檔_I2C 總線設備

    RT-Thread文檔_I2C 總線設備
    發(fā)表于 02-22 18:35 ?0次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>I</b>2C 總線<b class='flag-5'>設備</b>

    RT-Thread文檔_PWM 設備

    RT-Thread文檔_PWM 設備
    發(fā)表于 02-22 18:35 ?1次下載
    <b class='flag-5'>RT-Thread</b>文檔_PWM <b class='flag-5'>設備</b>

    RT-Thread文檔_SPI 設備

    RT-Thread文檔_SPI 設備
    發(fā)表于 02-22 18:36 ?2次下載
    <b class='flag-5'>RT-Thread</b>文檔_SPI <b class='flag-5'>設備</b>

    RT-Thread文檔_Pulse Encoder 設備

    RT-Thread文檔_Pulse Encoder 設備
    發(fā)表于 02-22 18:39 ?1次下載
    <b class='flag-5'>RT-Thread</b>文檔_Pulse Encoder <b class='flag-5'>設備</b>

    RT-ThreadI/O設備模型與分類

    RT- ThreadI/O設備模型(簡稱“設備
    的頭像 發(fā)表于 10-11 17:12 ?677次閱讀
    <b class='flag-5'>RT-Thread</b>的<b class='flag-5'>I</b>/<b class='flag-5'>O</b><b class='flag-5'>設備</b><b class='flag-5'>模型</b>與分類
    RM新时代网站-首页