本帖最后由 safu枫 于 2018-5-7 10:51 编辑
第一篇:炫酷地点亮一盏LED灯我们学单片机,第一个程序就是点亮一盏LED灯,那么我单片机开启面向对象方式的第一步也是点亮一盏LED灯,这里主要是用到了继承和封装的2个概念;这里我们先讲一下,使用传统的一些LED操作,并分析这些操作有什么问题:以前我点亮一盏LED是这样的
1:我每增加一个灯,就要写一段LED初始化代码,要定义一个端口;[mw_shl_code=c,true]#define LED1 PAout(1)
#define LED_ON 1
#define LED_OFF 0
void LED1_Init()
{
......;//初始化IO口之类的函数
}
LED1 = LED_ON; //点亮[/mw_shl_code]
2:我要实现LED功能的拓展不方便,比如我要实现LED的闪烁;
------------------------------------------------------------------------------------------所以我现在这样点亮一盏LED灯,以及让它闪烁起来首先创建一个结构体,或者我们叫做 定义一个 LED类[mw_shl_code=c,true]typedef struct CLASS_LED
{
void (* const SetLedGPIOCMD)(struct CLASS_LED * p, GPIO_TypeDef* GPIOx, u16 GPIO_Pin); //设置LED端口
void (* const LED_SetST)(struct CLASS_LED * p,u8 LED_ST);
//struct CLASS_LEDBlink * LEDBlink; //这里是继承了 LED闪烁类,我们下面再来编写,先不看,有需要详细了解的朋友,可以下载工程文件查看源码
GPIO_TypeDef* _GPIOx; //LED端口
u16 _GPIO_Pin; //LED端口
u8 _LED_ST; //记录LED灯当前的状态
}typ_CLASS_LED;[/mw_shl_code] 然后我们来编写相关的函数
[mw_shl_code=c,true]void SetLedGPIOCMD(struct CLASS_LED * p, GPIO_TypeDef* GPIOx, u16 GPIO_Pin) //初始化LED指定的端口
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOx, &GPIO_InitStructure);
p->_GPIOx = GPIOx;
p->_GPIO_Pin = GPIO_Pin;
}
void LED_SetST(struct CLASS_LED * p,u8 LED_ST)
{
switch(LED_ST)
{
case LED_ON:
GPIO_ResetBits(p->_GPIOx, p->_GPIO_Pin);
break;
case LED_OFF:
GPIO_SetBits(p->_GPIOx, p->_GPIO_Pin);
break;
case LED_RE:
GPIO_WriteBit(p->_GPIOx, p->_GPIO_Pin,!GPIO_ReadOutputDataBit(p->_GPIOx, p->_GPIO_Pin));
default:
break;
}
} [/mw_shl_code]
然后我们来定义一个宏定义,来给这个结构体赋值(面向对象里面叫实例化这个类)[mw_shl_code=c,true]#define NewLed() {
SetLedGPIOCMD, //这里我们把上面定义的函数名赋值过来,也就是 赋值函数指针
LED_SetST,
NULL,
0,
0,
0
} [/mw_shl_code]好了,这些我们就来创建(实例化)这个LED对象,以及操作它[mw_shl_code=c,true]typ_CLASS_LED led0 = NewLed(); //创建了一个led0的对象
led0.SetLedGPIOCMD(&led0, GPIOB, GPIO_Pin_5); //设置指定的端口,这样是不是很方便,不用重新去写了,这就是面向对象的一个思维,把很类似的代码提取出来,减少代码的重复率
led0.LED_SetST(&led0,LED_ON);//点亮led0, 这样逻辑是不是很清楚,而且你想要增加功能,就往结构体里面增加相关的方法,比如你可以增加blink功能[/mw_shl_code]
好了,这下我们就完成了点亮一盏LED灯,虽然代码量比传统的大了很多,一开始也会觉得比较复杂,但是你想一下 我们以后这样操作就可以了,想要增加一个LED,只要定义一个LED对象,然后指定其端口就可以随意操作了(比较起来,好像传统的方式也可以,但是这主要是一个思维上的进步,这里的进步主要体现在封装的概念,而且你要想拓展都很方便,而且逻辑很清楚),在实际的工程中,功能增加了很多,比如继承了led_blink类,比如使用了链表结构
第一篇,写的很多地方可能不是很清楚,以后尽量把它理顺吧。。。有兴趣的请看源码工程,我随后上传。。。里面有操作说明和相关注释,有什么问题欢迎交流看到下面的评论有很多朋友支持,当然也有部分朋友持反对意见,这里还是谢谢大家的意见。。我这里只是把这种思路和编程方式分享给大家,另外这种思路也不是完全由我原创,我也是从书上学来的。。。我看了下大家的意见,持反对意见的可能认为这种方式1:内存开销大,对性能有影响(这里我觉得 保持这种思路,在代码实现上还是可以尽可能的优化,比如我把这些代码移植到51上我会做一些修改以适应51)2:认为嵌套啊,函数啊,结构体啊,过于繁杂,反而失去了C的简洁(这里可能新手或者对面向对象思维理解不深的人,会为了用而用,而不是为了实际需要,所以实际项目还是得灵活使用)3:。。。我也不知道为什么、、还是希望持反对意见的朋友能提出你详细的原因持赞同意见的朋友:1:封装好,逻辑结构清楚,维护方便,代码易读开篇传送门,有推荐书籍:http://www.openedv.com/forum.php?mod=viewthread&tid=270535&extra=
在51和STM32单片机上使用面向对象的编程,第二篇:强大的按键http://www.openedv.com/forum.php?mod=viewthread&tid=270631&extra=在51和STM32单片机上使用面向对象的编程,第三篇:按键控制开灯关灯也能爆炸http://www.openedv.com/thread-270786-1-1.html
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
这方法不错,代码维护变简洁,但是一个项目里不停改代码,也是一个不小的工作量。不需要经常更改代码的功能模块,封装成LIB的话,调用很方便。
一周热门 更多>