写点什么

基于 CC2530 设计智慧农业控制系统

作者:DS小龙哥
  • 2023-06-23
    湖北
  • 本文字数:4791 字

    阅读完需:约 16 分钟

一、项目背景

智慧农业是近年来发展迅速的领域,其目的是利用先进的传感技术、物联网技术和云计算技术等,实现自动化、智能化的农业生产管理,并提高农业生产效率和质量。本文基于 CC2530 设计了一种智慧农业控制系统,采用 DHT11 模块、BH1750 模块和土壤湿度传感器等传感器,通过串口协议将采集的数据上传给上位机显示。

二、系统框架

本系统主要包括一下的组成部分:


【1】采集端:由 CC2530 单片机和各种传感器构成,负责测量环境温湿度、环境光照强度和土壤湿度等信息,并通过串口协议将采集的数据上传给上位机显示。


【2】上位机:采用 Qt 进行开发,负责接收串口上传的数据并进行显示。


【3】传输介质:采用串口协议进行数据传输,支持异步通信,具有数据帧结构。


【4】传感器模块:包括 DHT11 模块、BH1750 模块和土壤湿度传感器等,通过采集环境温湿度、环境光照强度和土壤湿度等信息,实现对农业生产环境的监测和控制。




CC2530 是德州仪器(Texas Instruments)推出的一款低功耗无线系统芯片,它是基于 ZigBee 协议的 SoC 系统,内置了 ARM Cortex-M3 处理器和 IEEE 802.15.4 标准无线通信模块,可以实现低速率的无线数据传输和网络互连。CC2530 芯片的主要特点是低功耗、高可靠性、灵活性强、易于集成和开发,被广泛应用于物联网、智能家居、智能电表、智能照明等领域的无线数据传输和控制系统中。



BH1750 是一款数字式环境光传感器,可用于测量光强度。它具有高分辨率和灵敏度,并且与普通光敏电阻相比,具有更广泛的动态范围和线性性。BH1750 可以通过 I2C 接口连接到微控制器或其他电子设备上,如 Arduino、树莓派等。它被广泛应用于夜间照明系统、自动控制系统、安防监控等领域。



DHT11 是一种数字温湿度传感器,可以测量环境的温度和相对湿度。它通常被用于家庭和工业自动化等领域,可以在各种应用中监测环境条件。


DHT11 有四个引脚:VCC(电源正极)、GND(地)、DATA(数据信号)和 NC(未使用)。它可以通过单一总线接口与微控制器连接,并以数字形式输出温度和湿度值。其温度测量范围为 0℃至 50℃,湿度测量范围为 20%RH 至 90%RH。


在使用 DHT11 传感器时,需要注意一些问题。例如,在读取数据之前,应将传感器加电并等待 1 至 2 秒钟,以使其稳定。此外,在读取数据后,还需要进行数据校验,以确保数据的准确性。


三、系统设计

【1】采集端设计


采集端主要由 CC2530 单片机和各种传感器构成。其中,温湿度采用 DHT11 模块,光照强度采用 BH1750 模块,土壤湿度采用土壤湿度传感器。通过采集这些信息,可以了解农田的环境状态,并根据需要进行相应的调节和控制,保证作物的正常生长。


【2】上位机设计


上位机采用 QT 进行开发,支持串口通信和数据显示。在数据传输端口的配置上,串口通信采用异步通信方式,支持数据帧结构,即每个数据包由起始位、数据位、校验码、停止位等几部分组成,以确保数据传输的稳定性和可靠性。同时,上位机还实现了数据的动态显示和历史数据的查询导出功能,以方便用户对农田环境数据进行分析和处理。

四、上位机源码实现

以下是 Qt 串口读取数据的实现代码:


#include <QCoreApplication>#include <QtSerialPort/QSerialPort>#include <QtSerialPort/QSerialPortInfo>#include <QDebug>
int main(int argc, char *argv[]){ QCoreApplication a(argc, argv);
QSerialPort serial; serial.setPortName("COM1"); // 根据实际情况设置端口号 if (!serial.open(QIODevice::ReadWrite)) { // 打开串口 qDebug() << "Failed to open serial port!"; return 1; }
// 设置串口参数 serial.setBaudRate(QSerialPort::Baud115200); serial.setDataBits(QSerialPort::Data8); serial.setParity(QSerialPort::NoParity); serial.setStopBits(QSerialPort::OneStop); serial.setFlowControl(QSerialPort::NoFlowControl);
while (true) { if (serial.waitForReadyRead(1000)) { // 等待数据 QByteArray data = serial.readAll(); // 读取所有数据 qDebug() << "Received data:" << data; // 打印所有数据
// 解析数据 QStringList dataList = QString(data).split(","); if (dataList.size() == 4) { float temperature = dataList[0].toFloat(); float humidity = dataList[1].toFloat(); float illumination = dataList[2].toFloat(); float soilMoisture = dataList[3].toFloat();
// 打印解析后的数据 qDebug() << "Temperature:" << temperature << "°C"; qDebug() << "Humidity:" << humidity << "%"; qDebug() << "Illumination:" << illumination << "lux"; qDebug() << "Soil Moisture:" << soilMoisture << "%"; } } }
return a.exec();}
复制代码


读取数据时,采用了 waitForReadyRead 函数等待串口数据到达,该函数的参数表示最长等待时间,单位为毫秒。在解析数据时,使用了 QString 的 split 函数将数据按逗号分隔为多个字符串,再分别转换为对应的浮点数。

五、CC2530 设备端源码

【1】BH1750 数据读取

以下是 CC2530 单片机读取 BH1750 光敏传感器的值并打印到串口的代码:


#include "hal_board_cfg.h"#include "hal_types.h"#include "hal_defs.h"#include "hal_uart.h"#include "onboard.h"#include "hal_i2c.h"
#define BH1750_ADDR 0x23 // BH1750默认地址
void initUART();void sendStr(char *str);void BH1750_init();uint16 BH1750_read();
void main(){ // 初始化 halBoardInit(); initUART(); BH1750_init();
while (TRUE) { // 读取传感器数据 uint16 illumination = BH1750_read(); char str[16]; sprintf(str, "%d", illumination);
// 将数据打印到串口 sendStr(str);
// 延时等待1秒 halMcuWaitMs(1000); }}
void initUART(){ HAL_UART_CFG_T uartCfg;
uartCfg.baudRate = HAL_UART_BR_115200; uartCfg.flowControl = FALSE; uartCfg.parity = HAL_UART_PARITY_NONE; uartCfg.stopBits = HAL_UART_STOP_BITS_1; uartCfg.startGuardTime = 0;
HalUARTInit(); HalUARTOpen(HAL_UART_PORT_0, &uartCfg);}
void sendStr(char *str){ while (*str != '\0') { HalUARTWrite(HAL_UART_PORT_0, (uint8*)str, 1); str++; }
HalUARTWrite(HAL_UART_PORT_0, (uint8*)"\r\n", 2);}
void BH1750_init(){ uint8 pBuf[2];
pBuf[0] = 0x01; // 开始测量命令 halI2CWrite(BH1750_ADDR, pBuf, 1);
pBuf[0] = 0x10; // 分辨率设置为1lx halI2CWrite(BH1750_ADDR, pBuf, 1);}
uint16 BH1750_read(){ uint8 pBuf[2];
halI2CRead(BH1750_ADDR, pBuf, 2);
uint16 illumination = (pBuf[0] << 8) | pBuf[1];
return illumination;}
复制代码


上述代码中,initUART 函数用于初始化串口,sendStr 函数用于将字符串打印到串口。BH1750_init 函数用于初始化 BH1750 传感器,包括发送开始测量指令和设置分辨率为 1lx 等操作。BH1750_read 函数用于读取传感器数据并计算出光照强度值。在 main 函数中,使用了一个 while 循环不断从传感器读取数据,并通过串口打印输出。代码中的延时函数 halMcuWaitMs 是 CC2530 提供的延时函数,可以使用其他方式实现延时等待功能。

【2】DHT11 温湿度数据读取

以下是 CC2530 单片机读取 DHT11 传感器的温度和湿度并打印到串口的代码:


#include "hal_types.h"#include "hal_board.h"#include "hal_uart.h"
#define DHT11_PORT 1 // DHT11连接到P1口
// 发送一个DHT11开始信号void DHT11_Start(void) { // 设置引脚为输出模式 P1SEL &= ~(1 << DHT11_PORT); P1DIR |= (1 << DHT11_PORT);
// 拉低引脚 P1_1 = 0;
// 等待至少18ms HalDelayMs(18);
// 拉高引脚 P1_1 = 1;
// 等待20~40us,并切换到输入模式 HalDelayUs(30); P1DIR &= ~(1 << DHT11_PORT);}
// 等待DHT11响应信号uint8 DHT11_WaitResponse(void) { uint8 timeOut = 0; while(P1_1 && timeOut < 200) { // 等待低电平出现,超时返回1 HalDelayUs(1); timeOut++; } if(timeOut >= 200) return 1;
timeOut = 0; while(!P1_1 && timeOut < 200) { // 等待高电平出现,超时返回1 HalDelayUs(1); timeOut++; } if(timeOut >= 200) return 1;
return 0;}
// 读取一个位uint8 DHT11_ReadBit(void) { uint8 timeOut = 0; while(P1_1 && timeOut < 200) { // 等待低电平出现,超时返回1 HalDelayUs(1); timeOut++; }
timeOut = 0; while(!P1_1 && timeOut < 200) { // 等待高电平出现,超时返回1 HalDelayUs(1); timeOut++; }
HalDelayUs(40); // 等待40us
if(P1_1) return 1; // 如果在40us内未出现低电平,返回1,表示数据错误
return 0;}
// 读取一个字节uint8 DHT11_ReadByte(void) { uint8 byte = 0; uint8 i; for(i=0;i<8;i++) { byte <<= 1; byte |= DHT11_ReadBit(); } return byte;}
// 从DHT11读取温度和湿度数据void DHT11_ReadData(uint8* temperature, uint8* humidity) { uint8 data[5];
// 发送开始信号 DHT11_Start();
// 等待响应信号 if(DHT11_WaitResponse()) { *temperature = 0; *humidity = 0; return; }
// 读取数据 data[0] = DHT11_ReadByte(); // 湿度整数部分 data[1] = DHT11_ReadByte(); // 湿度小数部分 data[2] = DHT11_ReadByte(); // 温度整数部分 data[3] = DHT11_ReadByte(); // 温度小数部分 data[4] = DHT11_ReadByte(); // 校验和
// 计算校验和 uint8 sum = data[0] + data[1] + data[2] + data[3]; if(sum != data[4]) { *temperature = 0; *humidity = 0; return; }
// 计算温度和湿度 *humidity = data[0]; *temperature = data[2];}
// 初始化串口void UART_Init(void) { HalUARTInit(); HalUARTCfg_t uartConfig; uartConfig.configured = TRUE; uartConfig.baudRate = HAL_UART_BR_115200; uartConfig.flowControl = FALSE; uartConfig.flowControlThreshold = 64; // 设置串口传输格式uartConfig.rx.maxBufSize = 128;uartConfig.tx.maxBufSize = 128;uartConfig.idleTimeout = 6;uartConfig.intEnable = TRUE;uartConfig.callBackFunc = NULL;HalUARTOpen(HAL_UART_PORT_0, &uartConfig);}
// 打印温度和湿度到串口void PrintData(uint8 temperature, uint8 humidity) {char buf[32];sprintf(buf, "Temperature: %dC, Humidity: %d%%\r\n", temperature, humidity);HalUARTWrite(HAL_UART_PORT_0, (uint8*)buf, strlen(buf));}
void main(void) {uint8 temperature, humidity;
// 初始化串口UART_Init();
while(1) {// 从DHT11读取数据DHT11_ReadData(&temperature, &humidity);
// 打印数据到串口PrintData(temperature, humidity);
// 等待1秒钟HalDelayMs(1000);}}
复制代码


这段代码使用 CC2530 单片机通过 DHT11 传感器读取环境温度和湿度,并将其打印到串口。具体实现过程为,首先发送一个开始信号,等待 DHT11 响应信号后,依次读取湿度整数、湿度小数、温度整数、温度小数和校验和。判断校验和是否正确后,计算得到温度和湿度,并通过串口输出。为了保证数据的准确性,每次读取数据前需要等待 1 秒钟。

发布于: 刚刚阅读数: 2
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022-01-06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
基于CC2530设计智慧农业控制系统_6 月优质更文活动_DS小龙哥_InfoQ写作社区