关注、星标公众号,直达精彩内容

来源:coolbacon

能从PC机器编程去看嵌入式问题,那是第一步;学会用嵌入式编程思想,那是第二步;用PC的思想和嵌入式的思想结合在一起,应用于实际的项目,那是第三步。

很多朋友都是从PC编程转向嵌入式编程的。在中国,嵌入式编程的朋友很少是正儿八经从计算机专业毕业的,都是从自动控制、电子相关专业毕业的。这些童鞋们,实践经验雄厚,但是理论知识缺乏;计算机专业毕业的童鞋很大一部分去弄网游、网页这些独立于操作系统的更高层的应用了。也不太愿意从事嵌入式行业,毕竟这条路不好走。他们理论知识雄厚,但缺乏电路等相关的知识,在嵌入式里学习需要再学习一些具体的知识,比较难走。

虽然没有做过产业调查,但从我所见和所招聘人员,从事嵌入式行业的工程师,要么缺乏理论知识,要么缺乏实践经验。很少两者兼备的。究其原因,还是中国的大学教育的问题。这里不探讨这个问题,避免口水战。我想列出我实践中的几个例子,引起大家在嵌入式中做项目时对一些问题的关注。

第一个问题:

同事在uC/OS-II下开发一个串口的驱动程序,驱动和接口在测试中均为发现问题。应用中开发了个通讯程序,串口驱动提供了一个查询驱动缓冲区字符的函数:GetRxBuffCharNum()。

高层需要接受一定数量的字符以后才能对包做解析。一个同事撰写的代码,用伪代码表示如下:

bExit = FALSE;do {if (GetRxBuffCharNum() >= 30)bExit = ReadRxBuff(buff, GetRxBuffCharNum());} while (!bExit);

这段代码判断当前缓冲区中超过30个字符,就将缓冲区中全部字符读到缓冲区中,直到读取成功为止。

逻辑清楚,思路也清楚。但这段代码是不能正常工作。如果是在PC机上,定然是没有任何问题,工作的异常正常。但在嵌入式里真的是不得而知了。同事很郁闷,不知道为什么。

来请我解决问题,当时我看到代码,就问了他,GetRxBuffCharNum()是怎么实现的?打开一看:

unsigned GetRxBuffCharNum(void)
{cpu_register reg;unsigned num;reg = interrupt_disable();num = gRxBuffCharNum;interrupt_enable(reg);return (num);
}

很明显,由于在循环中,interruput_disable()和interrupt_enable()之间是个全局临界区域,保证gRxBufCharNum的完整性。

但是,由于在外层的do { } while() 循环中,CPU频繁的关闭中断,打开中断,这个时间非常的短。实际上CPU可能不能正常的响应UART的中断。当然这和uart的波特率、硬件缓冲区的大小还有CPU的速度都有关系。我们使用的波特率非常高,大约有3Mbps。

uart起始信号和停止信号占一个比特位。一个字节需要消耗10个周期。3Mbps的波特率大约需要3.3us传输一个字节。3.3us能执行多少个CPU指令呢?100MHz的ARM,大约能执行150条指令左右。结果关闭中断的时间是多长呢?一般ARM关闭中断都需要4条以上的指令,打开又有4条以上的指令。接收uart中断的代码实际上是不止20条指令的。所以,这样下来,就有可能出现丢失通信数据的Bug,体现在系统层面上,就是通信不稳定。

修改这段代码其实很简单,最简单的办法是从高层修改。即:

