Skip to content

实验五:传感器数据收发实验 ​

一句话理解

这不是"照着步骤做一遍"的实验,而是一次设计型训练:工程里有一套能跑通的基线代码,你的任务是 ① 读懂它 ② 改造它 ③ 验证你的改造——代码要自己看、自己改、自己测,具体怎么改成什么样,由你设计。

项目内容
实验名称传感器数据收发(设计与实现)
建议学时90 分钟
分组2 人一组
实验类型设计型
实验板CC2530 实验板 2 块(1 块协调器,1 块传感器节点)

⚠️ 本实验不是"照着步骤做一遍"

工程里有一套能跑通的基线代码。你的任务是三件事:

① 读懂它 ② 改造它 ③ 验证你的改造

代码要自己看、自己改、自己测。 每个任务都给了"改哪里"的提示和"怎么算通过"的验收标准,但具体怎么改、改成什么样,由你设计。


一、实验目的 ​

  1. 读懂 ZCL 属性上报的完整实现链路:采样 → 更新属性 → 组装报文 → 无线发送 → 接收解析
  2. 能独立定位并修改上报周期、上报条件等关键参数,并说明改动的后果
  3. 掌握"改前 / 改后对比"的验证方法:用可观测的现象证明你的改动确实生效了

二、实验原理(你要读懂的机制) ​

2.1 谁是发送方,谁是接收方 —— 这是最关键的一点 ​

本实验里两个角色的分工是不对称的:

角色固件配置干什么串口打印什么
传感器节点RouterEB(或 EndDeviceEB)采样 → 上报自己采集到的数值
协调器CoordinatorEB接收 → 显示收到的、别人发来的数值

⚠️ 协调器不会去采样

它没有接传感器,也不会主动去读 —— 它只负责"听"。

这不是巧合,是代码里刻意做的。读代码时请找出:哪些地方用条件编译把"采样/上报"排除在协调器之外? (提示:Components\hal\common\hal_drivers.c 和 Source\zcl_sampletemperaturesensor.c 各有一处)

2.2 上报的是什么:三个 ZCL 属性 ​

上报的不是"一条自定义消息",而是 ZCL(ZigBee Cluster Library)属性:

簇(Cluster)簇 ID属性数据来源单位
Illuminance Measurement0x0400MeasuredValue光敏传感器ADC 原始值 0~1023
Temperature Measurement0x0402MeasuredValueDHT110.01 ℃
Relative Humidity Measurement0x0405MeasuredValueDHT110.01 %RH

注意单位:串口上的 2650 不是 2650 ℃,而是 26.50 ℃。

2.3 数据是怎么流动的 ​

   ┌──────────── 传感器节点(RouterEB)────────────┐
   │  周期任务(每 3 秒):                          │
   │    ① 读光敏 ADC(P0_5)  → 光照值                 │
   │    ② 读 DHT11(P0_4)    → 温度值、湿度值          │
   │    ③ 更新三个 ZCL 属性                          │
   │    ④ 串口打印  ← 发送端看到的                    │
   │    ⑤ 判断"有没有变化" → 有变化才发上报报文        │
   └───────────────────┬───────────────────────────┘
                       │  空口(ZigBee 无线)
                       │  Report Attributes × 3
                       ▼
   ┌──────────── 协调器(CoordinatorEB)───────────┐
   │  收到报文 → 解析 → 串口打印收到的数值            │
   │                     ← 接收端看到的              │
   │            → 同时在 OLED 上显示 Rx Temp:        │
   └───────────────────────────────────────────────┘

2.4 上报机制的三个可调参数(任务改造的入口) ​

读代码时,把这三件事弄清楚,后面的任务就好做了:

参数当前值在哪里改成什么会影响
多久上报一次3 秒zcl_sampletemperaturesensor.h 的 SAMPLETEMPERATURESENSOR_REPORT_PERIOD报文密度、实时性、功耗
什么样才上报三个值有任一变化GetAndReportEx() 里的 changed 标志空口流量、功耗
发给谁协调器 0x0000ReportAttr() 里的 destAddr数据的去向

