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

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

摘要:

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

原文链接:

FreakStudio 的博客

往期推荐:

可能是全网最适合入门的面向对象编程教程:Python实现-嵌入式爱好者必看!

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

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

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

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

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

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

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

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

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

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

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

更多精彩内容可看:

CM3调试系统简析

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

比赛获奖的武林秘籍:04 电子类比赛嵌入式开发快速必看的上手指南

比赛获奖的武林秘籍:03 好的创意选取-获得国奖的最必要前提

比赛获奖的武林秘籍:02 国奖秘籍-大学生电子计算机类竞赛快速上手的流程,小白必看

比赛获奖的武林秘籍:01 如何看待当代大学生竞赛中“卷”“祖传老项目”“找关系”的现象?

比赛获奖的武林秘籍:00 学科竞赛-工科类大学生绕不开的话题,你了解多少?

电子计算机类比赛的“武林秘籍”-电赛光电设计大赛计算机设计大赛嵌入式芯片与系统设计竞赛,你要的都在这里!

文档和代码获取:

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

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

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

在这里插入图片描述

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

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

相关文章

OpenHarmony 入门——单元测试UnitTest快速入门

引言 OpenHarmony 的单元测试(UnitTest)是一个关键的软件开发过程,它确保代码的各个部分能够按预期工作,OpenHarmony的测试框架中提供了很多种的单元测试,今天简单介绍下UnitTest 类型的TDD测试。 OpenHarmony 的TDD …

Nacos 国际化

项目需要,后端异常信息需要进行国际化处理。所有想有没有方便易用的可选项。 1、国际化配置调整,不需要重启系统 2、可支持添加不同或自定义语言包(就是配置的资源文件) 参考: Nacos实现SpringBoot国际化的增强_spr…

Android IP地址、子网掩码、默认网关、首选DNS服务器、备用DNS服务器校验

Android IP地址、子网掩码、默认网关、首选DNS服务器、备用DNS服务器校验 public String isIP(String ip) {String regex = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)){3}";Pattern p = Pattern.compile(regex)

LeetCode热题100刷题9:25. K 个一组翻转链表、101. 对称二叉树、543. 二叉树的直径、102. 二叉树的层序遍历

25. K 个一组翻转链表 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), nex…

uni-app + vue3项目引入unocss

使用方法:unocss 版本最好使用0.58,版本太高的话不兼容引入时会报错 在class中使用,如:class"w-full"

华为机考前准备工作

很多同学在刷完真题后,就直接去考试了,会发现不是卡在了题目的难度上,而是卡在了代码数据的如何输入上。为了避免各位有志之士忽略小细节而导致的前功尽弃,博主特意总结了华为机考试题数据输入的几种情况及其源代码,仅…

go语言day12 包 init() time包 file包

包 包中的 结构体 及结构体属性 方法 都可以通过设置首字母大小写来实现权限访问,首字母大写任何包中都可以访问,首字母小写只在同包中可以访问。 再导入包go文件时,可以给.go文件取别名。 在导入的包名前加入 _ 意思是调用该包的初始…

普中51单片机:矩阵按键扫描与应用详解(五)

文章目录 引言电路图开发板IO连接矩阵键盘的工作原理行列扫描逐行/逐列扫描 LCD1602代码库代码演示——暴力扫描代码演示——数码管(行列式)代码演示——线翻转法代码演示——LCD1602密码锁 引言 矩阵按键是一种通过行列交叉连接的按键阵列,可以有效地减少单片机I/…

AI学习指南机器学习篇-K均值聚类模型应用与Python实践

AI学习指南机器学习篇-K均值聚类模型应用与Python实践 1. 介绍 在机器学习领域,聚类算法是一种常用的无监督学习方法,其中K均值聚类是其中一种经典算法。K均值聚类算法通过将样本分配到K个不同的簇中,使得簇内的样本相似度最大,…

计算机网络 - 万字长文

计算机网络 二、计算机网络2.1 七层模型表格2.2 通俗讲解七层模型2.3 TCP与UDP对比2.4 TCP 三次握手过程==为什么握手是三次,而不是两次或者四次?====三次握手可以携带数据吗?====TCP三次握手失败,服务端会如何处理?====什么是半连接队列?全连接====ISN(Initial Sequence…

基于单片机的太阳能热水器控制系统设计

随着我国经济水平的不断提高,民众对生活质量的追求也在不断进步,对于现代家庭而言,热水器成为了必备的生活电器。目前市面上的电器主要是电热水器、燃气热水器以及太阳能热水器。就能源节约性能而言,太阳能热水器占据了绝对优势&a…

Java | Leetcode Java题解之第223题矩形面积

题目: 题解: class Solution {public int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) {int area1 (ax2 - ax1) * (ay2 - ay1), area2 (bx2 - bx1) * (by2 - by1);int overlapWidth Math.min(ax2, bx2) -…

C语言8 数组与字符串

目录 一、数组 定义和初始化 访问数组元素 多维数组 定义和初始化二维数组 访问二维数组元素 多维数组的更多示例 三维数组 访问三维数组元素 二、字符串 定义和初始化字符串 访问字符串元素 字符串操作 计算字符串长度 字符串复制 字符串连接 字符串比较 字…

开源高效在线电子表格解决方案:Luckysheet

Luckysheet:体验幸运,掌握高效数据表格编辑!- 精选真开源,释放新价值。 概览 Luckysheet 是一个功能强大、配置简单且完全开源的在线电子表格工具,它类似于我们熟知的 Excel,但更加灵活和易于集成。它是一…

windows环境下部署多个端口Tomcat服务和开机自启动设置保姆级教程

前言 本文主要介绍了 windows环境下,配置多个Tomcat设置不同端口启动服务。其实在思路上Linux上也是适用的,只是 Linux 上没有可视化客户端,会麻烦些,但总体的思路上是一样的。 注:文章中涉及些文字和图片是搬运了其他…

如何调整Oracle SGA的大小

调整Oracle SGA(System Global Area,系统全局区)的大小可以通过两种主要方式实现:手动设置和自动管理。以下将详细介绍这两种方法: 一、手动设置SGA大小 确定SGA各组件的大小 SGA由多个组件组成,包括数据…

企业如何利用短视频平台做口碑塑造和品牌营销?

随着短视频平台的不断发展,新型的双微一抖小红书等新媒体平台,正在成为网民聚集的核心平台,小马识途营销顾问认为越来越多的企业应该利用这些平台进行品牌营销和宣传。其中,抖音和小红书作为短视频平台的代表,吸引了大…

麒麟系统部署BS架构的系统

一、安装jdk 自带的即可,不必另外安装 二、安装MySQL 麒麟系统安装MySQL 三、安装Redis 麒麟系统安装Redis 四、安装Nginx 麒麟系统安装Nginx 五、数据库初始化 1、登录MySQL mysql -uroot -p 2、创建数据库 create database dbname; createt database…

OpenGL3.3_C++_Windows(28)

Demo演示 demo 视差贴图 视差/高度/位移贴图(黑--白):和法线贴图一样视差贴图能够极大提升表面细节,使之具有深度感。第一种思路(置换顶点):对于一个quad ,分成约1000个顶点&#x…

【ARMv8/v9 GIC- 700 系列 1 -- Programmers model for GIC-700】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 GIC-700 Programmers model寄存器实现和访问模式接口宽度和数据格式访问类型安全寄存器访问地址映射和页面GIC-700 Register map pagesSummaryGIC-700 Programmers model GIC-700是ARM的一种通用中断控制器,它遵循GICv3和GICv4架构…