Real-Time C++ 嵌入式C++ 程序设计(二)

news2025/2/25 13:44:13

翻译自 Real-Time C++ Efficient Object-Oriented and Template Microcontroller Programming 4th Edition - Kormanyos, Christopher,这书涉及了从C++11 到C++20 的内容,主要介绍使用C++ 的模板、面向对象等特性设计嵌入式程序。书里的示例代码都是公开的:https://github.com/ckormanyos/real-time-cpp


二、在硬件上实践实时C++ 程序

本章介绍了构建、刷写和执行微控制器C++程序的完整示例。LED程序将在MinGW/MSYS 环境中使用GCC交叉工具构建。我们的目标微控制器是8位Microchip® AVR®微控制器。这种流行的微控制器具有最先进的质量和广泛的可用性。此外,这种微控制器有一个维护良好的GCC端口,使其非常适合我们的示例。在本章的后半部分,我们将根据LED程序的示例研究效率方面以及编译器警告和错误。

注:基本就是用经典的Arduino 8位单片机平台,比如UNO 和NANO 上的ATMega328P。我默认看这个的都知道Arduino 程序基本上要怎么整,所以原文中程序编译之类的琐碎内容大部分省略

2.1 目标硬件

我们的目标硬件如图2.1所示。它是一个手工在面包板上构建的单片微控制器电路。这块板子使用了一颗8位Microchip® AVR®微控制器(ATmega328p),具有32 kB的程序代码、2 kB的RAM和1 kB的EEPROM。微控制器使用外部石英晶体产生16 MHz的时钟频率。我们的目标硬件电路的原理图和在板上用分立元件构建它的细节在附录D中给出。

我们的目标硬件使用与著名且多功能的ARDUINO®开源项目,相同的微控制器和LED端口引脚(pin13,SCK)。此外,本章的练习还可以选择使用ARDUINO®或ARDUINO®兼容板。但是,请注意,我们的目标硬件并不完全兼容ARDUINO®,因为它缺少用于通信的串行UART接口电路。

图2.1

注:这就是把一片328P 芯片插在面包板上,手工整了一圈外围电路,做成了最小系统板,很难理解为什么不直接用Arduino。面包板上还有个编号,估计是哪个学校里的教具

2.3 在LED 程序中添加时序控制

如上所述,LED程序切换LED的速度太快,无法观察。因此,我们将在另一个版本的LED程序中使用计时来减慢切换速度。这个版本的程序包含在配套代码的chapter02_03项目中,部分列在下面:

// The LED program with timing.
#include <cstdint>
#include <util/utility/util_time.h>
#include <mcal/mcal.h>

class led
{
	// ...
};

namespace
{
	// Define a convenient local 16-bit timer type.
	typedef util::timer<std::uint16_t> timer_type;
	// Create led_b5 at port B, bit-position 5. 
	// 这里只是用C++11 新增的花括号语法调用了led 类的构造函数,把LED 引脚设置为PB5
	const led led_b5{mcal::reg::portb, mcal::reg::bval5};
}

int main()
{
	// 使能总中断.
	mcal::irq::enable_all();
	// 这个mcal 就是作者自己造的轮子,mcal 是作者名字的缩写。详细的可以去看原文,或者github 上的配套代码.
	mcal::init();
	// 每隔一秒切换一次LED 的状态
	for(;;)
	{
		led_b5.toggle();
		// 阻塞延时1 秒.
		timer_type::blocking_delay(timer_type::seconds(1));
	}
}

主要的改变就是在切换一次LED 后添加了一秒的延时,这将LED切换频率降低到1/2 Hz,使人眼可以观察到切换。为了实现计时,我们包含了更多的软件组件。特别地,我们包含了一个计时器实用程序头文件util_time.h,并使用typedef 定义了timer_type,用于简化代码。参见第6.9节和第15.3节。我们还初始化了一个mcal,以便创建系统时钟(system tick),如第9.3节所述。

如上所述,chapter02_03项目中的LED切换频率来自1秒的阻塞延迟。然而,使用阻塞延迟可能被认为是不良风格。多任务方法(第11章)可能会产生更优秀的实现。为了举例说明这一点,在第2.3节中创建了一个名为chapter02_03a的附加项目,并包含在配套代码中。示例chapter02_03a还使用本书后面的材料来实现一个微型多任务调度器,它管理一个LED应用任务。LED应用任务使用1秒定时器来生成LED切换频率。

