“智能检测,精准把控。温湿度检测系统,为您的生活带来全方位的健康保障。”#非标协议项目【下】(分文件编程)

前言

  本篇博文介绍的是用51单片机的非标准写协议项目温湿度检测系统【下】(分文件编程),包含温湿度检测系统需求,分文件编程核心思路,分文件编程操作,利用分文件操作建立uart.c、lcd1602.c、dht11.c、delay.c文件,将串口的代码,LCD1602代码,DHT11代码,延时代码整合到对应的C文件中,利用分文件操作建立uart.h、lcd1602.h、dht11.h、delay.h、io.h文件,在主C文件中调用这些“.h”文件,在uart.c、lcd1602.c、dht11.c、delay.c调用需要的“.h”文件,在主C文件中保留主函数代码,引入外部变量,完整程序代码截图。看到这篇博文的朋友,可以先赞再看吗?

预备知识

  一、基本电路标识识别和接线,例如VCC,GND。
  二、电脑基本操作复制粘贴
  三、C头文件
  四、C变量
  五、基本输入输出
  六、流程控制
  七、函数

  八、指针
  九,字符串

  如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!

1温湿度检测系统需求

  • 能够实时通过51单片机串口发送温湿度信息
  • 能够实时通过51单片机驱动LCD1602显示温湿度信息
  • 能够实现判断温度到达一定温度让LED亮,也可以通过串口发送指令使LED亮灭
  • 采用分文件编程

2.分文件编程核心思路

  • 分文件编程操作
  • 利用分文件操作建立uart.clcd1602.cdht11.cdelay.c文件
  • 串口的代码LCD1602代码DHT11代码延时代码整合到对应的C文件中。
  • 利用分文件操作建立uart.hlcd1602.hdht11.hdelay.hio.h文件。
  • 在主C文件中调用这些“.h”文件,在uart.clcd1602.cdht11.cdelay.c调用需要的“.h”文件
  • 在主C文件中保留主函数代码,引入外部变量。

  注:此程序是基于温湿度检测系统_1602显示串口发送工程修改而来。

3.分文件编程操作

  • 操作步骤

1.打开温湿度检测系统\_分文件编程工程

在这里插入图片描述

2.在Source Group 1 上右键,在弹出的界面上选择第二项

在这里插入图片描述

3.在弹出的界面中,我们可以添加C文件头文件等,之后的操作都是如此。

在这里插入图片描述

4利用分文件操作建立uart.c、lcd1602.c、dht11.c、delay.c文件

在这里插入图片描述

5.将串口的代码,LCD1602代码,DHT11代码,延时代码整合到对应的C文件中

5.1串口的代码

sfr AUXR = 0x8e;   //声明AUXR寄存器地址
sbit LED2 = P3^6;

char LEDStatus[12];

void UartInit(void)		//自己配
{
	//配置串口工作方式为方式1,从只收不发改为能收能发
	SCON =  0x50;
  //配置辅助寄存器,减少电磁辐射,稳定晶振频率  
	AUXR =  0x01;
	//设置定时器工作方式为定时器1的8位自动重装
	TMOD &= 0x0F;
	TMOD |= 0x20;
	//设置串口波特率为9600,0误差
	TH1   = 0xFD;
	TL1   = 0xFD;
	//打开定时器1
	TR1   = 1;
	//打开总中断
	EA    = 1;
	//打开串口中断
	ES    = 1;
	
}

void sendByte(char data_mas)
{
	SBUF = data_mas;
	while(!TI);
	TI = 0;          //一定要软件置零,不然会出现乱序
}

void sendString(char *str)
{
	while(*str != '\0')
	{
		sendByte(*str);
		str++;
	}
}

void UART_handler() interrupt 4
{
	static char i = 0;
	//在串口中段函数中可以对发送接收中断标志进行处理
	if(RI == 1)
		{
			RI = 0;     //必须软件置零
			
			LEDStatus[i] = SBUF;
			i++;
			if(strstr(LEDStatus,"开灯"))
			{
				LED1 = 0;
				LED2 = 0;
				Delay1000ms();
				Delay1000ms();
				i    = 0;
				memset(LEDStatus,'\0',12);
			}
			if(strstr(LEDStatus,"关灯"))
			{
				LED1 = 1;
				LED2 = 1;
				Delay1000ms();
				i    = 0;
				memset(LEDStatus,'\0',12);
			}
		}
		
	
	if(TI);
		
}

5.2 LCD1602代码

//数据线定义
//D0到D7 -- P0.1到P0.7
#define dataBuffer P0

//控制线定义
/*
RS--P1.0
RW--P1.1
EN--P1.4
*/
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;

