Linux 物联网网关主控系统-感知层部分(一)
- [一、 什么是 CC2530](#一、 什么是 CC2530)
- [二、 硬件操作核心逻辑](#二、 硬件操作核心逻辑)
- 三、LED
- 四、蜂鸣器
- 五、继电器
- 六、人体热红外
- 七、KEY
- 八、USART
- 九、ADC
- 十、光敏
- 十一、MQ-2烟雾传感器
- 十二、温湿度传感器DHT11
- 十三、屏幕
一、 什么是 CC2530
CC2530 是 TI(德州仪器)推出的一款兼容 8051 内核的无线射频单片机(SoC),专为物联网、无线传感器网络(WSN)设计,核心定位是 "低功耗 + 无线通信 + 强外设扩展"。
它完全支持 IEEE 802.15.4 协议(ZigBee 通信标准),可直接 作为 ZigBee 网络的协调器、路由器或终端设备,是物联网感知层的核心控制芯片,广泛应用于智能家居、工业监测、无线抄表等场景。
二、 硬件操作核心逻辑
SFR 是什么?(Special Function Register)
全称:Special Function Register,中文叫:特殊功能寄存器。SFR 就是单片机的 "控制面板",你想控制任何硬件(LED、蜂鸣器、传感器、串口),都必须通过操作 SFR 实现。
- 将代码编译成CPU能识别的语言
- cpu解析执行代码流
- 然后通过总线找到外设连接的控制器的寄存器(即SFR),
通过设置这些寄存器,来指挥控制器工作。
三、LED
1.电路图

P10 为 1 (高电平)的时候, 二极管导通,LED1 亮,
P10 为 0 (低电平)的时候, LED1 灭,
所以要控制LED1亮灭只需要控制P10输出电平即可。
2.GPIO控制
核心寄存器(4 个)

IO 口使用通用流程(3 步走)
先配置 PxSEL:确定端口是用作普通 IO,还是关联外设功能;
再配置 PxDIR:明确普通 IO 的工作方向(输入 / 输出);
按需配置 PxINP:仅输入模式需额外设置,选择上拉 / 下拉 / 三态(输出模式可忽略此步)。
- 配置阶段(初始化)
PxSEL 选功能(IO / 外设)
PxDIR 定方向(输入 / 输出)
PxINP 输入模式(可选)
不需要 Px!- 真正使用引脚时
必须用 Px!
想让 LED 亮 → Px = 1
想让蜂鸣器响 → Px = 1
想读取按键是否按下 → if(Px == 0)
想读取传感器信号 → value = Px
四、蜂鸣器
1.分类
有源蜂鸣器和无源蜂鸣器:
• 有源蜂鸣器:
• 只要给它加上恒定的电压,就能发声;
无源蜂鸣器:
• 必须给它加上一定频率的方波或正弦波才能发声。
2.电路图

P00
• 置1 响
• 置0 不响
3.代码
c
#define BEEP P0_0
• P0DIR |= 0x01;
• POSEL &= 0xFE; //1111 1110
• BEEP = 0; //灭
• BEEP = 1; //响
选功能:P0SEL &= 0xFE → P0.0 设为通用 I/O
定方向:P0DIR |= 0x01 → P0.0 设为输出模式
控电平:BEEP=0/1 → 控制蜂鸣器静音 / 鸣叫
五、继电器
1.原理和背景
继电器(英文名称:relay)
• 是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路
中使被控量发生预定的阶跃变化的一种电器。
• 作为控制元件,概括起来,继电器有如下几种作用:
• 1)扩大控制范围:
• 例如,多触点继电器控制信号达到某一定值时,可以按触点组的不同形式,同时换接、开断、接
通多路电路。
• 2)放大:
• 例如,灵敏型继电器、中间继电器等,用一个很微小的控制量,可以控制很大功率的电路。
• 3)综合信号:
• 例如,当多个控制信号按规定的形式输入多绕组继电器时,经过比较综合,达到预定的控制效果。
• 4)自动、遥控、监测:
• 例如,自动装置上的继电器与其他电器一起,可以组成程序控制线路,从而实现自动化运行。

