全网最适合入门的面向对象编程教程:11 类和对象的Python实现-子类调用父类方法-模拟串口传感器和主机

news/2024/11/19 17:36:58/文章来源:https://www.cnblogs.com/FreakEmbedded/p/18290960

全网最适合入门的面向对象编程教程:11 类和对象的 Python 实现-子类调用父类方法-模拟串口传感器和主机

摘要:

本节课,我们主要讲解了在 Python 类的继承中子类如何进行初始化、调用父类的属性和方法,同时讲解了模拟串口传感器和主机类的具体实现,并使用 xcom 串口助手与两个类进行串口通信使用。

原文链接:

FreakStudio 的博客

往期推荐:

学嵌入式的你,还不会面向对象??!

全网最适合入门的面向对象编程教程:00 面向对象设计方法导论

全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念

全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类

全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性

全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法

全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签

全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装

全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解

全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器

全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系

全网最适合入门的面向对象编程教程:10 类和对象的Python实现-类的继承和里氏替换原则

更多精彩内容可看:

给你的 Python 加加速:一文速通 Python 并行计算

一文搞懂 CM3 单片机调试原理

肝了半个月,嵌入式技术栈大汇总出炉

电子计算机类比赛的“武林秘籍”

一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库

文档和代码获取:

可访问如下链接进行对文档下载:

https://github.com/leezisheng/Doc

image

本文档主要介绍如何使用 Python 进行面向对象编程,需要读者对 Python 语法和单片机开发具有基本了解。相比其他讲解 Python 面向对象编程的博客或书籍而言,本文档更加详细、侧重于嵌入式上位机应用,以上位机和下位机的常见串口数据收发、数据处理、动态图绘制等为应用实例,同时使用 Sourcetrail 代码软件对代码进行可视化阅读便于读者理解。

相关示例代码获取链接如下:https://github.com/leezisheng/Python-OOP-Demo

正文

模拟串口传感器和主机类的具体实现:

接下来看一下我们新建的两个类方法的具体实现,可以明确的是,SensorClass 和 MasterClass 都需要调用 SerialClass 类中有关串口收发的方法,也就是子类调用父类的方法,子类调用父类的方法有三种方式:

  • 父类名.方法名(self):此时需要加上父类的类名前缀,且需要带上 self 参数变量。该方法单继承或多继承均适用。
  • super(子类名,self).父类方法名()/super().父类方法名:使用 super()函数,但如果涉及多继承,该函数只能调用第一个直接父类的构造方法。

SensorClass 类的实现

(1)首先,我们将 SensorClass 中工作状态的对应字符表示和命令对应字符表示设置为类属性,什么意思?我们来看如下代码:

class SensorClass(SerialClass):_# 类变量:__#   RESPOND_MODE-响应模式-0__#   LOOP_MODE   -循环模式-1_RESPOND_MODE,LOOP_MODE = (0,1)_# 类变量:__#   START_CMD       - 开启命令      -0__#   STOP_CMD        - 关闭命令      -1__#   SENDID_CMD      - 发送ID命令    -2__#   SENDVALUE_CMD   - 发送数据命令   -3_START_CMD,STOP_CMD,SENDID_CMD,SENDVALUE_CMD = (0,1,2,3)

类属性归类所有,与前面讲的实例属性不同,类属性就相当与全局变量,是实例对象共有的属性,类属性影响类的所有对象;而实例对象的属性为实例对象自己私有,实例属性只影响当前对象。类属性常用于存储常量、定义默认值或构造一个所有对象都能访问的缓存。

这里,我们定义了两种类属性:

RESPOND_MODE,LOOP_MODE = (0,1)

用于表示 SensorClass 不同工作模式。

START_CMD,STOP_CMD,SENDID_CMD,SENDVALUE_CMD = (0,1,2,3)

用于表示不同命令。

(2)在初始化中,我们调用父类初始化方法进行,同时可以在初始化 SensorClass 类时指定 id、state、port 三个参数。

def __init__(self,id:int = 0,state:int = RESPOND_MODE,port:str = "COM11"):# 调用父类的初始化方法,super() 函数将父类和子类连接super().__init__(port)self.sensorvalue = 0self.sensorid    = idself.sensorstate = state

这里,实际上 SensorClass 类初始化的参数应该包括其他有关串口配置相关的参数(波特率、校验位、数据位、停止位),由于串口通信双方这些参数配置相同,这里为了方便讲解故而简化。

(3)模拟传感器上电初始化,在实际传感器上电过程中会完成校准、自检等操作,这里我们简单输出传感器状态和 ID 号:

_# 传感器上电初始化_def InitSensor(self):_# 传感器上电初始化工作__# 同时输出ID号以及状态_print("Sensor %d Init complete : %d"%(self.sensorid,self.sensorstate))