void checkBusy()
{
  char tmp   = 0x80;
	dataBuffer = 0x80;
	while(tmp & 0x80)    //只要dataBuffer中的第8位为1就为忙,因为BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
	{
		RS = 0;            //根据手册中指令表可知RS=0,RW=1
		RW = 1;            //RW=1为读的操作,所以需要配置读的时序图
		EN = 0;            //根据手册中的写时序图,EN开始为低电平
		_nop_();           //执行空函数等待EN拉高
		EN = 1;            //根据手册中的读时序图,EN被拉高
		_nop_();           //执行空函数等待tpw和tF高电平过程
		_nop_();
		tmp = dataBuffer;  //读取dataBuffer中的忙信号
		EN = 0;            //根据手册中的写时序图,EN被拉低
		_nop_();           //根据手册中的写时序图,让EN保持一段时间的低电平
	}
}

void writeCmd(char cmd)
{       
	checkBusy();       //检测忙信号
	RS = 0;            //RS等于零,是写指令操作
	RW = 0;            //RW在手册中写的时序图是可以全程低电平
	EN = 0;            //根据手册中的写时序图,EN开始为低电平
	_nop_();           //执行空函数等待EN拉高
	dataBuffer = cmd;  //根据手册中的写时序图,数据在EN还在低电平时就建立数据
	EN = 1;            //根据手册中的写时序图,EN被拉高
	_nop_();           //执行空函数等待tpw和tF高电平过程
	_nop_();
	EN = 0;            //根据手册中的写时序图,EN被拉低
	_nop_();           //根据手册中的写时序图,让EN保持一段时间的低电平
}

void weiteData(char cData)
{
	checkBusy();       //检测忙信号
	RS = 1;            //RS等于1,是写数据操作
	RW = 0;            //RW在手册中写的时序图是可以全程低电平
	EN = 0;            //根据手册中的写时序图,EN开始为低电平
	_nop_();           //执行空函数等待EN拉高
	dataBuffer = cData;  //根据手册中的写时序图,数据在EN还在低电平时就建立数据
	EN = 1;            //根据手册中的写时序图,EN被拉高
	_nop_();           //执行空函数等待tpw和tF高电平过程
	_nop_();
	EN = 0;            //根据手册中的写时序图,EN被拉低
	_nop_();           //根据手册中的写时序图,让EN保持一段时间的低电平
}

void initLCD1602()
{
//(1) 延时 15ms
	Delay15ms();
//(2) 写指令 38H(不检测忙信号)
	writeCmd(0x38);
//(3) 延时 5ms
	Delay5ms();
//(4) 以后每次写指令,读/写数据操作均需要检测忙信号
//(5) 写指令 38H:显示模式设置
	writeCmd(0x38);
//(6) 写指令 08H:显示关闭
	writeCmd(0x08);
//(7) 写指令 01H:显示清屏
	writeCmd(0x01);
//(8) 写指令 06H:显示光标移动设置
	writeCmd(0x06);
//(9) 写指令 0CH:显示开及光标设置
	writeCmd(0x0C);
}

void LCD1602ShowARow(char line,char column,char *str)
{
	switch(line) //选择哪行显示
	{
		case 1:                                        //第一行显示
				writeCmd(0x80 + column);                   //选择哪个位置显示,因为位置地址的最高位必须为1,所以0x80+列数
				while(*str)                                //判断字符串指针变量不为空执行循环,不用判断字符串结束标志
				{
					weiteData(*str);                         //发送字符串单个字符
					str++;                                   //字符串指针变量偏移
				}
				break;
		case 2:                                        //第二行显示
				writeCmd(0x80 + 0x40 + column);            //选择哪个位置显示,因为位置地址的最高位必须为1,所以0x80+列数,又因为第二行的列从0x40开始
				while(*str)                                //所以是从0x80 + 0x40 + 列数(特别注意)
				{                     
					weiteData(*str);
					str++;
				}
				break;
	}
}

5.3 DHT11代码

sbit Data = P3^3; //把DHT11接在单片机的P3.3口

char THdata[5];      //存放温湿度数据变量
char Temperature[9]; //定义温度字符数组
char Humidness[9];   //定义湿度字符数组

void startDHT()
{
	Data = 1;
	Data = 0;
	//至少延时18ms,那么延时30ms
	Delay30ms();
	Data = 1;
	//检测d点
	while(Data);
	//检测e点
	while(!Data);
	//检测f点
	while(Data);
}

void readDHTData()
{
	char i; //轮次
	char j; //次数
	char flag;
	char tmp;
	
	//打开DHT11高速模式
	startDHT();
	
	for(i=0; i<5; i++)
	{
		for(j=0; j<8; j++)
		{
			//检测G点
			while(!Data);
			//根据传送1和0的时间不同,0是26us,1是70us。等待60us后,如果Data = 1,就传1,Data = 0;就传0
			//Delay60us();   延时60微妙太长了,可能在读0时读到下一个发送序列了,延时40微妙
			Delay40us();
			if(Data == 1)
			{
				flag = 1;
				while(Data); //传1的时间比较久,所以要等传1结束
			}
      else
			{
				flag = 0;
			}
			tmp = tmp << 1;
			tmp |= flag;
		}
		THdata[i] = tmp;
	}
}

