自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(39)
  • 收藏
  • 关注

原创 C++基类和派生类的类型转换

一、类型转换 公有派生类对象可以被当作基类的对象使用,反之则不可。派生类的对象可以隐含转换为基类对象;派生类的对象可以初始化基类的引用;派生类的指针可以隐含转换为基类指针。 通过基类对象名、指针只能使用从基类继承的成员。二、类型转换举例#include <iostream>using namespace std;// 定义类Aclass A{private: int m_a;public: cout << "A::func()" <<

2021-02-05 16:29:53 454

原创 C++继承和派生

一、继承与派生概述继承和派生是同一过程从不同角度看保持已有类的特性而构造新类的过程称为继承。在已有类的基础上新增自己的特性而产生新类的过程称为派生。被继承的已有类称为基类(或父类)。派生出的新类称为派生类(或子类)。直接参与派生出某类的基类称为直接基类。基类的基类甚至更高层的基类称为间接基类。继承的目的:实现设计和代码的重用。派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造。二、单继承时派生类的定义语法:class 派生类名:继承方式

2021-02-04 22:29:10 192

原创 C++ string类

一、string类常用的构造函数string(); // 默认构造函数,建立一个长度为0的串。 string s1;string(const char *s); // 用指针s所指向的字符串常量初始化string对象。 string s2 = "abc";string(const string& rhs); // 复制构造函数。 string s3 = s2;二、string类常用操作s + t 将串s和t连接成一个新串s = t 用t更新ss == t 判断s与

2021-02-04 10:32:56 143

原创 C++深拷贝与浅拷贝(深层复制与浅层复制)

一、浅层复制实现对象间数据元素的一一对应复制。pointsArray1:对象points_size:指针数据成员,指向new出来的动态空间pointArray2:用pointsArray1初始化的对象,发生一次复制构造(浅层复制)当pointArray1析构delete之后,pointArray2析构的时候会发生错误。因为对同一块空间进行了两次delete二、深层复制当被复制的对象数据成员是指针类型时,不是复制该指针成员本身,而是将指针所指对象进行复制。在利用pointsArray1对象对

2021-02-03 20:10:05 1307

原创 C++ vector对象

一、为什么需要vector?封装任何类型的动态数组,自动创建和删除。数组下标越界检查。二、vector对象的定义vector<元素类型> 数组对象名(数组长度)vector<int> arr(5) // 建立大小为5的int数组三、vector对象的使用 对数组元素的引用与普通数组具有相同形式:vector对象名[下表表达式]vector数组对象名不表示数组首地址 获得数组长度用size长度vector对象名.size()四、基于范围的for循

2021-02-03 19:38:31 129

原创 C++共享数据的保护

一、常类型常对象:必须进行初始化,不能被更新。const 类名 对象名;常成员:用const进行修饰的类成员——常数据成员和常函数成员。const 类型说明符 &引用名;常数组:数组元素不能被更新类型说明符 const 数组名[大小]常指针:指向常量的指针。二、常对象用const修饰的对象。例:class A{public: A(int i, intj) { x = i; y = j; }private: int x, y;};A const

2021-02-03 13:57:48 74

原创 C++友元

一、类的友元友元是C++提供的一种破坏数据封装和数据隐藏的机制。(效率和隐藏之间做平衡)通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。可以声明友元 函数和友元类。为了确保数据的完整性,及数据封装与隐藏的原则,建议慎用友元。二、友元函数友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象访问private和protected成员。作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。访问对象中的成员必须通过

2021-02-03 11:27:44 302 4

原创 C++结构体、联合体、枚举类

结构体是一种特殊形态的类。与类唯一的区别: 类的缺省访问权限是private,结构体的缺省访问权限是public结构体中可以有数据成员和函数成员结构体的初始化如果:一个结构体的全部数据成员都是公共成员;没有用户定义的构造函数;没有基类和虚函数这个结构体的变量可以用下面的语法形式初始化:类型名 变量名 = {成员数据1初值, 成员数据2初值,......};...

2021-02-02 22:04:17 138

原创 C++类的组合

