[MCU] 【CH579M-R1】+求助:如何接收完整的串口数据

hujj   2020-10-6 15:34 楼主

    通过串口的范例测试可以接收和发送数据,在串口调试助手中发送和接收都正常,下图为测试过程,无论发送的字符串长短不同,开发板均能返回正确的字符串。

uart_11.jpg

    但是我试图的开发板中将接收到的字符串显示在LCD屏幕上却遇到了问题,接收函数总是按照每7个字符截取,无法获得完整的字符串。如下图,我发送的是“2020-10-06 14:36:50”,但最后只显示"36:50",之前的“2020-10-06 14:"却看不到,仔细分析是先显示前7个字符”2020-10“,然后显示第二组7个字符”-06 14:"时覆盖了前7个字符,最后的5个字符“36:50"又将第二组字符覆盖了。

uart_12.jpg

    下图是发送”2020-10-06 14:36:50 Test"字符串(长度24),显示的是最后3个字符“est”(第3组的最后一个“T”没有被覆盖)。

uart_13.jpg

    下图是发送“2020-10-06”字符串(10个字符),也是按照7+3的方式显示。

uart_14.jpg

    查看资料说是接收函数设定的每次接收长度为7个字节,我找了很久也没有发现是在哪里设定的,是不是可以将这个长度设定为16个字节或者更多,或者用什么办法才能将接收到的每段字符串“拼接”起来?希望能够得到各位大佬帮助,谢谢!

补充内容 (2020-10-19 09:39): 按照damiaa版主的提示,终于能显示出完整的串口接收字符了,详见11楼。

回复评论 (13)

我是在串口中断函数中设置一个接收标志,然后在主循环中根据这个标志来显示接收到的字符串,并清除标志。下面是串口中断函数,这里除了添加了设置标志的代码外,未作任何修改:

void UART1_IRQHandler(void)
{
    UINT8 i;
    
    switch( UART1_GetITFlag() )
    {
        case UART_II_LINE_STAT:        // 线路状态错误
            UART1_GetLinSTA();
            break;
        
        case UART_II_RECV_RDY:          // 数据达到设置触发点
            for(i=0; i!=trigB; i++)
            {
                RxBuff[i] = UART1_RecvByte();
                UART1_SendByte(RxBuff[i]);
            }
            rxok = i;                   //设置接收标志
            break;
        
        case UART_II_RECV_TOUT:         // 接收超时,暂时一帧数据接收完成
            i = UART1_RecvString(RxBuff);
            UART1_SendString( RxBuff, i ); 
        
            break;
        
        case UART_II_THR_EMPTY:         // 发送缓存区空,可继续发送
            break;
        
        case UART_II_MODEM_CHG:         // 只支持串口0
            break;
        
        default:
            break;
    }
}

 

下面是主循环中的判断和显示的代码:

        if(rxok>0){
            LCD_clear_line(2);        //清除当前行
            LCD_clear_line(3);
            LCD_clear_line(4);
            LCD_write_BG(0,2,RxBuff); //显示接收到的字符
            LCD_write_ASCII(0,4,1,RxBuff);
            LCD_write_value(0,5,3,0,0,rxok);
            UART1_CLR_RXFIFO();       //清除缓存
            rxok = 0;
        }

点赞  2020-10-6 15:59

我将串口接收中断函数中的接收循环trigB用16替换,串口调试助手接收到的数据却与发送的不同:

uart_20.jpg

修改的代码见下面粗体字部分:

void UART1_IRQHandler(void)
{
    UINT8 i;
    
    switch( UART1_GetITFlag() )
    {
        case UART_II_LINE_STAT:        // 线路状态错误
            UART1_GetLinSTA();
            break;
        
        case UART_II_RECV_RDY:          // 数据达到设置触发点
            for(i=0; i!=trigB; i++)                 //其中的i!=trigB;修改为i < 16
            {
                RxBuff = UART1_RecvByte();
                UART1_SendByte(RxBuff);
            }
            rxok = i;                   //设置接收标志
            break;
        
        case UART_II_RECV_TOUT:         // 接收超时,暂时一帧数据接收完成
            i = UART1_RecvString(RxBuff);
            UART1_SendString( RxBuff, i ); 
        
            break;
        
        case UART_II_THR_EMPTY:         // 发送缓存区空,可继续发送
            break;
        
        case UART_II_MODEM_CHG:         // 只支持串口0
            break;
        
        default:
            break;
    }
}

点赞  2020-10-6 16:20

