怎样给单片机写程序.
单片机程序分c和汇编2种.使用c++给单片机写的人比较少.那么我先说说c和汇编.
先说,汇编,因为汇编比c低级一些.好多学校的课本还沿用汇编.一些古典级的大师们还有可能觉得汇编更直观(这里直观和易读不是一个意思).这里提醒大家不要盲目跟风.汇编必不可少.原因是某些芯片,根本就没有c的编译器.就必须无奈写汇编.所以我在汇编中提出2个观点:1注释明确2模块清晰. 1.注释明确 汇编的注释要最多化.哪怕是一行一个注释.不要相信自己写的代码自己能明白.出现错误的时候,一般自己找不到原因.比如一个哥们写的 mov a, dptr这种寄存器位数搞错的错误自己是绝对段时间找不出来的,这种郁闷会大大削弱你找到错误的信心.如果有注释,则先看注释是否正确,然后调试,看看注释和代码功能是否一致.汇编中循环有多种判断和写法,自己选择那一种,到维护的时候根本不知道.要自己看.这样真的是自找麻烦.不如注释明确. 2.模块清晰 对于汇编,大部分都比较简单.多数人都喜欢一个大函数搞定.并且其中的跳转使用的名称都是懒得定义,因为自称是高手.所以就有AAA,BBB,DD,XS(显示)这种命名.因为当时学汇编的时候就是这个写法,留下了一个懒于命名的坏毛病.以至于写完的代码自己都维护不了了,只能跳槽走人了... 模块清晰最明显的表现就是复制粘贴.最明显的用法是显示一串固定数.好,写一个显示函数,复制几次.每次改点东西.为什么不写个函数呢?调用一下,后面写这注释不就好了吗? 3.总结汇编. 一般需要改别人汇编的时候,都比较麻烦.因为高手写的代码不用别人维护,bug量极低.需要维护的代码一般结构和易读都比较烂.只能说功能有,还带bug.一般汇编的调试都是从上到下.从大模块开始理清.可是这些人写的都是乱七八糟在那呆着根本就没有大模块.还有一个问题就是运行汇编的这些单片还不支持debug,困难依旧比较多.比较推荐的办法就是proteus搭必要的部分(其他部分使用代替信号.只要能够执行过去,不至于死在那里就行),然后用keil和proteus联合仿真.粗略的猜测功能.然后加上一些注释.如果能知道你要修改地方的某些函数,那从下往上"搜索"函数调用.进行功能分析也可以.这里的搜索是ctrl+f,千万不要人工肉眼搜索....这个搞不定的就用仿真器吧. ----多写注释,英文标号,多些函数,禁止拷贝代码------
其次,c c是最常用的东西.如果还学不会c的话,那我就不说什么了.本来写代码就是个力气活.... 1.c让我们离开了石器时代 一个for,while能顶太多汇编了.所以,我们应该更关注其他的东西,要提高效率,提高质量. 如果是给操作系统开发软件,那就不用说了,和pc的计算机软件一样,驱动稍有差别.这里说一下单片机工程师需要多关注的:datasheet.在这里建议大家在设计寄存器配置的时候,前面写上详细的寄存器功能.详细到位,使用的和未使用的都要写.这样以后读的时候会一目了然是在配置什么.比如说avr的定时器配置寄存器功能定义中的分频比在TCCR0A和TCCR2A是不一样的.所以,还是抄过去好.例如: 7.初始化计数器/定时器0 //1普通模式 (WGM02:0 = 0) 为最简单的工作模式。在此模式下计数器不停地累加 //TCCR0A: COM0A1 COM0A0 COM0B1 COM0B0 – – |WGM01 WGM00 // 0普通模式,不与pin相连 |0 0 普通计数模式 //TCCR0B: FOC0A FOC0B – – WGM02 |CS02 CS01 CS00 // 注意:使用时先清零 // 强制比较 0 0 0 |时钟源选择0:stop 1:1 2:8 3:64 4:256 5:1024 6:t0 下降沿 7:t0上升沿 //TCNT0:计数寄存器 //T/C 中断屏蔽寄存器—TIMSK0 //TIMSK0: – – – – – OCIE0B OCIE0A TOIE0 // 0 0 0 0 0 0 0 1:溢出中断使能 TCCR0A = 0; // 普通计数模式 TIMSK0 = _BV(TOIE0); // 允许溢出中断 //1 8.初始化计数器/定时器2 //1普通模式 (WGM02:0 = 0) 为最简单的工作模式。在此模式下计数器不停地累加 //TCCR2A: COM2A1 COM2A0 COM2B1 COM2B0 – – |WGM21 WGM20 // 0普通模式,不与pin相连 |0 0 普通计数模式 //TCCR2B: FOC2A FOC2B – – WGM22 |CS22 CS21 CS20 // 注意:使用时先清零 // 强制比较 0 0 0 |时钟源选择0:stop 1:1 2:8 3:32 4:64 5:128 6:256 7:1024 //TCNT2:计数寄存器 //T/C 中断屏蔽寄存器—TIMSK0 //TIMSK2: – – – – – OCIE2B OCIE2A TOIE2 // 0 0 0 0 0 0 0 1:溢出中断使能 TCCR2A = 0; TIMSK2 = _BV(TOIE2); 最近有人在说从上到下的开发方式.但是好多人用的还是从下到上的开发方式.虽然后者更加古老.但是这2种谁更优秀比较难说,只能说谁更适合.对于单片机工程师来说,这两种方式差距不是很大.只能说基本相同.对于经验少的工程师和比较小的项目.从下到上也是不错的选择.对于有经验的工程师,和大的项目,从上到下更好一些.后者,比前者多了一步,就是设计评审.一个小的公司根本就没这一步.因为这是让更多的人来考虑你的设计是否可实现?如果到下层才发现有个设计不可实现,那你就惨了.再者,从上到下是面向对象的.对于c来说,只能构造一个类似的对象.而pc软件构架师在从上倒下设计的时候,就等于已经写了代码.因为他们的设计软件最后能自动生成c++代码.而单片机工程师没有这样的软件.所以,从上到下的效率并不高.其次是流程图.我认为,流程图转换成注释先写到程序里.然后再写程序会是更现实的.因为流程图软件和程序的更新对应是需要人做的.往往工程师会懒于此.而c++构架软件也支持流程图.只不过能否生成代码我就没实验了.***********(若干...)所以,还要选择最适合的.而不是盲目跟风.使用其思想,心中有剑,手中无剑,可是可以的. 什么样的剑法最适合呢? 肯定有人注意到单片机c和pc的c相似也有不相似.那么,如果能把相似和不相似绝对分开,那就是最好的办法.其实也很简单,就是把配置硬件寄存器的都按照功能进行函数封装.把注释写好.然后注意可重用性.把参数配置函数接口搞好.可以参考国外开源程序的写法.和大家提出的函数头写法都一样.这种封装底层配置就是从下到上的设计.一定要测试函数功能.修改bug.这样底层做好之后,可以做成一个库.以后的开发会很舒服.纯软件层,使用从需求到代码的从上到下的开发方式就可以了.因为,对于单片机工程师的感觉,可能这一堆代码没有上下之分了.如果必须要画个分界线的话,还是认为显示,通讯,和人机交互算上层吧. 需求---管理代码(类似咱们在操作系统下写的调用下层接口来实现功能程序)---功能代码(为上层功能提供接口和实现的可重用代码)----配置代码(配置硬件寄存器所写的可重用代码).这样我认为,如果需求变化,那就先改管理代码.能实现就ok,工作量小修改方便.如果需要增加新硬件功能,那再增加功能代码,扩展功能库.配置代码基本不用改.这样,可以保证修改的代码少,bug就会少,随着开发,测试这些代码,并且维护,可以减少bug提高稳定性.把配置寄存器代码分离出来,还可以增加可移植性.如果处理器选型出问题,移植到新处理器上也不会需要修改太多地方. 2.有空就多上上论坛吧,我记得以前有人贴的使用struct来做对象来开发,也是很好的办法.总之,要在设计上下功夫. |