在51和STM32单片机上使用面向对象的编程,第一篇:炫酷地点亮一盏LED灯。。持续更新!!

2019-07-21 01:07发布

本帖最后由 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


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
49条回答
safu枫
2019-07-24 13:51
本帖最后由 safu枫 于 2018-5-3 11:30 编辑
程功之道 发表于 2018-5-3 11:19
p->LEDBlink->_SetBlinkTime_ms = SetBlinkTime_ms;这个为啥不是用.访问,而是用->这个符号,LEDBlink是 ...

访问结构体变量使用.符号, 如果是 通过结构体指针访问结构体变量 就需要使用->符号;
这里是C语言的 结构体相关的知识点, 这个 嵌套相当于是面向对象里面的继承的概念;
更像组合的概念, 就是把2个类组合在一起了,打个比方就像是一辆车由车身 车轮等组成,
这里的 LED 就用LED类和 led_blink组合在一起了,这里的工程代码是我比较早写的,那时候还不理解继承的概念,谢谢你的提醒,我应该写成以led类为基类,led_blink为子类, led_blink去继承led这里 你把它看成是组合的概念吧, 后面的有个例子 会比较清晰地说明继承的概念。。

一周热门 更多>