1.外设介绍APM32F427拥有最多114个IO引脚这些引脚都能映射到外部中断向量同时可以配置为输入模式、输出模式、复用模式和模拟模式。2.硬件APM32F427ZG TINY板3.驱动介绍GPIO使用的状态一般为2种有效状态、无效状态在电路中表现为高电平或者低电平而不同的硬件电路设计或者IC输入或输出有效状态可能为高电平也可能为低电平。因此为了更好的让应用层理解并以统一的思想使用底层代码GPIO的封装可以以有效状态或有效电平的方式执行。如下代码中使用结构体数组统一管理所有的输出和输入GPIO信息并记录对应GPIO的有效电平。此方式不仅能清晰明了的知道用到的所有GPIO情况也能一目了然的知道对应GPIO的有效电平同时在全新产品开发的前期阶段往往第一版硬件回板后调试完成第二版原理图一般都存在调整IO的需求这种方式能很好的适应只需要修改结构体数组的内容即可不影响后面函数接口的代码实现和应用层的代码编写。复制typedefstruct{GPIO_T *port;/* PIN组 */uint16_tpin;/* 引脚 */GPIO_MODE_T mode;/* 模式 */uint32_tAHB1Periph;/* 时钟使能 */uint8_tvalid_level;/* 有效电平 */}gpio_info_t;/* 输出引脚信息 */staticgpio_info_toutput_gpio_info[OUTPUT_NUM] {{GPIOF, GPIO_PIN_0, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_RESET },{GPIOF, GPIO_PIN_1, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_RESET },{GPIOF, GPIO_PIN_2, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_SET },{GPIOF, GPIO_PIN_3, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_SET }};/* 输入引脚信息 */staticgpio_info_tinput_gpio_info[INPUT_NUM] {{GPIOD, GPIO_PIN_7, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_SET },{GPIOD, GPIO_PIN_8, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_SET },{GPIOD, GPIO_PIN_9, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_RESET },{GPIOD, GPIO_PIN_10, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_RESET }};头文件定义各个IO的枚举是为了能做到见名知义因本次代码使用的是开发板所以直接枚举命名为对应的GPIO名称而实际的产品开发中更加建议直接按照IO的引脚功能进行命名或者按照电路板的接口丝印进行命名。例如PA0在产品中被用于开门检测同时在电路板中的接口丝印为CN1此时可以将枚举命名为INPUT_DOOR_DETECT或者INPUT_CN1。以电路板接口丝印进行命名更多的是把同一块电路板当作是不同产品的通用电路板进行使用因为不同的产品对同一个接口的用法不同但接口名称都是一致的。复制/* 电平状态 */enumlevel_status_e {INVALID_LEVEL,/* 无效电平 */VALID_LEVEL/* 有效电平 */};enumoutput_pin_e {OUTPUT_PF0,OUTPUT_PF1,OUTPUT_PF3,OUTPUT_PF4,OUTPUT_NUM};enuminput_pin_e {INPUT_PD7,INPUT_PD8,INPUT_PD9,INPUT_PD10,INPUT_NUM};使用上面的结构体数组后GPIO的初始化就能代码很精简降低冗余度。复制/** brief 引脚通用初始化** param gpio_info: GPIO信息* gpio_num: GPIO数量** retval None**/staticvoidbsp_gpio_init_common(gpio_info_t*gpio_info,uint8_tgpio_num){GPIO_Config_T gpioConfig;uint8_ti 0;for(i 0; i gpio_num; i) {RCM_EnableAHB1PeriphClock(gpio_info[i].AHB1Periph);GPIO_ConfigStructInit(gpioConfig);gpioConfig.pin gpio_info[i].pin;gpioConfig.mode gpio_info[i].mode;gpioConfig.otype GPIO_OTYPE_PP;gpioConfig.speed GPIO_SPEED_50MHz;gpioConfig.pupd GPIO_PUPD_NOPULL;GPIO_Config(gpio_info[i].port, gpioConfig);}}/** brief 引脚初始化** param None** retval None**/voidbsp_gpio_init(void){bsp_gpio_init_common(output_gpio_info,sizeof(output_gpio_info) /sizeof(output_gpio_info[0]));bsp_gpio_init_common(input_gpio_info,sizeof(input_gpio_info) /sizeof(input_gpio_info[0]));}有了上面的框架后应用层在调用底层的控制GPIO接口函数时都将变为传入对应的引脚然后控制输出有效电平或者无效电平而至于此引脚在电路中的有效电平是高电平还是低电平应用层并不需要关心底层接口函数根据前面的GPIO信息表执行转换即可。复制/** brief 引脚输出** param pin: 输出引脚号* level: 输出电平** retval None**/voidbsp_gpio_output(enumoutput_pin_e pin,enumlevel_status_e level){uint8_toutput BIT_RESET;if(pin OUTPUT_NUM) {if(level VALID_LEVEL) {output output_gpio_info[pin].valid_level;}else{output (output_gpio_info[pin].valid_level BIT_RESET) ? BIT_SET : BIT_RESET;}GPIO_WriteBitValue(output_gpio_info[pin].port, output_gpio_info[pin].pin, output);}}GPIO的翻转控制无需关心电平有效或者无效只管翻转输出即可。复制/**brief引脚翻转**parampin: 翻转引脚号**retvalNone**/void bsp_gpio_toggle(enum output_pin_e pin){if(pin OUTPUT_NUM) {(GPIO_ReadOutputBit(output_gpio_info[pin].port, output_gpio_info[pin].pin) BIT_SET) ? \GPIO_ResetBit(output_gpio_info[pin].port, output_gpio_info[pin].pin) : \GPIO_SetBit(output_gpio_info[pin].port, output_gpio_info[pin].pin);}}GPIO的输入检测检测到实际输入电平再与GPIO的信息表有效电平进行比对转换为有效电平或者无效电平反馈给应用层即可。复制/** brief 引脚输入** param pin: 输入引脚号** retval 输入电平**/enumlevel_status_ebsp_gpio_input(enuminput_pin_e pin){enumlevel_status_e level INVALID_LEVEL;if(pin INPUT_NUM) {level (GPIO_ReadInputBit(input_gpio_info[pin].port, input_gpio_info[pin].pin) input_gpio_info[pin].valid_level) ? \VALID_LEVEL : \INVALID_LEVEL;}returnlevel;}这种GPIO封装的编程思想让应用层能更好的与底层进行隔离不受底层的代码更改影响同时也无需知道电路板的硬件细节只管以见名知义的方式使用底层代码即可。4.测试在输出测试中PF0和PF1的有效电平为低电平PF2和PF3的有效电平为高电平。让4个引脚同时输出有效电平或者无效电平因为PF0和PF1的有效电平一致PF2和PF3的有效电平也一致因此PF0和PF1同时为低电平时PF2和PF3同时为高电平正好相反。复制/* 输出引脚 */output_level (output_level INVALID_LEVEL) ? VALID_LEVEL : INVALID_LEVEL;for(out_pin OUTPUT_PF0; out_pin OUTPUT_NUM; out_pin) {// bsp_gpio_output(out_pin, output_pins[out_pin]);// bsp_gpio_toggle(out_pin);bsp_gpio_output(out_pin, output_level);}在输入测试中PD7和PD8的有效电平为高电平PD9和PD10的有效电平为低电平。让4个引脚同时输入低电平或者高电平因为PD7和PD8的有效电平一致PD9和PD10的有效电平也一致因此PD7和PD8同时为有效电平时PD9和PD10同时为无效电平正好相反。复制/* 输入引脚 */for(in_pin INPUT_PD7; in_pin INPUT_NUM; in_pin) {input_pins[in_pin] bsp_gpio_input(in_pin);}5.详细代码IO_CTRL.zip(6.57 MB, 下载次数: 0)---------------------作者口天土立口链接https://bbs.21ic.com/icview-3495932-1-1.html?_dsign16635fb1来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。
[APM32F4] APM32F427的GPIO驱动(IO分层封装)
1.外设介绍APM32F427拥有最多114个IO引脚这些引脚都能映射到外部中断向量同时可以配置为输入模式、输出模式、复用模式和模拟模式。2.硬件APM32F427ZG TINY板3.驱动介绍GPIO使用的状态一般为2种有效状态、无效状态在电路中表现为高电平或者低电平而不同的硬件电路设计或者IC输入或输出有效状态可能为高电平也可能为低电平。因此为了更好的让应用层理解并以统一的思想使用底层代码GPIO的封装可以以有效状态或有效电平的方式执行。如下代码中使用结构体数组统一管理所有的输出和输入GPIO信息并记录对应GPIO的有效电平。此方式不仅能清晰明了的知道用到的所有GPIO情况也能一目了然的知道对应GPIO的有效电平同时在全新产品开发的前期阶段往往第一版硬件回板后调试完成第二版原理图一般都存在调整IO的需求这种方式能很好的适应只需要修改结构体数组的内容即可不影响后面函数接口的代码实现和应用层的代码编写。复制typedefstruct{GPIO_T *port;/* PIN组 */uint16_tpin;/* 引脚 */GPIO_MODE_T mode;/* 模式 */uint32_tAHB1Periph;/* 时钟使能 */uint8_tvalid_level;/* 有效电平 */}gpio_info_t;/* 输出引脚信息 */staticgpio_info_toutput_gpio_info[OUTPUT_NUM] {{GPIOF, GPIO_PIN_0, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_RESET },{GPIOF, GPIO_PIN_1, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_RESET },{GPIOF, GPIO_PIN_2, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_SET },{GPIOF, GPIO_PIN_3, GPIO_MODE_OUT, RCM_AHB1_PERIPH_GPIOF, BIT_SET }};/* 输入引脚信息 */staticgpio_info_tinput_gpio_info[INPUT_NUM] {{GPIOD, GPIO_PIN_7, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_SET },{GPIOD, GPIO_PIN_8, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_SET },{GPIOD, GPIO_PIN_9, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_RESET },{GPIOD, GPIO_PIN_10, GPIO_MODE_IN, RCM_AHB1_PERIPH_GPIOD, BIT_RESET }};头文件定义各个IO的枚举是为了能做到见名知义因本次代码使用的是开发板所以直接枚举命名为对应的GPIO名称而实际的产品开发中更加建议直接按照IO的引脚功能进行命名或者按照电路板的接口丝印进行命名。例如PA0在产品中被用于开门检测同时在电路板中的接口丝印为CN1此时可以将枚举命名为INPUT_DOOR_DETECT或者INPUT_CN1。以电路板接口丝印进行命名更多的是把同一块电路板当作是不同产品的通用电路板进行使用因为不同的产品对同一个接口的用法不同但接口名称都是一致的。复制/* 电平状态 */enumlevel_status_e {INVALID_LEVEL,/* 无效电平 */VALID_LEVEL/* 有效电平 */};enumoutput_pin_e {OUTPUT_PF0,OUTPUT_PF1,OUTPUT_PF3,OUTPUT_PF4,OUTPUT_NUM};enuminput_pin_e {INPUT_PD7,INPUT_PD8,INPUT_PD9,INPUT_PD10,INPUT_NUM};使用上面的结构体数组后GPIO的初始化就能代码很精简降低冗余度。复制/** brief 引脚通用初始化** param gpio_info: GPIO信息* gpio_num: GPIO数量** retval None**/staticvoidbsp_gpio_init_common(gpio_info_t*gpio_info,uint8_tgpio_num){GPIO_Config_T gpioConfig;uint8_ti 0;for(i 0; i gpio_num; i) {RCM_EnableAHB1PeriphClock(gpio_info[i].AHB1Periph);GPIO_ConfigStructInit(gpioConfig);gpioConfig.pin gpio_info[i].pin;gpioConfig.mode gpio_info[i].mode;gpioConfig.otype GPIO_OTYPE_PP;gpioConfig.speed GPIO_SPEED_50MHz;gpioConfig.pupd GPIO_PUPD_NOPULL;GPIO_Config(gpio_info[i].port, gpioConfig);}}/** brief 引脚初始化** param None** retval None**/voidbsp_gpio_init(void){bsp_gpio_init_common(output_gpio_info,sizeof(output_gpio_info) /sizeof(output_gpio_info[0]));bsp_gpio_init_common(input_gpio_info,sizeof(input_gpio_info) /sizeof(input_gpio_info[0]));}有了上面的框架后应用层在调用底层的控制GPIO接口函数时都将变为传入对应的引脚然后控制输出有效电平或者无效电平而至于此引脚在电路中的有效电平是高电平还是低电平应用层并不需要关心底层接口函数根据前面的GPIO信息表执行转换即可。复制/** brief 引脚输出** param pin: 输出引脚号* level: 输出电平** retval None**/voidbsp_gpio_output(enumoutput_pin_e pin,enumlevel_status_e level){uint8_toutput BIT_RESET;if(pin OUTPUT_NUM) {if(level VALID_LEVEL) {output output_gpio_info[pin].valid_level;}else{output (output_gpio_info[pin].valid_level BIT_RESET) ? BIT_SET : BIT_RESET;}GPIO_WriteBitValue(output_gpio_info[pin].port, output_gpio_info[pin].pin, output);}}GPIO的翻转控制无需关心电平有效或者无效只管翻转输出即可。复制/**brief引脚翻转**parampin: 翻转引脚号**retvalNone**/void bsp_gpio_toggle(enum output_pin_e pin){if(pin OUTPUT_NUM) {(GPIO_ReadOutputBit(output_gpio_info[pin].port, output_gpio_info[pin].pin) BIT_SET) ? \GPIO_ResetBit(output_gpio_info[pin].port, output_gpio_info[pin].pin) : \GPIO_SetBit(output_gpio_info[pin].port, output_gpio_info[pin].pin);}}GPIO的输入检测检测到实际输入电平再与GPIO的信息表有效电平进行比对转换为有效电平或者无效电平反馈给应用层即可。复制/** brief 引脚输入** param pin: 输入引脚号** retval 输入电平**/enumlevel_status_ebsp_gpio_input(enuminput_pin_e pin){enumlevel_status_e level INVALID_LEVEL;if(pin INPUT_NUM) {level (GPIO_ReadInputBit(input_gpio_info[pin].port, input_gpio_info[pin].pin) input_gpio_info[pin].valid_level) ? \VALID_LEVEL : \INVALID_LEVEL;}returnlevel;}这种GPIO封装的编程思想让应用层能更好的与底层进行隔离不受底层的代码更改影响同时也无需知道电路板的硬件细节只管以见名知义的方式使用底层代码即可。4.测试在输出测试中PF0和PF1的有效电平为低电平PF2和PF3的有效电平为高电平。让4个引脚同时输出有效电平或者无效电平因为PF0和PF1的有效电平一致PF2和PF3的有效电平也一致因此PF0和PF1同时为低电平时PF2和PF3同时为高电平正好相反。复制/* 输出引脚 */output_level (output_level INVALID_LEVEL) ? VALID_LEVEL : INVALID_LEVEL;for(out_pin OUTPUT_PF0; out_pin OUTPUT_NUM; out_pin) {// bsp_gpio_output(out_pin, output_pins[out_pin]);// bsp_gpio_toggle(out_pin);bsp_gpio_output(out_pin, output_level);}在输入测试中PD7和PD8的有效电平为高电平PD9和PD10的有效电平为低电平。让4个引脚同时输入低电平或者高电平因为PD7和PD8的有效电平一致PD9和PD10的有效电平也一致因此PD7和PD8同时为有效电平时PD9和PD10同时为无效电平正好相反。复制/* 输入引脚 */for(in_pin INPUT_PD7; in_pin INPUT_NUM; in_pin) {input_pins[in_pin] bsp_gpio_input(in_pin);}5.详细代码IO_CTRL.zip(6.57 MB, 下载次数: 0)---------------------作者口天土立口链接https://bbs.21ic.com/icview-3495932-1-1.html?_dsign16635fb1来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。