×
单片机 > 单片机程序设计 > 详情

AVR编程感悟

发布时间:2020-08-24 发布时间:
|
公司的项目中用的单片机都是avr,有Atmega128,Atmega2561,和刚刚用的Attiny2313,玩了两三个月了,这三个单片机也玩熟了,因之前都是写上层应用的,一些编程的观念,特别是在玩完2313后有了很大的改变,把最近的一些编程中认识到的问题及想法先记录下来,当个备忘录吧。
  1. 首先是“封装”的思想
    • 先说下原先的观念吧,原先参加的项目比较大,芯片资源也很丰富,RAM都是几十兆的,ROM都是过百兆的,自己只负责一个模块的,这方面特别的重视,包括一些用到的变量,都根据实际用途进行封装,这样便于维护,也便于编写程序,同时也便于后期扩展,变量的封装对应要有相应的函数封装,将所有的全局变量的操作都封装起来,会提高程序的灵活度以及移植性,在与别人的模块接口方面也比较灵活,所以养成了习惯,只要抽象成一个功能模块的,都将其封装起来,然后复杂的功能用一些小的功能往起拼,个人觉得这样降低了逻辑的复杂度,而且也是遵循软件工程的“低耦合,高内聚”的原则。这也是先前一直认为很好的编程习惯,所以写程序前都要规划规划,看看那些能做成模块,方便开放和关闭一些功能(应对定制版或多平台的需求)。
    • 最近这几个项目都很小,软件的工作量都是一个人搞定的,资源都很有限,128-->RAM(4K bytes),ROM (128Kbytes),2561->RAM(8K+32K ext),ROM(256K bytes),2313->RAM(128 bytes),ROM(2K bytes),刚开始玩128,哇塞才4K的RAM,记得原来做一个FAX的buffer都超过4K了,偶滴神那,但用起来,慢慢发现也不是那么恐怖,里面还有4K的EEProm嘛,用的过程中才真正的体会到了RAM和ROM的功能,原来写程序真的不是特别清楚,也没有去想过自己的程序中所有的东西怎么分配的,有点“活的不明不白”。原来4K的RAM可以干好多好多事情的,包括LCD的控制显示,485通信,控制多个模块的工作,接收PC的控制命令,按键的控制等等。对于128,它的代码空间已经足够大了,所以可以将一些功能啥的都封装起来,这些一点问题没有,2561也是同理,但最近这两天玩的2313,让我豁然发现,并不是所有的程序都适用这个原则的。开始用结构体将相关功能封装起来,在把基本的功能(IO口的配置,定时器的配置,串口的配置,看门狗的配置,中断的配置,串口的解包,EEPROM的接口)完成后,我了个去,ICC提示代码空间已用了80%多了,我去了,这还玩个P啊,先不管了,将串口的处理完成后,90%多了,先不管了,用VB写了个简单的上位机,调试了大半天,终于连上位机和这些简单的功能调通了。还要用IO模拟另一个串口啊,没空间了,咋整涅,精简代码被,想想看那些可以精简,首先想到的是函数调用的地方,将只用到了一次的直接将代码搬过去,函数干掉,多次用到的保留,函数调用最多只要两层(main函数本身不包括),清理了下,少了点,然后觉得还不行,应该还能清理,后来发现那些结构体封装的变量了,因为从结构体变量成员的访问需要在结构体的基址上加偏移玩的,所以估计这块会多消耗一些额外的指令的,所以将结构体通通干掉,改用多个全局变量,对其直接访问(这也是我原先最痛恨的一种写代码的方式),试了下,少了好多,代码变成70%多了,不错,继续看看,然后发现解包函数中有些共用的语句,包括正常的处理和异常的处理,想着,干脆放一块,用两个goto跳过去得了,试了下,恩,又小了些,已经很满足了。至此程序已改的和原先设计的结构完全不一样了,有点“面目全非”了,不过实用性提高了很多,将IO模拟的另一个串口的接收完成后,代码空间80%多一点,还好,还有其他的余地来干一些事情,到此我的工作也暂时完成了。此时我认识最深刻的就是稀缺资源的嵌入式设备编程时要尽量的用全局变量,尽量直接访问,少些函数,少用调用,多用goto,当然了,需要斟酌着用。完全和原先的观念相反。
  2. 对于RAM使用的认识,对于很小的RAM设备,能共用就共用,必然2313这个东东,串口的首发的buff完全可以用一个来实现,刚开始我也用的两个,但后来在用IO模拟另一个串口是发现RAM不够用了,因128的RAM,30个字节还要用到函数栈空间,程序的空间只剩下可怜的90多个字节了,一条串口命令最长还有17个字节,所以很是吃紧了,后来干脆将串口的收发合到一起,因为只有在收完了才会发送的,所以在发送时关闭接收中断得了。RAM终于足够IO模拟用了。另外实在不够,还可以用128字节的EEPRom做中转,还是比较可观的。另外一个就是函数栈空间,这里面的空间包括函数调用的地址保存,局部变量的保存,所以嘛这就是函数为什么尽可能的少调用,因为函数里面少不了局部变量,调用的多了,将栈空间用完,栈溢出,你就哭吧,程序某些功能正常,某些功能异常。最开始,为了确认板子程序启动了,在main的开始部分添加了个20字节的buf,惨了。。。后来终于被我发现这个罪魁祸首了
  3. 另外一些算是常识性的东西,最近印象比较深刻的,记录下吧:
    • 每个有效的功能变量都有范围的,一定要限定边界值
    • 如果代码空间比较富裕,对EEPROM的操作最好做加校验,好处是在EEPROM被冲掉后,程序检测出异常会做异常的保护,也可以用来调试,提醒系统有问题。
    • 看门狗一定是要的
    • AD采样,一定要多次采样,求平均值,这样可以减少异常的干扰
    • 程序一定要有版本号,否则,版本多了,哼哼。。。
    • 按键不仅要检测按下,还要检测释放按键,否则长按着。。。。。(这个就看需求了)
    • 驱动一定要隔离,一定要做成模块,为上层应用提供接口,上层应用不要直接控制驱动相关的东东
    • avr的单片机呢,熔丝位(fuse)一定要烧写的,根据datasheet来确定
    • 对于每一个功能性的变量,要确定好其实际范围,符号类型,来选择适当的数据类型及符号类型,不要将有符号和无符号的数进行比较。

先写到这儿吧,以后想到在更新吧。


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32中断向量表的位置.重定向