• 【制作】基于金沙滩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/

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

  • 相关阅读:
    【洛谷3214】[HNOI2011] 卡农(思维)
    【洛谷2609】[ZJOI2012] 数列(高精度)
    【洛谷4501】[ZJOI2018] 胖(二分+RMQ)
    【洛谷4726】【模板】多项式指数函数(多项式 exp)
    uC/OS-II之入门与介绍20160525
    [转]Delphi 关键字详解
    [转]单元文件结构
    Delphi ComboBox的属性和事件、及几个鼠标事件的触发
    Delphi 用ToolButton和MonthCalendar实现DateTimePicker的功能
    Delphi 动态改变Rzsplitter的Orientation(方向)属性
  • 原文地址:https://www.cnblogs.com/minuy/p/14493915.html
Copyright © 2020-2023  润新知