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

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

前言

**  本篇博文介绍的是用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串口的代码

c 复制代码
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代码

c 复制代码
//数据线定义
//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代码

c 复制代码
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延时代码

c 复制代码
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 文件内容

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


void sendByte(char data_mas);


void sendString(char *str);

6.2 lcd1602.h 文件内容

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


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

6.3 dht11.h 文件内容

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


void THDataHandler();

6.4 delay.h 文件内容

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


void Delay5ms();		//@11.0592MHz


void Delay30ms();		//@11.0592MHz


void Delay40us();		//@11.0592MHz


void Delay1000ms();		//@11.0592MHz

6.5 io.h 文件内容

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

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

7.1主C文件调用".h"文件

c 复制代码
#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"文件

c 复制代码
#include "reg52.h"
#include "delay.h"
#include "io.h"
#include "string.h"

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

c 复制代码
#include "reg52.h"
#include "intrins.h"
#include "delay.h"

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

c 复制代码
#include "reg52.h"
#include "delay.h"

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

c 复制代码
#include "intrins.h"

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

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

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为引入外部变量标志
c\ 复制代码
//引入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代码截图

结束语

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

相关推荐
B1nna3 小时前
Redis学习(三)缓存
redis·学习·缓存
_im.m.z3 小时前
【设计模式学习笔记】1. 设计模式概述
笔记·学习·设计模式
就爱学编程4 小时前
重生之我在异世界学编程之C语言:数据在内存中的存储篇(下)
java·服务器·c语言
落羽的落羽5 小时前
【落羽的落羽 C语言篇】动态内存管理·下
c语言
7yewh5 小时前
Linux驱动开发 IIC I2C驱动 编写APP访问EEPROM AT24C02
linux·arm开发·驱动开发·嵌入式硬件·嵌入式
上海易硅智能科技局有限公司5 小时前
AG32 MCU 的电机控制方案
单片机·嵌入式硬件
左漫在成长6 小时前
王佩丰24节Excel学习笔记——第十九讲:Indirect函数
笔记·学习·excel
程序员JerrySUN6 小时前
Yocto 项目 - 共享状态缓存 (Shared State Cache) 机制
linux·嵌入式硬件·物联网·缓存·系统架构
叫我阿呆就好了6 小时前
C 实现植物大战僵尸(一)
c语言·开发语言
柒月的猫6 小时前
求和(2022蓝桥杯A组试题C)
c语言·算法·蓝桥杯