当前位置: 首页 > 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;  // 未知端口}
}

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

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

http://www.xdnf.cn/news/1006849.html

相关文章:

  • 如何处理HTML5兼容性的问题
  • glibc
  • 数据信号处理方法三板斧
  • 会技术的产品经理
  • Keep-Alive 续集:Vue.extend 的遗产解析与优雅告别
  • 文档测试发送
  • 聚集索引与非聚集索引
  • Chapter07-信息披漏
  • Python原生爬虫教程:微店商品详情API接口攻略指南
  • 安徽省考计算机专业课笔记
  • XSS攻击概念通俗解释
  • STM32H7 SD卡使用以及其DMA读写
  • 【AI】理解神经网络原理
  • Java学习笔记之:Vue中路由的基本使用
  • 日语学习-日语知识点小记-构建基础-JLPT-N4阶段(34):ようですそうですばかりのに
  • 由于现在ui设计软件百花齐放,用传统的photoshop设计页面的方式正被摒弃
  • YOLOv2 技术详解:目标检测的又一次飞跃
  • 力扣100- 环形链表
  • vue-property-decorator实践(一)
  • 在 pgvector 中指定相似度搜索方法
  • 能提升30%!Infortrend普安存储自动分层增强版赋能文件共享与医疗影像
  • 华为OD机考-英文输入法-逻辑分析(JAVA 2025B卷)
  • 从 CAN FD 到 SD NAND(SLC)存储:S32K146 T-Box 如何驱动车载数据架构革新?
  • LeetCode 1143. 最长公共子序列 | 动态规划详解
  • 无人机遥控器低延迟高刷新技术解析
  • C# .NET Core Source Generator(C# .NET Core 源生成器)
  • md文件转word文档
  • 单元测试基本步骤
  • Spring MVC 常用请求处理注解总结
  • llm agent