一、类组合的构造函数设计原则:不仅要负责对本类中的基本类型成员数据初始化,也要对对象成员初始化。声明形式:类名::类名(对象成员所需的形参,本类成员形参): 对象1(参数),对象2(参数),......{ //函数体其他语句}二、构造组合类对象时的初始化次序首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)进行初始化,初始化次序是成员在类体中定义的次序。 成员对象构造函数调用顺序:按对象成员的定义顺序,先声明者先构造。 初始化列表中未出现的成员对象,调用默认构造

2021-02-02 21:58:02 184

原创 C++析构函数

一、析构函数语法析构函数的原型 ~类名();析构函数没有参数,没有返回类型二、析构函数完成对象被删除前的一些清理工作。三、在对象的生存期结束的时刻系统自动调用析构函数。四、如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数,其函数体为空。...

2021-02-02 21:34:46 205

原创 C++复制构造函数(拷贝构造函数)

一、复制构造函数定义复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。作用是用一个已知的对象去初始化同类型的新对象。class 类名{public: 类型(形参);//构造函数 类名(const 类名 &对象名);//复制构造函数//...};类名::类(const 类名 &对象名)//复制构造函数的实现{ 函数体 }二、复制构造函数被调用的三种情况定义一个对象时,以本类另一个对象作为初始值,发生复制构造;如果函数的形参是类的对象,调用函数时,将使用

2021-02-02 21:25:43 1831 2

原创 C++委托构造函数

委托构造函数使用类的其他构造函数执行初始化过程。对于同一个类中构造函数的重载,有些时候可以调用另一个已实现的构造函数来简化代码,调用其他构造函数来实现的构造函数就叫做委托构造函数。例:Clock类的两个构造函数:Clock(int newH, int newM, int newS): hour(newH), minute(newH), second(newS){ //构造函数}Clock():hour(0), minute(0), second(0){} //默认构造函数上面的默认构造函

2021-01-31 20:12:58 154

原创 C++构造函数

问题:当我们定义对象的时候,如何初始化(对对象成员进行赋值)?类是我们自定义的类型,按照什么规则进行初始化,编译器是不知道的,这件事需要我们自己编写构造函数描述初始化的算法。一、构造函数的作用在对象被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态。例如:希望在构造一个Clock类对象时,将初始时间设置为0:0:0,就可以通过构造函数来设置。二、构造函数的形式函数名与类名相同不能定义返回值类型,也不能有return语句可以有形式参数,也可以没有形式参数可以是内联函数可以

2021-01-31 18:59:13 102

原创 C++类和对象的定义

设计 类 就是 设计 类型此类型的“合法值”是什么?此类型应该有什么样的函数和操作符?新类型的对象该如何被创建和销毁?如何进行对象的初始化和赋值?对象作为函数的参数如何以值传递?谁将使用此类型的对象成员?一、类定义的语法形式class 类名称{public: 公有成员(外部接口)private: 私有成员protected: 保护型成员};设置类内初始值,如果构造函数没有初始化,则会采用内类初始值:class Clock{public: void showTi

2021-01-31 18:31:43 374

原创 C++面向对象程序的基本特点

一、抽象对同一类对象的共同属性和行为进行概括,形成类。首先注意问题的本质和描述,其次是实现的过程和细节。数据抽象:描述某类对象的属性和状态(对象相互区别的物理量)。代码抽象:描述某类对象的共有的行为特征或具有的功能。抽象的实现:类二、封装将抽象出的数据、代码封装在一起,将他们视为一个整体。目的:增强安全性和简化编程,使用者不必了解具体的实现细节,二只需要通过外部接口,以特定的访问权限,来使用类的成员。实现封装:类声明中的 { }三、继承在已有类的基础上,进行扩展形成新的类。四

2021-01-31 14:13:06 134

原创 C++函数重载

函数重载是由静态多态机制实现的,也就是说这种多态性是在编译阶段实现的。例:int abs(int x){ return x < 0 ? -x : x;}double abs(double x){ return x < 0 ? -x : x;}这两个求绝对值的函数,函数名相同,在C语言中编译器会报语法错误,但是C++允许功能相近的函数在相同的作用域内以相同的函数名声明,从而形成重载。方便使用,便于记忆。编译器区分重载函数的因素:重载函数的形参必须不同。形参类型不同:

2021-01-31 13:51:53 315

原创 C++带默认参数值的函数

一、可以预先设置默认的参数值,调用时如果给出实参,则采用实参值,否则使用预先设置的默认参数值。int add(int x = 5, int y = 6){ return x + y;}int main(){ add(10, 20); // 10+20 add(10); // 10+6 add(); // 5+6}二、默认参数值的说明次序有默认参数的形参必须列在形参列表的最右,即默认参数值的右面不能无默认值的参数;调用是实参与形参的结合次序是从左向右。例:int add(i

2021-01-31 13:33:40 249

原创 C++引用类型

一、引用类型引用(&)是标识符的别名定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象例如:int i, j;int &ri = i; // 定义int引用ri,并初始化为变量i的引用j = 10;ri = j; // 相当于i = j一旦一个引用被初始化后,就不能改为指向其他对象引用可以作为形参(函数形实结合的时候引用才被定义,同时被初始化)二、引用的本质引用的本质是一个指针常量。首先引用是一个常量,所以必须在定义的时候被初始化。编译器内部处理

2021-01-31 13:06:26 1117

原创 modbus协议详解二

modbus的代码实现有很多开源的版本,比如libmodbus、freemodbus等。下面讲解一下freemodbus的源码,因为freemodbus更适合单片机的应用场景。freemodbus源码下载,源码的讲解从串口接收开始,怎么接收到一帧数据,进而怎么解析,怎么执行动作。一、串口接收部分和定时器部分串口接收状态机://这个函数在串口接收中断中被调用BOOL xMBRTUReceiveFSM( void ){ BOOL xTaskNeedSwitch = FA

2020-12-29 23:18:05 350

原创 modbus协议详解一

一、什么是modbus协议?首先必须清楚通信过程中的 物理层协议 和 应用层协议。(如果清楚直接跳过)物理层协议:为了保证传输在物理线路上的数据的正确性而规定的协议。目的是保证通信线路上的数据传输正确。举个例子:uart串口通信协议,就属于物理层协议,它规定了一个字节怎么传输才能保证被正确接收。串口协议规定如下:1、没有开始通信之前,线路上保持高电平,这个时候表示处于空闲状态;2、直到线路上出现一个下降沿,表示要开始进行数据传输了;3、紧接着进行8个bit数据的传输;4、紧接着拉高电平,表示停止

2020-12-29 17:12:33 1281

原创 C++ primer读书笔记(一)——变量和基本类型

一、为什么设计数据类型?数据类型决定了程序中数据和操作的意义。数据的意义:在不同的应用场景下,变量需要占用不同大小的内存空间,布局方式和该空间能储存的值的范围,这些不同由数据类型体现;操作的意义:两个整数相加和两个对象相加的算法是不一样的,这个不一样由数据类型体现。二、C++输出没有占位符,用什么数据类型来解析?unsigned u = 10;int i = -42;std::cout << i + i << endl; //输出 -84std::cout <&lt

2020-08-09 01:49:42 86

原创 打造高质量代码之三(表驱动法)

表驱动法是一种编程模式——从表里面查找信息而不是使用逻辑语句(if和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具有吸引力。举例:把字符划分为字母、标点和数字三类。使用复杂逻辑if ( (('a' <= inputChar) && (inputChar <= 'z')) || ( ('A' <= inputChar) &&

2020-06-16 15:42:01 239

原创 打造高质量代码之二(慎用全局变量)

与全局数据有关的代码重入问题:可以由一个以上的线程访问的代码变得越来越常见。多线程代码造成了这样一种可能性,那就是全局数据将不但在多个子程序之间共享,而且也将在同一个程序的不同拷贝之间共享。在这种环境下,你必须确保即使一个程序的多个拷贝同时运行,全局数据也会保持其意义。全局数据阻碍代码重用:要把一个程序里的代码应用于另一个程序,你必须能够把它从第一个程序中取出来,然后插入到另一个程序里面。在理想状况下,你可以把一个单一子程序或者类取出,把它插到另一个程序里面去,然后高兴地继续。然而全局数据是这件事情变得复

2020-06-16 11:28:33 314

原创 打造高质量代码之一(防御式编程)

防御式编程即保护程序不受传入的错误数据和意外情况而被破坏。一、断言用于在代码中说明各种假定,澄清各种不希望的情形。可以用断言检查如下这类假定:输入参数或输出参数的取值处于预期范围内;子程序开始(或者结束)执行时文件或流是处于打开(或关闭)的状态;子程序开始(或者结束)执行时,文件或流的读写位置处于开头(或结尾)处;文件或流已用只读、只写或可读可写方式打开;仅用于输入的变量的值没有被子程序所修改;指针非空;传入子程序的数组或其他容器至少能容纳X个数据元素;表已初始化,储存着真是的数值;

2020-06-16 10:46:15 173

原创 TI CC2541 HAL之二(I2C)

一、主机模式通过将I2CCFG.ENS1和I2CCFG.STA位置1,可以将I2C模块配置为I2C主设备。 当主机是多主机系统的一部分时,必须将其自己的地址编程到I2CADDR.ADDR寄存器中。 I2CADDR.GC位的值确定I2C模块是否响应general call。(1) 发送要启用主发送模式,请将I2CCFG.ENS1和I2CCFG.STA位置1。 然后,I2C模块将等待,直到I2C总线空闲为止。 当I2C总线空闲时,它会产生一个START条件,发送从机地址,并传输一个发送方向位。 然后它产生

2020-06-10 17:39:05 565

转载 串口缓冲区管理算法之ring buffer

参考文章link一、ring buffer初始化// The definition of our circular buffer structure is hidden from the userstruct circular_buf_t { uint8_t * buffer; size_t head; size_t tail; size_t max; //of the buffer bool full;};//buffer封装(对buffer的有效数据头尾位置记录,有效数据数量记录)

2020-06-01 20:59:56 1327

原创 TI CC2540 HAL之一(UART_DMA)

TI的BLE协议栈中在链路层发送数据的时候回关中断,而且这个关中断时间可能达到1ms,假设串口波特率是115200的话,在这1ms内串口将进不了接收中断,所以有概率会丢失数据。所以需要利用DMA来进行高速的串口通信。一、DMA初始化(1)初始化第一步:DMA通道配置地址寄存器,对应的是在RAM中定义的DMA配置结构体变量的地址。将DMA结构体变量的地址写到下面的寄存器中,然后DMAARM置一开启DMA通道,DMA硬件控制器会自动装载配置。//DMA配置 结构体,包括目标地址,源地址,数据长度t

2020-06-01 20:23:11 761

原创 BLE协议栈入门四(Client端读写属性表)

客户端读写服务器端属性表中的Characteristic。/** * Write Request format. */ //发送数据打包,然后调用GATT_WriteCharValue发送 // Do a writetypedef struct{ uint16 handle; //!< Handle of the attribute to be written (must be first field) uint8 len;

2020-05-20 13:54:37 816

原创 BLE协议栈入门三(Server端读写属性表)

以TI BLE协议栈为例,Server端对自己的属性表进行读写操作的函数Simple Profile Service Callbacks如下,下面两个回调是有GATT层的Lib调用:Server端读属性表的回调函数/********************************************************************* * @fn simpleProfile_ReadAttrCB * * @brief Read an attribut

2020-05-20 11:43:52 833

原创 BLE协议栈入门二(添加service和characteristic)

蓝牙应用开发的目的是实现数据的无线传输,首先要有数据,其次以什么方式组织起来,最后发送。BLE协议栈GATT层规定了数据的组织方式,如下图:上图的Profile是一个数组,叫做属性表,每个Characteristic(结构体)叫做属性,是数组的组成元素。举个实例化的例子,如下图是一个具体的Service:需要将这个service(项目开发对象)和属于这个service的若干个characteristic加入到BLE协议栈中,添加service和characteristic就是修改GATTProfil

2020-05-20 10:11:41 1312

原创 BLE协议栈入门一(基本概念)

一、什么是BLE?BLE全称Bluetooth Low Energy,低功耗蓝牙,是一种无线传输小数据的超低功耗蓝牙技术。蓝牙设备总共分为三种:Bluetooth、Bluetooth smart、Bluetooth smart ready。Bluetooth设备是经典蓝牙设备(比如蓝牙耳机),包括BR/EDR/AMP三种技术;Bluetooth smart是BLE设备(比如蓝牙温度计),即低功耗蓝牙设备;Bluetooth smart ready是双模蓝牙设备(比如手机),即同时支持传统蓝牙个低功耗蓝牙

2020-05-19 14:46:51 2842

原创 TI OSAL之五(回调定时器)

OSAL的回调定时器的功能是定时执行回调函数,需要利用定时器链表。一个回调定时器对应一个回调函数,当定时器定时时间到,回调函数将被执行。通过设置定时器事件来触发定时器回调函数,定时器回调相关的处理是作为任务存在的;一个回调定时器的任务可以定义15个事件(即15个回调函数),还有一个是系统消息SYS_EVENT_MSG;同时还可以定义多个回调定时器任务。一、回调定时器相关初始化void osalInitTasks( void ){ uint8 taskID = 0; tasksEvents =

2020-05-13 11:41:29 534

原创 TI OSAL之四(软件定时器链表)

OSAL中的每个任务的每个事件都可以拥有一个软件定时器,而这些定时器由一个链表统一组织起来。软件定时器的作用就是对 任务和相应的事件 周期执行提供支持。一、定时器链表节点结构typedef struct{ void *next; //指向下一个节点 osalTime_t timeout; //定时器定时时间 uint16 event_flag; //事件标志 uint8 task_id; //任务ID uint32 reloadTimeout; //定时器重载的定时时间}

2020-05-12 19:35:34 405

原创 TI OSAL之三(RTC时钟管理)

OSAL的实时时钟以硬件层的timer作为定时器计数,计数时基是625us,用一个32位的整型变量记录秒数,以2000年1月1日00:00:00为时间起点,支持完整的UTC时间。一、秒数更新//函数功能:将硬件定时器的计数值转换为msvoid osalTimeUpdate( void ){ uint16 tmp; uint16 ticks625us; uint16 elapsedMSec = 0; // Get the free-running count of 625us tim

2020-05-12 14:25:16 413

原创 TI OSAL之二(消息队列)

不管裸机还是操作系统,都有任务间的通信。在裸机程序中,我们大多数时候用全局变量进行任务间的通信。而在操作系统中,任务间通信可以使用信号量,互斥量,消息队列等。在OSAL中使用消息队列作为任务间通信的手段。OSAL中消息队列的本质就是一个单向链表,在这一个链表上挂接着所有任务的消息事件,有一个链表头指向队列中第一个节点中的消息内容首地址,链表的每个节点由消息头部和消息内容组成,消息头部由消息长度,目标任务ID和一个指向下个消息内容首地址的指针组成。如下图(图中的task_id有可能重复,也就是说链表节点以消

2020-05-12 09:50:19 775 1

原创 TI OSAL之一(任务管理)

TI为了使蓝牙协议栈和应用的开发与硬件平台相独立,设计了一个OSAL操作系统抽象层,严格意义上说是一个伪操作系统,因为不支持任务优先级抢占、时间片轮转调度等。OSAL支持任务管理、任务同步、定时器、内存管理、电源管理等。下面通过协议栈源代码提取OSAL的任务管理部分。1、定义任务对应的事件处理函数指针数组//Event handler function prototype//事件处理函数形参、返回值固定如下typedef unsigned short (*pTaskEventHandlerFn)(

2020-05-11 16:11:34 735

原创 I2C协议之软件模拟(三)-- 实际应用之AT24C02

EEPROM AT24C02的软件I2C读写驱动以ATMEL的AT24C02为例(其他厂商的大同小异,兼容性都非常好的),下面说明设备地址、写操作(以字节为单元和以页为单元)、读操作。AT24C01有16个page,每个page有8个字节。AT24C02有32个page,每个page有8个字节。AT24C04有32个page,每个page有16个字节。AT24C08有64个page,每个page有16个字节。AT24C16有128个page,每个page有16个字节。一、AT24C02读写过程

2020-05-11 14:22:53 455

原创 I2C协议之软件模拟(二)-- 实际应用之SHT20

下面利用软件模拟I2C读写SHT20温湿度传感器。一、SHT20通讯定义(1)设备I2C地址:0x40;(2)命令:测量温度和湿度都有两种模式:主机模式和非主机模式,这两种模式的区别在于测量期间(发出测量命令后需要等待一段时间才能读取)是否允许主机与别的I2C设备通信。在保持主机模式下,发出测量命令后,在测量完成之前传感器会一直拉低SCL,迫使主机进入等待状态,传感器内部处理完成会释放S...

2020-05-05 23:53:32 3252 3

原创 I2C协议之软件模拟(一)

I2C(Inter-Integrated Circuit)协议是一种用于同步、半双工、串行总线(由SCL时钟线、SDA数据线组成)上的协议。规定了总线空闲状态、起始条件、停止条件、数据有效性、字节格式、响应ACK信号。有主从机之分,主机master就是掌控SCL时钟信号的一方,并且起始信号和停止信号也由主机发送。一、协议说明(1)总线空闲状态:SCL、SDA均为高电平,此时主从设备都不控制总线...

2020-05-05 00:44:09 2629 2

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除