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

news2024/9/28 17:28:29

全网最适合入门的面向对象编程教程: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 = 0
        self.sensorid    = id
        self.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 = 0
        self.sensorid    = id
        self.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 cmd

class 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()
            break
    print(" 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.coloradmin.cn/o/1909186.html

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

相关文章

Go语言---文本文件处理

字符串操作 Contains func Contains(s,substr string) bool功能:字符串s中是否包含 substr,返回bool值 Join func Join(a []string,sep string) string功能:字符串链接,把slice a通过sep链接起来 Index func Index(a ,sep s…

Pytest单元测试系列[v1.0.0][Pytest基础]

Pytest安装与配置 和Unittest一样,Pytest是另一个Python语言的单元测试框架,与Unittest相比它的测试用例更加容易编写、运行方式更加灵活、报错信息更加清晰、断言写法更简洁并且它可以运行有unittest和nose编写的测试用例。 Pytest 安装 启动命令行&…

VMware安装部署Android手机操作系统

VMware安装部署Android手机操作系统 原创 wangyangsheng 计算机科学与技术研究员 2024年07月09日 08:30 广东 本文主要描述在VMware中安装部署Android-x86版本手机操作系统。 www.android-x86.org 如上所示,从开源网站下载Android-x86最新版本操作系统安装文件 …

小阿轩yx-Haproxy搭建Web群集

小阿轩yx-Haproxy搭建Web群集 Haproxy 简介 提供高可用性 能做出标准的负载均衡 支持虚拟主机 具备健康检查能力 能用于各式各样的代理 轻量级代理环境 解决方案优势 免费 快速 可靠 特性 特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或…

几种不同的方式禁止IP访问网站(PHP、Nginx、Apache设置方法)

1、PHP禁止IP和IP段访问 <?//禁止某个IP$banned_ip array ("127.0.0.1",//"119.6.20.66","192.168.1.4");if ( in_array( getenv("REMOTE_ADDR"), $banned_ip ) ){die ("您的IP禁止访问&#xff01;");}//禁止某个IP段…

01-图像基础-颜色空间

1.RGB颜色空间 RGB是一种常用的颜色空间&#xff0c;比如一幅720P的图像&#xff0c;所对应的像素点个数是1280*720&#xff0c;每一个像素点由三个分量构成&#xff0c;分别是R,G,B。 R代表红色分量&#xff0c;G代表绿色分量&#xff0c;B代表蓝色分量&#xff0c;以24位色来…

一网统管/视频汇聚/安防监控平台EasyCVR启动后无法访问是什么原因?

智慧城市/一网统管/视频汇聚/安防监控平台EasyCVR兼容性强&#xff0c;支持多协议接入&#xff0c;包括国标GB/T 28181协议、GA/T 1400协议、部标JT808协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SDK等&#xff0c;并能对外分…

插件更新了!

最近花了点时间&#xff0c;给网页插件添加了新功能&#xff0c;下面简单给大家介绍一下如何使用 我们安装好插件后&#xff0c;进入网页就可以看到一个带logo的按钮了&#xff0c;我们可以点一下就可以跳出快捷操作 不同页面点击会出现不同的功能&#xff0c;大家可以根据自己…

解析java128陷阱

一、提要 在java开发时&#xff0c;由于基本类型不能调用方法&#xff0c;在某些方面很不方便&#xff0c;因此产生了包装类。我们把基本类型和对应的包装类的转换叫装箱、拆箱。 1.装箱 基本类型转成包装类对象 关键字valueOf->装箱,可以指定进制&#xff1a; Integer…

2024年【道路运输企业主要负责人】考试内容及道路运输企业主要负责人找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业主要负责人考试内容是安全生产模拟考试一点通生成的&#xff0c;道路运输企业主要负责人证模拟考试题库是根据道路运输企业主要负责人最新版教材汇编出道路运输企业主要负责人仿真模拟考试。2024年【道路…

俯卧撑计数器(Python)

通过 MediaPipe 检测人体姿态&#xff0c;计算俯卧撑角度和计数&#xff0c;并在图像上进行可视化展示 需要有cv2库和mediapipe库 mediapipe库&#xff1a; MediaPipe是Google开源的机器学习框架&#xff0c;用于构建实时音频、视频和多媒体处理应用程序。它提供了一组预训练的…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 7月9日,星期二

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年7月9日 星期二 农历六月初四 1、 最高检&#xff1a;对小摊小贩、小微企业处以高额罚款不符合法律精神。 2、 公安部&#xff1a;全国机动车保有量达4.4亿辆&#xff0c;驾驶人达5.32亿人。 3、 科技部&#xff1a;严禁将…

Echarts:渲染成Canvas还是SVG,该如何抉择?

ECharts 从初始一直使用 Canvas 绘制图表。而 ECharts v4.0 发布了 SVG 渲染器&#xff0c;从而提供了一种新的选择。在初始化图表实例时&#xff0c;只需设置 renderer 参数 为 canvas 或 svg 即可指定渲染器&#xff0c;比较方便。贝格前端工场带领大家看下如何选择。 一、C…

2024年【低压电工】最新解析及低压电工复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 低压电工最新解析根据新低压电工考试大纲要求&#xff0c;安全生产模拟考试一点通将低压电工模拟考试试题进行汇编&#xff0c;组成一套低压电工全真模拟考试试题&#xff0c;学员可通过低压电工复审考试全真模拟&…

为什么要学习Go?

目录 前言 一、Go 语言的发展史 Robert Griesemer Rob Pike Ken Thompson 二、Go语言全面分析 主要优势 主要挑战 三、Go 语言最佳实践 1. 云原生开发 2. 网络服务开发 3. 系统工具和实用程序 4. 数据处理和分析 四、哪些知名公司使用 Go 语言&#xff1f; Google …

16 - Python语言进阶

Python语言进阶 数据结构和算法 算法&#xff1a;解决问题的方法和步骤 评价算法的好坏&#xff1a;渐近时间复杂度和渐近空间复杂度。 渐近时间复杂度的大O标记&#xff1a; - 常量时间复杂度 - 布隆过滤器 / 哈希存储 - 对数时间复杂度 - 折半查找&#xff08;二分查找&am…

重点区域分布式无人机探测防御系统详解

重点区域分布式无人机探测防御系统采用模块化设计&#xff0c;结合先进的传感技术、通信技术和数据处理技术&#xff0c;实现对无人机的高效探测与防御。系统架构由无人机探测模块、数据分析中心、防御与反制模块以及用户交互界面四大部分组成。系统特点包括分布式部署、高灵敏…

在audio DSP中如何做软件固化

在audio DSP中&#xff0c; 软件的code和data主要放在3种不同的memory上&#xff0c;分别是片内的ITCM、DTCM和片外的memory&#xff08;比如DDR&#xff09;上。ITCM只能放code&#xff0c;DTCM只能放data&#xff0c;片外的memory既能放code也能放data。在写代码时要规划好哪…

【Java开发实训】day01

目录 1.Java开发步骤 2.目录的三个表达方法 3.Java的三种注释方法 4.文档注释的作用 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&…

UML中用例之间的可视化表示

用例除了与参与者有关联关系外&#xff0c;用例之间也存在着一定的关系&#xff0c;如泛化关系、包含关系、扩展关系等。 4.2.1 包含关系 包含关系指的是两个用例之间的关系&#xff0c;其中一个用例&#xff08;称为基本用例&#xff0c;Base Use Case&#xff09;的行为包…