2.5 本实验的四个关键约定 ​

约定值
上报周期3 秒(SAMPLETEMPERATURESENSOR_REPORT_PERIOD = 3000)
上报条件数值有变化才发(但串口每周期都打印)
上报目标协调器,短地址 0x0000
串口参数38400 / 8 / 1 / 无

三、代码导读(动手改之前必须读完) ​

3.1 你要看的文件 ​

工程路径:

TemperatureSensor工程源码分析\TemperatureSensor工程源码分析\Z-Stack 3.0.1\
    Projects\zstack\HomeAutomation\SampleTemperatureSensor\
文件你要从这里看懂什么
Source\zcl_sampletemperaturesensor.c主战场:采样、上报、串口打印、接收解析
Source\zcl_sampletemperaturesensor_data.c属性表:哪些属性可读、可写、可上报
Source\zcl_sampletemperaturesensor.h端点号、事件位、上报周期宏
Source\OSAL_SampleTemperatureSensor.c任务表与初始化顺序(了解即可)
Components\hal\target\CC2530EB\HW_DHT11\hal_dht11.hDHT11 的状态码定义

3.2 五个核心函数(先找到它们,再往下读) ​

函数在哪个文件干什么对应本实验哪个环节
zclSampleTemperatureSensor_GetAndReportEx().c周期任务:采样 + 更新属性 + 判断变化 + 上报发送端全流程
zclSampleTemperatureSensor_ReportAll().c决定上报哪几个簇发送
zclSampleTemperatureSensor_ReportAttr().c组一条上报报文并发送发送
zclSampleTemperatureSensor_PrintReport().c发送端的串口输出格式观测
zclSampleTemperatureSensor_PrintRxReport().c协调器端的接收解析与输出接收

小技巧:在 IAR 里用 Ctrl+Shift+F(全局搜索)搜函数名,能直接跳到定义处。

3.3 代码走查问题(必须书面回答,计入成绩) ​

带着这些问题去读代码,读不懂就先别改:

  1. GetAndReportEx() 里有一个 changed 变量。它什么时候被置为 TRUE?总共几处?最后它是怎么决定"要不要上报"的?
  2. ReportAll() 为什么要调用三次 ReportAttr()?一次不行吗?(提示:想想 ZCL 对一条上报报文的限制)
  3. ReportAttr() 里 destAddr.addr.shortAddr 被设成了多少?这个地址代表谁?
  4. PrintRxReport() 为什么被放在 #ifdef ZCL_REPORT ... #endif 里面?而 PrintReport() 却在 #else 分支里?这个条件编译的边界在哪里?
  5. _data.c 的属性表里,温度属性的权限写着 ACCESS_CONTROL_READ | ACCESS_REPORTABLE。ACCESS_REPORTABLE 是干什么的?如果去掉它会怎样?
  6. 协调器的采样代码为什么被排除?找出两处条件编译,写出行号。
  7. DHT11 读到数据后,为什么代码里写 dat.temp * 100 才赋给属性?
  8. 发送端每 3 秒都在串口打印,那接收端是不是每 3 秒也一定收到?为什么?

四、开发环境与基线验证 ​

4.1 工程与两个配置 ​

板子IAR 配置角色
A 板CoordinatorEB协调器(接收端)
B 板RouterEB传感器节点(发送端)

4.2 编译与烧写 ​

  1. IAR 打开 CC2530DB\SampleTemperatureSensor.eww
  2. 左上角配置下拉框选 CoordinatorEB → Project → Rebuild All → 连 A 板 → Download and Debug
  3. 配置切到 RouterEB → Rebuild All → 连 B 板 → Download
  4. 两块板都要擦除 NV

为什么要擦 NV? 板子里可能残留上次组网的参数(PANID、信道、父节点)。不擦的话,节点会拿着旧参数反复尝试加入一个已经不存在的网络,可能十几分钟都连不上。

擦除方法:IAR Project → Download → Erase memory,或用 TI Flash Programmer 的 Erase。

4.3 上电顺序(顺序错了实验会失败) ​

