精华内容
下载资源
问答
  • 中断回调函数
    千次阅读
    2021-03-29 16:07:50

    STM32编程时,如何确定中断回调函数的函数名

    换句话说,就是如何找到中断回调函数的函数名
    程序进中断时,都会调用中断回调函数,很多初学者朋友在用STM32编程时,经常不知道这个回调函数的函数名。

    ADC等函数简单的中断

    其实这个问题有个通用的解法。下面以ADC1为例,来查找它的中断回调函数。首先打开CubeMX生成的代码,找到所有中断函数入口的C文件
    在这里插入图片描述
    首先需要编译一下,接下来找到ADC1对应的中断入口,它是和ADC2共用一个入口函数,函数前一行有说明

    /**
      * @brief This function handles ADC1 and ADC2 global interrupts.
      */
    void ADC1_2_IRQHandler(void)
    {
      /* USER CODE BEGIN ADC1_2_IRQn 0 */
    
      /* USER CODE END ADC1_2_IRQn 0 */
      HAL_ADC_IRQHandler(&hadc1);			//查看这个函数
      /* USER CODE BEGIN ADC1_2_IRQn 1 */
    
      /* USER CODE END ADC1_2_IRQn 1 */
    }
    

    选中HAL_ADC_IRQHandler这个函数,按F12具体查看这个函数。
    往下翻,直到这个函数结束,再往后,就是这个函数所包含的所有回调函数,以__weak打头,比如ADC就包含了以下这几个回调函数和它们的描述。篇幅所限,此处没有列出描述。
    __weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
    __weak void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
    __weak void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
    __weak void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
    看描述选中你需要的,
    以ADC来说,一般是用这一个:HAL_ADC_ConvCpltCallback

    重写需要的回调函数,在里面实现你所需要的功能。建议是新建.c和.h文件,然后这样后续代码复会比较方便。当然前面的 __weak 描述符要去掉。

     void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
     {
       if(hadc.Instance == ADC1)
       {
         //在这里写代码,实现需要的功能
       }
     }
    

    在自己重写的这个函数中,还需要做一下判断,以区分ADC1还是ADC2
    最后将.h和.c文件加入到工程中即可。

    定时器等函数特别多的中断

    以TIM3为例,中断入口是这样的:

    /**
      * @brief This function handles TIM3 global interrupt.
      */
    void TIM3_IRQHandler(void)
    {
      /* USER CODE BEGIN TIM3_IRQn 0 */
    
      /* USER CODE END TIM3_IRQn 0 */
      HAL_TIM_IRQHandler(&htim3);
      /* USER CODE BEGIN TIM3_IRQn 1 */
    
      /* USER CODE END TIM3_IRQn 1 */
    }
    

    选中 HAL_TIM_IRQHandler ,按F12键,进入函数定义,搜索Callback(,意思是寻找回调函数,一定要加上括号哦。
    接下来找到的就都是回调函数了 ,注意看找到的函数名称,它代表了具体的相关功能,找到你要的那个功能,然后按上面的方法去重写这个弱函数即可。如下:
    HAL_TIM_IC_CaptureCallback(htim);
    HAL_TIM_OC_DelayElapsedCallback(htim);
    HAL_TIM_PWM_PulseFinishedCallback(htim);
    HAL_TIM_PeriodElapsedCallback(htim);
    HAL_TIMEx_BreakCallback(htim);
    HAL_TIM_TriggerCallback(htim);
    HAL_TIMEx_CommutCallback(htim);

    更多相关内容
  • STM32CubeMX定时器中断回调函数的研究.pdf
  • STM32CubeMX 开发笔记 (Ⅲ)—— 最快找到CubeMX的中断回调函数 系列文章目录 STM32CubeMX 开发笔记 (Ⅰ)——串口DMA的问题 STM32CubeMX 开发笔记 (Ⅱ)—— ADC过采样与DMA 文章目录STM32CubeMX 开发笔记 (Ⅲ...

    STM32CubeMX 开发笔记 (Ⅲ)—— 最快找到CubeMX的中断回调函数

    系列文章目录

    STM32CubeMX 开发笔记 (Ⅰ)——串口DMA的问题
    STM32CubeMX 开发笔记 (Ⅱ)—— ADC过采样与DMA



    STM32CubeMX 开发笔记

    软件环境:

    • STM32CubeMX 6.4.0
    • Clion 2021.3.2
    • gcc-arm-none-eabi-10.3-2021.10
    • CMake 3.21.1
    • MinGW 5.4

    硬件环境:

    STM32L432KBU6自制PCB
    请添加图片描述

    HAL库配合Cubemx如何快速找到中断回调函数?

    什么是中断回调函数这里就不再多说,你可以简单理解为中断服务函数(但实际上概念不一样,功能更强),

    大概有两类:一种是弱类型的回调函数:

    如串口发送完成回调:

    __weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(huart);
    
      /* NOTE : This function should not be modified, when the callback is needed,
                the HAL_UART_TxCpltCallback can be implemented in the user file.
       */
    }
    

    另一种是DMA过程中,DMA各个状态的中断是没有针对的弱类型的函数的,通常是对应外设的回调通过函数指针的方式送过来。

    在每个外设使用DMA之前都会有一个启动的函数:

    HAL_XXXX_Transmit_DMA()
    HAL_XXX_Start_DMA()
    

    在这个启动函数里面就有对应的中断回调注册:

    拿ADC启动函HAL_ADC_Start_DMA()数举例:

     /* Check if a conversion is on going on ADC group injected */
            if ((hadc->State & HAL_ADC_STATE_INJ_BUSY) != 0UL)
            {
              /* Reset ADC error code fields related to regular conversions only */
              CLEAR_BIT(hadc->ErrorCode, (HAL_ADC_ERROR_OVR | HAL_ADC_ERROR_DMA));
            }
            else
            {
              /* Reset all ADC error code fields */
              ADC_CLEAR_ERRORCODE(hadc);
            }
    
    		//在这个位置注册了三个对应DMA传输过程的回调函数
    
            /* Set the DMA transfer complete callback */
            hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
    
            /* Set the DMA half transfer complete callback */
            hadc->DMA_Handle->XferHalfCpltCallback = ADC_DMAHalfConvCplt;
    
            /* Set the DMA error callback */
            hadc->DMA_Handle->XferErrorCallback = ADC_DMAError;
    

    那该如何使用这些注册的回调函数来实现中断服务过程呢?

    HAL库如何快速找到对应外设的弱类型回调函数呢?

    对于第一种针对每个外设的回调函数很简单以我的项目为例子:

    打开对应外设的HAL库的驱动头文件,一般在如下结构:

    请添加图片描述

    我这里拿定时器的来举个例子:

    打开后直接搜索CallBack,注意大小写,跳转到下边的你就可以看到tim的所有弱类型的函数都在这里:

    请添加图片描述

    换个串口试一试:

    请添加图片描述

    这是我目前发现的最快的方法。

    HAL库如何快速找到对应外设的DMA传输回调函数呢?

    这里先拿ADC开启DMA来举例子:

    我们打开这个函数:
    请添加图片描述

    往下翻一番找到对应的回调注册位置:

    请添加图片描述

    这里打开向DMA注册传输完成函数:

    请添加图片描述

    void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)
    {
        /* 省略部分代码 */
        /* 可以看到转换成向ADC的回调函数:
        /* Conversion complete callback */
    #if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
        hadc->ConvCpltCallback(hadc);
    #else
        HAL_ADC_ConvCpltCallback(hadc);
    #endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
      }
      else /* DMA and-or internal error occurred */
      {
        if ((hadc->State & HAL_ADC_STATE_ERROR_INTERNAL) != 0UL)
        {
          /* Call HAL ADC Error Callback function */
    #if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
          hadc->ErrorCallback(hadc);
    #else
          HAL_ADC_ErrorCallback(hadc);
    #endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
        }
        else
        {
          /* Call ADC DMA error callback */
          hadc->DMA_Handle->XferErrorCallback(hdma);
    }
    

    跳转到对应函数,实际上就是ADC的传输完成中断回调,所以以后使用DMA就可以用对应的外设的传输过程中断即可:

    __weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(hadc);
    
      /* NOTE : This function should not be modified. When the callback is needed,
                function HAL_ADC_ConvCpltCallback must be implemented in the user file.
       */
    }
    

    一些小问题

    关于sizeof关键字

    sizeof操作符判断它的操作数的类型长度,以字节为表示单位。操作数既可以是个表达式(常常是单个变量),也可以是两边加上括号的类型名。

    这里有个例子:

    sizeofint
    sizeof x
    

    第一个表达式返回整型变量的字节数,其结果自然取决于所使用的环境(STM32的编译器指定为4个字节)。第二个表达式返回变量所占据的字节数。如果sizeof的操作数是个数组名,则返回该数组的长度,以字节为单位。在表达式的操作数两边加上那个括号也是合法的。

    sizeof (x)

    这是因为括号在表达式中总是合法的。在判断表达式长度的时候,并不需要对表达式求值

    所以说sizeof(a= b+1)并没有向a赋任何值。

    展开全文
  • NXP JN5169滴答定时器中断注册回调函数一、滴答定时器介绍二、中断处理1、中断注册回调函数2、 回调函数原型和参数3、 回调行为4、外设中断枚举(u32DeviceId)5、外围中断源(u32ItemBitmap)三、实现代码1、宏定义...



    一、滴答定时器介绍

    JN5169使用滴答定时器进行精准延时


    二、中断处理

    1、中断回调函数

            片上外设的中断由一组特定于外设的回调函数处理。 可以使用Integrated Peripherals API的适当回调注册功能来引入这些用户定义的功能。 例如,可以编写自己的UART0中断处理程序,然后注册使用vAHI_Uart0RegisterCallback()函数的回调函数。
            下表提供了外设中断源的完整列表和相应的回调注册功能。

    在这里插入图片描述
    *包括DIO,比较器,唤醒定时器,脉冲计数器,随机数和掉电中断。
    **用于SI主设备和SI从设备中断。
    注:
    ① 回调函数在中断上下文中执行。 因此,必须确保函数及时返回主程序。
    ② 可以使用函数vAHI_InterruptSetPriority()设置来自各种中断源的中断的优先级。
    ③ 注册的回调函数仅在RAM保持供电的睡眠模式下保留。 如果在睡眠期间关闭RAM的电源并需要中断,则在唤醒时调用u32AHI_Init()之前必须重新注册所有回调函数。

    2、 回调函数原型和参数

    所有外围设备的用户定义回调函数必须按照以下原型设计:
    void vHwDeviceIntCallback(uint32 u32DeviceId, uint32 u32ItemBitmap);

    形参:u32DeviceId
            标识产生中断的外设。 上面的表中列出了可能的来源。API中提供了这些来源的枚举,外设中断枚举(u32DeviceId)对此进行了详细说明。
    形参:u32ItemBitmap
            u32ItemBitmap是一个位图,用于标识通过上述u32DeviceId标识的外围模块内的中断的具体原因。 API中提供了掩码,允许检查特定的中断原因。 UART中断是一个例外,因为在这种情况下,枚举值是通过此参数而不是位图传递的。 掩码和枚举在外围中断源(u32ItemBitmap)详细介绍。

    3、 回调行为

            在调用其中一个回调函数之前,API会清除中断源,这样就不会存在相同中断的危险,从而不会导致处理器进入永久尝试处理同一中断的状态(由于回调函数编写不当)。 这也意味着可以使用NULL回调函数。
            UART是该规则的例外。 当产生可用的接收数据或超时指示中断时,仅当从UART接收缓冲区读取数据后,UART才会清除该中断。 因此,至关重要的是,如果要启用UART中断,则回调函数通过在返回之前从UART读取数据来处理可用数据接收和超时指示中断。
            如果正在使用Application Queue API,则该API将处理上述与UART中断有关的问题,因此应用程序无需对其进行处理。

            处理唤醒中断本篇博客不涉及,不做展开介绍。


    4、外设中断枚举(u32DeviceId)

    在这里插入图片描述

    5、外围中断源(u32ItemBitmap)

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述


    三、实现代码

            使用BeyondStudio for NXP编写,SDK为JN-SW-4170,不带栈协议,仅外设功能实现。

    1、宏定义

    /* Value enumerations: Tick Timer */
    #define E_AHI_TICK_TIMER_DISABLE        (0x00) /* Disable tick timer */
    #define E_AHI_TICK_TIMER_RESTART        (0x01) /* Restart timer when match occurs */
    #define E_AHI_TICK_TIMER_STOP           (0x02) /* Stop timer when match occurs */
    #define E_AHI_TICK_TIMER_CONT           (0x03) /* Timer does not stop when match occurs */
    
    #define TRUE            (1)   /* page 207 K+R 2nd Edition */
    #define FALSE           (0)
    
    #define DELAY_TICK_TIME         16000000	/* 1s  */
    #define TICK_COUNT              16000       /* 1ms */
    
    #define LED2                    (1 <<  0)
    #define LED3                    (1 <<  1)
    #define LED4                    (1 <<  2)
    #define LED5                    (1 <<  3)
    #define LED6                    (1 <<  4)
    #define LED8                    (1 <<  5)
    #define LED_DIO                 ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5))
    
    #define LED_ON(Led)             vAHI_DioSetOutput(0, Led)
    #define LED_OFF(Led)            vAHI_DioSetOutput(Led, 0)
    
    

    2、全局变量

    PRIVATE uint8  u8Tick;			/*滴答定时器中断次数*/
    PRIVATE uint32 u32Second;		/*秒数*/
    

    3、滴答定时器初始化函数

    PRIVATE void vTickTimerInit (void)
    {
        vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);/* 关闭滴答定时器*/
        vAHI_TickTimerWrite(0); /* 设置起始值*/
        vAHI_TickTimerInterval(TICK_COUNT * 10); /* 设置参照值 10ms*/
        vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_RESTART);  /* 重新开始计数*/
        vAHI_TickTimerRegisterCallback(vCbTickTimer); /* 注册中断回调*/
        vAHI_TickTimerIntEnable(TRUE); /* 启动*/
    }
    

    4、中断回调函数

    PRIVATE void vCbTickTimer(uint32 u32Device, uint32 u32ItemBitmap)
    {
        PRIVATE bool_t bLedStatus;
        if (++u8Tick > 99) {		/*满一秒*/
            u8Tick = 0;				/*重置计数次数*/
            ++u32Second;			/*秒++*/
            (bLedStatus = !bLedStatus) ? LED_ON(LED_DIO) : LED_OFF(LED_DIO);/* 每秒翻转一次输出*/
        }
    }
    

    5、完整代码

    PRIVATE uint8  u8Tick;			/*滴答定时器中断次数*/
    PRIVATE uint32 u32Second;		/*秒数*/
    
    /*初始化IO*/
    PRIVATE void vLedsInit (void)
    {
        vAHI_DioSetDirection(0, LED_DIO);
        vAHI_DioSetPullup(LED_DIO, 0);
    }
    /*滴答定时器初始化*/
    PRIVATE void vTickTimerInit (void)
    {
        vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);               /* 关闭滴答定时器                */
        vAHI_TickTimerWrite(0);                                          /* 设置起始值                          */
        vAHI_TickTimerInterval(TICK_COUNT);                              /* 设置参照值                          */
        vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_RESTART);               /* 重新开始计数                    */
        vAHI_TickTimerRegisterCallback(vCbTickTimer);                    /* 注册中断回调                    */
        vAHI_TickTimerIntEnable(TRUE);                                   /* 启动                                        */
    }
    /*中断回调函数*/
    PRIVATE void vCbTickTimer (uint32 u32Device, uint32 u32ItemBitmap)
    {
        PRIVATE bool_t bLedStatus;
        if (++u8Tick > 99) {
            u8Tick = 0;
            ++u32Second;
            (bLedStatus = !bLedStatus) ? LED_ON(LED_DIO) : LED_OFF(LED_DIO);/* 每秒翻转一次输出              */
        }
    }
    /*主函数*/
    PUBLIC void AppColdStart (void)
    {
        u8Tick = 0;
        u32Second = 0;
    
        vAHI_WatchdogStop();
        (void)u32AHI_Init();
        vLedsInit();
    
        vTickTimerInit();
    
        while (1) {
            vAHI_CpuDoze();  /* Doze*/
        }
    }
    /*热启动*/
    PUBLIC void AppWarmStart (void)
    {
        AppColdStart();
    }
    
    展开全文
  • (USART_BRR)控制寄存器 x (USART_CRx)控制寄存器 1 (USART_CR1)控制寄存器 2 (USART_CR2)控制寄存器 3 (USART_CR3)串口配置串口初始化GPIO配置,开启中断中断函数串口1中断服务函数串口1中断回调函数写在最后 ...

    相关寄存器

    状态寄存器 (USART_SR)

    在这里插入图片描述
    主要关注RXNE位和TC位
    在这里插入图片描述
      RXNE(读数据寄存器非空):当该位被置1的时候,就是提示已经有数据被接收到了,并且可以读出来了。读取USART_DR,从而将该位清零,也可以向该位写0,直接清除。
      TC(发送完成):当该位被置1的时候,表示USART_DR内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:读USART_SR,写USART_DR;直接向该位写0。

    数据寄存器 (USART_DR)

    在这里插入图片描述
      进行发送数据操作时,往USART_DR写入数据会自动存储在TDR内;当进行读取数据操作时,向USART_DR读取数据会自动提取RDR数据。
      发送数据时把TDR内容转移到发送移位寄存器上,接收数据时则是把接收到的每一位顺序保存在接收移位寄存器内进而转移到RDR。

    波特率寄存器 (USART_BRR)

    在这里插入图片描述
      波特率寄存器包括定义了两个部分:DIV_Mantissa(整数部分)和DIV_Fraction(小数部分)。
    在这里插入图片描述

    控制寄存器 x (USART_CRx)

    控制寄存器 1 (USART_CR1)

    在这里插入图片描述

    控制寄存器 2 (USART_CR2)

    在这里插入图片描述

    控制寄存器 3 (USART_CR3)

    在这里插入图片描述
      控制寄存器主要用于各类使能,如USART使能、检验控制使能、校验选择(奇校验偶校验)、发送缓冲区空中断使能、发送完成中断使能、接收缓冲区非空使能、发送使能、接受使能等等,具体位请查找中文参考手册。
    在这里插入图片描述

    串口配置

    使用CubeMX配置.

    串口初始化

    UART_HandleTypeDef huart1;
    
    void MX_USART1_UART_Init(void)
    {
    	huart1.Instance = USART1;
    	huart1.Init.BaudRate = 115200;	//波特率
    	huart1.Init.WordLength = UART_WORDLENGTH_8B;	//字长为8位数据格式
    	huart1.Init.StopBits = UART_STOPBITS_1;	//一个停止位
    	huart1.Init.Parity = UART_PARITY_NONE;	//无奇偶校验位
    	huart1.Init.Mode = UART_MODE_TX_RX;		//收发模式
    	huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    	huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    	if (HAL_UART_Init(&huart1) != HAL_OK)	//初始化
    	{
    		Error_Handler();
    	}
    	HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
    	//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量,下文中断部分有介绍。
    }
    

    结构体类型UART_HandleTypeDef 变量huart1作为UART的句柄。如下图:其中UART_InitTypeDef用于初始化波特率,奇偶校验位等。

    typedef struct __UART_HandleTypeDef
    {
      USART_TypeDef                 *Instance;        /*!< UART registers base address        */
    
      UART_InitTypeDef              Init;             /*!< UART communication parameters      */
    
      uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */
    
      uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */
    
      __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */
    
      uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */
    
      uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */
    
      __IO uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */
    
      DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */
    
      DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */
    
      HAL_LockTypeDef               Lock;             /*!< Locking object                     */
    
      __IO HAL_UART_StateTypeDef    gState;           /*!< UART state information related to global Handle management and also related to Tx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */
    
      __IO HAL_UART_StateTypeDef    RxState;          /*!< UART state information related to Rx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */
    
      __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */
    
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
      void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Tx Half Complete Callback        */
      void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Tx Complete Callback             */
      void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Rx Half Complete Callback        */
      void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Rx Complete Callback             */
      void (* ErrorCallback)(struct __UART_HandleTypeDef *huart);             /*!< UART Error Callback                   */
      void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Abort Complete Callback          */
      void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
      void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart);  /*!< UART Abort Receive Complete Callback  */
      void (* WakeupCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Wakeup Callback                  */
    
      void (* MspInitCallback)(struct __UART_HandleTypeDef *huart);           /*!< UART Msp Init callback                */
      void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Msp DeInit callback              */
    #endif  /* USE_HAL_UART_REGISTER_CALLBACKS */
    
    } UART_HandleTypeDef;
    

    GPIO配置,开启中断

    void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
    {
    
      GPIO_InitTypeDef GPIO_InitStruct = {0};
      if(uartHandle->Instance==USART1)
      {
        /* USART1 clock enable */
        __HAL_RCC_USART1_CLK_ENABLE();	//使能串口1时钟
      
        __HAL_RCC_GPIOA_CLK_ENABLE();		//使能GPIOA时钟
        
        /*
    	    USART1 GPIO Configuration    
    	    PA9     ------> USART1_TX
    	    PA10     ------> USART1_RX 
        */
        
        //GPIO配置
        GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
        /* USART1 interrupt Init */
        //开启串口1中断
        HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
      }
    }
    

    中断函数

    引用原子哥一张串口接收中断的流程图更好理解。
    在这里插入图片描述
    由流程图可以看到,当RxXferCount为0时,才调用中断回调函数

    首先在.h文件中声明几个变量

    #define USART_REC_LEN  			200  	//定义最大接收字节数 200
    #define RXBUFFERSIZE   			1 		//缓存大小
    
    extern uint8_t aRxBuffer[RXBUFFERSIZE];			//HAL库USART接收Buffer
    extern uint8_t  USART_RX_BUF[USART_REC_LEN]; 	//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
    extern uint16_t USART_RX_STA;         			//接收状态标记
    

    我们在前文串口初始化时提到了HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);如下:

    HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    {
      /* Check that a Rx process is not already ongoing */
      if (huart->RxState == HAL_UART_STATE_READY)
      {
        if ((pData == NULL) || (Size == 0U))
        {
          return HAL_ERROR;
        }
    
        /* Process Locked */
        __HAL_LOCK(huart);
    
        huart->pRxBuffPtr = pData;
        huart->RxXferSize = Size;
        huart->RxXferCount = Size;
    
        huart->ErrorCode = HAL_UART_ERROR_NONE;
        huart->RxState = HAL_UART_STATE_BUSY_RX;
    
        /* Process Unlocked */
        __HAL_UNLOCK(huart);
    
        /* Enable the UART Parity Error Interrupt */
        __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
    
        /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
    
        /* Enable the UART Data Register not empty Interrupt */
        __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
    
        return HAL_OK;
      }
      else
      {
        return HAL_BUSY;
      }
    }
    

    由函数定义可以看到,RxXferCount为我们传入的参数RXBUFFERSIZE为1,另外 这个函数使能了接收完成中断__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);,也就是说每接收一个字节就会进入一次中断USART1_IRQHandler

    串口1中断服务函数

    串口产生中断,就会自动调用USART1_IRQHandler这个中断服务函数

    void USART1_IRQHandler(void)                	
    { 
    	uint32_t timeout=0;
      	uint32_t maxDelay=0x1FFFF;
    #if SYSTEM_SUPPORT_OS	 	//使用OS
    	OSIntEnter();    
    #endif
    	
    	HAL_UART_IRQHandler(&huart1);	//调用HAL库中断处理函数
    	
    	timeout=0;
        while (HAL_UART_GetState(&huart1)!=HAL_UART_STATE_READY)//等待就绪
    	{
            timeout++;超时处理
            if(timeout>maxDelay)
            	break;		
    	}
    	timeout=0;
    	while(HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, RXBUFFERSIZE)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
    	{
            timeout++; //超时处理
            if(timeout>maxDelay) 
            	break;	
    	}
    #if SYSTEM_SUPPORT_OS	 	//使用OS
    	OSIntExit();  											 
    #endif
    } 
    

    在这个函数里,首先调用HAL_UART_IRQHandler(&huart1);这个HAL库中断处理函数,主要用于判断中断类型。通过这个中断处理函数会调用UART_Receive_IT(huart);如下:(由于函数太长,只选取了一小部分)

    void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
    {
          if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
          {
            UART_Receive_IT(huart);
          }
    }
    

    该函数是将接收到的数据保存到指定的串口缓冲区aRxBuffer。接着再判断。RxXferCount自减后是否等于0.
    如果等于0 ,则关闭接收完成中断,进行中断回调函数。如果需要再一次开启时。需要再一次开启中断,也就是调用 HAL_UART_Receive_IT()函数。

    串口1中断回调函数

    首先,在win系统下enter表示回车(\r)加换行(\n),在16进制的表示下,\r的ascii码为0x0d,\n的ascii码为0x0a.由此下面逻辑就比较好理解了。16位置1表示接收完成,即0x8000;15位置1表示接收到了0x0d.将收到的数据储存在数组USART_RX_BUF[]

    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
    	if(huart->Instance==USART1)//如果是串口1
    	{
    		if((USART_RX_STA&0x8000)==0)//接收未完成
    		{
    			if(USART_RX_STA&0x4000)//接收到了0x0d	\r
    			{
    				if(aRxBuffer[0]!=0x0a)
    					USART_RX_STA=0;//接收错误,重新开始 0x0a	\n
    				else 
    					USART_RX_STA|=0x8000;	//接收完成了 
    			}
    			else //还没收到0X0D
    			{	
    				if(aRxBuffer[0]==0x0d)
    					USART_RX_STA|=0x4000;
    				else
    				{
    					USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
    					USART_RX_STA++;
    					if(USART_RX_STA>(USART_REC_LEN-1))
    						USART_RX_STA=0;//接收数据错误,重新开始接收	  
    				}		 
    			}
    		}
    	}
    }
    

    写在最后

    本文为学习笔记,如有错误,欢迎指正。
    在这里插入图片描述

    展开全文
  • STM32CubeMX-HAL库-UART串口接收中断回调函数代码分析
  • STM32Cube MX串口中断回调函数的研究.pdf
  • void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) ...{ //添加回调后的程序逻辑  if (htim->Instance == htim2.Instance) //判断是否定时器2 { } } void HAL_UART_RxCpltCallba...
  • 介绍如何使用中断回调函数。 1、头文件声明 #include "FreeRTOS.h" #include "task.h" #include "timers.h" #include "supporting_functions.h" #define mainINTERRUPT...
  • STM32CubeMX定时器中断回调函数的研究
  • STM32Cube MX串口中断回调函数的研究
  • 中断回调函数中使用rt_thread_mdelay()产生了奇怪的效果。 解决方法: 1.删除./libraries/HAL_Drives/drv_common.c 里的HAL_Delay空函数。 2.将rt_thread_mdelay()改为HAL库的延时函数HAL_Delay() 究其原因是rt_...
  • dpdk pmd 中注册中断回调函数并使能中断 这里以 ixgbe pmd 驱动为例,进行研究。 eth_ixgbe_dev_init 是 ixgbe 网卡的初始化函数,在这个函数的最后注册中断回调并使能中断。 在配置了收发队列等等步骤后,注册中断...
  • 所谓线程同步就是一个线程或者ISR中断往某个消息队列发送一个消息后,触发调度器将另外一个线程(等待这个消息队列的线程)马上从阻塞态切换至运行态,读取消息与解析消息。线程标志组与事件标志组也可以用于线程...
  • STM32中断数据回调函数接收处理

    千次阅读 2021-05-23 08:50:42
    1.定义一个空的指针函数 指针函数的参数是uint8_t 类型chtypedef void (* usart_recv_callback)(uint8_t ch);...3.串口配置时,一个形参为串口中断接收回调void Usart_Config(USART_TypeDef* USARTx, uint32_t bau...
  • 本节我们来学习STM32最基础的定时器应用,并利用hal库生成的代码,添加用户自己的功能到回调函数中。 程序实现的功能是:以10ms的定时器中断为周期,循环检测一个按键的状态,如果按下,则点亮LED灯;没有按下则...
  • 看上面回调函数的定义,通过特定条件调用『回调函数』,这里触发的条件就是中断。 3扩展说明 这里也简单说几点: 1.初学者想直接使用HAL不是不行,需要有一定C语言功底 针对大部分初学者来说,是不建议直接上手HAL...
  • 单片机每完成接收一个字符,就会进入一次中断处理函数,而在中断处理函数中,我们又调用了函数“void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)”,该函数会间接调用回调函数,也就是说回调函数是由中断处理...
  • 串口使用流程: 1、初始化串口 2、使能中断(在非阻塞模式下接收一定量的数据。...注意:如果设置要接受的数据量为1个字节数,那么当接受1个字节以后就会进入回调函数。 接受回调函数如下: HAL_U
  • c语言回调函数的使用及实际作用详解

    万次阅读 多人点赞 2021-07-16 23:49:20
    回调函数这个知识点其实并不是很难,难是难在网上很多讲解回调函数的都说的太学术化了化了,一点也不亲民。 很多人即使知道怎么写回调函数也根本就搞不懂它们在实际产品中也有什么用,什么时候用。 所以这节课呢...
  • matlab串口收发及回调函数编程

    热门讨论 2011-08-20 16:38:27
    matlab创建com对象。并采用中断方式响应回调函数,功能完整,包括创建初始化及关闭销毁。回调函数的格式,实现方法。
  • 当触发中断时会调用对应的中断函数 例如定时器2中断: TIM2_IRQHandler(void) HAL 库中对中断的类型进行了分类处理,每一种类型的中断方式对应一个回调函数; 例如定时器有五种中断方式,对应着五个回调函数: ...
  • STM32Cube HAL库中断处理机制,以及回调函数实现原理

    万次阅读 多人点赞 2019-03-20 18:00:05
    看上面回调函数的定义,通过特定条件调用『回调函数』,这里触发的条件就是中断。 4 扩展说明 这里也简单说几点: 1.初学者想直接使用HAL不是不行,需要有一定C语言功底 针对大部分初学者来说,是不建议直接上手HAL...
  • https://www.cnblogs.com/UnfriendlyARM/p/10321838.html
  • 本文是关于按键开关,回调函数中断
  • 中断回调

    千次阅读 2020-09-07 22:25:40
    回调函数的原理是使用函数指针实现类似“软中断”的概念。 比如在上层的两个函数A和B,把自己的函数指针传给了C,C通过调用A和B的函数指针达到“当做了什么,通知上层来调用A或者B”的目的。 从更底层的角度上,代码...
  • 定时器回调函数

    千次阅读 2021-03-11 16:04:05
    定时器回调函数: 如图1所示。 图1为定时器0初始化,溢出时间为1ms。初始化时会传入一个timer0_handler()函数,这个函数在定时器初始化代码中被赋值给了m_tim0_hdl 。定时器溢出后进入中断会判断m_tim0_hdl...
  • STM32定时回调函数

    2018-11-30 19:18:07
    STM32定时回调函数
  • 【STM32】通俗易懂的讲解回调函数

    千次阅读 多人点赞 2020-11-26 15:52:37
    通过助理、大厨和你之间的关系通俗易懂的讲解了回调函数的本质
  • 第一步、使用stm32cubeMX创建工程,选择相应的芯片,配置RCC、SYS、引脚和时钟如下图所示: 注意,由于按键上有上拉电阻,这里选择中断模式的时候,我们选择下降沿触发中断。 第二步,配置输出Keil工程

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 86,741
精华内容 34,696
关键字:

中断回调函数

友情链接: encoladora Pony.zip