从电磁继电器的控制原理可以看出,继电器线圈电压没
有正负之分,因为无论正向还是反向电流,线圈都会产
生吸力。
2.电路图

- p13设置为输出
• 2. p13设置为
• 1:打开
• 0:关闭
松乐继电器SRD-05VDC-SL-C
3.代码
c
P1SEL &= 0xF7; //1111 0111
• P1DIR |= 0x08; //0000 1000
• DATA_PIN = 1;
• DATA_PIN = 0;
选功能:P1SEL &= 0xF7 → P1.3 设为通用 I/O
定方向:P1DIR |= 0x08 → P1.3 设为输出模式
控电平:DATA_PIN=1/0 → 控制 P1.3 输出高 / 低电平
六、人体热红外
1.基本介绍
热释电传感器是一种传感器,别称人体红外传感器
• 用于生活的防盗报警、来客告知等,原理是将释放电荷经放大
器转为电压输出。

全自动感应:
• 人进入其感应范围则输出高电平,人离开感应范围则自动延时关闭高电平,输出低电平。
光敏控制(可自己购买了安装,出厂时未设):
• 模块预留有位置,可设置光敏控制,白天或光线强时不感应。
触发方式跳线选择。
• 不可重复触发方式:
• 即感应输出高电平后,延时时间段一结束,输出将自动从高电平变成低电平;
• 可重复触发方式:
• 即感应输出高电平后,在延时时间段内,如果有人体在其感应范围活动,其输出将一直保持高电平,直到人离开后才延时将高
电平变为低电平(感应模块检测到人体的每一次活动后会自动顺延一个延时时间段,并且以最后一次活动的时间为延时时间的
起始点)。
2.电路图

3.代码
传感器 → 输出模式(主动发信号)
单片机引脚 → 输入模式(被动读信号)
c
#define HONGWAI P0_5 // 宏定义:人体红外 = P0.5
P0SEL &= ~0x20; // 配置功能
P0DIR &= ~0x20; // 配置方向
if(HONGWAI == 1) 有人
if(HONGWAI == 0) 无人
P0SEL &= ~0x20
→ 设置 P0.5 为 通用 IO
P0DIR &= ~0x20
→ 设置 P0.5 为 输入模式
人体红外是数字信号,直接用默认模式即可,不用PxINP。
人体红外传感器输出的数字信号,是「强驱动」的 ------ 高电平就是标准 3.3V,低电平就是标准 0V,不会出现 "似高非高、似低非低" 的情况。
七、KEY
1.电路图

按键S1是一个输入设备
按下按键P01是低电平
放开时候P01是高电平
2.代码
使能S1按键,操作步骤如下
• 1. 配置P0SEL,设置P01为普通IO口
• 2. 配置P0DIR,设置P01口为输入
• 3. 配置P0INP,设置P01上拉

3.按键消抖
由于物理特性,按键按下瞬间会多次置为1/0,俗称抖动
• 所以我们第一次判断出P0_1为0时,需要给一个合理的延时
• 然后再次判断P0_1是否为0
• 如果仍然为0,表示按键按下
其他方案:
• 定时器
八、USART
• 通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter) 是
一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。
• 有别于 USART 还有一个 UART(Universal Asynchronous Receiver and Transmitter),它是
在 USART 基础上裁剪掉了同步通信功能,只有异步通信。(区别:对外提供时钟输出),我们平时用
的串口通信基本都是 UART。
• 通信双方只要采用相同的帧格式和波特率,就能在未共享时钟信号的情况下,仅用两根信号线(Rx
和Tx)就可以完成通信过程,因此也称为异步串行通信
• UART总线双向通信,可以实现全双工传输和接收
• 串行通信一般是以帧格式传输数据,即是一帧一帧的传输,每帧包含有起始信号、数据信息、停止信
息,可能还有校验信息。
1.基本知识
数据收发

