正点原子串口例程解读

ops/2025/1/2 16:50:44/

首先是串口初始化,这里初始化的是usart3

void esp8266_init(void)
{huart_wifi.Instance=ESP8266;    //uart3huart_wifi.Init.BaudRate=115200; // 设置波特率为115200huart_wifi.Init.WordLength=UART_WORDLENGTH_8B; // 设置数据位长度为8位huart_wifi.Init.StopBits=UART_STOPBITS_1; // 设置停止位为1位huart_wifi.Init.Parity=UART_PARITY_NONE; // 设置奇偶校验为无huart_wifi.Init.Mode=UART_MODE_TX_RX; // 设置模式为接收和发送huart_wifi.Init.HwFlowCtl=UART_HWCONTROL_NONE; // 设置硬件流控制为无huart_wifi.Init.OverSampling=UART_OVERSAMPLING_16; // 设置过采样为16if(HAL_UART_Init(&huart_wifi)!=HAL_OK){Error_Handler();}/* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);}

其中,HAL_UART_Receive_IT开启标志位UART_IT_RXNE后,我们就可以配置uart3的中断函数

void ESP8266_IRQHandler(void)
{HAL_UART_IRQHandler(&huart_wifi);
}

    函数中用的是hal库的中断函数代码,函数实现比较复杂,我们可以自己写一个中断函数,配合实现。

      这边是按照官方回调函数,在void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart),中定义何时结束数据传输。

        先讲一下调用结构 

由于   HAL_UART_Receive_IT开启接收中断,会调用我们写好的ESP8266_IRQHandler,进入到

HAL_UART_IRQHandler(&huart_wifi);   第一个if语句判断状态寄存器sr中的RXNE:读取数据寄存器不为空 (Read data register not empty)。和控制寄存器cr中的RXNEIERXNE 中断使能 (RXNE interrupt enable),当rxne不为空切使能rxne中断时候,进入UART_Receive_IT(huart);

点击跳转,找到如下

这个函数的实现官方是弱定义,我们可以重写。

调用结构: 调用  → 被调用

HAL_UART_IRQHandler   → UART_Receive_IT  →  HAL_UART_RxCpltCallback。

下面我们看一下正点原子是怎么实现自定义的串口通讯格式。

/*** @brief       Rx传输回调函数* @param       huart: UART句柄类型指针* @retval      无*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{//g_usart_rx_sta  0-13位表示交收到if(huart->Instance == ESP8266)             /* 如果是串口3 */{if((g_wifi_rx_sta & (1<<15)) == 0)      /* 接收未完成 */{if(g_wifi_rx_sta & (1<<14) )         /* 接收到了0x0d,换行符是由 2个字节组成:0x0D 和 0x0A */{if(uart_recv_it_buf[0] != 0x0a) {g_wifi_rx_sta = 0;         /* 接收错误,重新开始 */}else {g_wifi_rx_sta |= (1<<15);   /* 接收完成了 */}}else                                /* 还没收到0X0D */{if(uart_recv_it_buf[0] == 0x0d){g_wifi_rx_sta |= (1<<14);}else{rx_wifi_msg[g_wifi_rx_sta & 0X3FFF] = uart_recv_it_buf[0] ;g_wifi_rx_sta++;if(g_wifi_rx_sta > (WIFI_RX_LEN - 1)){g_wifi_rx_sta = 0;     /* 接收数据错误,重新开始接收 */}}}}HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);}}

打开正点原子f407开发指南,我们看到

        原子的开发手册对接收中断回调函数代码解读非常完整,清晰,大家可以去看下。

注意的是,用串口助手一定要勾选发送新行(结尾自动发送回车符号),因为代码涉及到对 回车的判断( 0x0d  + 0x0a 表示回车符 )。

g_wifi_rx_sta,表示接受状态标识符,uint16_t类型。

        下面我说一下我理解的代码思路

1.在回调函数中判断是否已经接收完成(bit 15 位为1)  g_wifi_rx_sta    &   (1<<15)    ==0

如果接收完成,调用接收中断函数HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);

2,如果已经接收到了 回车的前半部分 :0x0d                  g_wifi_rx_sta    &   (1<<14)    ==1

如果 后面接上的是后半部分 0x0a,那么就判定为接收完成(g_wifi_rx_sta |=(1<<15)),相反如果不是,那么g_wifi_rx_sta

置0,重新开始计数。

3,如果还没有接收到回车的前半部分,那么就先判定是否中断里面接受到的buffer:uart_recv_it_buf[0]已经是0x0d,如果是的话,那么将bit14置1,g_wifi_rx_sta    |=  (1<<14)