void THDataHandler()
{
	//湿度数据处理
	Humidness[0] = 'H';
	Humidness[1] = ':';
	Humidness[2] = THdata[0]/10 + 0x30;
	Humidness[3] = THdata[0]%10 + 0x30;
	Humidness[4] = '.';
	Humidness[5] = THdata[1]/10 + 0x30;
	Humidness[6] = THdata[1]%10 + 0x30;
	Humidness[7] = '%';
	Humidness[8] = '\0';
	
	//温度处理
	Temperature[0] = 'T';
	Temperature[1] = ':';
	Temperature[2] = THdata[2]/10 + 0x30;
	Temperature[3] = THdata[2]%10 + 0x30;
	Temperature[4] = '.';
	Temperature[5] = THdata[3]/10 + 0x30;
	Temperature[6] = THdata[3]%10 + 0x30;
	Temperature[7] = 'C';
	Temperature[8] = '\0';
}

5.4延时代码

void Delay15ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 27;
	j = 226;
	do
	{
		while (--j);
	} while (--i);
}

void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 9;
	j = 244;
	do
	{
		while (--j);
	} while (--i);
}

void Delay30ms()		//@11.0592MHz
{
	unsigned char i, j; 

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void Delay40us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 15;
	while (--i);
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

6.利用分文件操作建立uart.h、lcd1602.h、dht11.h、delay.h、io.h文件。

6.1 uart.h 文件内容

  • 这个文件的作用主要起到声明函数的作用。
void UartInit(void);		//自己配


void sendByte(char data_mas);


void sendString(char *str);

6.2 lcd1602.h 文件内容

  • 这个文件的作用主要起到声明函数的作用。
void initLCD1602();


void LCD1602ShowARow(char line,char column,char *str);

6.3 dht11.h 文件内容

  • 这个文件的作用主要起到声明函数的作用。
void readDHTData();


void THDataHandler();

6.4 delay.h 文件内容

  • 这个文件的作用主要起到声明函数的作用。
void Delay15ms();		//@11.0592MHz


void Delay5ms();		//@11.0592MHz


void Delay30ms();		//@11.0592MHz


void Delay40us();		//@11.0592MHz


void Delay1000ms();		//@11.0592MHz

6.5 io.h 文件内容

  • 这个文件的作用主要起到声明函数的作用。
sbit LED1 = P3^7; //用尾定义声明LED1

7.在主C文件中调用这些“.h”文件,在uart.c、lcd1602.c、dht11.c、delay.c调用需要的“.h”文件

7.1主C文件调用“.h”文件

#include "reg52.h"
#include "intrins.h"
#include "delay.h"
#include "uart.h"
#include "lcd1602.h"
#include "dht11.h"
#include "io.h"

7.2 uart.c调用需要的“.h”文件

#include "reg52.h"
#include "delay.h"
#include "io.h"
#include "string.h"

7.3 lcd1602.c调用需要的“.h”文件

#include "reg52.h"
#include "intrins.h"
#include "delay.h"

7.4 dht11.c调用需要的“.h”文件

#include "reg52.h"
#include "delay.h"

7.5 delay.c调用需要的“.h”文件

#include "intrins.h"

8.在主C文件中保留主函数代码,引入外部变量。

8.1主C文件中保留主函数代码

LED1 = 1;            //一上电就让灯灭
Delay1000ms();
UartInit();          //初始化串口
initLCD1602();               //初始化LCD1602
Delay1000ms();       //等待DHT模块稳定
Delay1000ms();
while(1)             //防止程序退出主函数,导致LED1微弱闪烁
{
    Delay1000ms();     //间隔1秒读一次
    readDHTData();     //读取DHT11温湿度数据
    THDataHandler();   //将DHT11传回的数据装入温湿度字符数组
    //通过串口发送温湿度数据
    sendString(Humidness);
    sendString("\r\n");
    sendString(Temperature);
    sendString("\r\n");
    sendString("\r\n");

    LCD1602ShowARow(1,4,Humidness); 
    LCD1602ShowARow(2,4,Temperature);
}

8.2 引入外部变量

  • extern为引入外部变量标志
//引入DHT11.c内的全局变量
extern char THdata[5];      //存放温湿度数据变量 extern为引入外部变量标志
extern char Temperature[9]; //定义温度字符数组
extern char Humidness[9];   //定义湿度字符数组

9.完整程序代码截图

9.1主C文件代码截图

在这里插入图片描述

9.2 uart.c 代码截图

在这里插入图片描述

9.3 lcd1602.c代码截图

请添加图片描述

9.4 dht11.c代码截图

在这里插入图片描述

9.5 delay.c代码截图

在这里插入图片描述

9.6 uart.h 代码截图

在这里插入图片描述

9.7 lcd1602.h代码截图

在这里插入图片描述

9.8 dht11.h代码截图

在这里插入图片描述

9.9 delay.h代码截图

在这里插入图片描述

9.10 io.h代码截图

在这里插入图片描述

结束语

  很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!

  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值