- 有无clock
- 一次传多少数据位
- 是否支持同时收发
- 是否需要回复ack
通信基础知识-同步、异步
同步通信
• 在发送数据信号的时候,会同时
送出一根同步时钟信号, 用来同
步发送方和接收方的数据采样频
率。

异步通信
• 数据发送方和数据接收方没有同
步时钟,只有数据信号线,只不
过发送端和接收端会按照协商好
的协议(固定频率)来进行数据
采样。

通信基础知识-串行、并行

最常见的片上通信协议
• 1. UART
• 2. IIC
• 3. SPI
• 4. PCI、PCIE
2.简单应用
UART 是嵌入式最基础的串行通信协议,主要用来调试和连接外设;电脑要和单片机通信,必须用 USB 转 UART 芯片(如 CH340)做电平 / 协议转换,最终通过串口助手交互。

3.代码
UART初始化
c
// 串口初始化函数 (UART0)
void InitUart(void)
{
// 1. 串口引脚位置选择:选择位置1(P0.2=RX,P0.3=TX)
PERCFG = 0x00;
// 2. P0.2、P0.3 设置为外设功能(串口专用,不是普通IO)
P0SEL = 0x0c;
// 3. P0 优先级设置为 UART0 优先
P2DIR &= ~0xC0;
// 4. 设置为 UART 模式
U0CSR |= 0x80;
// 5. 波特率设置为 115200
U0GCR |= 11;
U0BAUD |= 216;
// 6. 清空发送中断标志
UTX0IF = 0;
// 7. 使能串口接收
U0CSR |= 0x40;
// 8. 打开总中断 + 打开串口接收中断
IEN0 |= 0x84;
}
选择串口引脚:P0.2(RX)、P0.3(TX)
将引脚设置为串口外设功能
设置波特率 115200
开启UART 模式
开启接收
开启总中断 + 接收中断
UART 发送
c
void UartSendString(char *Data, int len)
{
uint i;
for(i=0; i<len; i++)
{
U0DBUF = *Data++; // 写一个字节到发送缓冲区
while(UTX0IF == 0); // 等待:直到硬件把 UTX0IF 置1(表示开始发送/发送完成)
UTX0IF = 0; // 软件手动清零,准备下一次发送
}
}
写数据到 U0DBUF → 硬件置 UTX0IF=1 → 等待发送完成 → 软件清 UTX0IF=0 → 继续发下一个字节。
UART 接收
c
// 告诉编译器:这个函数是 UART0 接收中断的处理函数
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{
URX0IF = 0; // 1. 先清中断标志!
RxBuf = U0DBUF; // 2. 再把收到的数据读走保存
}
硬件收到字节 → 置 URX0IF=1 → 触发中断 → 中断函数里先清标志、再读数据 → 完成一次接收。
示例代码
c
while(1)
{
if(UartState == UART0_RX) // 接收状态
{
if(RxBuf != 0)
{
if(RxBuf != '#') && (count < 50)) // 以'#'结束,最多收50个字符
{
RxData[count++] = RxBuf;
}
else
{
if(count == 50)
{
count = 0; // 计数清零
memset(RxData, 0, SIZE); // 清空接收缓冲区
}
else
{
UartState = UART0_TX; // 进入发送状态
}
RxBuf = 0;
}
}
}
if(UartState == UART0_TX) // 发送状态
{
U0CSR &= ~0x40; // 禁止接收
UartSendString(RxData, count); // 发送已记录的字符串
U0CSR |= 0x40; // 允许接收
UartState = UART0_RX; // 恢复到接收状态
count = 0; // 计数清零
memset(RxData, 0, SIZE); // 清空接收缓冲区
}
} // end while 1
九、ADC
1.基础知识
ADC(Analog-to-Digital Converter)的缩写,指模/
数转换器。
• 是指将连续变化的模拟信号转换为离散的数字信号的器
件。
• 真实世界的模拟信号例如温度、压力、声音或者图像等,
需要转换成更容易储存、处理和发射的数字形式。
原理就是1.数字化:
将时间上连续变化的模拟量转化为脉冲有无的数字量(ADC)
2.ADC:
数模转换器,将时间和幅值连续的模拟量转化为时间和幅值离散的数字量
3.过程:
采样、保持、量化、编码
几个技术指标量程:
• ADC所能输入模拟信号的类型和电压范围(参考电压),信号类型
包括单极性和双极性
• 转换位数:
• 量化过程中的量化位数n,A/D转换后的输出结果用n位二进制数表
示
• 分辨率:
• ADC能够分辨的模拟信号最小变化量,分辨率 = 量程 / 2^n
• 转换时间:
• ADC完成一次完整的A/D转换所用时间,包括采样、保持、量化、
编码的全过程
2.代码
- 清EOC标志 读取ADCH
- 设置参考电源电压、抽取率、ADC通道 ADCCON3
- 使能A/D转换 ADCCON1 PS:ADCCON1 管启动,ADCCON3 管设置!
- 等待转换完毕 while (!(ADCCON1 & 0x80));
- 读取数据 ADCL/ADCH
- 转换成模拟值 (float)value*3.3/2^n
c
// ADC初始化函数
void InitialAD(void)
{
P1DIR = 0x03; // P1口控制LED
led1 = 1; // 关LED
led2 = 1; // 关LED
ADCCON1 &= 0x0C; // 清EOC标志(转换结束标志)
ADCCON3 = 0xBF; // 1011 1111:单次转换,参考电压为电源电压,对1/3 VDD进行A/D转换
// 14位分辨率
ADCCON2 = 0x30; // 停止A/D(配置参数)
ADCCON1 |= 0x40; // 启动A/D转换
}
// 主循环
while(1)
{
if(ADCCON1 >= 0x80) // 等待转换完成(EOC=1)
{
led1 = 0; // 转换完毕指示(点亮LED)
// 拼接ADC数据
uint16 reading = ADCL;
reading |= (uint16)ADCH << 8;
reading >>= 2; // 右移2位,对齐有效数据(14位结果)
ADCCON1 |= 0x40; // 开始下一次A/D转换
// 转换为模拟电压值(参考电压3.3V,14位精度,含符号位,有效位13位)
float num = (float)reading * 3.3 / 8192; // 2^13 = 8192
// 格式化字符串并通过串口发送给PC
sprintf(strTemp, "vol:%.2fV", num);
UartSendString(strTemp, 12); // 发送字符串(包含空格等)
DelayMS(1000);
led1 = 1; // 完成数据处理(熄灭LED)
DelayMS(1000);
}
}
十、光敏
1.基本知识
光敏电阻器是利用半导体的光电效应制成的一种电阻值
随入射光的强弱而改变的电阻器; 入射光强,电阻减小,
入射光弱,电阻增大。
• 光敏电阻器一般用于光的测量、光的控制和光 电转换
(将光的变化转换为电的变化)

