当前位置: 首页 > news >正文

单片机中面向对象的思维

前言:

        面向对象的编程方式用在C语言中,听起来是不是很怪。从C语言入门开始,老师就和你说过,C语言是面向过程的,你现在却要用它来实现面向对象操作。可能是太久没谈对象了,想要new一个对象出来解闷。开玩笑的,面向对象自然有面向对象的好处,C语言是面向过程的语言,他的小弟C++是半面向对象,半面向过程的。所以我们使用C语言类比C++的方式实现面向对象的操作。面向对象三大考点,封装,继承,多态。有的时候我们在操作的时候会面临重复的操作,你有想到过面向对象的特点嘛,考虑面向对象的特点是不是就可以避免重复的操作。

一、面向对象特点与面向过程的类比

        面向过程的代码就是便于直观的查看整体流程,而面向对象的则需要你能够将你所需要的部分抽象出来,但是不管是整么个方式,程序猿最重要的还是代码能跑就行,不然就得你,我的朋友跑了。C++中对象class(类)包含的的成员属性,成员函数,C语言是没有这个叫法的,但是我们可以通过struct结构体成员类比出来,通过void*万能指针实现成员函数的调用。

二、总结:你就得有抽象思维,只要够抽象就不怕找不到对象。

三、接下来我以按键为例简单展示一下单片机中的面向对象思维。

3.1 先简单说一下按键功能:

        我们通常在单片机中用按键作为外部触发事件,按下按键,实现一段操作,松开按键实现另外的操作,每次按键的触发都会存在 “消抖” 问题,每次消抖都是在重复一样的操作,这个时候我就想到了,既然是重复的操作,那干嘛写那么多重复的函数呢,所以我就想到了面向对象的多态。只要创建对象,改写一下他的成员函数就可以了。下面是我原先按键的代码(面向过程的方式消抖)。