(4)在传感器使能和关闭方法中,我们开启或关闭串口并打印相关信息:

_# 开启传感器_def StartSensor(self):super().OpenSerial()print("Sensor %d start serial %s "%(self.sensorid,self.dev.port))_# 停止传感器_def StopSensor(self):super().CloseSerial()print("Sensor %d close serial %s " % (self.sensorid, self.dev.port))

(5)在传感器发送 ID 号的方法中,我们调用了父类的 WriteSerial 方法:

_# 发送传感器ID号_def SendSensorID(self):super().WriteSerial(str(self.sensorid))print("Sensor %d send id "%self.sensorid)

(6)在传感器发送数据方法中,我们使用如下语句生成一个随机数:

_# 生成[1, 10]内的随机整数_data = random.randint(1, 10)

注意,此方法需要使用 import random 语句导入 random 库。

同时调用父类的 WriteSerial 方法实现传感器数据的发送:

_# 发送传感器数据_def SendSensorValue(self):_# 生成[1, 10]内的随机整数_data = random.randint(1, 10)super().WriteSerial(str(data))print("Sensor %d send data  %d" % (self.sensorid,data))

(7)在传感器接收命令方法中,我们调用了父类的 ReadSerial 接收命令:

_# 接收主机指令_def RecvMasterCMD(self):cmd = super().ReadSerial()print("Sensor %d recv cmd %d " % (self.sensorid,cmd))return cmd

MasterClass 类的实现

(1)首先定义关于工作模式和命令的类属性:

class MasterClass(SerialClass):_# 类变量:__#   BUSY_STATE  -忙碌状态-0__#   IDLE_STATE  -空闲状态-1_BUSY_STATE, IDLE_STATE = (0, 1)_# 类变量:__#   START_CMD       - 开启命令      -0__#   STOP_CMD        - 关闭命令      -1__#   SENDID_CMD      - 发送ID命令    -2__#   SENDVALUE_CMD   - 发送数据命令   -3_START_CMD, STOP_CMD, SENDID_CMD, SENDVALUE_CMD = (0, 1, 2, 3)

(2)在初始化函数中调用父类的初始化方法,并定义 valuequeue 和__masterstatue 属性:

_# 类的初始化_def __init__(self,state:int = IDLE_STATE,port:str = "COM17"):_# 调用父类的初始化方法,super() 函数将父类和子类连接_super().__init__(port)self.valuequeue   = queue.Queue(10)self.__masterstatue = state

(3)在 StartMaster 方法中我们打开串口并使用 logging.info()方法输出调试信息:

_# 开启主机_def StartMaster(self):super().OpenSerial()logging.info("START MASTER :"+self.dev.port)

这里,需要导入 logging 库并设置日志输出级别:

import logging
_# 设置日志输出级别_
logging.basicConfig(level=logging.DEBUG)

(4)关闭主机方法中调用父类的 CloseSerial 方法:

_# 停止主机_def StopMaster(self):super().CloseSerial()logging.info("CLOSE MASTER :" + self.dev.port)

(5)如下调用父类的 ReadSerial 方法接收 ID 号和数据:

_# 接收传感器ID号_def RecvSensorID(self):sensorid = super().ReadSerial()logging.info("MASTER RECIEVE ID : " + str(sensorid))return sensorid_# 接收传感器数据_def RecvSensorValue(self):data = super().ReadSerial()logging.info("MASTER RECIEVE DATA : " + str(data))self.valuequeue.put(data)return data

(6)调用父类的 WriteSerial 方法发送指令:

_# 主机发送命令_def SendSensorCMD(self,cmd):super().WriteSerial(str(cmd))logging.info("MASTER SEND CMD : " + str(cmd))

(7)如下 RetMasterStatue 方法获取主机状态:

_# 主机返回工作状态-_def RetMasterStatue(self):return self.__masterstatue

完整代码

以下为两个类的完整代码:

