基于FreeRTOS中的串口不定长接收(使用队列进行数据传输)

简介: 基于FreeRTOS中的串口不定长接收(使用队列进行数据传输)

基于FreeRTOS中的串口不定长接收(使用队列进行数据传输)

一.基本收发

首先是仿照江科大标准库移植的串口基本收发函数,进行了一些改写,能够在单字节以及数据包之间进行模式转换:

uint8_t Receive_Mode = 0;//接收模式:单字节或数据包
uint8_t Receive_State;//状态机变量
uint8_t Receive_Byte[1],Receive_ITFlag;//接收单字节数据;接收标志位//!!!这里单字节接收缓冲一定要用数组形式!!!
uint8_t Receive_PocketData[Receive_Pocket_Max_Len] = {
   0};//接收数据包数组
uint16_t Receive_Pocket_Index = 0;//接收指向

extern QueueHandle_t xQueueHandle_Usart3;//队列句柄

void Serial_ChangeMode(Serial_Mode Mode)
{
   
    Receive_Mode = (uint8_t)Mode;
}

void Serial_SendByte(uint8_t Byte)
{
   
    //这里非阻塞发送暂时不能用,否则数据会传输错误,原因暂不明
    //HAL_UART_Transmit_IT(&huart3,&Byte,1);
    HAL_UART_Transmit(&huart3,&Byte,1,HAL_MAX_DELAY);
}

void Serial_SendString(uint8_t *String)
{
   
    HAL_UART_Transmit(&huart3,String,strlen((const char*)String),HAL_MAX_DELAY);
}

void Serial_SendArray(uint8_t* ArrayData,uint16_t Length)
{
   
    HAL_UART_Transmit(&huart3,ArrayData,Length,HAL_MAX_DELAY);
}

void Serical_SendPocket(uint8_t* PocketData)
{
   
    Serial_SendByte(0xFD);
    Serial_SendArray(PocketData,Receive_Pocket_Index);
    Serial_SendByte(0xFE);
    Serial_SendByte(0xFF);
}
//接收单字节和数据包标志位
uint8_t Serial_GetReceiveFlag(void)
{
   
    if(Receive_ITFlag == 1)
    {
   
        Receive_ITFlag = 0;
        return 1;
    }
    return 0;
}

//单字节数据
uint8_t Serial_ReceiveByte(void)
{
   
    return Receive_Byte[0];
}
//数据包数据
void Serial_ReceivePocket(uint8_t *PocketArray)
{
   
    uint8_t i = 0;
    Receive_GetDataState = 0;
    for (i = 0; Receive_PocketData[i] != '\0'; i ++)
    {
   
        PocketArray[i] = Receive_PocketData[i];
    }
}
//数据包长度
uint16_t Serial_GetPocketLength(void)
{
   
    return Receive_Pocket_Index;
}

下面是中断回调函数:

​ 注意中断回调函数中一定要使用中断安全API:xQueueSendToBackFromISR

​ 否则不能正确接收数据或者程序卡死

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   
    if(huart->Instance == USART3)
    {
   
        switch(Receive_Mode)
        {
   
        case 0:
            Receive_ITFlag = 1;
            xQueueSendToBackFromISR(xQueueHandle_Usart3,&Receive_Byte,0);
        break;
        case 1:
                if(Receive_State == 0)
                {
   
                    if (Receive_Byte[0] == 0xFD)
                    {
   
                        Receive_Pocket_Index = 0;
                        Receive_State = 1;
                    }
                }
                else if(Receive_State == 1)
                {
   
                     if(Receive_Byte[0] == 0xFE)
                        Receive_State = 2;
                     else
                     {
   
                        Receive_PocketData[Receive_Pocket_Index] = Receive_Byte[0];
                        Receive_Pocket_Index++;
                     }
                     if(Receive_Pocket_Index >= Receive_Pocket_Max_Len)
                     {
   
                        Receive_ITFlag = 1;
                        Receive_PocketData[Receive_Pocket_Index] = '\0';
                        Receive_State = 0;
                     }

                }
                else if(Receive_State == 2)
                {
   
                    if(Receive_Byte[0] == 0xFF)
                    {
   
                        Receive_ITFlag = 1;
                        Receive_PocketData[Receive_Pocket_Index] = '\0';
                        Receive_State = 0;
                        xQueueSendToBackFromISR(xQueueHandle_Usart3,&Receive_PocketData,0);
                    }
                }
        break;
        }
        HAL_UART_Receive_IT(&huart3,Receive_Byte,1);//使能中断函数,每次使用完就要调用
    }
}

二.测试部分

以下是在freertos.c中写的测试代码:

​ 这里是一些定义声明:

/**********串口相关变量************/
extern uint8_t Receive_Byte[1];
BaseType_t ret;

/**********************************/

/**********任务句柄声明************/
TaskHandle_t  xLedTaskHandle;
/**********************************/

/**********队列句柄声明************/
QueueHandle_t xQueueHandle_Usart3;//串口3队列句柄
/**********************************/