① 先只给 A 板(协调器)上电  →  等 10~15 秒,让它把网络建起来
② 再给 B 板(传感器节点)上电  →  等 20~30 秒,让它加入网络

4.4 串口设置 ​

两块板都要接串口(两个窗口并排摆):

参数值
波特率38400
数据位 / 停止位 / 校验位8 / 1 / 无
流控无

怎么确定 COM 口? 拔掉某块板 → 设备管理器"端口"里少了哪个 COM 就是它。 两块板的 COM 号通常不一样,别选错。

4.5 ★ 先验证基线(改代码之前必须做) ​

在动手改任何代码之前,先把原样的固件跑通,确认你能看到正常现象。

B 板(发送端)应每 3 秒打印:

------ SENSOR REPORT ------
DHT11  : OK
Temp   : 2650  (0.01 C)
Humi   : 6100  (0.01 %RH)
Light  : 512  (ADC 0~1023)
---------------------------

A 板(接收端)应打印:

<<< RX REPORT  src=0x796F  cluster=0x0402
   Temperature = 2650  (0.01 C)
<<< END
<<< RX REPORT  src=0x796F  cluster=0x0405
   Humidity    = 6100  (0.01 %RH)
<<< END
<<< RX REPORT  src=0x796F  cluster=0x0400
   Illuminance = 512  (ADC 0~1023)
<<< END

逐项确认:

检查期望
B 板 DHT11 :显示 OK
B 板 Temp / Humi / Light数值合理(温度 15~35 ℃、湿度 30~90 %RH、光照 0~1023)
A 板是否有输出有 RX REPORT,且 src 有值
A 板的数值与 B 板同一时刻的数值完全相等

用环境变化验证数据是真的:

动作两端都应出现的现象
对着 DHT11 哈气(或靠近热水杯)Humi 明显上升,Temp 略升
手电筒照光敏电阻Light 明显下降(注意是下降!)
遮住光敏电阻Light 明显上升

为什么"越亮读数越小"? 光敏电阻接在分压电路低侧:光越强 → 阻值越小 → 分压点电压越低 → ADC 越小。这是硬件决定的,不是错误。

把基线数据记入表 1。

⚠️ 基线跑不通就不要改代码 —— 否则出了问题分不清是你的改动还是原来的问题。


五、实验任务 ​

5.0 任务总览 ​

编号任务改动位置
1修改上报周期.h 的宏 SAMPLETEMPERATURESENSOR_REPORT_PERIOD
2改为无条件周期上报.c 的 GetAndReportEx()

每次改完都要:① Rebuild All ② 重新烧写对应板 ③ 用可观测现象验证 ④ 记录数据。 每次只改一处,改完验证完再改下一处 —— 不要一次改一堆。


任务 1:修改上报周期 ​

设计要求

把上报周期从 3 秒改成 1 秒,然后再改成 10 秒,观察差异。

改哪里

Source\zcl_sampletemperaturesensor.h 里的宏:

c
#define SAMPLETEMPERATURESENSOR_REPORT_PERIOD       3000

提示

  • 这个宏在 zcl_sampletemperaturesensor.c 里被用作 osal_start_timerEx() 的周期(在 Init() 里启动,在事件循环里重新装载)
  • 找到这两个地方,理解"周期任务"是怎么自我重新触发的
  • ⚠️ 不要小于 1000 ms:DHT11 本身需要一定的采样间隔,读太快会频繁出错

验收标准

周期60 秒内 B 板打印次数(理论值)实测
3000 ms(原值)约 20 次
1000 ms约 60 次
10000 ms约 6 次

回答:周期变短会带来什么代价?(从无线信道占用、功耗、DHT11 读取耗时三个角度说)


任务 2:改为"无条件周期上报" ​

设计要求

当前代码是"三个值有任一变化才上报"。请改成"每个周期都上报"。

改哪里

Source\zcl_sampletemperaturesensor.c → zclSampleTemperatureSensor_GetAndReportEx()

该函数末尾现在是这样的逻辑:

c
  /* 有变化才上报 */
  if (changed)
  {
    zclSampleTemperatureSensor_ReportAll();
  }

提示

  • 最简做法是把判断条件直接去掉;但更好的做法是先想清楚:changed 这个变量在整个函数里起了什么作用?去掉它会不会有副作用?
  • 想一想:串口打印和无线上报是两条独立的路径吗?改动只影响哪一条?

验收标准

场景改前改后
环境稳定(不哈气、光照不变),观察 60 秒A 板收不到或很少收到A 板应收到约 20 轮

回答:

  • 改完之后,空口报文的数量是增加还是减少?大约增加多少倍?
  • 如果这是一块电池供电的节点,你会选哪种策略?为什么?

六、数据记录表 ​

表 1 基线验证(改代码之前) ​

序号发送端 Temp接收端 Temperature发送端 Humi接收端 Humidity发送端 Light接收端 Illuminancesrc
1
2
3

发送端与接收端数值是否完全一致? □ 是 □ 否 src = 0x__________ 你是如何确认它就是发送端的地址的? ____________________

表 2 任务 1 —— 上报周期 ​

周期设置60 秒内 B 板打印次数60 秒内 A 板收到轮次是否符合预期
3000 ms(原值)
1000 ms
10000 ms

表 3 任务 2 —— 上报条件 ​

上报条件稳定环境下 60 秒内 A 板收到轮次与发送端打印次数之比
有变化才上报(原值)
无条件周期上报(改后)

表 4 环境变化的影响(基线阶段) ​

动作变化前 Temp/Humi/Light变化后 Temp/Humi/Light变化方向
哈气 / 靠近热水/ // /
强光照/ // /
遮光/ // /

七、思考题 ​

  1. 谁在发送、谁在接收? 协调器会不会主动去读传感器?为什么这么设计?
  2. 为什么一次上报会变成三条报文? 如果三个属性属于同一个簇,会是几条?
  3. Temp : 2650 代表多少摄氏度? ZCL 为什么用它作为单位,而不是直接传 26?
  4. 为什么光越强 Light 反而越小? 结合分压电路说明。
  5. "数值不变就不上报"有什么好处? 你把它改成无条件上报后,代价是什么?
  6. ReportAttr() 里的 destAddr 决定了什么? 如果网络里有 5 个传感器节点,协调器靠报文的哪个字段区分它们?
  7. 串口打印和无线上报是两件独立的事吗? 用你在任务 1、2 中的实测数据说明。
  8. 如果两块板都上电了但协调器一直收不到数据,按可能性从高到低列出你的排查顺序。

八、常见问题排查 ​

现象可能原因处理
编译报错语法/类型错误看 IAR 的 Error[...] 信息里的文件名和行号,双击跳过去
编译警告 Pe177: declared but never referenced你删掉了某个函数的调用,但前置声明还留着把没用的声明也注释掉,或恢复调用
串口完全没输出COM 口选错;波特率不对;端口没打开拔插板子确认 COM;波特率 38400;先"关闭"再"打开"
只有乱码波特率不对确认 38400(不是 115200)
发送端 DHT11 : 不是 OK传感器没接好 / 超量程换环境再试
发送端正常,接收端一直没有输出① 传感器没入网 ② 两块板不在同一网络按 4.3 的顺序上电;两块板都擦 NV 后重来
改了代码但现象没变忘记 Rebuild All;烧错了板;没擦 NV重新 Rebuild + 确认烧到正确的那块板
烧完就死机 / 不打印你的改动导致内存或数组越界用 Rebuild All 的全部警告逐条排查;先恢复原代码确认基线正常
OLED 一直空白正常(协调器只在收到温度上报时写一行)收到上报后应显示 Rx Temp:
板上电没反应USB 线不能传数据换一根 USB 线(很多线只充电不传数据)