2、电路图

3.代码
ADC输入使用
- 当使用ADC时,端口0 对应的引脚必须配置为 ADC输
入。 - 8个 ADC输入引脚。
- 要配置一个端口0 引脚为一个ADC输入,APCFG寄存
器中相应的位必须设置为1(默认值选择端口0引脚为非ADC
输入) - APCFG 寄存器的设置将覆盖P0SEL的设置。
驱动分析
c
// 读取光照强度传感器的ADC值函数
uint16 myApp_ReadLightLevel(void)
{
uint16 reading = 0; // 定义变量,保存最终ADC结果
/* 1. 使能ADC对应通道(这里是AIN6通道) */
ADCCFG |= 0x40; // 将AIN6设为模拟输入,开启ADC通道功能
/* 2. 配置ADC参数并启动单次转换 */
ADCCON3 = 0xb6; // 设置参考电压、分辨率、输入通道(光照传感器通道)
/* 3. 启动A/D转换 */
ADCCON1 |= 0x40; // 写1启动ADC开始转换
/* 4. 等待转换完成 */
// ADCCON1的第7位(EOC)=1表示转换结束
while (!(ADCCON1 & 0x80));
/* 5. 转换完成,关闭ADC通道,释放IO */
ADCCFG &= ~0x40; // 关闭AIN6的模拟输入功能
/* 6. 读取ADC转换结果(高低字节拼接) */
reading = ADCL; // 读取低8位
reading |= (int16)(ADCH << 8); // 读取高8位并左移8位,拼接成16位数据
/* 7. 数据对齐:14位ADC结果需要右移2位才是有效数据 */
reading >>= 2;
/* 返回最终采集到的光照ADC数值 */
return (reading);
}
十一、MQ-2烟雾传感器
1.基本知识
敏式烟雾传感器的典型型号有MQ-2气体传感器。
• 该传感器常用于家庭和工厂的气体泄漏装置,适宜于液化气、丁烷、丙烷、甲烷、酒精、氢气、烟雾等的探测。

