在一個(gè)嵌入式系統(tǒng)中,可能存在許多輸入或輸出的IO口,輸入有霍爾傳感器、紅外對(duì)管等,輸出有LED、電源控制開關(guān)等。如果說硬件可以一次成型,那么隨便一份代碼都可以完成IO的配置工作,但研發(fā)階段的產(chǎn)品,硬件各種修改是難免的,每一次 IO 的修改,對(duì)于底層開發(fā)人員來說,可能都是一次挑戰(zhàn)。因?yàn)橐坏┯心骋粋€(gè) IO 配置錯(cuò)誤,或者原來的配置沒有修改正確(比如一個(gè) IO 在原來的硬件適配中是輸入,之后的硬件需要修改成輸出),那么你很難查出來這是什么問題,因?yàn)檫@個(gè)時(shí)候不僅硬件修改了,軟件也修改了,你需要先定位到底是軟件問題還是硬件問題,所以一個(gè)好用的 IO 的配置框架就顯得很有必要了。
有道友會(huì)說,不如使用 CubeMx 軟件進(jìn)行開發(fā)吧。
1、這個(gè)軟件適用于 ST 單片機(jī),以前還能用,現(xiàn)在,除非你家里有礦,不然誰用的起STM32?基本上都國(guó)產(chǎn)化了(雖然有些單片機(jī)號(hào)稱兼容,但到底還是有些差異的)。2、公司原本的代碼就是使用標(biāo)準(zhǔn)庫(kù),只是因?yàn)?/span>IO 的變化,你就需要把整個(gè)庫(kù)換掉嗎?時(shí)間上允許嗎?你確定修改后不會(huì)出現(xiàn)大問題?3、國(guó)產(chǎn)化的芯片可沒有所謂的標(biāo)準(zhǔn)庫(kù)和HAL庫(kù)供你選擇,每一家都有各自的庫(kù),如果你的產(chǎn)品臨時(shí)換方案怎么辦?4、HAL 效率問題。今天魚鷹介紹一個(gè)簡(jiǎn)單實(shí)用的框架,可用于快速增加或修改IO配置,甚至修改底層庫(kù)。假設(shè)有3個(gè) LED 作為輸出、3 個(gè)霍爾傳感器作為輸入:輸入配置代碼:調(diào)試的時(shí)候,我們可以很方便的查看每個(gè) 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),};// 單個(gè) 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 個(gè) 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;}// 讀取單個(gè) 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,另一個(gè)枚舉值自動(dòng)修改為相反值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)試模式后點(diǎn)擊全速運(yùn)行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);}}
輸出配置代碼:這個(gè)框架有啥好處呢?1、自動(dòng)完成 GPIO 的時(shí)鐘初始化工作,也就是說你只需要修改引腳即可,不必關(guān)心時(shí)鐘配置,但對(duì)于特殊引腳(比如PB3),還是得另外配置才行。2、應(yīng)用和底層具體 IO 分離,這樣一旦修改了 IO,應(yīng)用代碼不需要進(jìn)行任何修改。3、增加或刪減 IO 變得很簡(jiǎn)單,增加 IO時(shí),首先加入對(duì)應(yīng)枚舉,然后就可以添加對(duì)應(yīng)的 IO 了。刪除 IO時(shí),只要屏蔽對(duì)應(yīng)枚舉值和引腳即可。4、參數(shù)檢查功能, IO 刪除時(shí),因?yàn)槠帘瘟藢?duì)應(yīng)的枚舉,所以編譯時(shí)可以幫你發(fā)現(xiàn)問題,而增加 IO 時(shí),它可以幫你在運(yùn)行時(shí)檢查該 IO是否進(jìn)行配置了,可以防止因?yà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)試模式后點(diǎn)擊全速運(yùn)行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、更改庫(kù)時(shí)可以很方便,只需要修改對(duì)應(yīng)的宏即可,目前可以順利在 GD32 和 STM32 庫(kù)進(jìn)行快速更換。6、對(duì)于輸入 IO 而言,可以方便的修改有效和無效狀態(tài),防止硬件修改有效電平。對(duì)于輸出 IO 而言,可以設(shè)定初始 IO 電平狀態(tài)。7、代碼簡(jiǎn)單高效,盡可能的復(fù)用代碼,增加一個(gè) IO 只需要很少的空間。8、缺點(diǎn)就是,只對(duì)同種配置的 IO 可以這樣用。
審核編輯 :李倩
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。
舉報(bào)投訴
-
單片機(jī)
+關(guān)注
關(guān)注
6076文章
45500瀏覽量
670646 -
霍爾傳感器
+關(guān)注
關(guān)注
28文章
798瀏覽量
66268
原文標(biāo)題:簡(jiǎn)單實(shí)用IO輸入輸出框架
文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
熱點(diǎn)推薦
MTK Android 13狀態(tài)欄耳機(jī)圖標(biāo)“失蹤”?這個(gè)SystemUI配置修改幫你找回
在 Android ROM 定制或設(shè)備調(diào)試中,SystemUI(系統(tǒng)界面)的配置修改往往直接影響用戶對(duì)設(shè)備的視覺感知 —— 比如狀態(tài)欄圖標(biāo)顯示 / 隱藏、通知樣式、導(dǎo)航欄布局等。今天我們就以 MTK
RK3588平臺(tái)串口配置修改指南:切換至串口8
在嵌入式開發(fā)中,串口作為基礎(chǔ)調(diào)試接口至關(guān)重要。本文檔針對(duì) RK3588 平臺(tái),詳細(xì)介紹如何將系統(tǒng)默認(rèn)串口修改為串口 8(UART8),包括 U-Boot 階段和內(nèi)核階段的配置調(diào)整。該修改適用于
碩博電子IO模塊修改波特率和節(jié)點(diǎn)ID操作步驟
正確設(shè)置波特率與節(jié)點(diǎn)ID,是保證IO模塊與控制器穩(wěn)定通信的關(guān)鍵。配置不當(dāng)易引發(fā)設(shè)備失聯(lián)、數(shù)據(jù)錯(cuò)亂等故障。本文將詳細(xì)講解波特率與節(jié)點(diǎn)ID的規(guī)范修改步驟,輕松搞定配置難題。
linux-arm開發(fā)環(huán)境的簡(jiǎn)單配置
linux-arm開發(fā)環(huán)境簡(jiǎn)單配置
關(guān)于linux-arm開發(fā)環(huán)境簡(jiǎn)單配置是ARM學(xué)習(xí)的第一步,很多初學(xué)者會(huì)在這問題上糾結(jié)很久都不能配置好
發(fā)表于 01-13 07:56
利用EasyGo DeskSim快速完成Modbus協(xié)議通訊交互
EasyGo DeskSim是一款配置型的實(shí)時(shí)仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實(shí)時(shí)仿真機(jī)上。實(shí)時(shí)仿真機(jī)支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號(hào),并通過
利用EasyGo DeskSim快速實(shí)現(xiàn)PWM波信號(hào)采集
EasyGo DeskSim是一款配置型的實(shí)時(shí)仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實(shí)時(shí)仿真機(jī)上。實(shí)時(shí)仿真機(jī)支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號(hào),并通過
利用EasyGo DeskSim快速實(shí)現(xiàn)PWM波信號(hào)輸出
EasyGo DeskSim是一款配置型的實(shí)時(shí)仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實(shí)時(shí)仿真機(jī)上。實(shí)時(shí)仿真機(jī)支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號(hào),并通過
GraniStudio:IO初始化以及IO資源配置例程
1.文件運(yùn)行 導(dǎo)入工程 雙擊運(yùn)行桌面GraniStudio.exe。 通過引導(dǎo)界面導(dǎo)入IO初始化以及IO資源配置例程,點(diǎn)擊導(dǎo)入按鈕。 打開IO初始化以及
GraniStudio:IO寫入例程
說明 實(shí)現(xiàn)輸出IO控制以及讀取。 2.1通過初始化IO算子連接格拉尼控制器IO塊,導(dǎo)入工程自動(dòng)進(jìn)行連接。 2.2 通過IO配置算子輸出
利用EasyGo DeskSim快速實(shí)現(xiàn)信號(hào)采集
EasyGo DeskSim是一款配置型的實(shí)時(shí)仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實(shí)時(shí)仿真機(jī)上。實(shí)時(shí)仿真機(jī)支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號(hào),并通過
干貨分享 | TSMaster IO功能使用指南—基于同星帶IO設(shè)備的配置與操作步驟
IO模塊是一種用于連接計(jì)算機(jī)系統(tǒng)或控制系統(tǒng)與外部設(shè)備之間的接口模塊。數(shù)字IO模塊用于處理二進(jìn)制信號(hào)的輸入和輸出,它們可以接收和發(fā)送數(shù)字信號(hào),
利用EasyGo DeskSim快速實(shí)現(xiàn)信號(hào)輸出
EasyGo DeskSim是一款配置型的實(shí)時(shí)仿真軟件,它允許用戶將 Simulink 算法程序快速部署到 EasyGo 實(shí)時(shí)仿真機(jī)上。實(shí)時(shí)仿真機(jī)支持選配不同的 FPGA 芯片和 IO 模塊,能夠處理高速信號(hào),并通過
Linux系統(tǒng)中iptables防火墻配置詳解
iptables是Linux內(nèi)核中用于配置防火墻規(guī)則的工具。它基于Netfilter框架,可以對(duì)通過網(wǎng)絡(luò)接口的數(shù)據(jù)包進(jìn)行過濾、修改等操作。通過設(shè)置一系列規(guī)則,iptables能夠控制哪
MCU是否可以使用普通IO口和數(shù)據(jù)總線控制cy7c68013a,用異步slavefifo模式增加一個(gè)與PC通信的USB口?
cy7c68013a的固件已經(jīng)配置成異步slave模式,是否有MCU用IO口控制cy7c68013a通過數(shù)據(jù)總線來實(shí)現(xiàn)與PC的USB口通信,這樣應(yīng)用的示例程序或教程?
目的就是在現(xiàn)有的MCU系統(tǒng)中
發(fā)表于 05-30 06:32
簡(jiǎn)單實(shí)用的框架,可用于快速增加或修改IO配置
評(píng)論