Arduino进阶二|自定义类库保姆级教程(从零手写属于自己的传感器类库+完整源码)

**文章标签:**Arduino、类库开发、C++面向对象、单片机开发、DIY库文件

**阅读难度:**入门进阶

**适用人群:**Arduino初学者、想要优化代码、实现代码复用、进阶单片机开发的开发者

在Arduino开发的过程中,我们几乎每天都会和各类类库打交道------从官方提供的Wire、SPI通信库,到第三方的传感器、显示屏驱动库,类库已经成为嵌入式开发中不可或缺的基础工具。很多新手刚开始接触开发时,会疑惑"为什么一定要用库?我直接写裸代码不行吗?",实际上,开发中使用类库有着不可替代的必要性:

  1. 避免重复造轮子:成熟的类库已经将底层的硬件操作、复杂的通信协议、传感器校准逻辑等通用功能封装完毕,开发者无需从零开始编写这些通用代码,只需聚焦于自身项目的业务逻辑,极大节省了开发时间。

  2. 降低开发门槛:对于新手而言,无需深入理解底层的寄存器配置、复杂的时序逻辑,就能通过调用库的接口快速实现功能。比如使用OLED显示屏时,无需研究SSD1306的指令集,直接调用`display.print()`就能完成内容显示,大幅降低了入门的难度。

  3. 提升代码可维护性:类库将底层功能与业务逻辑解耦,主程序只需关注上层逻辑,无需关心底层实现细节。当出现问题时,也能快速定位问题根源------是业务逻辑出错,还是库的底层实现问题,让项目维护变得更加简单。

  4. 标准化团队协作:在团队开发中,统一的类库可以提供标准化的接口,所有开发者都遵循相同的调用规范,避免了每个人重复编写功能相似的代码,大幅提升了协作效率,也让项目的代码风格更加统一。

不过,很多新手在使用现成类库时,往往停留在"拿来主义"的阶段:只知道`#include`头文件,调用库提供的函数,却完全不理解这些类库是如何实现的,为什么能做到开箱即用,这就导致新手对类库的理解始终停留在表面。而编写自定义类库,正是帮助新手深入理解类库本质的最佳途径:

当你亲手从零开始编写一个完整的类库时,你会彻底搞清楚头文件(.h)与源文件(.cpp)的分工------原来头文件只负责声明接口,源文件才负责具体实现,这就是为什么使用库时只需要引入头文件就能调用功能;你会理解面向对象的封装逻辑------为什么库能把内部的私有变量保护起来,只对外暴露必要的接口,这和那些成熟开源库的设计思路完全一致;你也会搞懂类库的部署、加载流程------为什么把库文件放到`libraries`目录下IDE就能识别,以后安装第三方库时也能明白背后的原理。

亲手实现过一遍类库之后,你再回头看那些成熟的开源库源码时,就不会再对着一堆.h和.cpp文件一头雾水,而是能轻松看懂它们的设计逻辑,真正做到"知其然,也知其所以然",让你对类库的理解从"会调用"升级为"懂原理"。

一、前言:为什么要自定义****Arduino 类库?

很多新手在Arduino开发中,都会遇到一个核心问题:重复代码过多、代码冗余、无法复用

如果是单次简单实验,直接写裸代码完全没问题。但如果是多个项目用到同一个传感器、同一个功能模块,反复复制粘贴代码不仅低效,还容易出错,项目也难以维护和扩展。

Arduino基于C++开发,核心支持面向对象编程 ,我们可以通过手写自定义类库,将模块功能封装起来,实现一次编写、随处调用、简洁高效、便于协作

本文将从零带大家吃透Arduino类库开发全流程,从编程思想区别、类库文件结构,到完整手写SR04超声波类库、部署本地库、实战调用,全程干货无废话,看完直接上手DIY任意模块类库!

二、核心基础:面向过程****VS 面向对象

想要学会写类库,首先要分清两种编程思想,这是Arduino进阶的关键。

2.1****面向过程( C 语言)

核心逻辑:关注步骤,强调怎么做

将功能拆解为一个个执行步骤,通过函数依次执行,适合简单小型项目。

优缺点:

  • ✅ 优点:运行性能高、资源消耗低
  • ❌ 缺点:代码复用性差、难以扩展、不适合大型项目、多人协作困难