2.6 实现该有的效率

C++是一种丰富的语言,具有强大的功能,可以对实现细节进行广泛控制。因此,为了有效地用C++编程微控制器,开发人员需要做出深思熟虑和明智的设计选择。

例如,在考虑第1章LED程序中的led类时,一位经验丰富的微控制器程序员可能会想:仅仅为了切换一个LED,那个类有很多额外开销!这可能是一个不好的设计选择。

在这种特殊情况下,这个敏锐的观察是正确的。实际上,仅仅led成员变量的存储需求就至少需要两个字节,甚至可能是四个字节或八个字节——这取决于CPU架构和编译器的内存对齐特性。再加上潜在的非内联调用toggle() 函数的开销,相比其功能,led类可能过于庞大。C++模板可以用来解决这个问题。C++ 模板是一个可以具有不同类型参数的函数或类。有关C++模板的更多信息,请参见第5章。

现在我们将把led类转换为模板类:

// 这个模板类接受两个整数port 和bval 作为参数,用来在toggle 函数中操作对应引脚,
// 前面两个port_type 和bval_type 是用来适应不同的整数类型,但实际没必要,特定环境下描述寄存器地址的整数类型是确定的,而且可以自动获取
// 用模板输入整数就省的给类里存储成员变量了,全变成“写死的”
template<typename port_type, typename bval_type, port_type port, bval_type bval>
class led_template
{
	public:
	led_template()
	{
		// Set the port pin value to low.
		*reinterpret_cast<volatile bval_type*>(port) &= static_cast<bval_type>(~bval);
		// 
		*reinterpret_cast<volatile bval_type*>(pdir) |= bval;
	}
	static void toggle()
	{
		// Toggle the LED.
		*reinterpret_cast<volatile bval_type*>(port)
		^= bval;
	}
	
	private:
	// 这里加一个static 是不必要的,这个常量用来访问控制引脚输入/输出模式的寄存器
	static constexpr port_type pdir = port - 1U;
};

在这个版本的类中,原始led 类中的类型和成员变量已被模板参数替换。这种非凡的方法极大地提高了效率,因为模板参数及其对应的代码是编译时已知的实体。模板可以通过提供可扩展性来提高效率并减少潜在的冗余代码。从这个意义上说,模板提供了高性能和强大的通用性。我们将在第5章中更深入地讨论模板编程。

模板类的使用方法如下:


// 把led 操作绑定到PB5
const led_template<std::uint8_t, std::uint8_t, mcal::reg::portb, mcal::reg::bval5> led_b5;

int main()
{
	// Toggle led_b5 forever.
	for(;;)
	{
		led_b5.toggle();
	}
}

在这个版本的main()中,led_b5的模板实例与前面第1.1节中使用的非模板实例完全相同。我们看到,模板类也可以用来封装对象。熟悉模板的语法并找到在代码中写出风格上令人愉悦的方法可能需要一些试错。这些问题是风格问题,可以通过一些练习轻松解决。

这个版本的LED程序可在第2章的配套代码中获得。现在我们将比较模板版本的LED程序与非模板版本的效率和资源消耗。led_template类的存储需求已经减少,因为成员变量port 和bval 已被替换为编译时常量的模板参数。这些模板参数可以通过常量折叠在编译时消除。此外,toggle()函数已被设为静态。这可能减少toggle() 的调用开销。

注:调用toggle 的开销减少的原因主要是常量折叠,toggle 函数内不需要再去访问成员变量,省去了几次访存的时间,给成员函数加个static 大部分时候毫无卵用。倒让我想起Java 了,因为Java 的函数只能放在类里面,于是Java 佬不得不把一些跟谁都不挨着的函数标成静态随便塞进一个类里,美其名曰“工具类”

注:原文的模板代码中,作者给整数参数前还加了个const,一个整数作为模板参数还能不const 呗?我复制过来去掉了。呃,我开始怀疑这作者的水平了,这书没中文翻译可能就是因为水平不行

如表2.1所示,模板版本的程序比非模板版本更小更快。这有点令人惊讶,但并不罕见,即基于模板的设计减少了内存消耗,同时提高了性能。

选择一个模板或非模板LED类是微控制器C++编程中典型设计选择的一个例子。虽然这只是无限多个潜在设计选择中的一个小例子,但它确实显示了关于设计和实现的决策如何关键地影响效率。

