元件清單:
stm32f103c8t6、mq2 檢測煙霧濃度(模擬量輸出)、mq7 檢測一氧化碳濃度、mq135 檢測空氣質(zhì)量、OLED屏幕(四引腳僅支持iic協(xié)議通信)、dht11檢測溫濕度(數(shù)字量輸出)、風(fēng)扇模塊、無源蜂鳴器、兩引腳按鍵、WH-NB73-B5、ttl-usb
接線圖:
?0:實現(xiàn)了dht11的溫濕度以及mq2煙霧濃度的采集并通過OLED顯示屏顯示
/*
濕度整數(shù) 濕度小數(shù) 溫度整數(shù) 溫度小數(shù) 校驗位
00000000 00000000 00000000 00000000 00000000
1 看原理圖確認GPIO引腳
2、 輸出模式, 輸出起始信號 :輸出低電平18~30ms, 20ms
3、 IO口配置浮空輸入模式,準檢測響應(yīng)信號
傳感器把數(shù)據(jù)總線( SDA)拉低 83μs,
再接高 87μs 以響應(yīng)主機的起始信號。
4、 40 個位的數(shù)據(jù),高位先發(fā);
一位一位的收,數(shù)據(jù)0: 54us低電平 + 23~27高電平
數(shù)據(jù)1: 54us低電平 + 68~74高電平
注意高位先發(fā)的(每個字節(jié))
5、校驗數(shù)據(jù)
前4個字節(jié),求和,把和值的末八位和校驗位對比
相同數(shù)據(jù)正確、否則數(shù)據(jù)異常
*/
//程序未寫零下
char tmp = 0,hum = 0;
void DHT_GPIO_Config(u8 flag)
{
GPIO_InitTypeDef GPIO_Config;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //開啟端口時鐘
GPIO_Config.GPIO_Pin = GPIO_Pin_8;
if(flag==OUTPUT)
GPIO_Config.GPIO_Mode = GPIO_Mode_Out_PP;//推挽輸出
else
GPIO_Config.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Config.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_Config);
}
u8 DHT_GetData(void)
{
u8 i = 0;
u8 count = 0;
u8 data[5]={0};
//輸出模式, 輸出起始信號 :輸出低電平18~30ms, 20ms
DHT_GPIO_Config(OUTPUT);
DHT_High;
DHT_Low;
Delay_ms(20);
//DHT_High;
DHT_GPIO_Config(INPUT);
/*IO口配置浮空輸入模式,準檢測響應(yīng)信號
傳感器把數(shù)據(jù)總線( SDA)拉低 83μs,
再接高 87μs 以響應(yīng)主機的起始信號。
*/
while(DHT_CHECK==1)
{
delay_1us();
count++;
if(count>100)
return 1;
}
count=0;
while(DHT_CHECK==0)
{
delay_1us();
count++;
if(count>100)
return 2;
}
for(i=0;i<40;i++)
{
count=0;
while(DHT_CHECK==1)
{
delay_1us();
count++;
if(count>100)
return 3;
}
count=0;
while(DHT_CHECK==0)
{
delay_1us();
count++;
if(count>100)
return 4;
}
Delay_us(30);
if(DHT_CHECK==1)
{
data[i/8] |= (1<<(7-i%8)); //置1
}else
{
data[i/8] &=~ (1<<(7-i%8));//清零
}
}
/*校驗數(shù)據(jù)
前4個字節(jié),求和,把和值的末八位和校驗位對比
相同數(shù)據(jù)正確、否則數(shù)據(jù)異常*/
if((data[0]+data[1]+data[2]+data[3])==data[4])
{
tmp=data[2];
hum=data[0];
return 0;
}
else
{
return 5;
}
}
1:在上邊的基礎(chǔ)上利用DMA實現(xiàn)多通道的數(shù)據(jù)采集(設(shè)置閥值,驅(qū)動風(fēng)扇轉(zhuǎn)動,并可手動按鍵改變閥值,并在屏幕顯示變化;通過NB模塊上傳數(shù)據(jù)至有人云)
//mq2 mq7 mq135的采集
void ADC1_Config(void)
{
GPIO_InitTypeDef GPIO_Struct = {0};
ADC_InitTypeDef ADC_Struct = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_Struct.GPIO_Mode = GPIO_Mode_AIN;//模擬輸入
GPIO_Struct.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_6|GPIO_Pin_7;
GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Struct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//設(shè)置ADC時鐘 72/6<14
ADC_Struct.ADC_Mode = ADC_Mode_Independent; //獨立工作模式
ADC_Struct.ADC_ContinuousConvMode = ENABLE;//連續(xù)模式
ADC_Struct.ADC_ScanConvMode = ENABLE; //多通道模式
ADC_Struct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //轉(zhuǎn)換由軟件觸發(fā)啟動
ADC_Struct.ADC_DataAlign = ADC_DataAlign_Right;//右對齊
ADC_Struct.ADC_NbrOfChannel = 3;//規(guī)定了順序進行規(guī)則轉(zhuǎn)換的 ADC 通道的數(shù)目
ADC_Init(ADC1,&ADC_Struct);
//設(shè)置指定 ADC 的規(guī)則組通道,設(shè)置它們的轉(zhuǎn)化順序和采樣時間
//MQ2
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);
//MQ7
ADC_RegularChannelConfig(ADC1,ADC_Channel_6,2,ADC_SampleTime_239Cycles5);
//MQ135
ADC_RegularChannelConfig(ADC1,ADC_Channel_7,3,ADC_SampleTime_239Cycles5);
ADC_DMACmd(ADC1,ENABLE);
DMA_Config();
ADC_Cmd(ADC1,ENABLE);
//校準:減小誤差
ADC_ResetCalibration(ADC1);//重置寄存器
while(ADC_GetResetCalibrationStatus(ADC1)==SET)//等待重置完成
{}
ADC_StartCalibration(ADC1);//啟動校準,用校準寄存器 校準 ADC1
while(ADC_GetCalibrationStatus(ADC1)==SET)//等待校準完成
{}
ADC_SoftwareStartConvCmd(ADC1,ENABLE); //啟動轉(zhuǎn)換 使能或者失能指定的 ADC 的軟件轉(zhuǎn)換啟動功能
}
u16 DMA_buf[3]={0};
void DMA_Config(void)
{
DMA_InitTypeDef DMA_Struct={0};
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //開啟DMA時鐘
DMA_Struct.DMA_PeripheralBaseAddr =(u32) &ADC1->DR; //定義DMA外設(shè)基地址
DMA_Struct.DMA_DIR = DMA_DIR_PeripheralSRC; //外設(shè)作為數(shù)據(jù)傳輸?shù)膩碓? DMA_Struct.DMA_BufferSize = 3; //地址遞增兩次(單位為字寬)
DMA_Struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設(shè)地址寄存器不變
DMA_Struct.DMA_MemoryInc = DMA_MemoryInc_Enable; //內(nèi)存地址寄存器遞增
DMA_Struct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //數(shù)據(jù)寬度為16位
DMA_Struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //數(shù)據(jù)寬度為16位
DMA_Struct.DMA_Mode = DMA_Mode_Circular; //工作在循環(huán)緩存模式
DMA_Struct.DMA_Priority = DMA_Priority_High;//優(yōu)先級
DMA_Struct.DMA_M2M = DMA_M2M_Disable;//DMA通道沒有設(shè)置為內(nèi)存到內(nèi)存?zhèn)鬏? DMA_Struct.DMA_MemoryBaseAddr = (u32)&DMA_buf[0]; //內(nèi)存基地址
DMA_Init(DMA1_Channel1,&DMA_Struct);
DMA_Cmd(DMA1_Channel1,ENABLE);
}
//不采用DMA的多通道采集方法
//u16 ADC_Result(u8 ADC_Channel_x)
//{
// u16 ADC_val = ADC_GetConversionValue(ADC1); //返回最近一次 ADCx 規(guī)則組的轉(zhuǎn)換結(jié)果
// ADC_RegularChannelConfig(ADC1,ADC_Channel_x,1,ADC_SampleTime_239Cycles5);
// ADC_SoftwareStartConvCmd(ADC1,ENABLE); //啟動轉(zhuǎn)換 使能或者失能指定的 ADC 的軟件轉(zhuǎn)換啟動功能
// while((ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC))==RESET);
//
// //float ADC_Cha = (ADC_val*3.3/4096);
// //printf("ADC_val == %d\r\n",ADC_val);
// return ADC_val;
//}
2:將按鍵連接PB引腳,通過外部終端配置實現(xiàn)部分功能
3、在進行有人云端鏈接之前,需要先再云端添加設(shè)備模板、創(chuàng)建設(shè)備。有人透傳云
在通信過程中,由底層開發(fā)板采集數(shù)據(jù),并將數(shù)據(jù)封裝成MODBUS-RTU格式,通過串口發(fā)送給NB模塊,然后NB模塊將數(shù)據(jù)上傳到云端(創(chuàng)建模板時選擇了MODBUS-RTU格式),NB模塊是直連有人云的,在這里,我們訪問云端,并將數(shù)據(jù)寫入到云端的寄存器中。?
在云端設(shè)置完成后,NB模塊主動發(fā)送數(shù)據(jù)、或重新上電之后即可上線。因為在測試階段已經(jīng)保證了設(shè)備是正常工作的,在這里我們直接嘗試上傳數(shù)據(jù)了。
在上傳數(shù)據(jù)時,有人云平臺支持MODBUS-RTU協(xié)議,我們只需要將采集的數(shù)據(jù)進行封裝,然后將數(shù)據(jù)通過串口發(fā)送給NB模塊。數(shù)據(jù)上傳成功后,可以在設(shè)備概況、監(jiān)控大屏或者云組態(tài)當中查看數(shù)據(jù)內(nèi)容、上傳時間、異常信息、設(shè)備上下線等。
通信格式: 設(shè)備號 功能碼 起始地址 寄存器數(shù)量 數(shù)據(jù)長度 數(shù)據(jù)塊(寄存器) 校驗(CRC)
#include "nbiot.h"
/*
buf[0] :溫度
buf[1] :濕度
buf[2] :光照強度
buf[3] :煙霧濃度
*/
void NB_Send_IOT1(uint16_t buf[4])
{
char sendbuf[256]={0};
char sendbuf1[256]={0};
uint8_t tmpbuf[64]={0};
uint16_t CRC_Tmp;
tmpbuf[0]=0x01;//從機地址
tmpbuf[1]=0x46;//操作碼
tmpbuf[2]=0x00;
tmpbuf[3]=0x00;//寄存器起始地址
tmpbuf[4]=0x00;
tmpbuf[5]=0x04;//寄存器數(shù)量
tmpbuf[6]=0x08;//字節(jié)數(shù) = 寄存器數(shù)量 * 2
tmpbuf[7]=(buf[0]>>8);
tmpbuf[8]=(buf[0]&0xFF);//高位清零
tmpbuf[9]=(buf[1]>>8);
tmpbuf[10]=(buf[1]&0xFF);
tmpbuf[11]=(buf[2]>>8);
tmpbuf[12]=(buf[2]&0xFF);
tmpbuf[13]=(buf[3]>>8);
tmpbuf[14]=(buf[3]&0xFF);
CRC_Tmp=CRC_16_Tab(tmpbuf,15);
tmpbuf[15]=(CRC_Tmp>>8);
tmpbuf[16]=(CRC_Tmp&0xFF);
//把16進制數(shù)據(jù)轉(zhuǎn)換為字符串,放入sendbuf
SIM7020_Hex_to_Str((char *)tmpbuf,17,sendbuf,256);
//拼接字符串,拼接成上述格式
//設(shè)備號 功能碼 起始地址 寄存器數(shù)量 數(shù)據(jù)長度 數(shù)據(jù)塊(寄存器) 校驗(CRC)
strcpy((char *)tmpbuf,"AT+NMGS=17,");
strcat(sendbuf1,(char *)tmpbuf);
strcat(sendbuf1,sendbuf);
strcat(sendbuf1,"\r\n");
NB_SendString((char *)sendbuf1);
//Send_String_NBlot((uint8_t *)sendbuf1);
printf("發(fā)送內(nèi)容= %s\r\n",sendbuf1);
}
/***************************************************************************/
//轉(zhuǎn)化數(shù)據(jù),轉(zhuǎn)成16進制字符串
/*
char *data :數(shù)據(jù)來源
int data_len :數(shù)據(jù)長度
char *out :存儲地址
int out_len :存儲地址長度
*/
void SIM7020_Hex_to_Str(char *data, int data_len, char *out, int out_len)
{
char temp[2];
int i;
memset(out,0,out_len); //清空緩沖區(qū)
for(i=0;i<data_len;i++)
{ //for循環(huán)
sprintf(temp,"%02X",data[i]); //轉(zhuǎn)化數(shù)據(jù),轉(zhuǎn)成16進制字符串
strcat(out,temp); //追加到out緩沖區(qū)
}
}
?上傳后:可以發(fā)現(xiàn),數(shù)據(jù)已經(jīng)改變
?也可以在“監(jiān)控大屏”中左側(cè)選擇設(shè)備、右側(cè)查看實時數(shù)據(jù),點擊變量可以下發(fā)數(shù)據(jù),或控制指令,完成數(shù)據(jù)指令下發(fā)。
在數(shù)據(jù)或指令下發(fā)時,云端下發(fā)指令也是MODBUS-RTU格式,以03功能碼為例:云端下發(fā)讀保持寄存器指令(03功能碼),通過 UDP鏈接傳輸?shù)轿覀兊腘B模塊,然后NB模塊將相應(yīng)的指令轉(zhuǎn)到我們的設(shè)備串口,在開發(fā)板上我們可以檢測串口的接收,在串口接收數(shù)據(jù)完成后,將所接收的數(shù)據(jù),按照MODBUS協(xié)議進行解析,如果下發(fā)的為03碼,則參照03功能碼的響應(yīng)方式對云端進行數(shù)據(jù)響應(yīng)。如果是其他功能碼,則根據(jù)需求進行解析。
程序資料已經(jīng)上傳到資源可以下載。
stm32c8t6+dht11+MQ系列環(huán)境檢測模塊+oled顯示屏(基于物聯(lián)網(wǎng)的家庭環(huán)境檢測系統(tǒng)設(shè)計)-智能家居文檔類資源-CSDN下載
如果這篇博客對你有幫助,給博主一個免費的點贊或者評論收藏以示鼓勵呀~感謝!??????文章來源:http://www.zghlxwxcb.cn/news/detail-787090.html
?有任何問題可以評論區(qū)留言~??????文章來源地址http://www.zghlxwxcb.cn/news/detail-787090.html
到了這里,關(guān)于stm32c8t6+dht11+MQ系列環(huán)境檢測模塊+oled顯示屏(基于物聯(lián)網(wǎng)的家庭環(huán)境檢測系統(tǒng)設(shè)計)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!