【制作】基于金沙滩51单片机的单点测温程序

基于金沙滩51单片机的单点测温程序

之前学51单片机的时候做了一个单点测温程序,现在分享一下。
用的是金沙滩的51单片机开发板,这个很好,推荐一下。

零、完成功能

本项目完成以下功能:

  1. 单点温度测量
  2. 测温范围 10℃-40℃
  3. 分辨率 1℃
  4. 两位温度显示
  5. 超出上下限(18℃-25℃)蜂鸣器响起警报

壹、硬件电路图

贰、软件代码

代码的注释很详细,程序很简单,就不一一介绍了。

#include <reg52.h>
#include <intrins.h>
#define T_MAX 25 // 最大温度限定值
#define T_MIN 18 // 最小温度限定值

sbit BUZZ = P1^6;
//_nop_()函数所在头文件


/*----------------音乐函数申明------------------------------*/
void InitBuzz();
bit isBuzz = 0; //蜂鸣器是否在响


/*----------------温度传感器申明----------------------------*/
bit Start18B20();			//初始化DS18B20
bit Get18B20Temp(int *temp);//读取温度
bit isGetTemp = 0;		   //是否在获取温度


/*----------------LCD1602显示模块申明------------------------*/
void InitLcd1602();			//LCD1602初始化函数
void display();			//显示控制模块

/*-------------------LCD1602显示缓存-------------------------*/
//LCD1602函数调用申明
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len);
unsigned char strbuff[4];//格式:“25°C”
unsigned char code waringStrHot[] = "      Hot!      ";//报警显示文字
unsigned char code waringStrCol[] = "      Cold!     ";//报警显示文字
unsigned char code striswaring[] = "            ";//取消报警显示文字


/*----------------------其他全局变量-------------------------*/
int Temp = 0;		//读取到的当前温度值(16bit二进制)
int intT;			//温度值的整数和小数部分
bit iswaring = 0;	//是否报警标志位


void main()
{
//	int n = 0;
//	char s[1];
	bit isReay = 0;
	bit sta;				//是否成功读取标志
	unsigned int cnt = 0;	//检测标志,主要用于控制检测温度的频率
	
	InitBuzz();					//蜂鸣器初始化
	Start18B20();			//启动DS18B20
    InitLcd1602();      	//初始化LCD1602液晶模块
	
	while(1)
	{
		if(isReay == 0)
		{
			cnt++;
		}

		if((cnt>28000&&isBuzz == 0)||(cnt>14000&&isBuzz == 1)) 				//大约0.8s(仿真得到) DS18B20最多750ms转化好
		{
			cnt = 0;
			isReay = 1;
		}
		  
		if(isReay == 1 && isBuzz == 0)
		{
//			n++;
//			s[0] = n+'0';
//			LcdShowStr(0, 0,s, 1);
			isGetTemp = 1;
			sta = Get18B20Temp(&Temp);	//读取当前温度
			isGetTemp = 0;
			if (sta)					//读取成功时,刷新当前温度显示
			{
				intT = Temp >> 4;		//分离出温度值整数部分
			}
			Start18B20();					//重新启动下一次转换
	
			if(intT > T_MAX || intT < T_MIN)
			{
				iswaring = 1;
			}else{
				iswaring = 0;
			}

			isReay = 0;
		}

		display();//显示
	}
}

/*-----------------------以下是LCD1602显示驱动------------------*/
//定义LCD1602显示相关的IO接口
#define LCD1602_DB  P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E  = P1^5;


//显示控制模块
void display()
{
	static int intTb;	//温度值的整数部分备份
	static bit isBuzzb;

	if(isBuzzb != isBuzz)
	{
		if(isBuzz == 0 && iswaring == 1)
		{
			if(intT > T_MAX)
			{
				LcdShowStr(0,1,waringStrHot,16);
			}else{
				LcdShowStr(0,1,waringStrCol,16);
			}
			
		}else{
			LcdShowStr(0,1,striswaring,11);
		}
		isBuzzb = isBuzz;
	}

	if(intTb != intT)//如果有变化
	{
		/*备份当前值*/
		intTb = intT;
		
		if((intT/10) == 0)strbuff[0] = ' ';else strbuff[0] = ((intT/10)%10)+0x30;//十位
		strbuff[1] = ((intT/1)%10)+0x30;//个位

		LcdShowStr(6,0,strbuff,4);	//显示,初始位置随意,只要能显示完整就好
	}
}

//等待液晶准备好
void LcdWaitReady()
{
    unsigned char sta;
     
    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;      //使能LCD1602
        sta = LCD1602_DB;   //读取状态字
        LCD1602_E = 0;      //避免干扰其他器件
    } while (sta & 0x80);   //第七位等于1表示液晶正忙,重复检测直到第七位等于0为止
}
//向LCD1602液晶写入一字节命令,cmd为待写入命令值
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
//向LCD1602液晶写入一字节数据,dat为待写入数据值
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
//设置显示RAM起始地址,亦即光标位置,(x,y)对应屏幕上的字符的坐标
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
     
    if (y == 0)  			//由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + x;	//第一行字符地址从0x00起始
    else
        addr = 0x40 + x;	//第二行字符地址从0x40起始
    LcdWriteCmd(addr | 0x80);	//设置RAM地址
}
//在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,
//str-字符串指针,len-需显示的字符长度
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len)
{
    LcdSetCursor(x, y);   //设置起始地址
    while (len--)         //连续写入len个字符数据
    {
        LcdWriteDat(*str++);  //先取str指向的数据,然后str自加1
    }
}

