1.在看别人单片机程序时,你也许是奔溃的,因为全局变量满天飞,不知道哪个在哪用了,哪个表示什么,而且编写极其不规范。
2.在自己写单片机程序时,也许你也是奔溃的,总感觉重新开启一个项目,之前的写过相似的代码也无法使用,得重新敲,代码重用度不高。编程效率低下。代码无法积累。
3.而且感觉写这个代码没有思想,没有灵魂,没有框架,只是一个一个功能代码的堆砌,很空泛。
那么这个时候,我就想在单片机中引入面向对象的思想,使代码更规范。
引入面向对象的思想有两种方式:
1.直接使用C++编程,但是不好的是,效率有所降低,有些单片机编译器不支持。
2.通过C语言引伸出一种写法:
2.1类(class):
用来描述具有相同的属性和方法的对象的集合.
然而C语言中并没有类,但是我们可以跟java一样,通过文件来当做一个类,如有个类叫LCD,那我们就可以用LCD.c来表示有这么一个类,同时在文件中定义一个结构体:struct ScmLCD。
2.2那么面向对象有四个基本特性:
抽象,封装,继承,多态。
那么去其中比较有用的主要是封装,继承,多态。
2.3继承
其中,继承的话,可以使用文件的形式来表示,比如LCD.c这个类在LCD文件夹下,而LCD1602这个对象是LCD的子类,那么在LCD文件夹下还有一个文件夹叫LCD1602,而这个文件夹里有个文件叫LCD1602.c,然后在该文件里定义一个结构体struct ScmLCD1602。那么LCD1602属于LCD的一个型号,所以LCD1602就是继承于LCD.
2.4封装
然后是封装的话,封装主要通过一个结构体来封装“成员变量”,当然,安全性还是没有那么高,但是至少可以降低全局变量的滥用,提高可读性,如stLCD这个类有特征边变量:型号,显示的颜 {MOD},点数等 动作方法有:显示字符,显示数字等。然后定义几个指针变量void (*get_xxx)()获取特征,通过void (*set_xxx)(char *)来设置特征。
对于安全性的进一步提高,可以使用static,如静态全局,变量和静态修饰的函数,只能在该文件中调用。
2.5多态
接下来就是多态了,多态的话,比如说,LCD类有一个 void LCD_ShowChar(char *)的方法,那么LCD的结构体里定义一个结构体指针 void(*LCD_ShowChar)(char *),那么继承类LCD1602只要在.c文件里写一个 void LCD1602_Showchar(char *)的方法,并在里面写上具体的实现。然后当要调用该类的这个现实方法时,则:
struct ScmLCD stLCD;
stLCD.LCD_ShowChar= LCD1602_Showchar;
那么接下来调用stLCD.LCD_ShowChar(“……”);就是调用LCD1602的方法。而如果今天换了一个型号的显示屏甚至主控芯片,那么这个时候则不需要重新编写实现代码,只要在文件夹LCD下增加如LCD12864文件夹,然后增加.c及结构体和实现方法,然后在开头修改stLCD.LCD_ShowChar= LCD12854_Showchar;那么接下来的就是调用LCD12864的方法,其他代码不变,哪天又换回来了,那么再改回stLCD.LCD_ShowChar= LCD1602_Showchar;即可。
补充:
单片机代码的需要大规模修改的原因有几个:
1.PCB布局的变化:
PCB布局变化主要是IO的变化,然后IO变化一般如果驱动程序是直接对IO操作的话就需要大规模改变代码,那么怎么提升代码的修改效率:可以在每个驱动子类里对IO进行define,那么只需要修改define代码,其他的不变的。
2.主控芯片的变化:
如果是主控芯片的变化,那么可能整个编译器或者说芯片内部资源的控制方式都发生变化,那么这个时候如果是按照上面的方法的话,驱动父类和功能类,及核心代码是不用变的,只要修改相应的驱动子类即可。
3.封装的变化:
那么封装发生变化,一般要修改IO和该封装的控制方式,即与之前的封装是有同一个父类,那么这个时候只需要添加相应的驱动即可,或者之前有已写好的,只要加入即可。
4.就是功能指标的变化:
功能指标的变化,那么一般分为子功能变化和核心功能变化,子功能只需要修改子功能类即可,核心功能修改的话,主要就是执行的顺序,那么这个需要引入队列和多任务机制,那么后续可以根据RTOS系统的一些写法来实现,这样的一个类来通用化