我从2011年开始做单片机开发,一直保持以下撸代码的习惯。
1. 做好代码版本管理
有些人,喜欢一个程序干到底,直到实现全部的产品功能,我以前做51单片机的项目就是这样。
如果功能比较多的产品,我不建议这样做,迟早有一天,有一个项目,会让你崩溃的,特别是还不具备模块化编程能力的时候。
之前我就踩过几次这种坑,一个程序版本实现了很多个功能,后面新增功能的时候,突然发现了一个BUG,怎么都调不出来。
这时候,如果有上一个版本,可以用上一个版本的代码,一点点代码复制过去看看,到底是哪个代码造成的。
从那次以后,我就养成了做代码版本管理的习惯,比如V1.0,V1.1,V1.2.....
然后每个程序版本里面,我都会写一个文档,描述下历史版本实现的功能记录,以防后面忘了。
2. 多学习优秀的代码和思维
刚工作那会,主要用STC的51单片机做项目,主要维护之前工程师遗留的代码,升级产品功能为主,基本是一堆屎山代码,实现功能就行了。
不会考虑怎么把代码写得更好,主要是自己当时也没那能力,项目又急,能改出来应付工作就不错了,有时项目急,我逻辑又理不清,甚至用了goto语句走了捷径,可能很多人都没见过。
工作了几年,一直是维持在这种水平,没有提升,因为接触不到更复杂的项目,接触不到好的编程思维和代码。
后面跳槽到一家公司,接收了一个网关项目,需要自己从0到1,完成整个项目的代码。
这个项目难度,已经超过了我的知识范围,主要有两个问题:
第一,很多功能没做过,不知道啥原理
第二,功能太多了,不知道怎么很好地把它们整合协调起来。
我是怎么解决这两个问题的呢?
第一个问题,最快的方式就是问同部门的研发同事。
不过不要指望别人会手把手教你,哪怕领导发话,别人也没这义务。
最关键的,不是指望让领导去给他下发命令,就能让他带你,而是看自己懂不懂得做人的。
举个例子:有些老铁来找我领单片机入门到高级的教程+工具包,我都是无套路直接发链接。
为什么要在我的朋友圈才发?
因为我是卖课佬,我觉得我们的项目课确实能帮到一些人,成就一些人,万一哪天你需要,我们又正好专业,各取所需共赢,我觉得没毛病。
但,我也深知,要让别人认可你,那就先贡献价值出来,所以我就不断输出自己经验和送粉丝教程+工具包了。
我感觉人和人之间,挺有意思,也差别挺大。
有些人很懂得感恩,还会给我发个小惊喜,收不收看我有没有给到他对应的价值了。
有些人,趾高气昂,理所当然,像我欠了他的一样。
我就想,怎么会有这种傻杯,然后拉黑了。
扯远了。
回到找同事帮忙的问题,也是同理,你得付出相应的价值,得请吃饭、得请喝奶茶、帮的忙多了得送礼....这不是潜规则,是对别人起码的尊重。
不能因为领导发话了,叫他去带你,你就能像个伸手党一样,一直索取他的价值,不信?你试试多问几个问题以后,看他鸟不鸟你。
第二个问题,功能太多了,不知道怎么很好地把它们整合协调起来。
这个其实最难,因为涉及到程序架构的问题,不是某个功能点,更多的是经验积累到一定程度后,再学习别人优秀的程序架构,突然开悟了。
我是参考别人工程师写的代码,一点点积累起来的,然后根据时间片轮询原理,设计了一个程序架构,我在2019年也录过这个程序架构的教程。
老规矩,有礼貌的粉丝,可以找我安排。
编程思维、高阶代码技巧、程序架构这些,如果能冲我们无际单片机项目特训营,系统把我们几个项目做完,那直接就是走捷径了,都是我们踩坑10年以上总结出来的精华。
3. 重视模块化
我第一次重视程序模块化,项目代码量编译完大概70kb+。
什么是模块化?
举个例子,以下两段代码,分别是非模块化写法和模块化写法:
非模块化写法:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| C #include <reg51.h> *//*假设是51单片机 void main() { *//*硬件初始化 P1 = 0xFF; *//*设置P1口为输入 IT0 = 1; *//*设置外部中断0为下降沿触发 EX0 = 1; *//*使能外部中断0 EA = 1; *//*开启全局中断 *//*主循环 while(1) { *//*功能实现 if(P1_0 == 0) { P1 = ~P1; *//*如果P1.0被按下,翻转P1口的状态 } } } *//*外部中断0服务程序 void exint0() interrupt 0 { *//*中断处理 P1 = P1 << 1; *//*每次中断,将P1口的值左移一位 } |
在这个例子中,硬件初始化、主循环和中断服务程序都混合在同一个.c文件中,阅读和维护起来会困难很多,特别是后期随着代码越来越多。
模块化写法:
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| C // hardware.h #ifndef HARDWARE_H #define HARDWARE_H void init_hardware(); #endif // hardware.c #include "hardware.h" void init_hardware() { P1 = 0xFF; // 设置P1口为输入 IT0 = 1; // 设置外部中断0为下降沿触发 EX0 = 1; // 使能外部中断0 EA = 1; // 开启全局中断 } // main.c #include "hardware.h" #include <reg51.h> void main() { init_hardware(); // 初始化硬件 while(1) { // 主循环功能实现 if(P1_0 == 0) { P1 = ~P1; // 如果P1.0被按下,翻转P1口的状态 } } } // exint0.c #include <reg51.h> // 外部中断0服务程序 void exint0() interrupt 0 { // 中断处理 P1 = P1 << 1; // 每次中断,将P1口的值左移一位 } |
在这个模块化的例子中,我们将硬件初始化放到了hardware.c和hardware.h中,主循环放在main.c中,而中断服务程序放在exint0.c中。这样,每个文件都有一个明确的作用,代码的结构更加清晰,也更好阅读和维护。
稍微复杂点的单片机项目,需要处理很多硬件接口和复杂的时序逻辑,还有各种产品业务逻辑组合,所以模块化尤其重要。
上面只是举了两个入门级模块化写法,高阶的模块化,远不止这些,首先是程序文件架构的模块化,分硬件层、中间层、应用层。
怎么实现多层之间依赖最少,这样后期万一需要更换单片机,只需要修改硬件层驱动代码就好了。
然后是里面每个功能模块化,怎么写方便后期增减功能。
这些其实都是系统的学问,所到之处全是细节,我们无际单片机特训营,都是通过这些思维和编程方式做的,特别是项目3和6。
提升这块的能力,主动学习意识和机遇都很重要,有些工程师做了4,5年,如果公司一直做简单的项目,那也是提升不了的,需要自己通过业余的时间,不断看别人代码摸索。
4. 有条件,换个好点的椅子
撸代码的,长时间对电脑,经常一坐就是几个小时,好点的椅子能缓解颈椎、腰椎的疲劳。如果能换个立式办公桌就更好了。
5. 不要做一个看完不点赞的冷漠青年
不知不觉,又写了两个多小时,原创不易,发财小手点起来...
最近很多粉丝问我单片机怎么学,我根据自己从业十年经验,累积耗时一个月,精心整理一份「单
片机最佳学习路径+单片机入门到高级教程+工具包」 ,全部无偿分享给铁粉!!!
除此以外,再含泪分享我压箱底的22个热门开源项目 ,包含源码+原理图+PCB+说明文档 ,让你迅速进阶成高手!
教程资料包和详细的学习路径可以看我下面这篇文章的开头。