赞
踩
不好意思!因为这几天要准备项目答辩,比较忙,所以没能及时更新。
OenMv方面的问题可以查看上一篇文章哦!
stm32串口接收数据其实大部分朋友都经常使用,应该都没什么问题的,可能我比较笨、总是遇到一些小问题,在这里我和大家分享一下。
后面有串口接收数据详细解析。
我遇到的主要问题是在串口中断服务函数那里出的错。我写代码程序一般都比较喜欢用LED作为调试使用。因为这样可以很明确知道程序运行到哪一行哪一步。在许多的程序中,这中方法都百试百灵,但这次却成为一个致命的错误,害我找了很久很久,总的来说还是不清楚串口中断的一些细节。
不过,虽然这种led调试方法让串口中断产生了异常,但它确实帮助我查出了OpenMv方面的错误!
接下来我将先和大家分享我利用led调试,检查出OpenMv方面错误的步骤。
下面展示一些 内联代码片
。
//使用正点原子串口实验源代码 void USART1_IRQHandler(void) //串口1中断服务函数 { uint8_t Res; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接受中断(接受到的数据必须是0x0D 0x0A结尾) { Res =USART_ReceiveData(USART1); //读取接受到的数据(每次是一位八位的数据) //在这里加入红色led亮起代码,如果红色led亮起,说明进入了串口中断了,并接受到数据 if((USART_RX_STA&0x8000)==0)//接收未完成 { //这里也加一个灯吧,但作用不大 if(USART_RX_STA&0x4000)//接收到了0x0D { if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else { USART_RX_STA|=0x8000; //接收完成了 //加入LED灯,判断有没有接收到0x0A,结束符 } } else //还没收到0x0D { if(Res==0x0d) { USART_RX_STA|=0x4000; //加入led,判断有没有接收到0x0D,结束符 } else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; //加入led,判断有没有进入数据转换 if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始 } } } } }
就是这样,看那些LED亮起来了,就可以明确程序运行到哪一步,因为接收结束符的那些LED灯没有亮起,一步步慢慢调试逐步发现问题根源。
那为什么我的串口中断服务函数会出现错误的呢,后来我在论坛上看到,有一位大佬说,最好不要再中断服务函数里面写太多的程序,然而我加入的led灯程序是这样的
bule = 0;
delsy-ms(200);
bule = 1;
200毫秒,对于单片机在说已经以很长很长的了,可以运行很多其他的代码了,大佬说的不要再服务函数里面写太多的程序的意思是,不要让程序再服务函数里面运行太久。我觉得说的很有道理,后来改了运行就正常了。问题解决。哎,这个问题真的搞了我好久好久。裂开。
下面是串口接收多帧数据的流程:
下面展示一些 内联代码片
。
//使用正点原子串口实验源代码 u8 USART_RX_BUF[USART_REC_LEN]; //一个八位的数组,用于存储接收的字符 u16 USART_RX_STA=0; //这是一个接收的标志位,是程序员用来识别和记录用的,开始的时候我以为这个是stm内部的一个寄存器(说出来羞死人) //bit15 接收到完成标志位,收到0x0A程序就会将这位置1 //bit14 接收到0x0D,收到0x0D程序就会将这位置1 //bit0~13 用于记录接收到的字符的长度 //那接下来我们开始接收数据啦!首先USART_RX_STA和USART_RX_BUF[USART_REC_LEN]都是空的;所有位都是零 void USART1_IRQHandler(void) //串口1中断服务函数 { uint8_t Res; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接受中断(接受到的数据必须是0x0D 0x0A结尾) !!!第一步 进入串口中断后,继续判断是否真的接收状态为真,也就是是否真的收到数据了,其实进入服务函数也就说明是接收到数据了,但为什么还要这样做呢,我也不是很清楚,可能是严谨一些吧,或者其他原因,有大佬知道的欢迎评论 { Res =USART_ReceiveData(USART1); //读取接受到的数据(每次是一位八位的数据) !!!第二步 串口收到数据后会将数据放在寄存器里面,我们通过这个函数USART_ReceiveData();读取出来,赋值给Res if((USART_RX_STA&0x8000)==0)//接收未完成 !!!第三步 判断是否接受完成,我们才刚刚开始,怎么可能完成了呢 是吧,刚刚进来,USART_RX_STA的bit15位还是零, 所以接受没完成,可以进入下一步。有朋友就有疑问了,诶!如果bit15是1,程序进入不了这一步,那中断服务函数岂不是运行 了一段中程序吗,而且如果程序进来的话,一般我们都不是要进行数据存储和转换的吗?所以为什么要这么做呢!其实我们在接 收完一帧一条字符串数据后,一般都在要进行一些处理是吧,比如在主函数里面进行一个数据的比较,那我们比较数据是要消耗 时间的,如果让新的数据继续存到我们的USART_RX_BUF()数组里面,那主函数的数据比较不就会出错吗?所以我们会在数 据用完后才将USART_RX_STA的bit15重新置零,置零后才能开始一次新的接收。所以,在OpenMv发送数据是,我们每次发送 玩一次数据后,需要等待一段时间后才能继续发送,不然stm在处理数据(也就是bit15还没置零的时候)那段时间,你发送的数 据我也是不会存储起来的,这样就会造成数据的丢失。 { !!!第四步 在这里会进行一个判断,大家慢慢看就可以理解。 现在 USART_RX_STA的bit14位还是零,所以不能进入if 语句,程序跳到else语句。我们去else语句看看。 if(USART_RX_STA&0x4000)//接收到了0x0D { !!!第六步 收到0x0d,USART_RX_STA的bit14置1 ,程序进入这一步,接下来会进行一个判断,判断Res是不是等 于0x0a,因为一个完整的结束标志是有0x0d和0x0a组成的,缺一个也不可以。如果是,那就是这一帧一条数据真的完 成了,进入else,将USART_RX_STA的bit15置1.。如果不是那就是接收发生错误了,需要重新开始。USART_RX_STA 需要清零,不然bit14还是1,下次进入服务函数,程序就会以为已经收到0x0d了。 那我们接受的步骤就讲完了。 if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else { USART_RX_STA|=0x8000; //接收完成了 } } else //还没收到0x0D { !!!第五步 在这里也有一个判断,如果Res == 0x0D(结束符开始),如果是那就进入if语句,就会将USART_RX_STA 的bit14位置1,标志着收到0x0d了。如果不等于0x0d,那就进入else语句,else里面的程序首先是将Res的数据给 USART_RX_BUF数组存起来。然后有一个数据长度的判断,如果数据超过我们定于的长度后,那肯定就是错了 呀(当然这可能是我们定于的数组长度太小了,我们可以根据需要调大一点)所以这里一般不会出错 只需要将空间 调大一点就行,不过会消耗存储空间,适当就行。如果我们在这次接受到了0x0D,那么下次再第四步的判断结果就 会发生改变(如果还没接收到0x0d,那下次进入中断还是这样运行下来,知道收到0xod才改变),那下面我们去看 看收到0x0d后的运行步骤。 if(Res==0x0d) { USART_RX_STA|=0x4000; } else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始 } } } } }
话比较多,不过对新手应该比较友好。
当然,说多错多,各位发现了希望可以及时提出。
接受数据我们就完成了,可能还有一个东西可以讲讲,就是将我们收到的数据和程序已经提前设定好的数据进行比较。通过这样的处理我们就真正的可以利用串口了。
这个我们下一篇文章写。
想查看OpenMv代码的可以查看上一篇文章。
关于STM32与OpenMv通讯踩过的那些坑(1)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。