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

news/2024/10/31 5:30:05/

翻译自 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++ 入门

1.8 C++ 标准库

std命名空间包含了C++标准库中的所有符号。标准库是一个庞大的类型、函数和类的集合,是C++语言不可或缺的一部分。标准库还包含了一个广泛的通用容器和算法集合,称为标准模板库(STL)。在本书中,我们将大量使用C++标准库和它的STL部分。另见第5.8节和附录A.6-A.8。

LED程序使用C++标准库中的std::uint8_t,这是多种可用固定大小整数类型之一。熟悉C语言C99规范的读者可能有使用<stdint.h>的经验。这个C库文件定义了相同的固定大小整数类型,但位于全局命名空间中。使用C++的固定大小整数类型可以提高可移植性,因为不再需要手动定义和管理潜在非可移植的用户定义类型,如my_uint8、my_uint16等,并且不再需要使用难以阅读的预处理器开关进行管理。有关固定大小整数类型的更多细节,请参见第3.2节和第6.10节。

注:包含cstdint 头文件后可以,uint8_t 会直接定义在全局空间,前面没必要加上std::

注:在这段之前,原文定义了一个用来点灯的类LED,很简单,所以省略了

1.10 底层寄存器访问

使用C++进行微控制器编程需要低级寄存器访问。例如,led类的构造函数和toggle()函数都通过直接内存访问来操作寄存器,以控制LED硬件。有关寄存器操作的进一步讨论,请参见第7章。

特别地,led的成员函数toggle()负责切换LED。

void toggle() const
{// Toggle the LED.*reinterpret_cast<volatile bval_type*>(port)^= bval;
}

模板转换运算符reinterpret_cast是C++中四种专用转换运算符之一。请参见A.1节中对C++转换运算符的描述。reinterpret_cast运算符是专为将整数类型转换为指针并返回而设计的。熟悉C语言中底层寄存器访问的读者可以参考下面的等效代码示例:

// C++ 访问寄存器.
*reinterpret_cast<volatile bval_type*>(port) ^= bval;// 等效的C 代码.
*((volatile bval_type*) port) ^= bval

注:这段代码先把整数类型的寄存器地址port 转换成用来访问寄存器的指针类型,然后再解引用、异或赋值

强大的reinterpret_cast运算符应谨慎使用,因为在C++中,实际上很少需要手动转换指针类型,通常都有更不易错的程序技术选项可用。通过直接内存访问进行微控制器寄存器操作是少数几种需要强制进行整数到指针转换的情况之一。

如上所述,本主题在A.1节中有更详细的介绍。此外,第7章全部内容都涉及处理微控制器寄存器,特别是第7.2节和第7.3节,它们介绍并实现了通用的微控制器寄存器读/写操作抽象层。

1.11 编译时常量

在LED 程序中,寄存器地址使用constexpr 关键字定义为C++ 的广义常量表达式,如下:

namespace mcal
{// 用编译时常量表示寄存器地址.namespace reg{// portb 的地址.constexpr std::uint8_t portb = 0x25U;// 对应portb 中8 个位的掩码.constexpr std::uint8_t bval0 = 1U;constexpr std::uint8_t bval1 = 1U << 1U;constexpr std::uint8_t bval2 = 1U << 2U;constexpr std::uint8_t bval3 = 1U << 3U;constexpr std::uint8_t bval4 = 1U << 4U;constexpr std::uint8_t bval5 = 1U << 5U;constexpr std::uint8_t bval6 = 1U << 6U;constexpr std::uint8_t bval7 = 1U << 7U;}
}

用关键字constexpr表示的广义常量表达式保证是编译时常量。通常,使用constexpr被认为优于使用宏常量#define,因为constexpr 常量表达式具有明确定义的类型信息。有关constexpr和广义常量表达式的更多信息,请参见第3.8节,以及第7.1节中有关寄存器地址的更多细节。