4,如果uart_recv_it_buf[0]不是是0x0d,那么就接收字符,原子在这里设置了一个 rx_wifi_msg[ buffer_len ] , buffer_len  是你设置的最大接受缓冲区长度,我这里设置最大128 。

前面我们在初始化esp8266已经开启了   HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);  意思是每次中断接收 1个字节的数据。

rx_wifi_msg[ g_wifi_rx_sta  & 0x3fff ]=uart_recv_it_buf[0] ,0x3fff因为是0-13位表示接受数据位数,

每次都接受1位数据,直到设定的最大接收值。

g_wifi_rx_sta ++(每次进入中断一次,而且没有接收到回车判定符号 0x0d,那么就会 自加)。

然后就是判定是否接收长度大于设定长度,如果大于,就将    g_wifi_rx_sta=0;。

main函数部分代码。

if (g_wifi_rx_sta & (1<<15) )         /* 接收到了数据? */{len = g_wifi_rx_sta & 0x3fff;  /* 得到此次接收到的数据长度 */printf("\r\n您发送的消息为:\r\n");HAL_UART_Transmit(&huart_wifi,(uint8_t*)rx_wifi_msg,len,1000);    /* 发送接收到的数据 */while(__HAL_UART_GET_FLAG(&huart_wifi,UART_FLAG_TC)!=SET);           /* 等待发送结束 */printf("\r\n\r\n");             /* 插入换行 */g_wifi_rx_sta = 0;}else{times++;if (times % 5000 == 0){printf("\r\n正点原子 STM32开发板 串口实验\r\n");printf("正点原子@ALIENTEK\r\n\r\n\r\n");}if (times % 200 == 0) printf("请输入数据,以回车键结束\r\n");if (times % 30  == 0) LED0_TOGGLE(); /* 闪烁LED,提示系统正在运行. */delay_ms(10);}}


http://www.ppmy.cn/ops/146305.html

相关文章

异步爬虫之协程的基本原理

我们知道爬虫是 IO 密集型任务&#xff0c;例如使用 requests 库来爬取某个站点&#xff0c;当发出一个请求后&#xff0c;程序必须等待网站返回响应&#xff0c;才能接着运行&#xff0c;而在等待响应的过程中&#xff0c;整个爬虫程序是一直在等待的&#xff0c;实际上没有做…

关于 PCB线路板细节锣槽问题 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/144783817 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

第二十七周学习周报

目录 摘要Abstract1. 文献阅读1.1 SVM1.2 BI-LSTM1.4 实验研究 总结 摘要 在本周阅读的文献中&#xff0c;作者提出了一种将SVM和BI-LSTM进行耦合的新型水质预测模型。BI-LSTM模型用于提取线性和非线性模式&#xff0c;然后将其发送到SVM模型。将BILSTM模型与SVM模型相结合提高…

linux上虚拟机显示网络不可用的解决方法

目录 类似这样的问题 一、检查虚拟机网络设置 二、检查主机网络连接 三、检查虚拟机内部网络配置 四、检查网络服务状态 五、管理网络服务冲突 六、配置静态IP地址 七、检查防火墙和安全组设置 八、重新安装网络驱动程序 十一、寻求专业帮助 类似这样的问题 一、检查…

安全攻防:中间人攻击

1. 中间人攻击定义 中间人攻击&#xff08;简称MITM&#xff09;是攻击者在进行网络通信的双方中间&#xff0c;分别与两端建立独立的联系&#xff0c;并进行数据嗅探甚至篡改&#xff0c;而通信的双方却对中间人毫不知情&#xff0c;认为自己是直接在与对端通信。2. 常见中间人…

基于websocket实现本地web语音聊天

基于libwebsockets库实现语音聊天 1、关于libwebsocket库自行编译2、client使用htmljs 代码3、服务端代码 1、关于libwebsocket库自行编译 2、client使用htmljs 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"…

《计算机组成及汇编语言原理》阅读笔记:p128-p132

《计算机组成及汇编语言原理》学习第 10 天&#xff0c;p128-p132 总结&#xff0c;总计 5 页。 一、技术总结 1.8088 organization and architecture 8088处理器是16位电脑&#xff0c;寄存器是16位&#xff0c;数据总线(data bus)是8位&#xff0c;地址总线是20位。 (1)g…

Visual Studio光标变为方块状换回方法

不知按了什么&#xff0c;Visual Studio光标变为方块状&#xff0c;输入内容会被覆盖掉&#xff0c;挺影响效率。 或者Visual Studio光标变为方块状&#xff0c;不影响输入内容。习惯了线光标&#xff0c;就是想换回来&#xff0c; Visual Studio Code 设置光标样式成功换回。…