加一个简单的协议,比如以'\n'结尾,收到\n时再处理数据

虾扯蛋,蛋扯虾,虾扯蛋扯虾
点赞  2020-10-6 20:07
引用: littleshrimp 发表于 2020-10-6 20:07 加一个简单的协议,比如以'\n'结尾,收到\n时再处理数据

谢谢指点!我试试看。

点赞  2020-10-6 20:46

    尝试加结束标志测试了一下,但没有成功,串口辅助调试助手接收的数据与发送的不一致(见下图):

uart_20.jpg

    其中不可见字符是十六进制11:

uart_21.jpg

    单片机中显示出来的字符如下:

uart_22.jpg

    也许是我的测试的代码不正确,代码如下:

        case UART_II_RECV_RDY:         // 数据达到设置触发点
/*
            for(i=0; i!=trigB; i++){
                RxBuff = UART1_RecvByte();
                UART1_SendByte(RxBuff);
            }
*/
            while(ok < 2){
                RxBuff = UART1_RecvByte();
                UART1_SendByte(RxBuff);
				if((RxBuff == 'n') & (ok > 0))
					ok++;              //收到结束标志2
				else{
				    if(RxBuff == '/')
						ok = 1;
					else
						ok = 0;
				}
                i++;
				if(i>15)
					ok = 2;            //最长不超过16个字节
            }
			rxok = i;                  //设置接收标志
            break;
        

 

    我想要是直接修改设置的触发点可能更方便些,因为我目前只想通过串口来设置日期和时间,字符串长度有16位就基本可行(年月日共8位、时分共4位,再加上若干标识符),现在就是不清楚在哪里可以修改这个接收长度。

 

点赞  2020-10-7 10:32
玩板看这里: https://bbs.eeworld.com.cn/elecplay.html EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!
点赞  2020-10-9 16:01

要自己处理,你可以百度一下 串口完整数据包 的相关文章.

默认摸鱼,再摸鱼。2022、9、28
点赞  2020-10-11 21:36
引用: freebsder 发表于 2020-10-11 21:36 要自己处理,你可以百度一下 串口完整数据包 的相关文章.

谢谢指点!我去搜索看看。

点赞  2020-10-12 08:06

串口程序一般可以这样处理。

 

接收单字节串口数据==》环形缓冲区=》解析程序读环形缓冲并释放已经读的数据,然后放到解析缓冲中解析数据=》(如果解析到一个完整命令)执行解析命令

 

接收单字节串口数据==》环形缓冲区 放在中断函数中 

解析程序读环形缓冲并释放已经读的数据,然后放到解析缓冲中解析数据=》(如果解析到一个完整命令)执行解析命令 放在主程序中

本帖最后由 damiaa 于 2020-10-12 09:00 编辑
点赞  2020-10-12 08:58

    感谢大家的热心帮助,今天按照damiaa版主的提示,用一个变量作接收和回发的中转,原RxBuff数组作环形缓冲区,中断触发的字节数改为1,顺利地实现了串口多字节接收。下图为测试过程:

uart_31.jpg

    从串口调试助手发送字符串,并接收回发的数据,没有任何问题(见下图):

uart_33.jpg

    单片机接收到的字符串显示在LCD屏幕上也完全一致(屏幕倒数第3行):

uart_32.jpg

    至此,已经基本上掌握了串口使用,再次感谢各位!

本帖最后由 hujj 于 2020-10-18 17:05 编辑
点赞  2020-10-18 17:01

这是串口中断设置的代码:

    // 中断方式:接收数据后发送出去
    UART1_ByteTrigCfg( UART_1BYTE_TRIG );
    trigB = 1;
    UART1_INTCfg( ENABLE, RB_IER_RECV_RDY|RB_IER_LINE_STAT );
    NVIC_EnableIRQ( UART1_IRQn );

 

这是串口中断处理的代码(部分):

        case UART_II_RECV_RDY:         // 数据达到设置触发点
            buf = UART1_RecvByte();
            UART1_SendByte(buf);
            RxBuff[RxID] = buf;
            RxID++;
            if(RxID > 49)
                RxID = 0;

点赞  2020-10-18 17:04

有直接可用的压缩包吗?

欲穷千里目 更上一层楼
点赞  2024-10-7 07:38
引用: 程英茂 发表于 2024-10-7 07:38 有直接可用的压缩包吗?

找到了之前的压缩文件,希望能够帮到你。

2024111016471595.zip (19.76 MB)
(下载次数: 0, 5 天前 上传)
点赞  2024-11-10 16:48
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复