温度,湿度,CO2作为农业生产中中非常重要的参数,需要准确的采样。该系统完成对于上述参数的精确采样,通过LCD显示在面板上,并将测量值发送到上位机进行显示。
(1)测量对应的温度、湿度、CO2的值。
(2)用OLED显示实际的温度值和湿度值
(3)实现对温度,湿度,CO2的实时采集。
(4)如果温湿度低于或者高于设定值,采取对应措施升降温和升降湿度值。
(5)在上位机上设计监测界面,实时显示各个测量值。
源码
链接:https://pan.baidu.com/s/1PWT5x9oD2lo6c3Wlz6RVfg
提取码:6666
控制器:stm32f407vet6核心板
显示屏:0.96寸OLED (SPI接口)
温湿度传感器:DHT11
CO2浓度传感器:SGP30 (I2C接口)
stm32编程软件:CUBEMX,keil5
上位机软件设计工具:MATLAB APP Designer
通过DHT11采集温湿度和SGP30采集二氧化碳并通过OLED实时显示,1s刷新一次,通过串口将采集到的数据上传到用MATLAB做的界面中。
//包含显示、初始化、和传感器读数程序
int main(void)
{
uint32_t CO2Data,TVOCData;//定义CO2浓度变量与TVOC浓度变量
uint16_t temperature;
uint16_t humidity;
unsigned long sgp30_dat;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_TIM6_Init();
MX_SPI2_Init();
HAL_UART_Receive_DMA(&huart1,aRxBuffer,1); //串口DMA初始化
OLED_Init(); //OLED初始化
Show_Str(0, 2,"Initializing...", 16, 0); //显示初始化中...
//DHT11初始化
while(DHT11_Init()){
HAL_Delay(500);
}
//初始化SGP30
SGP30_Init();
HAL_Delay(100);
SGP30_Write(0x20,0x08);
sgp30_dat = SGP30_Read();//读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16;
TVOCData = sgp30_dat & 0x0000ffff;
//SGP30模块开机需要一定时间初始化,在初始化阶段读取的CO2浓度为400ppm,TVOC为0ppd且恒定不变,因此上电后每隔500ms读取一次
//SGP30模块的值,如果CO2浓度为400ppm,TVOC为0ppd,则屏幕闪烁显示“正在检测中...”,直到SGP30模块初始化完成。
while(CO2Data == 400 && TVOCData == 0)
{
SGP30_Write(0x20,0x08);
sgp30_dat = SGP30_Read();//读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
TVOCData = sgp30_dat & 0x0000ffff; //取出TVOC值
HAL_Delay(500);
}
OLED_Clear(); //清屏
while (1)
{
DHT11_Read_Data(&temperature,&humidity); //读取温度湿度值
SGP30_Write(0x20,0x08);
sgp30_dat = SGP30_Read();//读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
printf("%02d%1d",temperature>>8,temperature&0xff);
printf("%02d%1d",humidity>>8,humidity&0xff);
printf("%03d",CO2Data);
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_6);
//OLED显示
//温度显示
Show_Str(4, 1,"temp:", 16, 0);
OLED_ShowNum(40,1,temperature>>8,3,16);
Show_Str(64, 1,".", 16, 0);
OLED_ShowNum(72,1,temperature&0xff,1,16);
Show_Str(84,1,"℃", 16, 0);
//湿度显示
Show_Str(4, 3,"humi:", 16, 0);
OLED_ShowNum(40,3,humidity>>8,3,16);
Show_Str(64, 3,".", 16, 0);
OLED_ShowNum(72,3,humidity&0xff,1,16);
Show_Str(84, 3,"%RH", 16, 0);
//CO2浓度显示
Show_Str(4, 5,"CO2:", 16, 0);
OLED_ShowNum(40,5,CO2Data,3,16);
Show_Str(70, 5,"PPM", 16, 0);
HAL_Delay(1000); //延时1s
}
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
uint8_t DHT11_Init(void)
{
DHT11_Rst();
return DHT11_Check();
}
//复位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //设置为输出
DHT11_DQ_OUT_LOW; //拉低DQ
HAL_Delay(20); //拉低至少18ms
DHT11_DQ_OUT_HIGH; //DQ=1
delay_us(30); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8_t DHT11_Check(void)
{
uint8_t retry=0;
DHT11_IO_IN(); //设置为输出
while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
return 0;
}
//从DHT11读取一次数据
//返回值:0,正常;1,读取失败
uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi)
{
uint8_t buf[5];
uint8_t i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//读取40位数据
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=(buf[0]<<8) + buf[1];
*temp=(buf[2]<<8) + buf[3];
}
}else return 1;
return 0;
}
//初始化IIC接口
void SGP30_Init(void)
{
SGP30_Write(0x20, 0x03);
}
5.SGP30模块测量CO2
uint32_t SGP30_Read(void)
{
uint32_t dat;
uint8_t crc;
SGP30_IIC_Start();
SGP30_IIC_Send_Byte(SGP30_read); //发送器件地址+读指令
SGP30_IIC_Wait_Ack();
dat = SGP30_IIC_Read_Byte(1);
dat <<= 8;
dat += SGP30_IIC_Read_Byte(1);
crc = SGP30_IIC_Read_Byte(1); //crc数据,舍去
crc = crc; //为了不让出现编译警告
dat <<= 8;
dat += SGP30_IIC_Read_Byte(1);
dat <<= 8;
dat += SGP30_IIC_Read_Byte(0);
SGP30_IIC_Stop();
return(dat);
}
App 设计工具并不要求软件开发专业背景。您只需拖放可视化组件即可实现图形用户界面 (GUI) 设计布局,还可以使用集成的编辑器快速为其行为编程。
App 设计工具集成了 App 构建的两大任务:图形用户界面 (GUI) 可视化组件布局,以及 App 行为编程。要在 MATLAB 中构建 App,App 设计工具是十分理想的环境。
在matlab命令行中输入appdesigner
>> appdesigner
将可视化组件拖放到设计画布,然后根据对齐提示实现精确布局。App 设计工具自动生成面向对象的代码,用于指定 App 的布局和设计。
其会自动生成代码。使用集成的 MATLAB 编辑器来定义 App 的行为。App 设计工具可以使用代码分析器自动检查代码问题。您可以在编写代码时查看关于代码的警告和错误消息,并根据这些消息修改您的 App。您还可以使用 Stateflow® 图对 App 行为建模。
生成自己的APP,双击.exe文件即可运行。
properties (Access = public)
COM; % 端口号
s ; %端口设置句柄
RX_num; %接收统计
TX_num; %发送统计
RX_once;%一次接收的数据
RX_Date;%接收的所以数据
is_open;%是否打开串口标志位
end
methods (Access = public)
function EveBytesAvailableFcn(app, src, event)
global i;
n = src.BytesAvailable;%获取接收到的字符个数
if n>0%n>0才继续执行,因为0为0也会触发中断
app.RX_num=app.RX_num+n;
%app.Label_RX.Text=num2str(app.RX_num);%将数字转化为字符串输出
app.RX_once=fread(src,n,'uchar');%读取函数,读取后矩阵为一列
app.RX_Date =strcat(app.RX_Date, app.RX_once');%字符串拼接,需要转置化为一行
%app.ReceiveView.Value= app.RX_Date;%textarea的设置格式为cell,或单行字符串
%温度显示
temp=floor(str2double(app.RX_Date)/1000000)*0.1;
app.Temp.Value=temp;
app.Gauge_Temp.Value=temp;
%温度最低最高值判断
if temp>=str2double(app.TextArea_Temp.Value)
app.Lamp_Temp.Color="1.00,0.00,0.00";
else
app.Lamp_Temp.Color="0.00,1.00,0.00";
end
if temp<=str2double(app.TextArea_Temp_2.Value)
app.Lamp_Temp_2.Color="1.00,0.00,0.00";
else
app.Lamp_Temp_2.Color="0.00,1.00,0.00";
end
%湿度显示
humi=mod((floor(str2double(app.RX_Date)/1000)),1000)*0.1;
app.Humi.Value=humi;
app.Gauge_Humi.Value=humi;
%波形显示
plot(app.UIAxes,i,temp,'r.');
plot(app.UIAxes_2,i,humi,'b.');
if i==20
i=0;
cla(app.UIAxes);
cla(app.UIAxes_2);
else
hold(app.UIAxes,'on'); % 这样就可以hold住了
hold(app.UIAxes_2,'on'); % 这样就可以hold住了
i=i+1;
End
%湿度最低最高值判断
if humi>=str2double(app.TextArea_Humi.Value)
app.Lamp_Humi.Color="1.00,0.00,0.00";
else
app.Lamp_Humi.Color="0.00,1.00,0.00";
end
if humi<=str2double(app.TextArea_Humi_2.Value)
app.Lamp_Humi_2.Color="1.00,0.00,0.00";
else
app.Lamp_Humi_2.Color="0.00,1.00,0.00";
end
%CO2显示
co2=mod(str2double(app.RX_Date),1000);
app.CO2.Value=co2;
app.Gauge_CO2.Value=co2;
if co2>=str2double(app.TextArea_CO2.Value)
app.Lamp_CO2.Color="1.00,0.00,0.00";
else
app.Lamp_CO2.Color="0.00,1.00,0.00";
end
app.RX_Date ='';
%app.ReceiveView.Value= app.RX_Date;
%app.TX_num=0;
%app.RX_num=0;
%app.Label_TX.Text=num2str(app.TX_num);
%app.Label_RX.Text=num2str(app.RX_num);
end
end
end
function Button_SendPushed(app, event)
%val=app.transmitView.Value;
val=strcat(strcat(app.TextArea_Temp.Value,app.TextArea_Humi.Value),app.TextArea_CO2.Value);
%val=num2str(app.EditField_Temp.Value);
if ~isempty(val{1})%textarea控件是cell格式,获取需要用{1}
app.TX_num=app.TX_num+length(val{1});
%app.Label_TX.Text=num2str(app.TX_num);
fwrite(app.s, char(val), 'uint8', 'async');%需要将val转化为char
End
function pbOpenSerialValueChanged2(app, event)
app.COM=get(app.ppCOM,'Value');
if strcmp(get(app.pbOpenSerial,'Text'),'打开串口')
try
app.s=serial(app.COM);
app.s.BaudRate=str2num(app.Baud.Value);%设置波特率 app.s.DataBits=8;%设置数据长度
app.s.StopBits=1;%设置停止位长度
app.s.InputBufferSize=1024000;%设置输入缓冲区大小为1M
app.s.BytesAvailableFcnMode='byte'; %串口事件回调设置
app.s.BytesAvailableFcnCount=1; %输入缓冲区存在10个字节触发回调函数
app.s.BytesAvailableFcn={@app.EveBytesAvailableFcn};%回调函数的指定
fopen(app.s);%打开串口
app.is_open=1;
app.pbOpenSerial.Text='关闭串口';
app.Lamp.Color=[0 1 0];
catch err
msgbox('打开失败');
end
else
try
fclose(app.s);
app.pbOpenSerial.Text='打开串口';
app.Lamp.Color=[0.15 0.15 0.15];
catch err
msgbox('关闭失败');
end
delete(app.s);
app.is_open=0;
end
end
https://download.csdn.net/download/qq_44181970/74730641
解决方法: 先初始化DMA,再初始化串口
us延时配置问题,应将168-1更改为84-1。