2.电路图

代码
ADC 已经在别的地方【全局初始化】过了,
这里只是【单次采集函数】,不是初始化!
c
// 读取气体传感器ADC值的函数
uint16 myApp_ReadGasLevel(void)
{
uint16 reading = 0;
/* 1. 使能ADC通道(这里是AIN7通道) */
ADCCFG |= 0x80;
/* 2. 配置ADC参数并启动单次转换 */
ADCCON3 = 0x87;
/* 3. 等待转换完成 */
while (!(ADCCON1 & 0x80));
/* 4. 转换完成后,关闭ADC通道,释放IO */
ADCCFG &= (0x80 ^ 0xFF); // 等价于 ADCCFG &= ~0x80
/* 5. 读取ADC转换结果(高低字节拼接) */
reading = ADCL;
reading |= (int16)(ADCH << 8);
/* 6. 数据对齐:12位ADC结果需要右移8位得到有效数据 */
reading >>= 8;
/* 返回最终采集到的气体传感器ADC数值 */
return (reading);
}
十二、温湿度传感器DHT11
1.基本知识
DHT11是一款有已校准数字信号输出的温湿度传感器。
• 其精度湿度±5%RH, 温度±2℃,量程湿度5~95%RH,
温度-20~+60℃。

CC2530如何数据读取
- DHT11之间的通讯和同步,采用单总线数据格式
- 一次通讯时间4ms左右
- 数据分小数部分和整数部分,当前小数部分用于以后扩
展,现读出为零- 一次完整的数据传输为40bit,高位先出。
数据格式数据格式:
• 8bit湿度整数数据+8bit湿度小数数据 +8bit温度整数数据
+8bit温度小数数据 +8bit校验和
校验和
• 8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据
+8bit温度小数数据 所得结果的末8位。
2.电路图
电路图

