串口通信RXNE+IDLE接受不定长数据

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

野火的板子usart1与ch340连接,通过串口发送的数据可以从PC端接收到,但是与8266连接的usart3没有,方便的话可以自己买一个usb转ttl模块,不然调试的时候两眼一抹黑,不知道哪里出了问题。
编程思路参考野火提供的历程,因为自己使用的事HAL库,所以就重写了一份,通过RXNE+IDLE中断进行不定长数据的接收,与8266模块进行通信。优点是可以知道具体接收的数据长度。缺点是需要频繁进出中断。之前尝试过也DMA+IDLE的方式,但是无法知道接收数据的具体长度,我比较菜鸡,没找到更好一点的办法,所以就放弃了。
编程思路:
每次进入Cplt中断,将DR中数据保存到结构体的数组中,字长加1(要记录字长,方便后续在结尾添加\0),当空闲中断(IDLE)产生时,表示一帧数据接受完成,在回调函数中将finish_flag置1。在主函数中不断查询是否标志位置1,如果u1接到一帧数据,通过u3将数据发送给8266,将字长清零,标志位置0,等待下一次数据到来。从8266中接回的数据同理。


一、串口通讯初始化

1)通过32cube直接生成初始化文件,简单方便,模式Asynchronous,波特率115200其他都默认就可以。usart1与usart3配置相同。
串口初始化界面

2)然后点击右上角生成既可
在这里插入图片描述

二、使用步骤

1.串口中断结构体创建

usart.h
#define MAX_RX_LEN        256
typedef struct USART_FRAM{        // 接收结构体框架
    uint8_t     Finish_flag;      // 接收一帧完成
    uint16_t    RX_Len;           // 接收字长
    char        *Data;            // 数组指针,在usart.c中创建数组,指向他,能减少全区变量的创建
}USART_FRAM, *pUSART_FRAM;

2.Cplt中断回调函数(RXNE)

代码如下(示例):

usart.c
/**
  * @brief  串口RxCplt中断回调(RXNE)
  * @param  huart句柄
  * @retval NONE
  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  
  if(USART3 == huart->Instance){      
    if( ESP8266_Fram.RX_Len < (MAX_RX_LEN - 1) ){
        ESP8266_Fram.Data[ESP8266_Fram.RX_Len ++ ] = Usart3_buf;
        ESP_Usart3_Start();              
    }    
  }
  else if(USART1 == huart->Instance){
    if( Usart1_Fram.RX_Len < (MAX_RX_LEN - 1) ){
        Usart1_Fram.Data[Usart1_Fram.RX_Len ++ ] = Usart1_buf;
        Usart1_Start();
    }    
  }
}

3.IDLE回调函数

代码如下(示例):

usart.c
/**
  * @brief  串口IDLE中断回调
  * @param  huart句柄
  * @retval NONE
  */
void UART_IDLECallback(UART_HandleTypeDef *huart)
{   
    uint32_t tmp;
    if(USART3 == huart->Instance){
        tmp = huart->Instance->SR;  
        tmp = huart->Instance->DR;
        __HAL_UART_CLEAR_IDLEFLAG(huart);      //IDLE清除标志位需要先读取SR,再读取DR,手册写的
            
        ESP8266_Fram.Finish_flag = 1;
    }
    else if(USART1 == huart->Instance){
        tmp = huart->Instance->SR;
        tmp = huart->Instance->DR;
        __HAL_UART_CLEAR_IDLEFLAG(huart);
        
        Usart1_Fram.Finish_flag = 1;
    }    
}

4.串口IT使能函数封装

/**
  * @brief  串口1中断使能
  * @param  VOID
  * @retval NONE
  */
void Usart1_Start(void){
    HAL_UART_Receive_IT(&huart1, &Usart1_buf, 1);
    __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
}

/**
  * @brief  串口3中断使能(ESP8266)
  * @param  VOID
  * @retval NONE
  */
void ESP_Usart3_Start(void){
    HAL_UART_Receive_IT(&huart3, &Usart3_buf, 1);
    __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);
}

5.返回结构体指针

/**
  * @brief  获得U1 fram
  * @param  VOID
  * @retval Usart1_Fram地址
  */
pUSART_FRAM Usart1_GetFram(void){
    pUSART_FRAM tmp = &Usart1_Fram;
    return tmp;
}  

/**
  * @brief  获得ESP_fram
  * @param  VOID
  * @retval ESP8266_Fram地址
  */
pUSART_FRAM ESP_GetFram(void){
    pUSART_FRAM tmp = &ESP8266_Fram;
    return tmp;
}

6.主函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USART3_UART_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
  Usart1_Start();                                //初始化u1
  ESP_Usart3_Start();                            //初始化u3
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  pUSART_FRAM pUsart1_Fram  = Usart1_GetFram();  //获取u1框架指针
  pUSART_FRAM pESP8266_Fram = ESP_GetFram();     //获取u3框架指针
  Usart_SendString(&huart3, (uint8_t*)AT);
  while (1)
  {
    if( pUsart1_Fram->Finish_flag ){
        pUsart1_Fram->Finish_flag = 0;
        pUsart1_Fram->Data[ pUsart1_Fram->RX_Len ]  = '\0';
        Usart_SendString(&huart3, (uint8_t*)pUsart1_Fram->Data);
        memset(pUsart1_Fram->Data, 0, pUsart1_Fram->RX_Len);
        pUsart1_Fram->RX_Len = 0;
    }
    else if( pESP8266_Fram->Finish_flag ){
        pESP8266_Fram->Finish_flag = 0;
        pESP8266_Fram->Data[ pESP8266_Fram->RX_Len ] = '\0';
        Usart_SendString(&huart1, (uint8_t*)pESP8266_Fram->Data);
        memset(pESP8266_Fram->Data, 0, pESP8266_Fram->RX_Len);
        pESP8266_Fram->RX_Len = 0;        
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

总结

如果有哪里写的不对,希望大家能帮忙指出,刚刚入门,轻喷
代码放在下面连接中,需要自取
链接:https://pan.baidu.com/s/1xjIGeWwHICtS3IwpeI5w0A
提取码:kxz5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值