九、实验报告要求 ​

  1. 实验目的(简写 2~3 条)
  2. 实验设备:板子数量、COM 口、固件配置
  3. 代码走查答案:第三.3 节的 8 个问题全部书面回答
  4. 任务完成情况:每个任务写清 —— 你改了什么(贴改动前后代码)→ 为什么这么改 → 实测结果
  5. 实验数据:第六节的表 1 ~ 表 4
  6. 实验现象:至少贴 2 段真实的串口输出(发送端 + 接收端),直接复制或截图,不要手抄
  7. 思考题:第七节 8 题全答
  8. 实验结论:用你自己的话说清"数据是怎么从传感器走到协调器的"
  9. 问题与体会:遇到的坑、怎么定位的(这一项计入成绩,写清楚比写漂亮重要)

格式:手写或打印均可。代码改动请贴 diff 形式(改前 / 改后对照)。


附录 A:两端串口输出格式速查 ​

发送端(RouterEB / EndDeviceEB)—— 每 3 秒一次 ​

------ SENSOR REPORT ------
DHT11  : OK
Temp   : 2650  (0.01 C)
Humi   : 6100  (0.01 %RH)
Light  : 512  (ADC 0~1023)
---------------------------

接收端(CoordinatorEB)—— 每收到一条报文的时刻 ​

<<< RX REPORT  src=0x796F  cluster=0x0402
   Temperature = 2650  (0.01 C)
<<< END
<<< RX REPORT  src=0x796F  cluster=0x0405
   Humidity    = 6100  (0.01 %RH)
<<< END
<<< RX REPORT  src=0x796F  cluster=0x0400
   Illuminance = 512  (ADC 0~1023)
<<< END

A 板上的 src 是发送方的短地址。数值对照一致,就证明这条数据确实来自那块传感器板。


附录 B:关键函数索引(改代码时查这里) ​

你想改什么去哪改
上报多久一次.h → SAMPLETEMPERATURESENSOR_REPORT_PERIOD
上报什么条件.c → GetAndReportEx() 的 changed 相关逻辑
上报哪几个簇.c → ReportAll()
一条报文怎么组.c → ReportAttr()
上报发给谁.c → ReportAttr() 里的 destAddr
发送端打印格式.c → PrintReport()
接收端打印/处理逻辑.c → PrintRxReport()、ProcessInReportCmd()
属性表(有哪些属性、权限、类型)_data.c → zclSampleTemperatureSensor_Attrs[]
光照值的换算.c → GetAndReportEx() 里处理光照那一段
DHT11 状态码含义hal_dht11.h → HAL_DHT11_SC_*

附录 C:三个簇/属性速查 ​

名称簇 ID属性名串口标签单位
光照测量0x0400MeasuredValueIlluminance / LightADC 0~1023
温度测量0x0402MeasuredValueTemperature / Temp0.01 ℃
相对湿度测量0x0405MeasuredValueHumidity / Humi0.01 %RH

换算:Temp : 2650 = 26.50 ℃ │ Humi : 6100 = 61.00 %RH


附录 D:一页速查卡 ​

┌────────────────────────────────────────────────┐
│  传感器数据收发 · 速查卡                          │
├────────────────────────────────────────────────┤
│  固件   A板(协调器)=CoordinatorEB                 │
│         B板(传感器)=RouterEB                      │
│  串口   38400 / 8 / 1 / 无                        │
│  上电   先 A 等10~15秒 → 再 B 等20~30秒            │
│  必做   两块板都擦 NV;先验证基线再改代码           │
├────────────────────────────────────────────────┤
│  上报周期 = SAMPLETEMPERATURESENSOR_REPORT_PERIOD │
│  上报条件 = GetAndReportEx() 里的 changed 标志     │
│  上报目标 = ReportAttr() 里的 destAddr(0x0000)     │
│  属性表   = _data.c 的 Attrs[]                     │
├────────────────────────────────────────────────┤
│  温度 = 显示值 ÷ 100  ℃                           │
│  湿度 = 显示值 ÷ 100  %RH                         │
│  光照 = ADC 原始值;越亮越小                       │
├────────────────────────────────────────────────┤
│  改完必做:Rebuild All → 烧对板 → 擦NV → 对比验证  │
└────────────────────────────────────────────────┘

aioteer · 物联网专业课程群

💬AI 伴学配置