main 函数代码大小 / 字节led类的RAM 占用 / 字节单次循环运行时间 /us
非模板类3620.44
模板类1600.31

注:到目前为止,这作者还没讲出来什么比较有用的东西

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

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

相关文章

【OpenCV DNN】Flask 视频监控目标检测教程 03

欢迎关注『OpenCV DNN Youcans』系列&#xff0c;持续更新中 【OpenCV DNN】Flask 视频监控目标检测教程 03 3.3 上传本地图片进行人脸检测3.3.1 OpenCV 级联分类器类 cv::CascadeClassifier3.3.2 cvFlask03 项目的构建步骤 本系列从零开始&#xff0c;详细讲解使用 Flask 框架…

Unity3D :运行时 UI 的性能注意事项

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 运行时 UI 的性能注意事项 本页介绍如何提高运行时的性能用户界面 . 优化数据存储 您可以使用 usageHints 来设置元素在运行时的使用方式&#xff0c;以便相应地优化数据存储。例…

三、CNNs网络架构-跨层连接思想的网络架构

《A review of convolutional neural network architectures and their optimizations》论文指出随着网络架构的深入&#xff0c;梯度消失、爆炸或退化问题变得越来越严重。跨层连接的思想是解决现有问题的有效方案&#xff0c;允许网络在非相邻层之间传递信息。因此&#xff0…

如何利用Python中的pymysql库来操作Mysql数据库,看这篇就够啦~

为了使python连接上数据库&#xff0c;你需要一个驱动&#xff0c;这个驱动是用于与数据库交互的库&#xff0c;本文是向大家介绍了如何利用python中的pymysql库来操作mysql数据库。 1、什么是pymysql&#xff1f; pymysql是从python连接到mysql数据库服务器的接口&#xff0c…

上门服务小程序|东邻到家系统|上门服务系统包含哪些功能?

使用东郊到家小程序&#xff0c;只需要一键预约即可在工作之余、休息娱乐的时候&#xff0c;点一个理按疗摩技师&#xff0c;做一个SPA&#xff0c;缓解工作压力&#xff0c;不失为一种享受&#xff0c;并且上门服务小程序可以为技师或从业岗位人员提供就业服务&#xff0c;线上…

抖音seo优化源代码搭建+抖音小程序私有化开源部署

抖音seo优化源码&#xff0c;抖音seo矩阵系统搭建&#xff0c;抖音账号矩阵系统开发&#xff0c;企业在做账号矩阵过程中&#xff0c;最头疼的莫过于私域线索转化&#xff0c;作为开发者都知道&#xff0c;目前市面上我们了解的矩阵系统除了挂载POI信息外&#xff0c;无法挂载留…

一篇关于 ApiKit 的简单介绍

简介 本文介绍 ApiKit 工具&#xff0c;它是 API 文档、API 调试、API Mock、API 自动化测试一体化协作平台。 一、常用解决方案 使用 Swagger 管理 API 文档 使用 Postman 调试 API 使用 mockjs 等工具 Mock API 数据 使用 JMeter 做 API 自动化测试 二、存在的问题 维护…

ffmpeg学习日记122-视频-获取视频的解码器,yuv格式名称,理解编码格式,封装格式,yuv格式的关系

Author: wencoo Blog&#xff1a;https://wencoo.blog.csdn.net/ Date: 25/05/2023 Email: jianwen056aliyun.com Wechat&#xff1a;wencoo824 QQ&#xff1a;1419440391 Details:文章目录 正文 或 背景获取像素格式&#xff0c;也就是yuv排列格式获取解码器id获取输出文件的封…

景区上线智慧客流人数采集分析系统的根本原因

智慧客流量采集系统是一种高效、智能的客流量采集解决方案&#xff0c;可以实现客流量的实时监控、数据分析和预测&#xff0c;提高服务质量、降低管理成本、提高安全性等优势。该系统适用于各种场所&#xff0c;如景区、商场、服务区、机场等。 AI客流视觉监控 一、智慧客流量…

安科瑞电力监控系统和五防系统在锡林郭勒项目的应用

摘要&#xff1a;随着电力、计算机、信息和网络等技术的不断发展&#xff0c;推动了电力监控的快速发展&#xff0c;人们对电力系统运行的安全性以及稳定性的要求越来越高。本文针对锡林郭勒供配电系统特点及供配电系统高可靠性的要求&#xff0c;提出了保护类、监测类和防误闭…