/*****************************************************************************函 数 名  : KEY1EintProc功能描述  : KEY1 消抖延时函数,双边沿中断触发中断后开启20ms定时任务输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY1EintProc(void)
{u8 mkeyStatu = KEY_VALUE_RELEASED;mkeyStatu=KEY1_STATUS_READ;if((mkeyStatu == KEY_VALUE_PRESSED)&&(KEY_VALUE_RELEASED == KEY1LastState)){DelayMs(20);mkeyStatu=KEY1_STATUS_READ;if(KEY_VALUE_PRESSED==mkeyStatu)//KEY1 按下{KEY1LastState=mkeyStatu;KEY1_NOTICE_OUT_EN_0;//按键1被拉低后,拉高对应引脚通知安卓端}}else if((mkeyStatu == KEY_VALUE_RELEASED)&&( KEY_VALUE_PRESSED== KEY1LastState))//松开{DelayMs(20);mkeyStatu=KEY1_STATUS_READ;if(KEY_VALUE_RELEASED==mkeyStatu)//KEY1释放{KEY1LastState=mkeyStatu;KEY1_NOTICE_OUT_EN_1;//按键1被拉高后,拉高对应引脚通知安卓端}}
}
/*****************************************************************************函 数 名  : KEY2EintProc功能描述  : KEY2 消抖延时函数,双边沿中断触发中断后开启20ms定时任务输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY2EintProc(void)
{u8 mkeyStatu = KEY_VALUE_RELEASED;mkeyStatu=KEY2_STATUS_READ;if((mkeyStatu == KEY_VALUE_PRESSED)&&(KEY_VALUE_RELEASED == KEY2LastState)){DelayMs(20);mkeyStatu=KEY2_STATUS_READ;if(KEY_VALUE_PRESSED==mkeyStatu)//KEY2按下{KEY2LastState=mkeyStatu;KEY2_NOTICE_OUT_0;//拉低}}else if((mkeyStatu == KEY_VALUE_RELEASED)&&( KEY_VALUE_PRESSED== KEY2LastState))//松开{DelayMs(20);mkeyStatu=KEY2_STATUS_READ;if(KEY_VALUE_RELEASED==mkeyStatu){KEY2LastState=mkeyStatu;KEY2_NOTICE_OUT_1;//拉高}} 
}
/*****************************************************************************函 数 名  : KEY3EintProc功能描述  : PTT 消抖延时函数,双边沿中断触发中断后开启20ms定时任务输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY3EintProc(void)
{u8 mkeyStatu = KEY_VALUE_RELEASED;mkeyStatu=KEY3_STATUS_READ;if((mkeyStatu == KEY_VALUE_PRESSED)&&(KEY_VALUE_RELEASED == KEY3LastState)){DelayMs(20);mkeyStatu=KEY3_STATUS_READ;if(KEY_VALUE_PRESSED==mkeyStatu)//KEY3 按下{KEY3LastState=mkeyStatu;KEY3_NOTICE_OUT_0;//拉低,按下KEY3后对应操作}}else if((mkeyStatu == KEY_VALUE_RELEASED)&&( KEY_VALUE_PRESSED== KEY3LastState))//松开{DelayMs(20);mkeyStatu=KEY3_STATUS_READ;if(KEY_VALUE_RELEASED==mkeyStatu)//KEY3 松开相对操作{KEY3LastState=mkeyStatu;KEY3_NOTICE_OUT_1;//拉高}}  
}
/*****************************************************************************函 数 名  :KEY4EintProc功能描述  : key4 消抖延时函数,双边沿中断触发中断后开启20ms定时任务输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY4EintProc(void)
{u8 mkeyStatu = KEY_VALUE_RELEASED;mkeyStatu=KEY4_STATUS_READ;if((mkeyStatu == KEY_VALUE_PRESSED)&&(KEY_VALUE_RELEASED ==KEY4LastState)){DelayMs(20);mkeyStatu=KEY4_STATUS_READ;if(KEY_VALUE_PRESSED==mkeyStatu)//{KEY4LastState=mkeyStatu;KEY4_OUT_0;//拉低}}else if((mkeyStatu == KEY_VALUE_RELEASED)&&( KEY_VALUE_PRESSED==KEY4LastState))//松开{DelayMs(20);mkeyStatu=KEY4_STATUS_READ;if(KEY_VALUE_RELEASED==mkeyStatu)//{KEY4LastState=mkeyStatu;KEY4_OUT_1;//拉高}} 
}

        可以看出在我消抖后的函数中一直在重复一样的内容,比较繁琐,但简单。

3.2 面向对象的操作,就需要我们将它的不变的内容抽象出来形成统一的模板。然后只需改变成员属性就可以了。下面是面向对象的操作方式。

3.2.1首先是整体对象属性

// 按键设备结构体
typedef struct {uint8_t (*read)(void);      // 读取状态函数指针void (*setState)(uint8_t);  // 读取状态后操作函数uint8_t lastState;          // 上次状态
} KEY_Device;

3.2.2建立对象,以及初始化对象函数

//将消抖函数抽象出来
KEY_Device KEY1;
KEY_Device KEY2;
KEY_Device KEY3;
KEY_Device KEY4;
// 初始化PTT设备
void KEY_Device_init(KEY_Device* dev, uint8_t (*readFunc)(void), void (*setStateFunc)(uint8_t)) {dev->read = readFunc;dev->setState = setStateFunc;dev->lastState = KEY_VALUE_RELEASED;
}

3.2.3设备对象初始化

/*****************************************************************************函 数 名  : KEY_DevicesInit功能描述  : 输入设备面向对象初始化输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY_DevicesInit(void)
{// 初始化KEY1KEY1.read = readKEY1;KEY1.setState = KEY1PressFunc;KEY1.lastState = KEY_VALUE_RELEASED;// 初始化KEY2KEY2.read = readKEY2;KEY2.setState = KEY2PressFunc;KEY2.lastState = KEY_VALUE_RELEASED;// 初始化KEY3KEY3.read = readKEY3;KEY3.setState = KEY3PressFunc;KEY3.lastState = KEY_VALUE_RELEASED;// 初始化KEY4KEY4.read = readKEY4;KEY4.setState = KEY4Func;KEY4.lastState = KEY_VALUE_RELEASED;
}

3.2.4 抽象出来的通用部分

// 处理KEY事件的通用方法
/*****************************************************************************函 数 名  : KEY_Device_process功能描述  : 消抖函数输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
uint8_t KEY_Device_process(KEY_Device* dev) {uint8_t currentState = dev->read();// 按下检测(上升沿)if ((currentState == KEY_VALUE_PRESSED) && (dev->lastState == KEY_VALUE_RELEASED)) {DelayMs(20);  // 防抖延时if (dev->read() == KEY_VALUE_PRESSED) {dev->lastState = KEY_VALUE_PRESSED;dev->setState(KEY_VALUE_PRESSED);return 1;  // 返回按下事件}} // 释放检测(下降沿)else if ((currentState == KEY_VALUE_RELEASED) && (dev->lastState == KEY_VALUE_PRESSED)) {DelayMs(20);  // 防抖延时if (dev->read() == KEY_VALUE_RELEASED) {dev->lastState = KEY_VALUE_RELEASED;dev->setState(KEY_VALUE_RELEASED);return 2;  // 返回释放事件}}return 0;  // 无状态变化
}

3.2.5 各自的按键操作函数

/*****************************************************************************函 数 名  : readKEY1功能描述  : 读取引脚函数输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
uint8_t readKEY1(void)
{ return KEY1_STATUS_READ;
}
/*****************************************************************************函 数 名  : KEY1PressFunc功能描述  : 读取按键后操作输入参数  : state:高低电平返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY1PressFunc(uint8_t state)
{if(state)//KEY1松开后{KEY1_NOTICE_OUT_EN_1;//通知安卓松开KEY1}else{  //KEY1 按下KEY1_NOTICE_OUT_EN_1; //通知安卓按下KEY1}
}
/*****************************************************************************函 数 名  : readKEY2功能描述  : 读取ptt2按键输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
// DMR PTT2 相关函数
uint8_t readKEY2(void)
{ return KEY2_STATUS_READ;
}
/*****************************************************************************函 数 名  : KEY_Device_process功能描述  : 读到状态后操作输入参数  : state:高低电平返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY2PressFunc(uint8_t state) 
{if(state)//Ptt1松开后{KEY2_NOTICE_OUT_EN_1;//通知安卓松开KEY2//PA4 DMR 停止发射}else{  //ptt2 按下KEY2_NOTICE_OUT_EN_0; //通知安卓按下KEY2 //PA4 发射}
}
/*****************************************************************************函 数 名  : readKEY3功能描述  : 读取M6状态输入参数  : void返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
// M6 PTT 相关函数
uint8_t readKEY3(void)
{     return KEY3_STATUS_READ;
}
/*****************************************************************************函 数 名  : KEY3PressFunc功能描述  : 消抖函数输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY3PressFunc(uint8_t state)
{if(state)//KYE3松开后{KEY3_NOTICE_OUT_1; //}else{  //KYE3 按下KEY3_NOTICE_OUT_0;//PA4 发射}    
}
/*****************************************************************************函 数 名  : KEY_Device_process功能描述  : 消抖函数输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
// KEY4 相关函数
uint8_t readKEY4(void)
{ return KEY4_STATUS_READ;
}
/*****************************************************************************函 数 名  : KEY_Device_process功能描述  : 消抖函数输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
void KEY4Func(uint8_t state)
{//KEY4按下后对应操作
}
/*****************************************************************************函 数 名  : KEY_Device_process功能描述  : 消抖函数输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
// 主处理函数

3.2.6 主函数

/*****************************************************************************函 数 名  : KEY_Device_process功能描述  : 消抖函数输入参数  : u8 power返 回 值  : void作  者    : Bright创建日期 : 20250607
*****************************************************************************/
// 主处理函数
uint8_t ExtiProc(uint8_t pttPort) 
{// 使用switch处理不同端口switch(pttPort) {case KEY1_Port:return KEY_Device_process(&KEY1);case KEY2_Port:return KEY_Device_process(&KEY2);case KEY3_Port:return KEY_Device_process(&KEY3);case KEY4Statu_Port:return KEY_Device_process(&KEY4);default:return 0;  // 未知端口}
}return KEY_Device_process(&KEY3);case KEY4Statu_Port:return KEY_Device_process(&KEY4);default:return 0;  // 未知端口}
}

