在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枫
1楼-- · 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这里 你把它看成是组合的概念吧, 后面的有个例子 会比较清晰地说明继承的概念。。
hgr211
2楼-- · 2019-07-24 14:17
 精彩回答 2  元偷偷看……
程功之道
3楼-- · 2019-07-24 19:09
safu枫 发表于 2018-5-3 11:28
访问结构体变量使用.符号, 如果是 通过结构体指针访问结构体变量 就需要使用->符号;
这里是C语言的 结 ...

是啊 楼主 有没有好书推荐啊 以前写8位单片机也没用过指针 结构体 在学校C语言老师就教了点for if switch语句 结构体啥的都没讲 还是我自己看了点
程功之道
4楼-- · 2019-07-24 23:07
本帖最后由 程功之道 于 2018-5-3 11:46 编辑
safu枫 发表于 2018-5-3 11:28
访问结构体变量使用.符号, 如果是 通过结构体指针访问结构体变量 就需要使用->符号;
这里是C语言的 结 ...

楼主 我觉得这里也可以不用宏定义吧#define NewLed()    {            
  SetLedGPIOCMD,                 
  LED_SetST,                     
  NULL,                          
  0,                             
  0,                              
  0
}
直接定义led0  为这个结构体类型不就可以吗?typ_CLASS_LED  led0;不需要赋值,不需要这个NewLed() 宏定义   
typ_CLASS_LED  led0 = NewLed();     
safu枫
5楼-- · 2019-07-25 03:13
 精彩回答 2  元偷偷看……
safu枫
6楼-- · 2019-07-25 06:46
程功之道 发表于 2018-5-3 11:43
楼主 我觉得这里也可以不用宏定义吧#define NewLed()    {            
  SetLedGPIOCMD,              ...

恩,这种写法是 学习了 书里面的写法,然后这也是 面向对象语言 像C# C++的写法,你要是直接定义结构体 你还得赋值啊。。。函数指针之类的

一周热门 更多>