ASEMI代理长电MCR100-6可控硅的性能与应用分析

编辑-Z 本文主要介绍了新型MCR100-6晶闸管的性能与应用。首先&#xff0c;从晶闸管的基本原理和结构出发&#xff0c;分析了MCR100-6晶闸管的性能特点&#xff1b;其次&#xff0c;探讨了MCR100-6晶闸管在各种电子电路中的应用&#xff1b;最后&#xff0c;对MCR100-6晶闸管的…

档案馆建设标准条文说明

第一章 总则 第一条 本条阐明了本标准的编制目的。 中国是一个历史悠久的文明古国&#xff0c;档案事业的发展源远流长。档案是人类活动的真实记录&#xff0c;是人们认识和把握客观规律的重要依据。借助档案&#xff0c;我们能够更好地了解过去、把握现在、预见未来。档案工…

工业机器视觉缺陷检测工作小结

工业机器视觉检测工作小结 &#xff08;因为网上没有很系统的讲义和文档&#xff0c;都是零零散散的&#xff0c;因此&#xff0c;我自己尝试着总结一下、仅供参考&#xff09; 你想知道的大概率在这都可以找到、相机的了解镜头的了解光源的了解传统算法DL深度学习方法 &#…

基于微信小程序渗透-反编译小程序

文章目录 一、概述二、使用电脑版微信获取小程序源码三、使用工具解密源码四、配置nodejs环境五、使用工具解包 一、概述 微信小程序渗透时&#xff0c;因为小程序没有网页端页面&#xff0c;所以不能直接访问抓包分析&#xff0c;如果需要抓包分析&#xff0c;那么一般就是用…

Spring:用 Spring 整合 MyBatis(Spring-MyBatis)代码整理

文章目录 Spring&#xff1a;Day 05Spring - MyBatis1. 依赖&#xff1a;pom.xml2. 外部配置文件&#xff1a;db.properties3. MyBatis 核心配置文件&#xff1a;mybatis-config.xml4. 实体类5. 接口&#xff1a;xxxMapper.java6. 实现类&#xff1a;xxxMapper.xml7. Spring 通…

ATA-4014高压功率放大器驱动超声马达测试应用

ATA-4014 高压功率放大器简介 ATA-4014是一款理想的可放大交、直流信号的单通道高压功率放大器。最大输出160Vp-p&#xff08;80Vp&#xff09;电压&#xff0c;452Wp功率&#xff0c;可以驱动高压功率型负载。电压增益数控可调&#xff0c;一键保存常用设置&#xff0c;为您提…

利用 PRIMO 重构 M87 黑洞图像,普林斯顿高等研究院成功将「甜甜圈」变身「金戒指」

内容一览&#xff1a;2019 年&#xff0c;「事件视界望远镜 (Event Horizon Telescope&#xff0c;简称 EHT)」全球研究团队发布了人类历史上第一张黑洞照片&#xff0c;受限于当时的观测条件&#xff0c;这张黑洞图像只呈现出一个模糊不清的轮廓。近日&#xff0c;天体物理学期…

打家劫舍 III——力扣337

文章目录 题目描述法一&#xff1a;动态规划 题目描述 法一&#xff1a;动态规划 问题简化&#xff1a;一棵二叉树&#xff0c;树上的每个点都有对应的权值&#xff0c;每个点有两种状态&#xff08;选中和不选中&#xff09;&#xff0c;问在不能同时选中有父子关系的点的情况…

Kafka题集 - kafka术语面试题总结

文章目录 01. 什么是 Kafka&#xff1f;02. 为什么要用kafka&#xff1f;03. Kafka 消息引擎模型04. kafka 消费方式&#xff1f;05. Kafka 传输消息的编码格式&#xff1f;06. kafka 体系架构&#xff1f;07. kafka 消息和批次&#xff1f;08. kafka 主题和分区&#xff1f;09…

Weex中,关于组件的水平排列竖直排列居中对齐居左对齐居右对齐低部对齐顶部对齐布局对齐说明

容器内子组件排列方向 子组件竖直方向排列&#xff08;默认&#xff09; 子组件水平方向排列 <style> .container {flex-direction: row;direction: ltr; } </style>子组件在父组件容器中的对齐方式 我们主要使用两个属性实现子组件在父组件的对齐方式&#xff…