class SensorClass(SerialClass):_# 类变量:__#   RESPOND_MODE -响应模式-0__#   LOOP_MODE    -循环模式-1_RESPOND_MODE,LOOP_MODE = (0,1)_# 类变量:__#   START_CMD       - 开启命令      -0__#   STOP_CMD        - 关闭命令      -1__#   SENDID_CMD      - 发送ID命令    -2__#   SENDVALUE_CMD   - 发送数据命令   -3_START_CMD,STOP_CMD,SENDID_CMD,SENDVALUE_CMD = (0,1,2,3)_# 类的初始化_def __init__(self,port:str = "COM11",id:int = 0,state:int = RESPOND_MODE):_# 调用父类的初始化方法,super() 函数将父类和子类连接_super().__init__(port)self.sensorvalue = 0self.sensorid    = idself.sensorstate = state_# 传感器上电初始化_def InitSensor(self):_# 传感器上电初始化工作__# 同时输出ID号以及状态_print("Sensor %d Init complete : %d"%(self.sensorid,self.sensorstate))_# 开启传感器_def StartSensor(self):super().OpenSerial()print("Sensor %d start serial %s "%(self.sensorid,self.dev.port))_# 停止传感器_def StopSensor(self):super().CloseSerial()print("Sensor %d close serial %s " % (self.sensorid, self.dev.port))_# 发送传感器ID号_def SendSensorID(self):super().WriteSerial(str(self.sensorid))print("Sensor %d send id "%self.sensorid)_# 发送传感器数据_def SendSensorValue(self):_# 生成[1, 10]内的随机整数_data = random.randint(1, 10)super().WriteSerial(str(data))print("Sensor %d send data  %d" % (self.sensorid,data))_# 接收主机指令_def RecvMasterCMD(self):cmd = super().ReadSerial()print("Sensor %d recv cmd %d " % (self.sensorid,cmd))return cmdclass MasterClass(SerialClass):_# 类变量:__#   BUSY_STATE  -忙碌状态-0__#   IDLE_STATE  -空闲状态-1_BUSY_STATE, IDLE_STATE = (0, 1)START_CMD, STOP_CMD, SENDID_CMD, SENDVALUE_CMD = (0, 1, 2, 3)_# 类的初始化_def __init__(self,state:int = IDLE_STATE,port:str = "COM17"):_# 调用父类的初始化方法,super() 函数将父类和子类连接_super().__init__(port)self.valuequeue   = queue.Queue(10)self.__masterstatue = state_# 开启主机_def StartMaster(self):super().OpenSerial()logging.info("START MASTER :"+self.dev.port)_# 停止主机_def StopMaster(self):super().CloseSerial()logging.info("CLOSE MASTER :" + self.dev.port)_# 接收传感器ID号_def RecvSensorID(self):sensorid = super().ReadSerial()logging.info("MASTER RECIEVE ID : " + str(sensorid))return sensorid_# 接收传感器数据_def RecvSensorValue(self):data = super().ReadSerial()logging.info("MASTER RECIEVE DATA : " + str(data))self.valuequeue.put(data)return data_# 主机发送命令_def SendSensorCMD(self,cmd):super().WriteSerial(str(cmd))logging.info("MASTER SEND CMD : " + str(cmd))_# 主机返回工作状态-_def RetMasterStatue(self):return self.__masterstatue

模拟实例

这里,我们使用 XCOM 软件和我们的 Python 程序进行交互。

传感器实验模拟

这里,我们首先在主函数中创建传感器对象,完成初始化后使能传感器中串口模块,并设置循环,轮询读取指令并执行操作,示例代码如下:

if __name__ == "__main__":_# 创建传感器对象_s = SensorClass(port="COM11", id=1, state=SensorClass.RESPOND_MODE)_# 初始化传感器_s.InitSensor()_# 传感器开启_s.StartSensor()while True:_# 根据不同指令执行不同操作_cmd = s.RecvMasterCMD()_# START_CMD, STOP_CMD, SENDID_CMD, SENDVALUE_CMD = (0, 1, 2, 3)_if cmd == SensorClass.SENDID_CMD:s.SendSensorID()elif cmd == SensorClass.SENDVALUE_CMD:s.SendSensorValue()elif cmd == SensorClass.STOP_CMD:s.StopSensor()breakprint(" Sensor Stop Work!")

我们来看一下实际验证效果:

image

主机实验模拟

这里,我们首先在主函数中创建并开启主机对象,我们的 xcom 模拟传感器,主机在轮询中发送接收数据指令,并将接收的数据加入主机类的队列,最后发送停机命令,并关闭主机。

if __name__ == "__main__":m = MasterClass(state=MasterClass.IDLE_STATE, port="COM17")m.StartMaster()_# START_CMD, STOP_CMD, SENDID_CMD, SENDVALUE_CMD = (0, 1, 2, 3)__# 发送指令,获取传感器ID_m.SendSensorCMD(MasterClass.SENDID_CMD)m.RecvSensorID()for i in range(3):_# 发送指令,获取传感器数据_m.SendSensorCMD(MasterClass.SENDVALUE_CMD)m.RecvSensorValue()m.SendSensorCMD(MasterClass.STOP_CMD)m.StopMaster()print("Master Stop Work!")

这里我们将主机日志打印到文件中:

_# 在配置下日志输出目标文件和日志格式_
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(filename='my.log', level=logging.DEBUG, format=LOG_FORMAT)

我们来看一下实际验证效果:

image