四、总体上只要找到找到函数的特点,就能够利用面向对象的思想来实现。面向对象的方式只要将抽象部分写完,后续只需要新建对象,写各自的函数就可以了,整体上看起来比较清爽。

        但无论是是用哪种方式,只要能够跑就行了,怎么简单怎么来,公司怎么要求怎么来,希望以上内容对大家有帮助。

相关文章:

  • 从零开始学Python(2)——流程控制语句和五种容器
  • 《射频识别(RFID)原理与应用》期末复习 RFID第四章 数据校验和防碰撞算法(知识点总结+习题巩固)
  • js判断手机操作系统(ios、安卓、华为)
  • FastDFS分布式存储
  • web3 资讯网址
  • Web 架构之 Kubernetes 弹性伸缩策略设计
  • 如何将 iPhone 中的短信导出为 PDF
  • C/C++ 面试复习笔记(6)
  • 一[3]、ubuntu18.04环境 利用 yolov8 训练开源列车数据集,并实现列车轨道检测
  • Java基于SpringBoot的牙科诊所管理系统,附源码+文档说明
  • Springboot实现Java程序和线程池的优雅关闭
  • 计算机视觉之三维重建(深入浅出SfM与SLAM核心算法)—— 1. 摄像机几何
  • Oracle DG库手动注册归档日志的两种方法
  • 【报错解决】RTX4090 nvrtc: error: invalid value for --gpu-architecture (-arch)
  • Android 手机操作系统的14个常见问题以及解决办法
  • PostgreSQL认证怎么选?PGCP中级认证、PGCM高级认证
  • Git 常用总结
  • 【Net】TCP/IP 协议
  • 《性能之巅》第十章 网络
  • 机器学习与深度学习20-数学优化
  • 自家宽带怎么建设网站/搜索引擎优化的定义是什么
  • 中国广东手机网站建设/百度竞价渠道代理
  • 电子商务网站建设实践课题背景/百度今日排行榜
  • 郑州网站seo厂家/真正免费的网站建站平台推荐
  • 省级政府网站集约化建设/百度指数行业排行
  • 闵行网站制作/网站如何优化排名软件