3.代码
1.DHT11 启动与数据接收函数
c
// DHT11温湿传感器启动与数据读取函数
void DHT11(void)
{
P0DIR |= 0x10; // 配置P0.4为输出方向
DATA_PIN = 0; // 拉低总线,发送开始信号
Delay_ms(19); // 保持低电平≥18ms,触发DHT11
DATA_PIN = 1; // 释放总线,拉高等待应答
P0DIR &= ~0x10; // 重新配置P0.4为输入方向
Delay_10us(); // 等待DHT11拉低应答
Delay_10us();
Delay_10us();
Delay_10us();
if(!DATA_PIN) // 检测到DHT11低电平应答
{
while(!DATA_PIN); // 等待应答低电平结束
while(DATA_PIN); // 等待应答高电平结束,准备接收数据
// 读取5字节数据:湿度高位、湿度低位、温度高位、温度低位、校验和
COM();
ucharRH_data_H_temp=ucharcomdata;
COM();
ucharRH_data_L_temp=ucharcomdata;
COM();
ucharT_data_H_temp=ucharcomdata;
COM();
ucharT_data_L_temp=ucharcomdata;
COM();
ucharcheckdata_temp=ucharcomdata;
DATA_PIN = 1; // 释放总线
// 校验和验证
uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp);
if(uchartemp==ucharcheckdata_temp)
{
// 校验通过,保存有效数据
ucharRH_data_H=ucharRH_data_H_temp;
ucharRH_data_L=ucharRH_data_L_temp;
ucharT_data_H=ucharT_data_H_temp;
ucharT_data_L=ucharT_data_L_temp;
ucharcheckdata=ucharcheckdata_temp;
}
}
}
作用:实现与 DHT11 温湿度传感器的通信握手,并完成一帧数据的读取与校验。
通信握手:
拉低总线 ≥18ms,向 DHT11 发送 "开始采集" 信号。
释放总线并切换为输入模式,等待 DHT11 应答。
检测 DHT11 拉低应答信号,确认传感器准备好发送数据。
数据读取:
调用 COM() 函数,依次读取 5 字节数据:湿度高位、湿度低位、温度高位、温度低位、校验和。
数据校验 :
计算前 4 字节数据之和,与第 5 字节校验和对比。
校验通过则保存有效温湿度数据,否则丢弃本次数据。
- 单字节数据接收函数
c
// 从DHT11单总线读取1字节数据(8位)
void COM(void)
{
uchar i;
for(i=0;i<8;i++) // 循环读取8位,组成1字节
{
while(!DATA_PIN); // 等待数据位的起始低电平结束
Delay_10us(); // 延时30us左右,进入数据位中部
Delay_10us();
Delay_10us();
uchartemp=0;
if(DATA_PIN) // 判断当前电平:高电平=1,低电平=0
uchartemp=1;
while(DATA_PIN); // 等待当前数据位的高电平结束
ucharcomdata<<=1; // 数据左移,为下一位腾出位置
ucharcomdata|=uchartemp; // 将当前位写入字节
}
}
时序解析:
等待总线低电平结束(每个数据位的起始信号)。
延时 30us 后,读取总线电平:
高电平 → 数据位 1
低电平 → 数据位 0
等待当前数据位的高电平结束,准备读取下一位。
数据拼接:
通过左移和按位或操作,将 8 个数据位拼接成 1 字节,存入 ucharcomdata。
十三、屏幕
1.像素
红色(R:255,G:0,B:0):
0xFF0000
绿色(R:0,G:255,B:0):
0x00FF00
蓝色(R:0,G:0,B:255):
0x0000FF
嵌入式系统常常资源有限,使用三个字节表示一个像素
过于消耗内存
• 所以在小型嵌入式系统中,常常使用两个字节(16Bit)来
表示一个像素的颜色。

2.电路图

3.SPI
硬件SPI和软件SPI
本实验用的是软件SPI的方式来控制LCD。
好处是可以使用任意的单片机引脚连接LCD,
缺点是发送速度没有硬件SPI快,而且占用CPU资源。
硬件SPI就是使用单片机特定的SPI引脚来进行通信。

4.代码
需要移植的代码(基本上网上都有)
1.hal_lcd.c
Lcd屏幕驱动
2.hal_lcd.h
对应头文件
3.hal_types.h
变量类型定义
4.pic.c
自己制作的图片临时文件
5.Chinese.h
汉字字模
驱动部分代码要稍微改下
c
static void halLcd_ConfigIO(void)
{
#define LCD_DC P1_6 // A0 H/L 命令数据选通端,H:数据,L:命令
#define LCD_SCL P1_7 // SCLK 时钟 D0(SCLK)
#define LCD_SDA P1_5 // SDA D1(MOSI) 数据
#define LCD_REST P1_2 // 复位端
P1SEL &= ~0xc4; // 让P1.2、P1.5、P1.6、P1.7为普通IO口
P1DIR |= 0xc4; // 把P1.2、P1.5、P1.6、P1.7设置为输出
LCD_DC = 1;
LCD_SCL = 1;
LCD_SDA = 1;
LCD_REST = 1;
}

.pic.c
自己制作的图片临时文件,用相应软件制作