void InitLcd1602()//初始化1602液晶
{
	strbuff[2] = 0XDF;
	strbuff[3] = 'C';

    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
    LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}


/*-----------------------以下是温度传感器驱动------------------*/
//DS18B20通信引脚
sbit IO_18B20 = P3^2;
void DelayX10us(unsigned char t)
{
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
    /*_nop_()函数在12M晶振中延迟1us,为什么这里是8个_nop_()
	因为while和--t也是需要时间的,这里不一定是准确的10us/循环
	只是大致的时间*/
}
bit Get18B20Ack() //DS18B20存在检测函数 
{
	bit ack;

	EA = 0;				//关中断 
	IO_18B20 = 0;		//拉低引脚 
	DelayX10us(50);		//延时500us(480us - 960us) 
	IO_18B20 = 1;		//释放总线 
	DelayX10us(6);		//延时60us(15us - 60us) 
	ack = IO_18B20;		//读取响应(60us - 240us) 
	while(!IO_18B20);	//等待DS18B20释放总线 (60us - 240us) 
	EA = 1;				//取消关中断 

	return ack;			//返回是否存在 (0:存在 1:不存在) 
}

void  Write18B20(unsigned char dat) //写DS18B20 
{
	unsigned char mask;			//临时变量定义 
	EA = 0;						//关中断 
	for(mask=0x01; mask!= 0; mask<<=1)	//循环发送单个bit位 
	{
		IO_18B20 = 0;			//拉低(请求读写操作) 
		_nop_();				//延时(1us < time <= 15us) 
		_nop_();
		if((mask&dat) == 0)		//按位读取dat 
			IO_18B20 = 0;		//本位是0,拉低 
		else
			IO_18B20 = 1;		//本位是1,拉高 
			//上面这个操作DS18B20读取(最小时间 0us<time<15us,
			//典型时间 15us,最大时间45us) 
		DelayX10us(6);			//等待60us(足够DS18B20读取) 
		IO_18B20 = 1;			//释放总线 
	}
	EA = 1;						//取消关中断 
}

unsigned char Read18B20()		//读DS18B20 
{
	unsigned char dat;			//数据缓存变量 
	unsigned char mask;			//临时变量 

	EA = 0;						//关中断 
	for(mask=0x01; mask!=0; mask<<=1)//同上循环按位操作 
	{
		IO_18B20 = 0;			//读写请求 
		_nop_();				//等待(1us < time < 15us) 
		_nop_();
		IO_18B20 = 1;			//初始化读操作 
		_nop_();				//等待DS18B20输出 
		_nop_();
		if(!IO_18B20)			//读 
			dat &= ~mask;		//“0” 
		else
			dat |= mask;		//“1” 
		DelayX10us(6);			//等待DS18B20释放总线 
	}
	EA = 1;						//取消关中断 

	return dat;					//返回数据 
}

bit Start18B20()		//初始化DS18B20 
{
	bit ack;			//存在标志 

	ack = Get18B20Ack();//检测存在 
	if(ack == 0)		//存在 
	{					//写命令使工作
		Write18B20(0xCC); 	//跳过ROM检测 
		Write18B20(0x44);	//启动温度转换 
	}
	return ~ack;		//返回是否成功(1是,0否) 
}

bit Get18B20Temp(int *temp)	//获取DS18B20温度存于temp 
{
	bit ack;				//存在标志 
	unsigned char LSB, MSB;	//数据低/高位 

	ack = Get18B20Ack();	//检测存在 
	if(ack == 0)			//存在 
	{						//写指令 
		Write18B20(0xCC);	//跳过ROM检测 
		Write18B20(0xBE);	//读寄存器 
		LSB = Read18B20();	//读低位 
		MSB = Read18B20();	//读高位 
		*temp = ((int)MSB<<8) + LSB;	//合并 
	}
	return ~ack;			//返回结果(1成功,0失败) 
}

//下面是蜂鸣器
void InterruptTimer0() interrupt 1
{
	static unsigned int timer;
	TH0 = 0x00;
	TL0 = 0x00;
	timer++;
	if(iswaring)
	{
		if(timer>3000)
		{
			isBuzz = 1;

			if(timer%5==1)
			{
				BUZZ = ~BUZZ;
			}

			if(timer>6000)
			{
				timer = 0;	
			}
		}else{
			isBuzz = 0;
		}
	}else{
		isBuzz = 0;
	}
}

void InitBuzz()
{
	TMOD = 0x02;
	TR0 = 1;
	ET0 = 1;	
}

叁、运行效果

视频演示:https://www.bilibili.com/video/BV1Fy4y1y7BP/

成功完成以上功能,哈哈~
喜欢的小伙伴支持一下吧

原文地址:https://www.cnblogs.com/minuy/p/14493915.html