2.2****面向对象( C++

核心逻辑:关注对象,强调谁去做

将复杂功能拆解为多个对象,每个对象包含专属属性(参数)行为(功能),Arduino类库就是基于该思想开发。

优缺点:

  • ✅ 优点:代码易复用、易维护、可扩展,适合复杂项目,支持团队协作
  • ❌ 缺点:相比面向过程,资源消耗略高、运行性能稍低

四、类和对象

在C++及Arduino编程中,对象是面向对象编程的两大基石。理解它们的关系,是掌握Arduino类库开发的关键。

  • 对象( object :世间万物(你、我、他、Led灯、机械臂夹东西的钳子的运行轨迹、GPS信息......)皆为对象
  • 类( class :具有相同属性和行为的对象的统称,是模板(比如:超声波SR04类、RGB灯类)
  • 成员变量:对象的属性(如传感器引脚、灯的亮度)
  • 成员函数:对象的行为(如测距、点亮灯光、切换颜色)

五、库

是一个打包好的代码集合,它将相关的类、函数、常量组织在一起,方便在多个项目中复用。在Arduino开发中,类(**Class 库(Library 是两个密不可分的核心概念。简单来说:库是类的"** 容器 " ,类是库的 " 心脏 "

Arduino的库分为三类:

类型 说明 位置 示例
核心库 IDE自带,由Arduino团队维护 hardware/arduino/avr/libraries/ Serial、EEPROM
自带库 官方审核通过的第三方库 libraries/ Servo、Wire、LiquidCrystal
外部库 用户自己编写或下载 文档/Arduino/libraries/ 你写的任何自定义库

**六、**Arduino 类库完整文件结构

标准的Arduino自定义类库由4 个核心文件组成,缺一不可:

  1. .h 头文件 :负责声明类、成员变量、成员函数,只定义不实现
  1. .cpp 源文件 :负责实现头文件中声明的所有函数功能
  1. 示例文件:库的调用demo,方便用户快速上手使用
  1. keyword.txt:关键字高亮文件,让自定义库的类名、函数名在IDE中高亮显示

七、实战教学:手写****SR04 超声波类库(全流程)

我们以最常用的SR04超声波传感器为例,从零完整编写一套可直接使用的自定义类库。

7.1****第一步:编写 .h 头文件(类的声明)

头文件核心作用:定义类的结构,声明变量和函数,不写具体执行代码。同时必须添加预编译防止重复包含。

在项目文件中新建 .h 头文件

头文件防护(必须)

复制代码
#ifndef 头文件名_H      // 如果没有定义头文件名_H

#define 头文件名_H      // 则定义它



// 类声明...



#endif              // 结束防护

类声明的基本语法

复制代码
class 类名 {

public:

    // 公有成员(外部可访问)

    构造函数声明;

    返回值 公有函数名(参数列表);



private:

    // 私有成员(仅类内部可访问)

    数据类型 私有变量名;

   

protected:

    // 供继承类使用(Arduino类库较少用)

};

构造函数 : 与类同名,无返回值。用于初始化对象(设置引脚、初始化串口等)

**成员变量命名规范(常见风格):**m_ 前缀表示成员变量

完整的 Arduino 头文件示例

复制代码
cpp
#ifndef sr04_H
#define sr04_H

// 定义SR04类
class sr04
{
  // 公共成员:外部可直接调用
  public:
    // 构造函数:初始化传感器引脚,与类名同名,无返回值
    sr04(int trPin, int ecPin);
    // 测距函数:返回距离数值
    float Get();

  // 私有成员:仅类内部可使用,外部无法访问
  private:
    int m_trPin;  // 触发引脚
    int m_ecPin;  // 回声引脚
};

#endif

核心知识点:

  • 构造函数必须与类名一致、无返回值,用于初始化对象参数
  • public:对外开放的函数,供主程序调用
  • private:私有变量,保护引脚参数,防止外部篡改
  • #ifndef / #define / #endif:预编译防护,避免库重复编译报错

7.2****第二步:编写 .cpp 源文件(函数实现)

源文件负责实现头文件中声明的所有函数逻辑,必须先引用对应头文件。

例如:

复制代码
#include "sr04.h"

#include "Arduino.h"

在类外定义(实现)成员函数的标准语法

复制代码
返回值类型 类名::函数名(参数列表) {

    // 函数实现

}

完整的 Arduino .cpp 文件示例

复制代码
cpp
// 引入自定义头文件和核心库文件
#include "sr04.h"
#include "Arduino.h"

// 构造函数实现:初始化引脚
sr04::sr04(int trPin, int ecPin)
{
  m_trPin = trPin; // 将传入的触发引脚参数保存到私有成员变量m_trPin中方便在内部传值
  m_ecPin = ecPin; // 将传入的回声引脚参数保存到私有成员变量m_ecPin中
  pinMode(m_trPin, OUTPUT);
  pinMode(m_ecPin, INPUT);
}

// 测距函数实现:计算并返回距离
float sr04::Get()
{
  digitalWrite(m_trPin, LOW);
  delayMicroseconds(2);
  digitalWrite(m_trPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(m_trPin, LOW);
  // 读取回声引脚高电平持续时间
  float time = pulseIn(m_ecPin, HIGH);
   // 超声波距离计算公式

  // 声速在空气中约为343米/秒 = 0.0343厘米/微秒

  // 距离 = 时间 × 声速 ÷ 2(因为超声波往返走了两倍的距离)
  float distance = time * 0.0343 / 2;
  return distance;
}

核心知识点:

  • 类名 :: 函数名:域解析符,标识该函数属于指定类
  • 所有头文件声明的函数,必须在cpp中完整实现
  • 保留传感器原生测距逻辑,封装后无需重复编写

7.3****第三步:编写示例调用文件

使用类的基本步骤

|-------|--------|------------------------------|
| 步骤 | 操作 | 说明 |
| 1 | 包含头文件 | #include "ClassName.h" |
| 2 | 创建对象 | ClassName objectName(参数); |
| 3 | 调用成员函数 | objectName.functionName(参数); |

使用自定义SR04

返回项目文件(.ino文件),测试我们编写的类库,实现串口打印测距数据:

复制代码
cpp
// 引入自定义的sr04类头文件

#include "sr04.h"

// 创建SR04对象,绑定触发引脚3,回声引脚4
sr04 mysr04(3,4);

void setup()
{
  Serial.begin(9600);  // 初始化串口
}

void loop()
{
  // 调用成员函数获取距离
  float dis = mysr04.Get();
  Serial.print("当前距离:");
  Serial.print(dis);
  Serial.println(" cm");
  delay(500);
}

八、部署自定义库到****Arduino IDE (全局可用)

完成以上四个文件后,我们就可以将其部署为本地全局库,所有项目均可直接调用:

1.打开"文档"------"Arduino"------新建文件夹,命名为 sr04

2.在Arduino IED中点击"项目"------"显示项目文件夹",打开项目文件夹。将 sr04.h、sr04.cpp放入文档 /Arduino/libraries/sr04文件夹

3.再把项目文件夹放进"sr04"

4.编写keywords.txt高亮文件

该文件用于让IDE识别自定义关键字,实现代码高亮,区分类名和函数名。

在文档/Arduino/libraries/sr04中单击右键------新建------文本文件(命名为 keywords.txt )------打开该文件键入以下内容(分隔必须是 Tab 键,不能是空格):

|---------------------------------------|
| Plain Text sr04 KEYWORD1 Get KEYWORD2 |

  • KEYWORD1:高亮类名
  • KEYWORD2:高亮成员函数名

5.重启Arduino IDE,即可在「项目-导入库」中找到自定义的sr04库

九、进阶实战:车位指示灯项目(库落地应用)

利用我们自定义的SR04库,实现智能车位检测功能:无车亮绿灯,有车亮红灯

硬件接线:

  • SR04:Trig-3、Echo-4
  • 红灯引脚13,绿灯引脚12

实战代码:

复制代码
cpp
#include "sr04.h"
sr04 mysr04(3,4);

const int redLed = 13;
const int greenLed = 12;
// 车位检测阈值:10cm内判定有车
const int checkDis = 10;

void setup()
{
  Serial.begin(9600);
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
}

void loop()
{
  float dis = mysr04.Get();
  Serial.print("距离:");
  Serial.println(dis);

  if(dis <= checkDis){
    // 有车:红灯亮
    digitalWrite(redLed, HIGH);
    digitalWrite(greenLed, LOW);
  }else{
    // 无车:绿灯亮
    digitalWrite(redLed, LOW);
    digitalWrite(greenLed, HIGH);
  }
  delay(500);
}

**十、课后拓展:**DIY RGB LED 类库(练手项目)

大家可以按照本文教程,自主编写RGB LED类库,需求如下:

10.1****类库参数定义

成员变量:R引脚、G引脚、B引脚

成员函数:构造函数、自定义颜色设置函数

10.2****实战功能要求

实现简易交通灯逻辑:红灯亮3秒→黄灯闪烁3次(亮0.5s/灭0.5s)→绿灯亮3秒,循环执行。

十一、总结与学习心得

  1. 自定义类库的核心是面向对象封装思想,将重复的模块功能打包,实现代码解耦;

  2. .h 文件管声明, .cpp 文件管实现,分工明确是类库开发的核心规则;

  3. 部署本地库后,可全局复用,极大提升后续Arduino项目开发效率;

  4. 掌握自定义类库是Arduino从入门到进阶的标志性能力,为后续复杂智能项目、设备开发打下基础。

十二、完整源码获取

本文SR04完整类库文件、RGB LED拓展练习模板已整理完毕,需要的小伙伴可以自行根据教程复刻,全程亲手敲一遍,快速掌握类库开发逻辑!

原创不易,点赞收藏,后续持续更新 Arduino 进阶实战教程!

相关推荐
minglie11 小时前
zynq用普通网口在局域网同步
单片机
Highcharts.js1 小时前
通过CSS变量实现图表色彩与逻辑解耦、图表主题统一|Highcharts Palette 详解
c++·echarts·highcharts·可视化开发·palette·styledmode·图表样式
玖玥拾1 小时前
C/C++ 基础笔记(八)
c语言·c++
清风6666661 小时前
基于单片机的64位多模式流水灯控制系统设计
单片机·毕业设计·课程设计·期末大作业
郝学胜_神的一滴1 小时前
Qt 高级开发 027: QTabWidget自定义样式表美化实战
c++·qt
进击的横打1 小时前
【车载开发系列】热敏电阻与上下拉电阻
单片机·嵌入式硬件
XINVRY-FPGA1 小时前
XCKU035-2FBVA676I AMD Xilinx Kintex UltraScale FPGA
arm开发·嵌入式硬件·网络安全·fpga开发·硬件工程·信号处理·fpga
啦啦啦啦啦zzzz1 小时前
数据结构:哈夫曼编码
数据结构·c++·哈夫曼编码
兵哥工控2 小时前
MFC开关量输出发脉冲实例
c++·mfc·开关量发脉冲