这里是初始化代码,删除了部分不重要的注释:

​ 这里的队列单元大小要注意,必须设置为sizeof(uint8_t *),在stm32这种32位MCU中指针的大小通常是4个字节,即32位,所以这里要把队列单元设置为指针的大小,代表存储地址,

​ 如果这里设置的不对,那么接收的数据就会出现丢包,数据错误。

void MX_FREERTOS_Init(void) 
{
   
    Serial_ChangeMode(Pocket);
    HAL_UART_Receive_IT(&huart3,Receive_Byte,1);//启动串口3

    xQueueHandle_Usart3 = xQueueCreate(128,sizeof(uint8_t*));

    ret = xTaskCreate(Led_Task,"Led_Task",512,NULL,24,&xLedTaskHandle);
}

这里是测试函数:

​ 这里非常重要,因为在串口模块中我们是将数据的地址写入队列中的,故这里接收必须使用二重指针,Signal来接收队列里储存的地址,将地址取出后解引*Signal即可读取数据

void Led_Task(void *params)
{
   
    uint8_t **Signal = 0;//这里必须是二维指针
    while(1)
    {
   
        if (xQueueReceive(xQueueHandle_Usart3,*Signal, portMAX_DELAY) == pdPASS)
        {
   
            //Serial_SendByte(**Signal);
            Serical_SendPocket(*Signal);//传入字符或字符串地址
            //Led_SetState((Led_State)(**Signal));

        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

三.实验现象

以下是实验现象:

a4f9bebd6bf9427a14c50d2f33f85239.png

这里单字节和不定长数据包都能实现相应功能,就只展示数据包的接收过程了。

相关文章
串口通讯,三种数据传输方式介绍
串口通讯,三种数据传输方式介绍
194 0
利用单片机串口实现甲乙两机的数据传输
简介:利用单片机串口实现甲乙两机的数据传输
利用单片机串口实现甲乙两机的数据传输
|
5月前
|
SQL 分布式计算 监控
在数据传输服务(DTS)中,要查看每个小时源端产生了多少条数据
【2月更文挑战第32天】在数据传输服务(DTS)中,要查看每个小时源端产生了多少条数据
56 6
|
5月前
|
存储 SQL NoSQL
数据传输DTS同步问题之同步失败如何解决
数据传输服务(DTS)是一项专注于数据迁移和同步的云服务,在使用过程中可能遇到多种问题,本合集精选常见的DTS数据传输问题及其答疑解惑,以助用户顺利实现数据流转。
|
5月前
|
Cloud Native NoSQL 关系型数据库
数据传输DTS校验问题之校验报错如何解决
数据传输服务(DTS)是一项专注于数据迁移和同步的云服务,在使用过程中可能遇到多种问题,本合集精选常见的DTS数据传输问题及其答疑解惑,以助用户顺利实现数据流转。
|
5月前
DTS数据传输延迟可能有多种原因
【1月更文挑战第16天】【1月更文挑战第79篇】DTS数据传输延迟可能有多种原因
260 2
|
5月前
|
NoSQL Redis 数据库
数据传输DTS中金融云跨账号同步Redis,增量校验报错了
【1月更文挑战第16天】【1月更文挑战第80篇】数据传输DTS中金融云跨账号同步Redis,增量校验报错了
103 1
|
2月前
|
存储 安全 关系型数据库
跨越地域的数据传输大冒险!如何轻松更换DTS实例地域,全面攻略揭秘!
【8月更文挑战第15天】在数字时代的浪潮中,数据传输服务(DTS)是企业跨地域扩张的重要桥梁。然而,更换DTS实例地域就像是一场冒险旅程,充满了未知和挑战。本文将带你踏上这场跨越地域的数据传输大冒险,揭示如何轻松更换DTS实例地域的秘密。无论你是追求速度的迁移高手,还是成本敏感的手动操作者,这里都有你需要的答案。让我们一起探索这个神秘的世界,解锁数据传输的无限可能!
41 0
|
2月前
|
关系型数据库 MySQL OLAP
数据传输DTS是什么?
【8月更文挑战第30天】数据传输DTS是什么?
102 3
|
4月前
|
关系型数据库 MySQL 分布式数据库
PolarDB操作报错合集之当使用DTS(数据传输服务)同步的表在目标库中进行LEFT JOIN查询时遇到异常,是什么导致的
在使用阿里云的PolarDB(包括PolarDB-X)时,用户可能会遇到各种操作报错。下面汇总了一些常见的报错情况及其可能的原因和解决办法:1.安装PolarDB-X报错、2.PolarDB安装后无法连接、3.PolarDB-X 使用rpm安装启动卡顿、4.PolarDB执行UPDATE/INSERT报错、5.DDL操作提示“Lock conflict”、6.数据集成时联通PolarDB报错、7.编译DN报错(RockyLinux)、8.CheckStorage报错(源数据库实例被删除)、9.嵌套事务错误(TDDL-4604)。