bExit = FALSE;do {DelayUs(20); //延时 20us,一般采用空循环指令实现num = GetRxBuffCharNum();if (num >= 30)bExit = ReadRxBuff(buff, num);} while (!bExit);

这样,让CPU有时间去执行中断的代码,从而避免了频繁关闭中断造成的中断代码执行不及时,产生的信息丢失。

在嵌入式系统里,大部分的RTOS应用都是不带串口驱动。自己设计代码时,没有充分考虑代码与内核的结合。造成代码深层次的问题。RTOS之所以称为RTOS,就是因为对事件的快速响应;事件快速的响应依赖于CPU对中断的响应速度。驱动在Linux这种系统中都是与内核高度整合,一起运行在内核态。RTOS虽然不能抄袭linux这种结构,但有一定的借鉴意义。

从上面的例子可以看清楚,嵌入式需要开发人员对代码的各个环节需要了解清楚。

第二个例子:

同事驱动一个14094串转并的芯片。串行信号是采用IO模拟的,因为没有专用的硬件。同事就随手写了个驱动,结果调试了3、4天,仍旧是有问题。

我实在看不下去了,就去看了看,控制的并行信号有时候正常有时候不正常。我看了看代码,用伪代码大概是:

for (i = 0; i < 8; i++)
{SetData((data >> i) & 0x1);SetClockHigh();for (j = 0; j < 5; j++);SetClockLow();
}

将数据的8个bit在每个高电平从bit0到bit7依次发送出去。应该是正常的啊。看不出问题在哪啊?我仔细想了想,有看了14094的datasheet,明白了。

原来,14094要求clock的高电平持续10个ns,低电平也要持续10个ns。这段代码之做了高电平时间的延时,没有做低电平的延时。如果中断插在低电平之间工作,那么这段代码是可以的。但是如果CPU没有中断插在低电平时执行,则是不能正常工作的。所以就时好时坏。

修改也比较简单:

for (i = 0; i < 8; i++){SetData((data >> i) & 0x1);SetClockHigh();for (j = 0; j < 5; j++);SetClockLow();for (j = 0; j < 5; j++);}

这样就完全正常了。但是这个还是不能很好移植的一个代码,因为编译器一优化,就有可能造成这两个延时循环的丢失。丢失了,就不能保证高电平低电平持续10ns的要求,也就不能正常工作了。

所以,真正的可以移植的代码,应该把这个循环做成一个纳秒级的DelayNs(10);

像Linux一样,上电时,先测量一下,nop指令执行需要多长时间执行,多少个nop指令执行10ns。执行一定的nop指令就可以了。利用编译器防止优化的编译指令或者特殊的关键字,防止延时循环被编译器优化掉。如GCC中的

__volatile__ __asm__("nop;\n");

从以上例子中可以清楚地看到,写好一段好代码,是需要很多知识支撑的。你说呢?

来源:本文为CSDN博主「coolbacon」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。版权归原作者所有,如有侵权,请联系删除。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

关注我的微信公众号,回复“加群”按规则加入技术交流群。
点击下面图片,有星球具体介绍,新用户有新人优惠券,老用户半价优惠,期待大家一起学习一起进步。
点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

其实嵌入式编程还是很难很复杂的相关推荐

  1. 泰勒公式推导过程_#泰勒#(Taylor)公式真的很难很难吗?

    编编因为好久没有写文案了,所以就有不少读者朋友前来催更了,哈哈看到今天文章的题目啦,就知道这一期我们要讲泰勒公式了.作为重名明星Taylor Swift的忠实粉丝,本期编编当然是要推送她的歌曲啦.话说 ...

  2. 变态跳台阶,很难很难,终于想出来了,附推导过程,为自己鼓掌

    https://www.nowcoder.net/practice/22243d016f6b47f2a6928b4313c85387?tpId=13&tqId=11162&tPage= ...

  3. 中国人新奋斗:行行都在卷,处处都很难,人人都在熬

    前言 01 从燃到熬 从自然轨迹看,一个国家的增长,总是先快后慢.从一马平川的奔,到愈高愈难.所见愈奇的登. 从精神轨迹看,一个民族的成长,往往是从燃到熬.在燃时代,机会遍地走,点一点星火就能燎原,胆 ...

  4. 2021年5月11日19:50:56 学习 真的很难吗?

    你们都是怎么看待学习的? 老子说:"为学日益,为道 日损." 意思就是 学习世间知识技能,越多越好.  学习智慧,脑子里面装的越少越好. 我的时间都去了哪里? 你们对于这个世间有什 ...

  5. 函数式编程很难,这正是你要学习它的原因

    很奇怪不是,很少有人每天都使用函数式编程语言.如果你用Scala,Haskell,Erlang,F#或某个Lisp方言来编程,很可能没有公司会花钱聘你.这个行业里的绝大部分人都是使用像Python,R ...

  6. 为什么大学感觉学编程很难?原因有这三点。

    为什么很多计算机系的大学生觉得在学校学不好编程? 大学学习还是以理论为主 大学开设的课程还是以主体的理论学习为主,主要是营造一个好的学术氛围,不可能太专注于专业实践,起到抛砖引玉的作用,把基础的理论铺 ...

  7. 大学生学习编程很难吗?怎么样才能学好编程?

    有很多的人是非常的想知道,学编程难吗?编程入门先学什么?往下看希望对你们有起到帮助. 一:学编程难吗? 编程说难不难,说难不难,说简单不简单,学习之前你首先要知道你的学习目标,知道要学来干嘛. 要从事 ...

  8. 学计算机编程难吗,编程真的很难吗?为什么会认为学编程难?

    对每一个决心学习编程的程序员来说,你的学习历程可能是这样:如同一片树叶,开始被各种建议拽着走,直到学完了每一个你能想象到的课程. 但会有很多的学生觉得编程很难?其实学习编程是很有趣很好玩很实用并很有成 ...

  9. 少儿编程c语言 难度,c语言很难学吗

    C语言是一种面向过程的编程语言,它已经从计算机硬件中分离出来,可以设计中等规模的程序.接下来给大家讲讲c语言很难学吗,希望对你们有帮助. C语言编程,除了让你知道相关的概念,带你进入编程大门,也让你了 ...

最新文章

  1. 对抗攻击最新研究:仅修改「一个像素」即可骗过神经网络!
  2. 如何查看tomcat是否安装成功_如何查看网站是否被收录?
  3. 金融领域下的数据挖掘算法应用:AdaBoost模型摩天
  4. 一次DeleteInsert引发的Mysql死锁
  5. kafka命令行操作
  6. javascript等待异步线程完成_前端:什么是单线程,同步,异步?彻底弄懂 JavaScript 执行机制...
  7. [MOSS开发]:如何使用用户控件
  8. 虚拟现实设备排行榜(2016年3月27日)
  9. 最大权闭合子图(poj 2987 Firing)
  10. 计算机管理创建新用户,win7系统添加新用户名的方法和win7系统计算机管理中没有本地用户和组的解决方法...
  11. 道一声java技术_java提高篇(二)-理解java的三大特性之继承 - Java 技术驿站-Java 技术驿站...
  12. 微信飞机小游戏java_Shoot Plane 仿微信打飞机游戏的java实现
  13. 史蒂夫·乔布斯传txt下载
  14. php字符串长度获取_php哪个函数能取得字符串长度
  15. 阿铭linux苹果客户端,2018年5月 – 阿铭Linux
  16. Vue.js 第5章 webpack配置
  17. RAITE Hypervisor介绍
  18. C语言常见问题(9):Value stored to ret is never read
  19. 画笔Paint及模拟画图工具
  20. Android 安装第三方远程协助APP无法控制屏幕

热门文章

  1. python爬取千图网图片(出现HTTP Error 403怎么解决)
  2. JavaScript 基础(002_Event Bubbling)
  3. Android实现一键开启自由窗口、分屏、画中画模式——画中画模式
  4. PHP使用FPDF的多字体解决
  5. R语言基础图形绘制——箱线图
  6. Hitting the database(Chapter 5 of Spring In Action)
  7. USB | 1. 技术演进及测试概览
  8. 关于STM32的裸机多任务多线程心得
  9. 【转】推荐系统入门实践:世纪佳缘会员推荐(完整版)
  10. 开始自学PHP之路3(HTML)