以51单片机为主控板,外接煤气传感器模块、烟雾传感器模块、LCD12864/OLED屏幕、DS1302时钟芯片、DHT11温度传感器等,实时采集环境数据,并伴有报警提示,同时将数据显示到上位机界面(vb/vs),实现智能家居环境温度的实时监测。此外还将附带远程遥控的基本智能功能
展示视频:
2022-11-07_16-52-39
LCD12864xianshi.c的代码:
#include "reg52.h"
#include <intrins.h>
#include <DHT11.h>
#include<uart.h>
#include"DS1302.h"
//#include"adc0832.h"
#define uchar unsigned char
#define uint unsigned int
#define width 15 /* 显示宽度 */
#define Graphic 1
#define TXT 0
#define LcmLengthDots 128
#define LcmWidthDots 64
#define RUN_CNT_MAX 2
#define MENU_NUM_LIMIT 3
sbit REST = P2^0; //复位信号,低电平有效
sbit C_D = P2^1; //L:数据 H:指令
sbit C_E = P2^2; //使能端,低电平有效
sbit R_D = P2^3; //读
sbit W_R = P2^4; //写
sbit CS = P1 ^ 0;
sbit CLK = P1 ^ 1;
sbit DO = P1 ^ 2;
sbit DI = P1 ^ 3;
sbit led = P1 ^ 5;
sbit led2 = P1 ^ 7;
sbit led3 = P2 ^ 5;
sbit HW = P1 ^ 4;
uchar sec;
uchar jishu;
uchar i;
uchar asd;
uchar add;
uchar shi, fen, miao,shi1,fen1,miao1,shi2,fen2,miao2;
char DHT[10];
uint DS[7];
uchar yu;
uchar shu = 0;
uchar hww = 0;
uchar yanwu,yanwu1,yanwu2,yanmwu3,yanwu4,yanwu5;
/****************************************液晶字库**************************************/
uchar num[] = "0123456789";
typedef struct typFNT_GB16
{
char Mask[60];
};
code struct typFNT_GB16 GB_16[] = /* 汉字取模 */
{
//你要显示的文字用汉字取模软件
};
/***************************************液晶字库结束***************************************/
void delay_nms(uint i); /* 延时函数 */
void write_commond(uchar com); /*LCD12864写入8位命令子函数*/
void write_date(uchar dat) ; /*LCD12864写入8位数据子函数*/
void F12864_init(); /*LCD12864 并行初始化子程序*/
void F12864_clear(void); /* LCD12864初始化函数 */
void goto_xy(uchar x,uchar y,uchar mode); /* 设定显示地址 */
void Putchar(uchar x,uchar y,uchar Charbyte); /* 显示一个字符 */
void display_string(uchar x,uchar y,uchar *p); /* 显示字符串 */
void display_num(uchar x,uchar y,uchar z); /* 显示数字 */
void Get_Dat();
void USB_cccc(void);
uchar AD0834(uchar channel);
void dprintf_hanzi_string_1(struct typFNT_GB16 code *GB_16,uint X_pos,uint Y_pos,uchar j,uchar k);
/* 汉字显示 更改汉字取模 可以更改显示汉字(数组),坐标,坐标,j=k+n (n,显示字的个数,k,从那个字开始) */
void delay2ms(void) //晶振12M,误差 0us,含调用
{
unsigned char a, b;
for (b = 133; b > 0; b--)
for (a = 6; a > 0; a--);
}
void main(void)
{
UART_init();
F12864_init();
F12864_clear();
DS1302_Init();
while(1)
{
sec++;
jishu++;
DHT11_receive();
switch (shu)
{
case 0:DS1302_ReadTime(); break;
case 1:DS1302_SetTime(); break;
}
//DS1302_ReadTime();
yanwu = AD0834(0);
yanmwu3 = AD0834(1);
yanwu1 = yanwu * 500 / 255 ;
yanwu2 = yanwu1 / 10;
yanwu4 = yanmwu3 * 500 / 255;
yanwu5 = yanwu4 / 10;
if (yanwu2 <10)
{
led = 1;
display_string(12, 7, "N");
}
else
{
led = 0;
display_string(12, 7, "Y");
}
if (yanwu5>10)
{
led2 = 1;
display_string(12, 6, "N");
}
else
{
led2 = 0;
display_string(12, 6, "Y");
}
if (HW == 0)
{
hww = !hww;
}
if (hww == 1)
{
led3 = 1;
}
else
{
led3 = 0;
}
if (sec >=5 )
{
shi1 = DS1302_Time[3] / 10 + 0x30;
shi2 = DS1302_Time[3] % 10 + 0x30;
fen1 = DS1302_Time[4] / 10 + 0x30;
fen2 = DS1302_Time[4] % 10 + 0x30;
miao1 = DS1302_Time[5] / 10 + 0x30;
miao2 = DS1302_Time[5] % 10 + 0x30;
DHT[0] = rec_dat[0];
DHT[1] = rec_dat[1];
DHT[2] = rec_dat[4];
DHT[3] = rec_dat[5];
DHT[4] = shi1;
DHT[5] = shi2;
DHT[6] = fen1;
DHT[7] = fen2;
DHT[8] = miao1;
DHT[9] = miao2;
DHT[10] = 0;
UART_Send_Str(DHT);
sec = 0;
}
dprintf_hanzi_string_1(GB_16,1,16,5,0); //左右移动8点阵,上下为1
DHT11_receive();
add = rec_dat[5] + (rec_dat[4] * 10) - 14 - 2;
asd = ((DHT[0]-0x30) * 10) + (DHT[1]-0x30);
shi = DS1302_Time[3];
fen = DS1302_Time[4];
miao = DS1302_Time[5];
display_string(0, 6, "SiDu"); //5表示横向8点阵倍数,7也是8点阵的倍数
display_string(4, 6, ":");
display_num(5, 6, asd);
display_string(0, 7, "WeDu");
display_string(4, 7, ":");
display_num(5, 7, add);
display_string(0, 5, "Time");
display_string(5, 5, ":");
display_num(6, 5, shi);
display_string(8, 5, "-");
display_num(9, 5, fen);
display_string(11, 5, "-");
display_num(12, 5, miao);
display_string(9, 6, "CO");
display_string(9, 7, "SM");
display_string(11, 6, ":");
display_string(11, 7, ":");
}
}
void USB_cccc(void) interrupt 4
{
if (RI)
{
RI = 0;
if (SBUF == 0x01)//切换模式
{
shu = !shu;
}
if (SBUF == 0x02)//时++
{
DS1302_Time[3]++;
}
if (SBUF == 0x03)//分++
{
DS1302_Time[4]++;
}
if (SBUF == 0x04)//秒++
{
DS1302_Time[5]++;
}
if (DS1302_Time[3] > 23) { DS1302_Time[3] = 0; }//时越界判断
if (DS1302_Time[4] > 59) { DS1302_Time[4] = 0; }//分越界判断
if (DS1302_Time[5] > 59) { DS1302_Time[5] = 0; }//秒越界判断
//if (SBUF == 0x01)
//{
// i = !i;
//}
//if (i == 1)
//{
// if (SBUF == 0x02)
// {
// DS1302_Time[3]++;
// }
// if (SBUF == 0x03)
// {
// DS1302_Time[4]++;
// }
// if (SBUF == 0x04)
// {
// DS1302_Time[5]++;
// }
//}
}
}
void delay_nms(uint i)
{
while(i)
i--;
}
/* 并行
* 写命令
*/
void write_commond(uchar com)
{
C_E = 0;
C_D = 1;
R_D = 1;
P0 = com;
W_R = 0; // write
_nop_();
W_R = 1; // disable write
C_E = 1;
C_D = 0;
}
/* 并行->写数据 */
void write_date(uchar dat)
{
C_E = 0;
C_D = 0;
R_D = 1;
P0 = dat;
W_R = 0;
_nop_();
W_R = 1;
C_E = 1;
C_D = 1;
}
/*
* 写一个指令 一个数据
*/
void write_dc(uchar com,uchar dat)
{
write_date(dat);
write_commond(com);
}
/*
* 写一个指令两个数据
*/
void write_ddc(uchar com,uchar dat1,uchar dat2)
{
write_date(dat1);
write_date(dat2);
write_commond(com);
}
/* 并行初始化 */
void F12864_init(void)
{
REST = 0;
delay_nms(2000);
REST = 1;
write_ddc(0x40,0x00,0x00); /* 设置文本显示首地址 */
write_ddc(0x41,128/8,0x00); /* 设置文本显示宽度 */
write_ddc(0x42,0x00,0x08); /* 设置文本显示首地址0x0800 */
write_ddc(0x43,128/8,0x00); /* 设置图形显示宽度 */
write_commond(0xA0); /* 设置光标形状8*8 */
write_commond(0x80); /* 显示方式设置 文本and图形(异或) */
write_commond(0x92); /* 设置光标 */
write_commond(0x9F); /* 显示开关设置,文本开,图形开,光标闪烁关 */
}
/* 清除显示函数 */
void F12864_clear(void)
{
unsigned int i;
write_ddc(0x24,0x00,0x00); /* 设置地址指针从零开始 */
write_commond(0xb0); /* 自动写 */
for(i = 0;i < 128 * 64 ;i++)write_date(0x00); /* 清一屏 */
write_commond(0xb2); /* 自动写结束 */
write_ddc(0x24,0x00,0x00); /* 重置地址指针 */
}
/* 设定显示地址
* mode 1:图形
* 0:汉字
*/
void goto_xy(uchar x,uchar y,uchar mode)
{
uint temp;
temp = 128 / 8 * y + x;
if(mode) //mode = 1为Graphic
{ //图形模式要加上图形区首地址0x0800
temp = temp + 0x0100;
}
write_ddc(0x24,temp & 0xff,temp / 256); //地址指针位置
}
/* 显示一个ASCII码 */
void Putchar(uchar x,uchar y,uchar Charbyte)
{
goto_xy(x,y,TXT);
write_dc(0xC4,Charbyte-32); //数据一次写入
}
void display_string(uchar x,uchar y,uchar *p)
{
while(*p != 0)
{
if(x > 15 ) //超出一行,自动换行
{
x = 0;
y++;
}
Putchar(x,y,*p);
++x;
++p;
}
}
void display_num(uchar x,uchar y,uchar z)
{
uchar z1,z2;
z1 = num[z / 10];
z2 = num[z % 10];
Putchar(x,y,z1);
Putchar(x+1,y,z2);
}
/* 显示一串汉字,j=k+n (n,显示字的个数,k,从那个字开始) */
void dprintf_hanzi_string_1(struct typFNT_GB16 code *GB_16,uint X_pos,uint Y_pos,uchar j,uchar k)
{
unsigned int address;
unsigned char m,n;
while(k < j)
{
m = 0;
address = LcmLengthDots / 8 * Y_pos + X_pos + 0x0800;
for(n = 0;n < 16;n++) //计数值16
{
write_ddc(0x24,(uchar)(address),(uchar)(address>>8)); //设置显示存储器地址
write_dc(0xc0,GB_16[k].Mask[m++]); //写入汉字字模左部
write_dc(0xc0,GB_16[k].Mask[m++]); //写入汉字字模右部
address = address + 128/8; //修改显示存储器地址,显示下一列(共16列)
}
X_pos += 2;
k++;
}
}
uchar AD0834(uchar channel)
{
uchar V = 0, i = 0;
CS = 0; //片选信号,低电平有效
DO = 0; //DO为高阻态,这里置低为后续读取做准备
delay2ms();
//前三个脉冲为配置设置
CLK = 0;
delay2ms();
DI = 1;
CLK = 1;//第一个脉冲,起始位
delay2ms();
CLK = 0;
delay2ms();
DI = 1;
CLK = 1;//第二个脉冲,该位为“1”时是单端输入模式,为“0”时是差分输入模式
delay2ms();
CLK = 0;
delay2ms();
DI = channel; //第三个脉冲,DI=1表示选择通道1(CH2),DI=0表示选择通道0(CH1)
CLK = 1;
delay2ms();
DI = 0; //DI转为高阻态,状态无关紧要,这里给低方便下一轮读取
DO = 1; //DO口恢复默认上拉,准备接收信号
CLK = 1;
delay2ms();
CLK = 0; //第一个下降沿,为去数做准备
delay2ms();//等待芯片接收下降沿并切换输出模式
//接收8位信号并转换
for (i = 0; i < 8; i++)
{
CLK = 1;
delay2ms();
CLK = 0;
if (DO)//如果DO为高电平,相应的位数是1
V = V | 1 << (7 - i);
}
CS = 1;//关闭片选,结束一个转换周期
return V;
}
DS1302.c代码
#include <REGX52.H>
#include"DS1302.h"
//引脚定义
sbit DS1302_SCLK = P3 ^ 6;
sbit DS1302_IO = P3 ^ 4;
sbit DS1302_CE = P3 ^ 5;
//寄存器写入地址/指令定义
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
//时间数组,索引0~6分别为年、月、日、时、分、秒、星期
unsigned char DS1302_Time[] = { 22,3,18,12,59,50,5 };
/**
* @brief DS1302初始化
* @param 无
* @retval 无
*/
void DS1302_Init(void)
{
DS1302_CE = 0;
DS1302_SCLK = 0;
}
/**
* @brief DS1302写一个字节
* @param Command 命令字/地址
* @param Data 要写入的数据
* @retval 无
*/
void DS1302_WriteByte(unsigned char Command, Data)
{
unsigned char i;
DS1302_CE = 1;
for (i = 0; i < 8; i++)
{
DS1302_IO = Command & (0x01 << i);
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
for (i = 0; i < 8; i++)
{
DS1302_IO = Data & (0x01 << i);
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
DS1302_CE = 0;
}
/**
* @brief DS1302读一个字节
* @param Command 命令字/地址
* @retval 读出的数据
*/
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i, Data = 0x00;
Command |= 0x01; //将指令转换为读指令
DS1302_CE = 1;
for (i = 0; i < 8; i++)
{
DS1302_IO = Command & (0x01 << i);
DS1302_SCLK = 0;
DS1302_SCLK = 1;
}
for (i = 0; i < 8; i++)
{
DS1302_SCLK = 1;
DS1302_SCLK = 0;
if (DS1302_IO) { Data |= (0x01 << i); }
}
DS1302_CE = 0;
DS1302_IO = 0; //读取后将IO设置为0,否则读出的数据会出错
return Data;
}
/**
* @brief DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中
* @param 无
* @retval 无
*/
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP, 0x00);
DS1302_WriteByte(DS1302_YEAR, DS1302_Time[0] / 10 * 16 + DS1302_Time[0] % 10);//十进制转BCD码后写入
DS1302_WriteByte(DS1302_MONTH, DS1302_Time[1] / 10 * 16 + DS1302_Time[1] % 10);
DS1302_WriteByte(DS1302_DATE, DS1302_Time[2] / 10 * 16 + DS1302_Time[2] % 10);
DS1302_WriteByte(DS1302_HOUR, DS1302_Time[3] / 10 * 16 + DS1302_Time[3] % 10);
DS1302_WriteByte(DS1302_MINUTE, DS1302_Time[4] / 10 * 16 + DS1302_Time[4] % 10);
DS1302_WriteByte(DS1302_SECOND, DS1302_Time[5] / 10 * 16 + DS1302_Time[5] % 10);
DS1302_WriteByte(DS1302_DAY, DS1302_Time[6] / 10 * 16 + DS1302_Time[6] % 10);
DS1302_WriteByte(DS1302_WP, 0x80);
}
/**
* @brief DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
* @param 无
* @retval 无
*/
void DS1302_ReadTime(void)
{
unsigned char Temp;
Temp = DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0] = Temp / 16 * 10 + Temp % 16;//BCD码转十进制后读取
Temp = DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1] = Temp / 16 * 10 + Temp % 16;
Temp = DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2] = Temp / 16 * 10 + Temp % 16;
Temp = DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3] = Temp / 16 * 10 + Temp % 16;
Temp = DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4] = Temp / 16 * 10 + Temp % 16;
Temp = DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5] = Temp / 16 * 10 + Temp % 16;
Temp = DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6] = Temp / 16 * 10 + Temp % 16;
}
uart.c代码
#include<reg52.h>
#include<uart.h>
#include<intrins.h>
/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
/*-----------------------------
串口初始化程序;
-------------------------------*/
void UART_init(void)
{
SCON = 0x50;
TMOD = 0x21;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
EA = 1;
ES = 1;
}
/*-----------------------------
串口发送程序;
-------------------------------*/
void UART_send_byte(char dat) //按发送字节
{
SBUF = dat; //发送
while (TI == 0); //等待发送完毕
TI = 0; //清发送完毕中断请求标志位
}
void UART_Send_Str(unsigned char *buf) //按字符串发送
{
while (*buf != '\0')
{
UART_send_byte(*buf++);
}
}
DHT11.h代码
#define uchar unsigned char
#define uint unsigned int
sbit Data = P1 ^ 6;
uchar rec_dat[9];
void DHT11_delay_us(uchar n)
{
while (--n);
}
void DHT11_delay_ms(uint z)
{
uint i, j;
for (i = z; i > 0; i--)
for (j = 110; j > 0; j--);
}
void DHT11_start()
{
Data = 1;
DHT11_delay_us(2);
Data = 0;
DHT11_delay_ms(30);
Data = 1;
DHT11_delay_us(30);
}
uchar DHT11_rec_byte()
{
uchar i, dat = 0;
for (i = 0; i < 8; i++)
{
while (!Data);
DHT11_delay_us(8);
dat <<= 1;
if (Data == 1)
dat += 1;
while (Data);
}
return dat;
}
void DHT11_receive()
{
uchar R_H, R_L, T_H, T_L, RH, RL, TH, TL, revise;
DHT11_start();
if (Data == 0)
{
while (Data == 0);
DHT11_delay_us(40);
R_H = DHT11_rec_byte();
R_L = DHT11_rec_byte();
T_H = DHT11_rec_byte();
T_L = DHT11_rec_byte();
revise = DHT11_rec_byte();
DHT11_delay_us(25);
if ((R_H + R_L + T_H + T_L) == revise)
{
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
}
rec_dat[0] = '0' + (RH / 10);
rec_dat[1] = '0' + (RH % 10);
rec_dat[2] = ' ';
rec_dat[3] = ' ';
//温度
rec_dat[4] = '0' + (TH / 10);
rec_dat[5] = '0' + (TH % 10);
rec_dat[6] = ' ';
}
}
DS1302.h代码
#ifndef __DS1302_H__
#define __DS1302_H__
//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期
extern unsigned char DS1302_Time[];
void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command, Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);
#endif
uart.h代码
#ifndef __UART_H__
#define __UART_H__
void DelayUs2x( unsigned char t);
void DelayMs( int t);
void UART_init( void);
void UART_Send_Str( unsigned char *buf);
#endif
仿真示意图