当前位置: 首页 > article >正文

正点原子串口例程解读

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

void esp8266_init(void)
{
    huart_wifi.Instance=ESP8266;    //uart3
    huart_wifi.Init.BaudRate=115200; // 设置波特率为115200
    huart_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; // 设置过采样为16
    if(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.kler.cn/a/458406.html

相关文章:

  • AI 自动化编程对编程教育的影响
  • windows下vscode使用msvc编译器出现中文乱码
  • OpenMV与STM32通信全面指南
  • 典型常见的基于知识蒸馏的目标检测方法总结三
  • 一文理清JS中获取盒子宽高各方法的差异
  • Zookeeper模式安装Kafka(含常规、容器两种安装方式)
  • Ollama+OpenWebUI+llama3本地部署
  • 跟着问题学3.1——R-CNN模型详解
  • Spring创建异步线程,使用@Async注解时不指定value可以吗?
  • IT6622: HDMI 1.4 Tx with eARC RX and Embedded MCU
  • 【视觉SLAM:一、初识SLAM】
  • Pytorch知识框架梳理
  • C# 语法糖集锦
  • 【每日学点鸿蒙知识】子窗口方向、RichEdit不居中、本地资源缓存给web、Json转对象丢失方法、监听状态变量数组中内容改变
  • dede-cms关于shell漏洞
  • Unity3D Huatuo技术原理剖析详解
  • 修改RuoYi框架,并添加新项目
  • 实现一个iOS晃动动画
  • KaiOS 4.0 | DataCall and setupData implemention
  • GAMES101:现代计算机图形学入门-笔记-12
  • 如何强制关闭mac卡死的进程
  • 前端(htmlcss)
  • python爬取网站
  • vue最新源码探索分析
  • git分支与部署环境的关系以及开发规范
  • 【HENU】河南大学计院2024 计算机网络 期末复习知识点