hujj 发表于 2020-10-6 15:34

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

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

<p></p>

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

<p></p>

<p>&nbsp; &nbsp; 下图是发送&rdquo;2020-10-06 14:36:50 Test&quot;字符串(长度24),显示的是最后3个字符&ldquo;est&rdquo;(第3组的最后一个&ldquo;T&rdquo;没有被覆盖)。</p>

<p></p>

<p>&nbsp; &nbsp; 下图是发送&ldquo;2020-10-06&rdquo;字符串(10个字符),也是按照7+3的方式显示。</p>

<p></p>

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


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

hujj 发表于 2020-10-6 15:59

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

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

<p>&nbsp;</p>

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

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

hujj 发表于 2020-10-6 16:20

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

<p></p>

<p>修改的代码见下面粗体字部分:</p>

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

littleshrimp 发表于 2020-10-6 20:07

<p>加一个简单的协议,比如以&#39;\n&#39;结尾,收到\n时再处理数据</p>

hujj 发表于 2020-10-6 20:46

littleshrimp 发表于 2020-10-6 20:07
加一个简单的协议,比如以&#39;\n&#39;结尾,收到\n时再处理数据

<p>谢谢指点!我试试看。</p>

hujj 发表于 2020-10-7 10:32

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

<p></p>

<p>&nbsp; &nbsp; 其中不可见字符是十六进制11:</p>

<p></p>

<p>&nbsp; &nbsp; 单片机中显示出来的字符如下:</p>

<p></p>

<p>&nbsp; &nbsp; 也许是我的测试的代码不正确,代码如下:</p>

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

<p><i><i><i>&nbsp;</i></i></i></p>

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

<p><i><i><i>&nbsp;</i></i></i></p>

okhxyyo 发表于 2020-10-9 16:01

<p><a href="https://bbs.eeworld.com.cn/thread-1140005-1-1.html" target="_blank">沁恒CH579M-R1开发板测评</a></p>

<p>汇总贴:<a href="https://bbs.eeworld.com.cn/thread-1140005-1-1.html">https://bbs.eeworld.com.cn/thread-1140005-1-1.html</a></p>

freebsder 发表于 2020-10-11 21:36

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

hujj 发表于 2020-10-12 08:06

freebsder 发表于 2020-10-11 21:36
要自己处理,你可以百度一下 串口完整数据包 的相关文章.

<p>谢谢指点!我去搜索看看。</p>

damiaa 发表于 2020-10-12 08:58

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

<p>串口程序一般可以这样处理。</p>

<p>&nbsp;</p>

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

<p>&nbsp;</p>

<p>接收单字节串口数据==》环形缓冲区 <strong>放在中断函数中&nbsp;</strong></p>

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

hujj 发表于 2020-10-18 17:01

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

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

<p></p>

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

<p></p>

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

<p></p>

<p>&nbsp; &nbsp; 至此,已经基本上掌握了串口使用,再次感谢各位!</p>

hujj 发表于 2020-10-18 17:04

<p>这是串口中断设置的代码:</p>

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

<p>&nbsp;</p>

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

<p>&nbsp; &nbsp; &nbsp; &nbsp; case UART_II_RECV_RDY: &nbsp; &nbsp; &nbsp; &nbsp; // 数据达到设置触发点<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buf = UART1_RecvByte();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;UART1_SendByte(buf);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;RxBuff = buf;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;RxID++;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(RxID &gt; 49)<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;RxID = 0;</p>

程英茂 发表于 2024-10-7 07:38

<p>有直接可用的压缩包吗?</p>

hujj 发表于 2024-11-10 16:48

程英茂 发表于 2024-10-7 07:38
有直接可用的压缩包吗?

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

<div></div>
页: [1]
查看完整版本: 【CH579M-R1】+求助:如何接收完整的串口数据