确保整数值是编译时常量的另一种方法是使用类类型的静态常量成员,在第4.10节中将进一步讨论静态常量整数类成员。使用编译时常量几乎总是有助于优化C++。例如,如前面第1.5节所述,led_b5的构造函数代码等效于以下内容。

const led led_b5
{0x25, // Address of portb.0x20 // Bit-value of portb.5.
}

由于构造函数的参数是编译时常量,编译器可以直接初始化led_b5的成员变量,而不使用堆栈或中间CPU寄存器。这种高效的优化被称为常量折叠,在实时C++编程中经常很有用。第2.6节描述了通过将常量折叠与C++模板结合来进一步提高性能的方法。

注:用constexpr 定义常量的好处我说过几次了,但相比宏常量也不是没有缺点。宏常量可以直接用在条件编译中,比如#ifdef,而硬要用constexpr 常量实现类似效果会让代码变得非常晦涩


http://www.ppmy.cn/news/83064.html

相关文章

通过注册表显示和隐藏“我的电脑”、“回收站”等图标

注册表路径&#xff1a; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel 其中{208D2C60-3AEA-1069-A2D7-08002B30309D}是我的电脑&#xff0c;值的类型为REG_DWORD&#xff0c;改为0后隐藏&#xff0c;1代表显示。 其…

最小生成树

1:什么是最小生成树? 最小生成树是一个无向连通图的生成树&#xff0c;它的所有边的权值之和最小。也就是说&#xff0c;最小生成树是一棵权值最小的连通子图&#xff0c;其中包含了原图中的所有节点&#xff0c;但只保留了一部分边。最小生成树通常用于在一个图中寻找一个最…

Windows中的Tomcat服务器安装证书并设置强制https访问

官网参考 阿里云 华为云 获取证书 自己生成证书 这边介绍一个生产开发环境证书的方式&#xff1a;使用 Java 提供的工具&#xff1a;keytool keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "d:\tomcat.keystore" Tomcat服…

Springboot +spring security,登录用户数据获取

一.简介 前面章节学习了登录表单的配置并且对源码进行了简单的分析&#xff0c;现在有个问题了&#xff0c;既然用户登录了&#xff0c;那么如何在接口中获取用户信息呢。这篇文章就来看下这个问题&#xff0c;代码中获取登录用户信息。 二.创建项目 如何创建一个SpringSecu…

设计模式 (一) 入门

目录 设计模式系列文章主要包含 1.什么是设计模式&#xff1f; 2.设计模式的分类 2.1 创建型设计模式 2.2 结构型设计模式 2.3 行为型设计模式 设计模式系列文章主要包含 设计模式 (一) 入门 设计模式 (二) 创建型设计模式系列 设计模式 (三) 结构型设计模式系列 …

平台使用篇 | 批处理(bat)脚本使用教程(三)

导读 本讲针对RflySim平台的一些特点简要介绍了平台使用批处理技术的原因&#xff0c;并根据CopterSim中仿真功能区的参数设置阐述了批处理技术在平台中的具体运用。 平台使用篇 | 批处理(bat)脚本使用教程(三&#xff09; RflySim平台使用批处理技术的原因 ①调用多个软件Rf…

【DNDC模型】农田生态、陆地生态系统的动态模拟模型

DNDC模型 DNDC模型是一个用于模拟和追踪农业生态系统中碳氮生物地球化学循环的过程模型&#xff0c;可以用来模拟农业生态系统碳氮排放、农作物产量、土壤固碳作用以及硝酸盐淋失等过程。 模型由两部分组成&#xff1a;第一部分包括土壤气候、植物生长和有机质分解等3个子模型…

热门 API 大全分享(含天气、物流等)

最近收录了一些常用、免费的 API 接口&#xff0c;在这里记录分享给大家~ 天气预报查询&#xff1a;查询全国以及全球多个城市的天气&#xff0c;包含15天天气预报查询。空气质量查询&#xff1a; 查询国内3400个城市的整点观测&#xff0c;获取指定城市的整点观测空气质量。分…