#include "io.h" #include #include "stm32f10x_exti.h" #include "usart.h" /******************************************************************************** * @file io.c * @author 晏诚科技 Mr.Wang * @version V1.0.0 * @date 11-Dec-2018 * @brief 提供IO 外部中断相关驱动 ****************************************************************************** * @驱动功能: * 1、GPIO初始化 * 2、IOEXTI初始化 * 3、外部中断回调函数注册函数 * 4、GPIO输出电平翻转 * 5、本驱动没有实现输出IO电平,在上册应用中直接使用位带操作更改输出高低电平 * @使用方法: * 1、先调用IoExti_Init()对IO初始化、NVIC、EXTI初始化 * 2、在上层注册回调函数,编写回调函数 *******************************************************************************/ /***************************************** *中断事件回调函数相关配置 ****************************************/ IOFP ioFp[PINSUM] = {NULL} ; //EXTI_Line0~EXTI_Line15 定义16个IO中断线对应的回调函数指针 /**************************************************************************** * IO EXTI相关配置 ****************************************************************************/ const uint32_t portRcc[PSUM] = {RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE, RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG} ; //所有IO端口的时钟 GPIO_TypeDef* portx[PSUM] = {GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG} ; //所有IO端口 const uint16_t pinx[PINSUM] = {GPIO_Pin_0, GPIO_Pin_1, GPIO_Pin_2, GPIO_Pin_3, GPIO_Pin_4, GPIO_Pin_5, GPIO_Pin_6, GPIO_Pin_7, GPIO_Pin_8, GPIO_Pin_9, GPIO_Pin_10, GPIO_Pin_11, GPIO_Pin_12,GPIO_Pin_13, GPIO_Pin_14, GPIO_Pin_15} ; //IO端口下的所有IO引脚 const uint8_t extiPort[PSUM] = {GPIO_PortSourceGPIOA, GPIO_PortSourceGPIOB, GPIO_PortSourceGPIOC, GPIO_PortSourceGPIOD, GPIO_PortSourceGPIOE, GPIO_PortSourceGPIOF, GPIO_PortSourceGPIOG} ; //所有中断端口 const uint8_t extiPin[PINSUM] = {GPIO_PinSource0, GPIO_PinSource1, GPIO_PinSource2, GPIO_PinSource3, GPIO_PinSource4, GPIO_PinSource5, GPIO_PinSource6, GPIO_PinSource7, GPIO_PinSource8, GPIO_PinSource9, GPIO_PinSource10, GPIO_PinSource11, GPIO_PinSource12, GPIO_PinSource13, GPIO_PinSource14, GPIO_PinSource15,} ; //所有IO外部中断引脚 const uint32_t extiLine[PINSUM] = {EXTI_Line0, EXTI_Line1, EXTI_Line2, EXTI_Line3, EXTI_Line4, EXTI_Line5, EXTI_Line6, EXTI_Line7, EXTI_Line8, EXTI_Line9, EXTI_Line10, EXTI_Line11, EXTI_Line12, EXTI_Line13, EXTI_Line14, EXTI_Line15} ; //所有外部中断线 const uint8_t extiChannel[PINSUM] = {EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, } ; //所有中断通道 /************************************************************************************************** * 名 称:void Gpio_Init(PORT_e ePortx, PIN_e ePinx, GPIOMode_TypeDef gpioMode) * 功能说明:GPIO初始化 * 入口参数: * @param1 ePortx PORT_e枚举类型,表示IO端口 * @param2 ePinx PIN_e枚举类型数据,表示IO引脚 * @param3 gpioMode GPIOMode_TypeDef枚举类型,表示IO引脚模式 * 出口参数:无 * 调用方法:外部调用 *************************************************************************************************/ void Gpio_Init(PORT_e ePortx, PIN_e ePinx, GPIOMode_TypeDef gpioMode) { /*通用IO引脚初始化*/ GPIO_InitTypeDef GPIO_InitStructure ; //GPIO参数 结构体定义 RCC_APB2PeriphClockCmd(portRcc[ePortx] , ENABLE); //GPIO 端口时钟开启 GPIO_InitStructure.GPIO_Pin = pinx[ePinx] ; //需要初始化引脚 GPIO_InitStructure.GPIO_Mode = gpioMode ; //IO引脚模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO速度配置 GPIO_Init(portx[ePortx], &GPIO_InitStructure); //GPIO 引脚初始化 } /************************************************************************************************** * 名 称:void IoExti_Init(PORT_e ePortx, PIN_e ePinx, GPIOMode_TypeDef gpioMode, EXTITrigger_TypeDef exitTrigger, * IntPriority_e ePriority, IOFP pCallback) * 功能说明:io初始化。GPIO初始化,判断如果gpioMode开启了外部中断则初始化EXTI和NVIC,接着注册中断回调函数 * 入口参数: * @param1 ePortx PORT_e枚举类型,表示IO端口 * @param2 ePinx PIN_e枚举类型数据,表示IO引脚 * @param3 gpioMode GPIOMode_TypeDef枚举类型,表示IO引脚模式 * @param4 exitTrigger EXTITrigger_TypeDef枚举类型数据,表示IO中断触发模式 * @param5 ePriority IntPriority_e枚举类型,表示IO端口中断抢占优先级 * @param6 pCallback IOFP类型函数指针 * 出口参数:无 * 调用方法:外部调用 *************************************************************************************************/ void IoExti_Init(PORT_e ePortx, PIN_e ePinx, GPIOMode_TypeDef gpioMode, EXTITrigger_TypeDef exitTrigger, IntPriority_e ePriority) { Gpio_Init(ePortx, ePinx, gpioMode) ; //通用IO引脚初始化 if((GPIO_Mode_IPD==gpioMode) || (GPIO_Mode_IPU==gpioMode)) //判断是否开启了IO外部中断 { /*开启EXIT功能需要 开启AFIO时钟且初始化 EXIT和NVIC*/ EXTI_InitTypeDef EXTI_InitStructure ; //EXIT参数 结构体定义 NVIC_InitTypeDef NVIC_InitStructure ; //NVIC参数 结构体定义 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //GPIO EXIT功能需要开启AFIO时钟 NVIC_InitStructure.NVIC_IRQChannel = extiChannel[ePinx] ; //外部中断线 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ePriority ; //抢占优先级配置 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0 ; //freertos无子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE ; //失能外部中断通道 NVIC_Init(&NVIC_InitStructure); //中断NVIC配置 GPIO_EXTILineConfig( extiPort[ePortx], extiPin[ePinx] ) ; //中断Line配置 EXTI_InitStructure.EXTI_Line = extiLine[ePinx] ; //中断引脚 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt ; //中断模式 EXTI_InitStructure.EXTI_Trigger = exitTrigger ; //IO外部中断触发方式 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能外部中断 EXTI_Init( &EXTI_InitStructure ); //外部中断初始化 /*清中断标志位后再开中断*/ EXTI_ClearITPendingBit( extiLine[ePinx] ); NVIC_EnableIRQ(extiChannel[ePinx]) ; } } /************************************************************************************************** * 名 称:void Io_Reverse(PORT_e ePortx, PIN_e ePinx) * 功能说明:GPIO输出电平翻转 * 入口参数: * @param1 ePortx PORT_e枚举类型,表示IO端口 * @param2 ePinx PIN_e枚举类型数据,表示IO引脚 * 调用方法:外部调用 *************************************************************************************************/ void Io_Reverse(PORT_e ePortx, PIN_e ePinx) { portx[ePortx]->ODR ^= pinx[ePinx] ; } /************************************************************************************************** * 名 称:IOFP Io_RegHookCallback(PIN_e ePinx, IOFP pCallback) * 功能说明:io外部中断回调函数-注册函数,EXTI驱动中定义了IOFP函数指针类型,并定义了ioFp16个中断指针变量 * Io_RegHookCallback函数就是将回调函数地址传递给ioFp指针变量 * 入口参数: * @param1 ePinx PIN_e枚举类型数据 * @param2 pCallback IOFP类型函数指针 * 出口参数: * @param1 pCallback IOFP类型函数指针 * 调用方法:外部调用 *************************************************************************************************/ IOFP Io_RegHookCallback(PIN_e ePinx, IOFP pCallback) { if( ioFp[ePinx] == NULL ) ioFp[ePinx] = pCallback ; else SysErr("IO Callback repeat reg!") ; return pCallback ; } /************************************************************************************************** * 名 称:void Io_Hook(uint32_t extiLine) * 功能说明:io外部中断内调用的钩子函数(执行到中断会把相应的回调函数勾出来运行,嘿嘿嘿。。。 * 当然不同的中断线(extiLine)会勾出不同的回调函数ioFp[]) * 入口参数: * @param1 extiLine 中断线EXTI_Line0~EXTI_Line15 *************************************************************************************************/ void Io_Hook(uint32_t extiLine) { int n = log(extiLine)/log(2) ; //对数运算将extiLine的值转化为中断线需要0~15 if( ioFp[n] != NULL) ioFp[n]() ; //通过ipFP函数指针跳转到已经注册的回调函数运行 } /************************************************************************************************** * 名 称: void EXTI0_IRQHandler(void) * 功能说明: EXTI0_IRQn中断处理函数 *************************************************************************************************/ void EXTI0_IRQHandler(void) { if( EXTI_GetFlagStatus(EXTI_Line0) != RESET ) { EXTI_ClearFlag( EXTI_Line0 ); //清除LINE0上的中断标志位 SysLog("EXTI0 IRQ!") ; Io_Hook(EXTI_Line0) ; //跳转到EXTI0中断回调函数运行 } EXTI_ClearITPendingBit( EXTI_Line0 ); //清除LINE0上的中断标志位 } /************************************************************************************************** * 名 称: void EXTI1_IRQHandler(void) * 功能说明: EXTI1_IRQn中断处理函数 *************************************************************************************************/ void EXTI1_IRQHandler(void) { if( EXTI_GetFlagStatus( EXTI_Line1 ) == SET ) { EXTI_ClearFlag( EXTI_Line1 ); SysLog("EXTI1 IRQ!") ; Io_Hook(EXTI_Line1) ; //EXTI1中断回调函数 } EXTI_ClearITPendingBit( EXTI_Line1 ); //清除LINE1上的中断标志位 } /************************************************************************************************** * 名 称: void EXTI2_IRQHandler(void) * 功能说明: EXTI2_IRQn中断处理函数 *************************************************************************************************/ void EXTI2_IRQHandler(void) { if( EXTI_GetFlagStatus(EXTI_Line2) != RESET ) { EXTI_ClearFlag( EXTI_Line2 ); //清除LINE2上的中断标志位 SysLog("EXTI2 IRQ!") ; Io_Hook(EXTI_Line2) ; //EXTI2中断回调函数 } EXTI_ClearITPendingBit( EXTI_Line2 ); //清除LINE2上的中断标志位 } /************************************************************************************************** * 名 称: void EXTI3_IRQHandler(void) * 功能说明: EXTI3_IRQn中断处理函数 *************************************************************************************************/ void EXTI3_IRQHandler(void) { if( EXTI_GetFlagStatus( EXTI_Line3 ) == SET ) { EXTI_ClearFlag( EXTI_Line3 ); SysLog("EXTI3 IRQ!") ; Io_Hook(EXTI_Line3) ; //EXTI3中断回调函数 } EXTI_ClearITPendingBit( EXTI_Line3 ); //清除LINE3上的中断标志位 } /************************************************************************************************** * 名 称: void EXTI4_IRQHandler(void) * 功能说明: EXTI4_IRQn中断处理函数 *************************************************************************************************/ void EXTI4_IRQHandler(void) { if( EXTI_GetFlagStatus(EXTI_Line4) != RESET ) { EXTI_ClearFlag( EXTI_Line4 ); //清除LINE4上的中断标志位 SysLog("EXTI4 IRQ!") ; Io_Hook(EXTI_Line4) ; //EXTI4中断回调函数 } EXTI_ClearITPendingBit( EXTI_Line4 ); //清除LINE4上的中断标志位 } /************************************************************************************************** * 名 称: void EXTI9_5_IRQHandler(void) * 功能说明: EXTI_Line5~EXTI_Line9中断处理函数 *************************************************************************************************/ void EXTI9_5_IRQHandler(void) { for( int n=5; n<=9; n++ ) { if( EXTI_GetITStatus(extiLine[n]) != RESET ) { EXTI_ClearFlag( extiLine[n] ); //清除EXTI9_5上的中断标志位 char log[64] = {0} ; snprintf(log, 64, "EXTI%d IRQ!", n) ; SysLog(log) ; Io_Hook(extiLine[n]) ; //EXTI9_5中断回调函数 } } } /************************************************************************************************** * 名 称: void EXTI15_10_IRQHandler(void) * 功能说明: EXTI_Line15~EXTI_Line10中断处理函数 *************************************************************************************************/ void EXTI15_10_IRQHandler(void) { for( int n=10; n<=15; n++ ) { if( EXTI_GetITStatus(extiLine[n]) != RESET ) { EXTI_ClearFlag( extiLine[n] ); //清除EXTI15_10上的中断标志位 char log[64] = {0} ; snprintf(log, 64, "EXTI%d IRQ!", n) ; SysLog(log) ; Io_Hook(extiLine[n]) ; //EXTI15_10中断回调函数 } } }