前言:
1.中断系统及EXTI外部中断知识点见我的博文:
9.中断系统、EXTI外部中断_eirq-CSDN博客文章浏览阅读301次,点赞7次,收藏6次。EXTI(Extern Interrupt)外部中断EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序。引脚电平变化,申请中断支持的触发方式(引脚电平的变化类型):上升沿(电平从低电平变到高电平的瞬间触发中断)/下降沿(电平从高电平变到低电平的瞬间触发中断)/双边沿(上升沿和下降沿都可以触发中断)/软件触发(程序执行代码就能触发中断)_eirqhttps://blog.csdn.net/m0_61712829/article/details/132433502?spm=1001.2014.3001.55022.本文重点讲USART串口接收中断分别在标准库和HAL库版本下如何使用,其它例如串口初始化程序就不重点阐述了。
IRQ(Interrupt Request)是一种用于请求中断服务的机制,IRQ Handler就是负责处理IRQ中断的中断处理程序。
“IRQHandler” 是中断处理程序的意思。中断处理程序是在计算机系统遇到硬件中断时执行的函数或程序代码。硬件中断可以由外部设备(如键盘、鼠标或计时器)触发,也可以由内部事件(如除零错误或内存故障)触发。 当一个中断事件发生时,操作系统会暂停当前的执行任务,跳转到相应的中断处理程序中执行。中断处理程序通常用于处理和响应中断事件,采取必要的操作来处理中断,并在完成后返回到中断发生的地方继续执行。
当串口接收到数据时,可以配置USART串口使用中断来触发数据接收中断。当接收到数据时,中断处理程序会被调用,可以在其中读取接收到的数据并进行处理。使用中断可以避免轮询方式的查询接收,提高实时性和效率。
1.在usart.c文件中写中断接收和变量的封装函数并重写USART1中断函数接受字符串数据函数。代码如下:
/**
* @brief 中断接收和变量的封装函数
* @param 无
* @retval 无
*/
uint8_t Serial_GetRxFlag(void)//读后自动清除标志位
{
if(usart1_RxFlag == 1)
{
usart1_RxFlag = 0;
return 1;
}
return 0;
}
uint8_t Serial_GetRxData(void)
{
return usart1_RxData;
}
/**
* @brief 重写USART1中断函数接受字符串数据
* @param 无
* @retval 无
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)
{
usart1_RxData = USART_ReceiveData(USART1);
usart1_RxFlag = 1;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
uint8_t Serial_GetRxFlag(void)函数解释如下。
- 判断
usart1_RxFlag
变量是否为1,表示接收到了新的数据。- 如果接收到了新的数据,将
usart1_RxFlag
变量置为0,表示接收标志位已被清除。- 返回1,表示接收到了新的数据。
- 如果没有接收到数据,返回0。
uint8_t Serial_GetRxData(void)函数解释如下。
- 该函数用于获取接收到的数据。
- 直接返回
usart1_RxData
变量,该变量存储了接收到的数据。
void USART1_IRQHandler(void)函数解释如下。
- 该函数是重写的USART1中断处理函数,用于接收字符串数据。
- 通过判断USART1的接收中断标志位
USART_IT_RXNE
是否被置位,确定是否接收到了新的数据。- 如果接收到了新的数据,使用
USART_ReceiveData()
函数从USART1接收数据,并将数据存储到usart1_RxData
变量中。- 将
usart1_RxFlag
变量置为1,表示接收到了新的数据。- 使用
USART_ClearITPendingBit()
函数清除USART1的接收中断标志位。 需要注意的是,以上代码中的函数调用和变量使用可能依赖于库函数和全局变量的定义,确保在使用这些函数之前进行适配,且USART1已正确初始化和配置中断。
2.在main.c中的main函数的while(1)循环中,定义串口中断接收函数。代码如下,这部分代码是在使用串口接收数据并进行处理的部分。
uint8_t RXData;//串口1接收数据
...省略
usart1_Init();//串口1初始化
...
/**
* @brief 串口1接收数据
* @ntoe
* @param 无
* @retval 无
*/
if(Serial_GetRxFlag() == 1)
{
RXData = Serial_GetRxData();
Serial_SendByte(RXData);//数据回传功能,将接收到的这一字节数据回传到电脑
OLED_ShowHexNum(1,8,RXData,2);
}
首先,声明了一个
RXData
变量用于保存串口1接收到的数据。 然后,调用了usart1_Init()
函数进行串口1的初始化设置。 接下来是一个条件判断语句,通过调用Serial_GetRxFlag()
函数判断是否接收到了新的数据。 如果接收到了新的数据,执行以下操作:
- 调用
Serial_GetRxData()
函数获取接收到的数据,将其存储到RXData
变量中。- 调用
Serial_SendByte(RXData)
函数将接收到的数据回传到电脑。- 调用
OLED_ShowHexNum(1,8,RXData,2)
函数在OLED屏幕上显示接收到的数据的十六进制形式。 需要注意的是,以上代码中的函数调用和变量使用可能依赖于其他部分的定义和实现,确保在使用之前进行适配,且串口1已正确初始化和配置。
3.串口接收数据测试。在main.c中的main函数的while(1)循环前,借用oled显示屏来显示接收到的串口数据。使用如下代码:
OLED_ShowString(1,1,"RxData:");//串口1接收数据测试
1.在stm32f1xx_it.c文件中,写void USART2_IRQHandler(void)函数。当USART2的中断发生时,系统会自动跳转到这个函数进行处理。
/**
* @brief This function handles USART2 global interrupt.
*/
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
uart2_receiver_handle();
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
解释如下:
uart2_receiver_handle();
:这是用户自定义的函数,用于处理USART2接收到的数据。在USART2接收到数据时,该函数将被调用,用户可在该函数内部处理接收到的数据。HAL_UART_IRQHandler(&huart2);
:这是调用HAL库函数的代码,用于处理USART2的中断。HAL库是一种硬件抽象层库,用于简化嵌入式系统的开发。该函数会处理USART2的中断,并根据具体情况执行相应的操作,如处理发送和接收缓冲区、错误处理等。 在这段代码中,用户可以根据自己的需求,在"USER CODE"注释处插入额外的代码来处理特定的操作或事件。例如,可以在USART2接收到数据后,根据接收的数据进行一些特定的处理,如解析命令、更新状态等。 需要注意的是,以上代码是一段模板代码,具体的操作和功能取决于用户自定义的函数和使用的USART2的配置。用户需要根据具体的需求,在USART2_IRQHandler
函数和uart2_receiver_handle()
函数中实现自己所需要的功能。
2.然后在usart.c文件中写串口数据接收处理与数据接收清0函数。
unsigned char receive_buf[512]; //串口2接收缓存数组
unsigned char receive_start = 0; //串口2接收开始标志位
uint16_t receive_count = 0; //串口2接收数据计数器
uint16_t receive_finish = 0; //串口2接收结束标志位
/**
* @brief 串口2数据接收处理函数
* @param[in] none
* @retval none
*/
void uart2_receiver_handle(void)
{
unsigned char receive_data = 0;
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_RXNE) != RESET)
{
HAL_UART_Receive(&huart2, &receive_data, 1, 1000);//串口2接收1位数据
receive_buf[receive_count++] = receive_data;
receive_start = 1; //串口2接收数据开始标志位置1
receive_finish = 0; //串口2接收数据完成标志位清0
}
}
/**
* @brief 串口2数据接收清0函数
* @param[in] len:清空的数据长度
* @retval none
*/
void uart2_receiver_clear(uint16_t len)
{
memset(receive_buf,0x00,len);
receive_count = 0;
receive_start = 0;
receive_finish = 0;
}
以上函数中的关键步骤如下:
- 声明一个无符号字符变量
receive_data
,用于保存接收到的数据。- 通过判断UART2的接收标志位
UART_FLAG_RXNE
是否被置位,确定是否接收到了数据。- 如果接收到了数据,使用HAL库函数
HAL_UART_Receive()
从UART2接收1个字节的数据,并存储到receive_data
变量中。- 将接收到的数据存储到一个接收缓冲区
receive_buf[]
中,使用receive_count
变量记录接收到的数据字节数。- 设置
receive_start
变量为1,表示串口2开始接收数据。- 清零
receive_finish
变量,表示串口2接收数据还未完成。 然后是uart2_receiver_clear()
函数,该函数用于清空接收缓冲区的数据。函数中的关键步骤如下:- 使用
memset()
函数将接收缓冲区receive_buf[]
中的数据清零,长度为len
。- 将
receive_count
、receive_start
和receive_finish
变量都重新赋值为0,表示接收缓冲区已清空,接收数据未开始。 这两个函数可以根据具体需求进行使用,如根据receive_count
和receive_buf[]
中的数据进行进一步处理、解析等。需要注意的是,以上代码中的函数调用和变量使用可能依赖于库函数和全局变量的定义,确保在使用这些函数之前进行适配,且串口2已正确初始化和配置。
3.根据串口接收开始标志位,进行使用串口接收中断。如上程序中使用到的标志位receive_start,为1则开始串口接收数据。在当判断标志位为1时,执行相应的功能程序就可以了。使用如下代码:
if(receive_start == 1) {.....}