加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

NRF52832开发日志——串口调试模块实现

(2016-11-05 23:34:11)
分类: NRF52832开发日志
开发时,除调试器以外,也经常使用printf结合串口来输出文本方式的数据或者消息。这种方式蛋疼之处在于:
1、printf使用时栈的占用会迅速升高。尤其是这种小型嵌入式系统,每个任务的栈空间都分配的比较小,如果各种用,很快内存就不够了,一方面,如果出现栈溢出,在这类没有MMU的处理器上找到源头很费事,其不会立刻出错,覆盖掉了其他任务的数据才导致出错,“运气好”的话,可以潜伏甚至好几个版本不被发现。
2、printf使用时会额外增加处理时间,导致程序运行情况和发生一定变化,尤其是如果在中断里面影响最大。
3、printf存在重入问题,主要在于最终调用串口输出那块。即使使用互斥量保护,想想如果在线程用着一半时候进了中断又调用了printf,会咋样?
因此我专门实现一个模块来完成这个任务,需要输出消息的线程或者中断程序通过队列将内容发送至调试模块,由其统一转换和输出,酱紫只需在给这个模块保证足够运行printf的栈空间即可,同时普通任务输出调试信息的时间也降低到最小。

printf是个变参函数,稍微看了下c库里面相关变参函数的使用和实现,还是挺复杂的...尤其是要把变参再传递给printf,更加蛋疼。
考虑时间紧迫,放弃这种编写一个实际至传递参数的函数的方式,而是通过宏来简单组合。消息分为4类:文本S,十进制数D,十六进制数H,浮点数F,要使用时候,直接带括号组合。比如:
S("voltage")D(i)S("=")F(val)S("mV\r\n")
如果i=2,val=3.23,打印在屏幕上就是“voltage2=3.23mV”
相比熟练到飞起的printf的格式肯定超级麻烦,不过想想能省去多少栈溢出的风险我觉得还是值得哈哈
下面上实现代码:
初始化:就是创建用来接收调试信息内容的消息队列,处理消息的线程。
接下来,需要输出调试信息调用的函数,为了简化实际用宏定义的简化名称代替。
这里就是负责向队列里面丢内容。考虑到这个需要在中断内被调用,通过__get_IPSR()来检测下是不是在中断内,如果是则需要用另外一套操作系统的API来发送
http://s9/mw690/002VF2gAzy76bGQHnpme8&690

接下来,消息处理函数,这个是一个独立的线程,基本上任务就是等着消息过来,然后分拣,处理。这边数字到字符串转换我直接用了sprintf往内存里面输出然后统一当字符串发送。
另外,这里加了一个简单的串口自动休眠功能。当超过UART_SLEEP_TIME(现在设置为10mS)没有新的请求来的话,就进入//enter sleep mode那个条件判断内,关闭串口,休眠,然后无限等待消息之后再重新开启串口
使用了这个特性后,实测总体功耗非常低,基本上可以保持调试功能可用同时继续评估整机的功耗了
http://s10/mw690/002VF2gAzy76bGutAJbf9&690

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有