【CH579M-R1】+求助:如何接收完整的串口数据
<p> 通过串口的范例测试可以接收和发送数据,在串口调试助手中发送和接收都正常,下图为测试过程,无论发送的字符串长短不同,开发板均能返回正确的字符串。</p><p></p>
<p> 但是我试图的开发板中将接收到的字符串显示在LCD屏幕上却遇到了问题,接收函数总是按照每7个字符截取,无法获得完整的字符串。如下图,我发送的是“2020-10-06 14:36:50”,但最后只显示"36:50",之前的“2020-10-06 14:"却看不到,仔细分析是先显示前7个字符”2020-10“,然后显示第二组7个字符”-06 14:"时覆盖了前7个字符,最后的5个字符“36:50"又将第二组字符覆盖了。</p>
<p></p>
<p> 下图是发送”2020-10-06 14:36:50 Test"字符串(长度24),显示的是最后3个字符“est”(第3组的最后一个“T”没有被覆盖)。</p>
<p></p>
<p> 下图是发送“2020-10-06”字符串(10个字符),也是按照7+3的方式显示。</p>
<p></p>
<p> 查看资料说是接收函数设定的每次接收长度为7个字节,我找了很久也没有发现是在哪里设定的,是不是可以将这个长度设定为16个字节或者更多,或者用什么办法才能将接收到的每段字符串“拼接”起来?希望能够得到各位大佬帮助,谢谢!</p>
补充内容 (2020-10-19 09:39):
按照damiaa版主的提示,终于能显示出完整的串口接收字符了,详见11楼。 <p>我是在串口中断函数中设置一个接收标志,然后在主循环中根据这个标志来显示接收到的字符串,并清除标志。下面是串口中断函数,这里除了添加了设置标志的代码外,未作任何修改:</p>
<p>void UART1_IRQHandler(void)<br />
{<br />
UINT8 i;<br />
<br />
switch( UART1_GetITFlag() )<br />
{<br />
case UART_II_LINE_STAT: // 线路状态错误<br />
UART1_GetLinSTA();<br />
break;<br />
<br />
case UART_II_RECV_RDY: // 数据达到设置触发点<br />
for(i=0; i!=trigB; i++)<br />
{<br />
RxBuff = UART1_RecvByte();<br />
UART1_SendByte(RxBuff);<br />
}<br />
rxok = i; //设置接收标志<br />
break;<br />
<br />
case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成<br />
i = UART1_RecvString(RxBuff);<br />
UART1_SendString( RxBuff, i ); <br />
<br />
break;<br />
<br />
case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送<br />
break;<br />
<br />
case UART_II_MODEM_CHG: // 只支持串口0<br />
break;<br />
<br />
default:<br />
break;<br />
}<br />
}</p>
<p> </p>
<p>下面是主循环中的判断和显示的代码:</p>
<p> if(rxok>0){<br />
LCD_clear_line(2); //清除当前行<br />
LCD_clear_line(3);<br />
LCD_clear_line(4);<br />
LCD_write_BG(0,2,RxBuff); //显示接收到的字符<br />
LCD_write_ASCII(0,4,1,RxBuff);<br />
LCD_write_value(0,5,3,0,0,rxok);<br />
UART1_CLR_RXFIFO(); //清除缓存<br />
rxok = 0;<br />
}</p>
<p>我将串口接收中断函数中的接收循环trigB用16替换,串口调试助手接收到的数据却与发送的不同:</p>
<p></p>
<p>修改的代码见下面粗体字部分:</p>
<p>void UART1_IRQHandler(void)<br />
{<br />
UINT8 i;<br />
<br />
switch( UART1_GetITFlag() )<br />
{<br />
case UART_II_LINE_STAT: // 线路状态错误<br />
UART1_GetLinSTA();<br />
break;<br />
<br />
case UART_II_RECV_RDY: // 数据达到设置触发点<br />
<strong> for(i=0; i!=trigB; i++) //其中的i!=trigB;修改为i < 16</strong><br />
{<br />
RxBuff = UART1_RecvByte();<br />
UART1_SendByte(RxBuff);<br />
}<br />
rxok = i; //设置接收标志<br />
break;<br />
<br />
case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成<br />
i = UART1_RecvString(RxBuff);<br />
UART1_SendString( RxBuff, i ); <br />
<br />
break;<br />
<br />
case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送<br />
break;<br />
<br />
case UART_II_MODEM_CHG: // 只支持串口0<br />
break;<br />
<br />
default:<br />
break;<br />
}<br />
}</p>
<p>加一个简单的协议,比如以'\n'结尾,收到\n时再处理数据</p>
littleshrimp 发表于 2020-10-6 20:07
加一个简单的协议,比如以'\n'结尾,收到\n时再处理数据
<p>谢谢指点!我试试看。</p>
<p> 尝试加结束标志测试了一下,但没有成功,串口辅助调试助手接收的数据与发送的不一致(见下图):</p>
<p></p>
<p> 其中不可见字符是十六进制11:</p>
<p></p>
<p> 单片机中显示出来的字符如下:</p>
<p></p>
<p> 也许是我的测试的代码不正确,代码如下:</p>
<pre>
<code> case UART_II_RECV_RDY: // 数据达到设置触发点
/*
for(i=0; i!=trigB; i++){
RxBuff<i> = UART1_RecvByte();
UART1_SendByte(RxBuff<i>);
}
*/
while(ok < 2){
RxBuff<i> = UART1_RecvByte();
UART1_SendByte(RxBuff<i>);
if((RxBuff<i> == 'n') & (ok > 0))
ok++; //收到结束标志2
else{
if(RxBuff<i> == '/')
ok = 1;
else
ok = 0;
}
i++;
if(i>15)
ok = 2; //最长不超过16个字节
}
rxok = i; //设置接收标志
break;
</i></i></i></i></i></i></code></pre>
<p><i><i><i> </i></i></i></p>
<p><i><i><i> 我想要是直接修改设置的触发点可能更方便些,因为我目前只想通过串口来设置日期和时间,字符串长度有16位就基本可行(年月日共8位、时分共4位,再加上若干标识符),现在就是不清楚在哪里可以修改这个接收长度。</i></i></i></p>
<p><i><i><i> </i></i></i></p>
<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>
<p>要自己处理,你可以百度一下 串口完整数据包 的相关文章.</p>
freebsder 发表于 2020-10-11 21:36
要自己处理,你可以百度一下 串口完整数据包 的相关文章.
<p>谢谢指点!我去搜索看看。</p>
本帖最后由 damiaa 于 2020-10-12 09:00 编辑
<p>串口程序一般可以这样处理。</p>
<p> </p>
<p>接收单字节串口数据==》环形缓冲区=》解析程序读环形缓冲并释放已经读的数据,然后放到解析缓冲中解析数据=》(如果解析到一个完整命令)执行解析命令</p>
<p> </p>
<p>接收单字节串口数据==》环形缓冲区 <strong>放在中断函数中 </strong></p>
<p>解析程序读环形缓冲并释放已经读的数据,然后放到解析缓冲中解析数据=》(如果解析到一个完整命令)执行解析命令 <strong>放在主程序中</strong></p>
本帖最后由 hujj 于 2020-10-18 17:05 编辑
<p> 感谢大家的热心帮助,今天按照damiaa版主的提示,用一个变量作接收和回发的中转,原RxBuff数组作环形缓冲区,中断触发的字节数改为1,顺利地实现了串口多字节接收。下图为测试过程:</p>
<p></p>
<p> 从串口调试助手发送字符串,并接收回发的数据,没有任何问题(见下图):</p>
<p></p>
<p> 单片机接收到的字符串显示在LCD屏幕上也完全一致(屏幕倒数第3行):</p>
<p></p>
<p> 至此,已经基本上掌握了串口使用,再次感谢各位!</p>
<p>这是串口中断设置的代码:</p>
<p> // 中断方式:接收数据后发送出去<br />
UART1_ByteTrigCfg( UART_1BYTE_TRIG );<br />
trigB = 1;<br />
UART1_INTCfg( ENABLE, RB_IER_RECV_RDY|RB_IER_LINE_STAT );<br />
NVIC_EnableIRQ( UART1_IRQn );</p>
<p> </p>
<p>这是串口中断处理的代码(部分):</p>
<p> case UART_II_RECV_RDY: // 数据达到设置触发点<br />
buf = UART1_RecvByte();<br />
UART1_SendByte(buf);<br />
RxBuff = buf;<br />
RxID++;<br />
if(RxID > 49)<br />
RxID = 0;</p>
<p>有直接可用的压缩包吗?</p>
程英茂 发表于 2024-10-7 07:38
有直接可用的压缩包吗?
<p>找到了之前的压缩文件,希望能够帮到你。</p>
<div></div>
页:
[1]