在一個嵌入式系統(tǒng)中,可能存在許多輸入或輸出的IO口,輸入有霍爾傳感器、紅外對管等,輸出有LED、電源控制開關(guān)等。如果說硬件可以一次成型,那么隨便一份代碼都可以完成IO的配置工作,但研發(fā)階段的產(chǎn)品,硬件各種修改是難免的,每一次 IO 的修改,對于底層開發(fā)人員來說,可能都是一次挑戰(zhàn)。因為一旦有某一個 IO 配置錯誤,或者原來的配置沒有修改正確(比如一個 IO 在原來的硬件適配中是輸入,之后的硬件需要修改成輸出),那么你很難查出來這是什么問題,因為這個時候不僅硬件修改了,軟件也修改了,你需要先定位到底是軟件問題還是硬件問題,所以一個好用的 IO 的配置框架就顯得很有必要了。
有道友會說,不如使用 CubeMx 軟件進(jìn)行開發(fā)吧。
1、這個軟件適用于 ST 單片機,以前還能用,現(xiàn)在,除非你家里有礦,不然誰用的起STM32?基本上都國產(chǎn)化了(雖然有些單片機號稱兼容,但到底還是有些差異的)。2、公司原本的代碼就是使用標(biāo)準(zhǔn)庫,只是因為IO 的變化,你就需要把整個庫換掉嗎?時間上允許嗎?你確定修改后不會出現(xiàn)大問題?3、國產(chǎn)化的芯片可沒有所謂的標(biāo)準(zhǔn)庫和HAL庫供你選擇,每一家都有各自的庫,如果你的產(chǎn)品臨時換方案怎么辦?4、HAL 效率問題。今天魚鷹介紹一個簡單實用的框架,可用于快速增加或修改IO配置,甚至修改底層庫。假設(shè)有3個 LED 作為輸出、3 個霍爾傳感器作為輸入:輸入配置代碼:調(diào)試的時候,我們可以很方便的查看每個 IO 的狀態(tài)是怎樣的,而不用管 0 或 1 到底代表什么意思:#defineGPIOx_DefGPIO_TypeDef*#define GPIOMode_Def GPIOMode_TypeDeftypedef struct{GPIOx_Def gpio;uint16_t msk;GPIOMode_Def pull_up_down;} bsp_input_pin_def;#define _GPIO_PIN_INPUT(id, pull, gpiox, pinx) [id].gpio = (GPIOx_Def)gpiox, [id].msk = (1 << pinx), [id].pull_up_down = (GPIOMode_Def)pull#define GPIO_PIN_INPUT(id, pull, gpiox, pinx) _GPIO_PIN_INPUT(id, pull, gpiox, pinx)#define bsp_pin_get_port(gpiox) ((uint16_t)((GPIO_TypeDef *)gpiox)->IDR)#define bsp_pin_get_value(variable,id) do{ bsp_pin_get_port(bsp_input_pin[id].gpio) & bsp_input_pin[id].msk ? variable |= (1 << id) : 0;} while(0)typedef enum{PIN_INPUT_HALL_0 = 0, // 輸入 IO 定義PIN_INPUT_HALL_1,PIN_INPUT_HALL_2,PIN_INPUT_MAX}bsp_pin_input_id_def;static const bsp_input_pin_def bsp_input_pin [PIN_INPUT_MAX] ={GPIO_PIN_INPUT(PIN_INPUT_HALL_0, BSP_GPIO_PUPD_NONE, GPIOA, 0),GPIO_PIN_INPUT(PIN_INPUT_HALL_1, BSP_GPIO_PUPD_NONE, GPIOB, 8),GPIO_PIN_INPUT(PIN_INPUT_HALL_2, BSP_GPIO_PUPD_NONE, GPIOE, 9),};// 單個 IO 初始化函數(shù)void bsp_pin_init_input(GPIOx_Def gpiox, uint32_t msk, GPIOMode_TypeDef pull_up_down){uint32_t temp;assert_param((msk & 0xffff0000) == 0 && gpiox != 0);temp = ((uint32_t) gpiox - (uint32_t) GPIOA) / ( (uint32_t) GPIOB - (uint32_t) GPIOA);/* enable the led clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA << temp, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = (GPIOMode_Def)pull_up_down;GPIO_InitStruct.GPIO_Pin = msk;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init((GPIO_TypeDef*)gpiox, &GPIO_InitStruct);}// 所有 IO 初始化void gpio_input_init(){bsp_input_pin_def *info;info = (bsp_input_pin_def *)&bsp_input_pin;for(int i = 0; i < sizeof(bsp_input_pin)/sizeof(bsp_input_pin[0]); i++){bsp_pin_init_input(info->gpio, info->msk, info->pull_up_down);info++;}}// 最多支持 32 個 IO 輸入uint32_t bsp_input_all(void){uint32_t temp = 0;bsp_pin_get_value(temp, PIN_INPUT_HALL_0);bsp_pin_get_value(temp, PIN_INPUT_HALL_1);bsp_pin_get_value(temp, PIN_INPUT_HALL_2);return temp;}// 讀取單個 IO 狀態(tài)uint32_t bsp_input_level(bsp_pin_input_id_def id){return (bsp_pin_get_port(bsp_input_pin[id].gpio) & bsp_input_pin[id].msk) ? 1 : 0;}typedef enum{HW_HAL_LEVEL_ACTIVE = 0, // 可直接修改為 0 或 1,另一個枚舉值自動修改為相反值HW_HAL_LEVEL_NO_ACTIVE = !HW_HAL_LEVEL_ACTIVE,}hw_input_hal_status_def;typedef struct{hw_input_hal_status_def hal_level0;uint8_t hal_level1;uint8_t hal_level2;}bsp_input_status_def;bsp_input_status_def bsp_input_status;int main(void){USRAT_Init(9600);//必須,進(jìn)入調(diào)試模式后點擊全速運行gpio_input_init();while(1){uint32_t temp = bsp_input_all();bsp_input_status.hal_level0 = (hw_input_hal_status_def)((temp >> PIN_INPUT_HALL_0) & 1);bsp_input_status.hal_level1 = ((temp >> PIN_INPUT_HALL_1) & 1);bsp_input_status.hal_level2 = ((temp >> PIN_INPUT_HALL_2) & 1);}}
輸出配置代碼:這個框架有啥好處呢?1、自動完成 GPIO 的時鐘初始化工作,也就是說你只需要修改引腳即可,不必關(guān)心時鐘配置,但對于特殊引腳(比如PB3),還是得另外配置才行。2、應(yīng)用和底層具體 IO 分離,這樣一旦修改了 IO,應(yīng)用代碼不需要進(jìn)行任何修改。3、增加或刪減 IO 變得很簡單,增加 IO時,首先加入對應(yīng)枚舉,然后就可以添加對應(yīng)的 IO 了。刪除 IO時,只要屏蔽對應(yīng)枚舉值和引腳即可。4、參數(shù)檢查功能, IO 刪除時,因為屏蔽了對應(yīng)的枚舉,所以編譯時可以幫你發(fā)現(xiàn)問題,而增加 IO 時,它可以幫你在運行時檢查該 IO是否進(jìn)行配置了,可以防止因為失誤導(dǎo)致的問題。#define GPIOx_Def GPIO_TypeDef*#define GPIOMode_Def GPIOMode_TypeDeftypedef struct{GPIOx_Def gpio;uint32_t msk;uint32_t init_value;} bsp_output_pin_def;#define _GPIO_PIN_OUT(id, gpiox, pinx, init) [id].gpio = gpiox, [id].msk = (1 << pinx), [id].init_value = init#define GPIO_PIN_OUT(id, gpiox, pinx, init) _GPIO_PIN_OUT(id, gpiox, pinx, init)#define _bsp_pin_output_set(gpiox, pin) (gpiox)->BSRR = pin#define bsp_pin_output_set(gpiox, pin) _bsp_pin_output_set(gpiox, pin)#define _bsp_pin_output_clr(gpiox, pin) (gpiox)->BRR = pin#define bsp_pin_output_clr(gpiox, pin) _bsp_pin_output_clr(gpiox, pin)typedef enum{PIN_OUTPUT_LED_G,PIN_OUTPUT_LED_R,PIN_OUTPUT_LED_B,PIN_OUTPUT_MAX}bsp_pin_output_id_def;static const bsp_output_pin_def bsp_output_pin [PIN_OUTPUT_MAX] ={GPIO_PIN_OUT(PIN_OUTPUT_LED_G, GPIOA, 0, 0),GPIO_PIN_OUT(PIN_OUTPUT_LED_R, GPIOF, 15, 0),GPIO_PIN_OUT(PIN_OUTPUT_LED_B, GPIOD, 10, 0),};void bsp_pin_init_output(GPIOx_Def gpiox, uint32_t msk, uint32_t init){uint32_t temp;assert_param((msk & 0xffff0000) == 0 && gpiox != 0);temp = ((uint32_t) gpiox - (uint32_t) GPIOA) / ( (uint32_t) GPIOB - (uint32_t) GPIOA);/* enable the led clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA << temp, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = (GPIOMode_Def)GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin = msk;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init((GPIO_TypeDef*)gpiox, &GPIO_InitStruct);if(init == 0){bsp_pin_output_clr(gpiox, msk);}else{bsp_pin_output_set(gpiox, msk);}}void bsp_output_init(){bsp_output_pin_def *info;info = (bsp_output_pin_def *)&bsp_output_pin;for(int i = 0; i < sizeof(bsp_output_pin)/sizeof(bsp_output_pin[0]); i++){bsp_pin_init_output(info->gpio, info->msk, info->init_value);info++;}}void bsp_output(bsp_pin_output_id_def id, uint32_t value){assert_param(id < PIN_OUTPUT_MAX);if(value == 0){bsp_pin_output_clr(bsp_output_pin[id].gpio, bsp_output_pin[id].msk);}else{bsp_pin_output_set(bsp_output_pin[id].gpio, bsp_output_pin[id].msk);}}int main(void){USRAT_Init(9600);//必須,進(jìn)入調(diào)試模式后點擊全速運行bsp_output_init();while(1){bsp_output(PIN_OUTPUT_LED_G, 1);bsp_output(PIN_OUTPUT_LED_B, 0);bsp_output(PIN_OUTPUT_LED_R, 1);}}
5、更改庫時可以很方便,只需要修改對應(yīng)的宏即可,目前可以順利在 GD32 和 STM32 庫進(jìn)行快速更換。6、對于輸入 IO 而言,可以方便的修改有效和無效狀態(tài),防止硬件修改有效電平。對于輸出 IO 而言,可以設(shè)定初始 IO 電平狀態(tài)。7、代碼簡單高效,盡可能的復(fù)用代碼,增加一個 IO 只需要很少的空間。8、缺點就是,只對同種配置的 IO 可以這樣用。
審核編輯 :李倩
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
單片機
+關(guān)注
關(guān)注
6074文章
45341瀏覽量
663649 -
霍爾傳感器
+關(guān)注
關(guān)注
28文章
791瀏覽量
65760
原文標(biāo)題:簡單實用IO輸入輸出框架
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
熱點推薦
IO口8種工作模式和應(yīng)用
在芯片設(shè)計中,IO口(輸入/輸出端口)是微控制器(MCU)或處理器與外部設(shè)備交互的關(guān)鍵接口。IO口的工作模式通常由芯片的硬件設(shè)計和軟件配置決定,不同的工作模式適
發(fā)表于 11-14 06:46
?基于ST EVLIOL4LSV1 IO-Link執(zhí)行器的工業(yè)物聯(lián)網(wǎng)技術(shù)解析
STMicroelectronics EVLIOL4LSV1 IO-Link執(zhí)行器設(shè)計用于工廠自動化和系統(tǒng)報警指示器應(yīng)用中使用的傳統(tǒng)塔式燈:它是一套完整的解決方案,可用作工業(yè)化的參考設(shè)計。通過
利用EasyGo DeskSim快速完成Modbus協(xié)議通訊交互
EasyGo DeskSim是一款配置型的實時仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實時仿真機上。實時仿真機支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號,并通過
TIOx1x2x IO-Link評估模塊技術(shù)解析與應(yīng)用指南
行業(yè)標(biāo)準(zhǔn)4引腳M12連接器,采用A類雙通道配置,該配置實施了TIOL1123的一個IO-Link通信通道和TIOS1023的一個數(shù)字輸出通道。它還具有螺釘端子塊,用于裸線連接和外部負(fù)載
利用EasyGo DeskSim快速實現(xiàn)PWM波信號采集
EasyGo DeskSim是一款配置型的實時仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實時仿真機上。實時仿真機支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號,并通過
利用EasyGo DeskSim快速實現(xiàn)PWM波信號輸出
EasyGo DeskSim是一款配置型的實時仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實時仿真機上。實時仿真機支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號,并通過
GraniStudio:IO初始化以及IO資源配置例程
1.文件運行 導(dǎo)入工程 雙擊運行桌面GraniStudio.exe。 通過引導(dǎo)界面導(dǎo)入IO初始化以及IO資源配置例程,點擊導(dǎo)入按鈕。 打開IO初始化以及
GraniStudio:IO寫入例程
說明 實現(xiàn)輸出IO控制以及讀取。 2.1通過初始化IO算子連接格拉尼控制器IO塊,導(dǎo)入工程自動進(jìn)行連接。 2.2 通過IO配置算子輸出
利用EasyGo DeskSim快速實現(xiàn)信號采集
EasyGo DeskSim是一款配置型的實時仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實時仿真機上。實時仿真機支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號,并通過
干貨分享 | TSMaster IO功能使用指南—基于同星帶IO設(shè)備的配置與操作步驟
IO模塊是一種用于連接計算機系統(tǒng)或控制系統(tǒng)與外部設(shè)備之間的接口模塊。數(shù)字IO模塊用于處理二進(jìn)制信號的輸入和輸出,它們可以接收和發(fā)送數(shù)字信號,
利用EasyGo DeskSim快速實現(xiàn)信號輸出
EasyGo DeskSim是一款配置型的實時仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實時仿真機上。實時仿真機支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號,并通過
Analog Devices / Maxim Integrated MAXREFDES177 IO-Link通用模擬IO特性/框圖
IO-Link收發(fā)器。該器件旨在演示軟件可完全配置的模擬IO模塊的性能,該模塊采用了MAX22000工業(yè)可配置模擬IO器件。MAX1448
Linux系統(tǒng)中iptables防火墻配置詳解
iptables是Linux內(nèi)核中用于配置防火墻規(guī)則的工具。它基于Netfilter框架,可以對通過網(wǎng)絡(luò)接口的數(shù)據(jù)包進(jìn)行過濾、修改等操作。通過設(shè)置一系列規(guī)則,iptables能夠控制哪
MCU是否可以使用普通IO口和數(shù)據(jù)總線控制cy7c68013a,用異步slavefifo模式增加一個與PC通信的USB口?
cy7c68013a的固件已經(jīng)配置成異步slave模式,是否有MCU用IO口控制cy7c68013a通過數(shù)據(jù)總線來實現(xiàn)與PC的USB口通信,這樣應(yīng)用的示例程序或教程?
目的就是在現(xiàn)有的MCU系統(tǒng)中
發(fā)表于 05-30 06:32
linux修改cst時區(qū)
在 Linux 系統(tǒng)中,可以通過以下步驟將時區(qū)修改為 CST(中國標(biāo)準(zhǔn)時間,GMT+8 或稱 Asia/Shanghai): 方法 1:通過?timedatectl?命令修改(適用于大

簡單實用的框架,可用于快速增加或修改IO配置
評論