有人会说,不如使用CubeMx软件进行开发吧。
1、这个软件适用于ST单片机,以前还能用,现在,除非你家里有矿,不然谁用的起STM32?基本上都国产化了(虽然有些单片机号称兼容,但到底还是有些差异的)。2、公司原本的代码就是使用标准库,只是因为IO的变化,你就需要把整个库换掉吗?时间上允许吗?你确定修改后不会出现大问题?3、国产化的芯片可没有所谓的标准库和HAL库供你选择,每一家都有各自的库,如果你的产品临时换方案怎么办?4、HAL效率问题。今天鱼鹰介绍一个简单实用的框架,可用于快速增加或修改IO配置,甚至修改底层库。假设有3个LED作为输出、3个霍尔传感器作为输入:输入配置代码:#defineGPIOx_DefGPIO_TypeDef*#defineGPIOMode_DefGPIOMode_TypeDeftypedefstruct{GPIOx_Defgpio;uint16_tmsk;GPIOMode_Defpull_up_down;}bsp_input_pin_def;#define_GPIO_PIN_INPUT(id,pull,gpiox,pinx)[id].gpio=(GPIOx_Def)gpiox,[id].msk=(1pinx),[id].pull_up_down=(GPIOMode_Def)pull#defineGPIO_PIN_INPUT(id,pull,gpiox,pinx)_GPIO_PIN_INPUT(id,pull,gpiox,pinx)#definebsp_pin_get_port(gpiox)((uint16_t)((GPIO_TypeDef*)gpiox)-IDR)#definebsp_pin_get_value(variable,id)do{bsp_pin_get_port(bsp_input_pin[id].gpio)bsp_input_pin[id].msk?variable
=(1id):0;}while(0)#defineBSP_GPIO_PUPD_NONEGPIO_Mode_IN_FLOATING#defineBSP_GPIO_PUPD_PULLUPGPIO_Mode_IPU#defineBSP_GPIO_PUPD_PULLDOWNGPIO_Mode_IPDtypedefenum{PIN_INPUT_HALL_0=0,//输入IO定义PIN_INPUT_HALL_1,PIN_INPUT_HALL_2,PIN_INPUT_MAX}bsp_pin_input_id_def;staticconstbsp_input_pin_defbsp_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初始化函数voidbsp_pin_init_input(GPIOx_Defgpiox,uint32_tmsk,GPIOMode_TypeDefpull_up_down){uint32_ttemp;assert_param((msk0xffff)==0gpiox!=0);temp=((uint32_t)gpiox-(uint32_t)GPIOA)/((uint32_t)GPIOB-(uint32_t)GPIOA);/*enabletheledclock*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOAtemp,ENABLE);GPIO_InitTypeDefGPIO_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初始化voidgpio_input_init(){bsp_input_pin_def*info;info=(bsp_input_pin_def*)bsp_input_pin;for(inti=0;isizeof(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_tbsp_input_all(void){uint32_ttemp=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);returntemp;}//读取单个IO状态uint32_tbsp_input_level(bsp_pin_input_id_defid){return(bsp_pin_get_port(bsp_input_pin[id].gpio)bsp_input_pin[id].msk)?1:0;}typedefenum{HW_HAL_LEVEL_ACTIVE=0,//可直接修改为0或1,另一个枚举值自动修改为相反值HW_HAL_LEVEL_NO_ACTIVE=!HW_HAL_LEVEL_ACTIVE,}hw_input_hal_status_def;typedefstruct{hw_input_hal_status_defhal_level0;uint8_thal_level1;uint8_thal_level2;}bsp_input_status_def;bsp_input_status_defbsp_input_status;intmain(void){USRAT_Init();//必须,进入调试模式后点击全速运行gpio_input_init();while(1){uint32_ttemp=bsp_input_all();bsp_input_status.hal_level0=(hw_input_hal_status_def)((tempPIN_INPUT_HALL_0)1);bsp_input_status.hal_level1=((tempPIN_INPUT_HALL_1)1);bsp_input_status.hal_level2=((tempPIN_INPUT_HALL_2)1);}}调试的时候,我们可以很方便的查看每个IO的状态是怎样的,而不用管0或1到底代表什么意思:输出配置代码:
#defineGPIOx_DefGPIO_TypeDef*#defineGPIOMode_DefGPIOMode_TypeDeftypedefstruct{GPIOx_Defgpio;uint32_tmsk;uint32_tinit_value;}bsp_output_pin_def;#define_GPIO_PIN_OUT(id,gpiox,pinx,init)[id].gpio=gpiox,[id].msk=(1pinx),[id].init_value=init#defineGPIO_PIN_OUT(id,gpiox,pinx,init)_GPIO_PIN_OUT(id,gpiox,pinx,init)#define_bsp_pin_output_set(gpiox,pin)(gpiox)-BSRR=pin#definebsp_pin_output_set(gpiox,pin)_bsp_pin_output_set(gpiox,pin)#define_bsp_pin_output_clr(gpiox,pin)(gpiox)-BRR=pin#definebsp_pin_output_clr(gpiox,pin)_bsp_pin_output_clr(gpiox,pin)typedefenum{PIN_OUTPUT_LED_G,PIN_OUTPUT_LED_R,PIN_OUTPUT_LED_B,PIN_OUTPUT_MAX}bsp_pin_output_id_def;staticconstbsp_output_pin_defbsp_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),};voidbsp_pin_init_output(GPIOx_Defgpiox,uint32_tmsk,uint32_tinit){uint32_ttemp;assert_param((msk0xffff)==0gpiox!=0);temp=((uint32_t)gpiox-(uint32_t)GPIOA)/((uint32_t)GPIOB-(uint32_t)GPIOA);/*enabletheledclock*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOAtemp,ENABLE);GPIO_InitTypeDefGPIO_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);}}voidbsp_output_init(){bsp_output_pin_def*info;info=(bsp_output_pin_def*)bsp_output_pin;for(inti=0;isizeof(bsp_output_pin)/sizeof(bsp_output_pin[0]);i++){bsp_pin_init_output(info-gpio,info-msk,info-init_value);info++;}}voidbsp_output(bsp_pin_output_id_defid,uint32_tvalue){assert_param(idPIN_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);}}intmain(void){USRAT_Init();//必须,进入调试模式后点击全速运行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);}}这个框架有啥好处呢?1、自动完成GPIO的时钟初始化工作,也就是说你只需要修改引脚即可,不必关心时钟配置,但对于特殊引脚(比如PB3),还是得另外配置才行。2、应用和底层具体IO分离,这样一旦修改了IO,应用代码不需要进行任何修改。3、增加或删减IO变得很简单,增加IO时,首先加入对应枚举,然后就可以添加对应的IO了。删除IO时,只要屏蔽对应枚举值和引脚即可。4、参数检查功能,IO删除时,因为屏蔽了对应的枚举,所以编译时可以帮你发现问题,而增加IO时,它可以帮你在运行时检查该IO是否进行配置了,可以防止因为失误导致的问题。5、更改库时可以很方便,只需要修改对应的宏即可,目前可以顺利在GD32和STM32库进行快速更换。6、对于输入IO而言,可以方便的修改有效和无效状态,防止硬件修改有效电平。对于输出IO而言,可以设定初始IO电平状态。7、代码简单高效,尽可能的复用代码,增加一个IO只需要很少的空间。8、缺点就是,只对同种配置的IO可以这样用。
-End-
「有用就扩散」
版权声明:文章转自网络,版权归原作者所有。如有侵权,请联系我们删除!
点击下方“硬件攻城狮”
转载请注明:http://www.0431gb208.com/sjszyzl/928.html