可以看到两个实验都可以完整运行,关于两个类的交互工作,我们将在后续多线程中讲到。

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/740879.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vite5+Electron聊天室|electron31跨平台仿微信EXE客户端|vue3聊天程序

基于electron31+vite5+pinia2跨端仿微信Exe聊天应用ViteElectronChat。 electron31-vite5-chat原创研发vite5+electron31+pinia2+element-plus跨平台实战仿微信客户端聊天应用。实现了聊天、联系人、收藏、朋友圈/短视频等模块。支持electron多开窗口管理、壁纸皮肤、自定义最大…

隐私计算核心技术

非对称加密算法 RSA RSA 算法基础欧拉函数:任意给定正整数 n,在小于等于 n 的正整数中,有多少个数与 n 构成互质关系?计算这些值的方法叫做欧拉函数,以 \(\varphi(n)\) 表示。 欧拉定理:如果两个正整数 a 和 n 互质,则 n 的欧拉函数可以让下面的等式成立:\[\begin{equa…

[Code Composer Studio] Memory Browser保存数据

造冰箱的大熊猫,适用于Code Composer Studio v5.5@cnblogs 2024/7/91、使用CCS>>View>>Memory Browser,可对目标板上的存储空间进行读写操作 2、要保存数据,在Memory Browser内,点击鼠标右键,在弹出的菜单中选择Save Memory 3、在Save Memory对话框中,在Fi…

[LeetCode] 135. Candy

和 238. Product of Array Except Self 计算除自己之外的乘积很像,先左侧遍历,再右侧遍历。 Hard不过如此。 class Solution:def candy(self, ratings: List[int]) -> int:# 1n = len(ratings)if n == 1:return 1# min element is not existif all(x == ratings[0] for x …

常用类

常用类 内部类 分类成员内部类 静态内部类 static 局部内部类 匿名内部类概念:在一个类的内部再定义一个完整的类 class Outer{class Inner{} }特点:编译之后可生成独立的字节码文件 (.class) 内部类可直接访问外部类的私有成员,而不破坏封装 可为外部类提供必要的内部…

一台 3000 元战未来主机装配方案

为了更好的阅读体验,请点击这里 下面是一个备选方案: CPU:酷睿I3 12100 四核八线程649 主板:微星H610M 爆破弹 金牌 569 内存:金百达16G 8GX2 3200 银爵 229 散热:赛普雷 涂城 双铜管散热器 49 固态:西数SN570 500G M2新蓝盘 249 显卡:UHD 730 电源:航嘉 GS400 好运来…

算法金 | 时间序列预测真的需要深度学习模型吗?是的,我需要。不,你不需要?

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」参考 论文:https://arxiv.org/abs/2101.02118 更多内容,见微*公号往期文章: 审稿人:拜托,请把模型时间序列去趋势!! 使用 Python 快速上手 LSTM 模型预测时间序列…

Pandas我这个填充nan值为什么填充不上呢?

大家好,我是Python进阶者。 一、前言 前几天在Python钻石交流群【逆光】问了一个Python数据处理的问题,问题如下:请问一下,我这个填充nan值为什么填充不上呢二、实现过程 这里【瑜亮老师】给了个思路如下:试试看这样,代码如下: sf_mergetotal.loc[sf_mergetotal[寄件人]…

python matplot绘图工具练习

matplot 数据可视化 seaborn# pyplot import matplotlib.pyplot as plt import numpy as np import seaborn as sns import pandas as pdx_point = np.array([0,6]) y_point = np.array([0,100]) plt.plot(x_point,y_point,b-.v) # 格式处理 plt.show()x = np.arange(0,4…

R语言用逻辑回归、决策树和随机森林对信贷数据集进行分类预测|附代码数据

原文链接:http://tecdat.cn/?p=17950 最近我们被客户要求撰写关于的研究报告,包括一些图形和统计输出。在本文中,我们使用了逻辑回归、决策树和随机森林模型来对信用数据集进行分类预测并比较了它们的性能数据集是 credit=read.csv("gecredit.csv", header = T…

代码随想录算法训练营第27天 | 122.买卖股票的最佳时机 II 55. 跳跃游戏 1005.K次取反后最大化的数组和

122.买卖股票的最佳时机 II 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。 返回 你能获得的 最大 利润 。 解题: 思路:最…

R语言实现 Copula 算法建模相依性案例分析报告

原文链接:http://tecdat.cn/?p=6193 原文出处:拓端数据部落公众号copula是将多变量分布函数与其边缘分布函数耦合的函数,通常称为边缘。Copula是建模和模拟相关随机变量的绝佳工具。Copula的主要吸引力在于,通过使用它们,你可以分别对相关结构和边缘(即每个随机变量的分…