单片机的智能温控器

        现代工业自动化和智能家居环境中,温度控制是一个至关重要的环节。市场上现有的智能温控器可能不够准确,导致控制温度不够精确,从而影响用户的舒适度和能源效率。精确的温度控制不仅影响着设备的性能和寿命,也直接关系到人们的舒适度和安全。因此,设计一款精确的基于单片机的智能温控器,实现对温度的实时监测和智能控制,具有重要的实际意义和应用价值。

        用单片机设计一个智能温控器,基于普中开发板进行实际测试,并用lcd1602显示温度。.一个电源开关,4个控制设定温度阈值按键(增大/减小),LCD1602显示设定温度和实际温度。量程为0-99度,打开电源后设定温度初始值位26度(仿真图)。采用温度传感器进行温度测量,模数转换采用ADC0809 。单片机根据设定温度D和实测温度P控制继电器R的动作。

        实际电路的仿真图

实现图

  1. 主程序

#include <REGX52.H>

#include "LCD1602.h"

#include "DS18B20.h"

#include "Delay.h"

#include "AT24C02.h"

#include "Key.h"

#include "Timer0.h"

#include "Buzzer.h"

#include "main1.h"

float T,TShow;

char TLow,THigh;

unsigned char KeyNum;

sbit JdqLow  = P1^0;                    // 加热

sbit JdqHig  = P1^1;              // 降温

void main()

{

       Delay(1);

       DS18B20_ConvertT();            //上电先转换一次温度,防止第一次读数据错误

       Delay(1000);                    //等待转换完成

       THigh=AT24C02_ReadByte(0);    //读取温度阈值数据

       TLow=AT24C02_ReadByte(1);

       if(THigh>=99 || TLow<=0 || THigh<=TLow)

       {

              THigh=33;                 //如果阈值非法,则设为默认值

              TLow=15;

       }

       LCD_Init();

       LCD_ShowString(1,1,"T:");

       LCD_ShowString(2,1,"TH:");

       LCD_ShowString(2,9,"TL:");

       LCD_ShowSignedNum(2,4,THigh,3);

       LCD_ShowSignedNum(2,12,TLow,3);

       Timer0_Init();

      

       while(1)

       {

              KeyNum=Key();

             

              /*温度读取及显示*/

              DS18B20_ConvertT();     //转换温度

              T=DS18B20_ReadT();     //读取温度

              if(T<0)                       //如果温度小于0

              {

                     LCD_ShowChar(1,3,'-');  //显示负号

                     TShow=-T;          //将温度变为正数

              }

              else                      //如果温度大于等于0

              {

                     LCD_ShowChar(1,3,'+');  //显示正号

                     TShow=T;

              }

              LCD_ShowNum(1,4,TShow,3);            //显示温度整数部分

              LCD_ShowChar(1,7,'.');          //显示小数点

              LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分

             

             

             

              /*阈值判断及显示*/

              if(KeyNum)

              {

                     Buzzer_Time(0);

                     if(KeyNum==1)  //K1按键,THigh自增

                     {

                            THigh++;

                            if(THigh>99){THigh=99;}

                     }

                     if(KeyNum==2)  //K2按键,THigh自减

                     {

                            THigh--;

                            if(THigh<=TLow){THigh++;}

                     }

                     if(KeyNum==3)  //K3按键,TLow自增

                     {

                            TLow++;

                            if(TLow>=THigh){TLow--;}

                     }

                     if(KeyNum==4)  //K4按键,TLow自减

                     {

                            TLow--;

                            if(TLow<0){TLow=0;}

                     }

                     LCD_ShowSignedNum(2,4,THigh,3);  //显示阈值数据

                     LCD_ShowSignedNum(2,12,TLow,3);

                     AT24C02_WriteByte(0,THigh);           //写入到At24C02中保存

                     Delay(5);

                     AT24C02_WriteByte(1,TLow);

                     Delay(5);

              }

              //超过限位蜂鸣器报警。

              if ((T>THigh  | T<TLow)  )

              {

                            Delay(10);

                            Buzzer_Time(1);

                    

              }

             

              if(T>THigh)               //越界判断

              {

                     LCD_ShowString(1,13,"OV:H");

                     Delay(5);

                            JdqLow=1;

                            JdqHig=0;

              }

              else if(T<TLow)

              {

                     LCD_ShowString(1,13,"OV:L");

                     Delay(1);

                     JdqLow=0;

                     JdqHig=1;

              }

              else

              {

                     LCD_ShowString(1,13,"OK  ");

                     JdqLow=1;

                     JdqHig=1;

              }

       }

}

void Timer0_Routine() interrupt 1

{

       static unsigned int T0Count;

       TL0 = 0x18;        //设置定时初值

       TH0 = 0xFC;             //设置定时初值

       T0Count++;

       if(T0Count>=20)

       {

              T0Count=0;

      

              Key_Loop(); //每20ms调用一次按键驱动函数

             

       }

}

  1. 延时程序

void Delay(unsigned int xms)

{

       unsigned char i, j;

       while(xms--)

       {

              i = 2;

              j = 239;

              do

              {

                     while (--j);

              } while (--i);

       }

}

  1. 显示屏

#include <REGX52.H>

//引脚配置:

sbit LCD_RS=P2^6;

sbit LCD_RW=P2^5;

sbit LCD_EN=P2^7;

#define LCD_DataPort P0

//函数定义:

/**

  * @brief  LCD1602延时函数,12MHz调用可延时1ms

  * @param  无

  * @retval 无

  */

void LCD_Delay()

{

       unsigned char i, j;

       i = 2;

       j = 239;

       do

       {

              while (--j);

       } while (--i);

}

/**

  * @brief  LCD1602写命令

  * @param  Command 要写入的命令

  * @retval 无

  */

void LCD_WriteCommand(unsigned char Command)

{

       LCD_RS=0;

       LCD_RW=0;

       LCD_DataPort=Command;

       LCD_EN=1;

       LCD_Delay();

       LCD_EN=0;

       LCD_Delay();

}

/**

  * @brief  LCD1602写数据

  * @param  Data 要写入的数据

  * @retval 无

  */

void LCD_WriteData(unsigned char Data)

{

       LCD_RS=1;

       LCD_RW=0;

       LCD_DataPort=Data;

       LCD_EN=1;

       LCD_Delay();

       LCD_EN=0;

       LCD_Delay();

}

/**

  * @brief  LCD1602设置光标位置

  * @param  Line 行位置,范围:1~2

  * @param  Column 列位置,范围:1~16

  * @retval 无

  */

void LCD_SetCursor(unsigned char Line,unsigned char Column)

{

       if(Line==1)

       {

              LCD_WriteCommand(0x80|(Column-1));

       }

       else if(Line==2)

       {

              LCD_WriteCommand(0x80|(Column-1+0x40));

       }

}

/**

  * @brief  LCD1602初始化函数

  * @param  无

  * @retval 无

  */

void LCD_Init()

{

       LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵

       LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关

       LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动

       LCD_WriteCommand(0x01);//光标复位,清屏

}

/**

  * @brief  在LCD1602指定位置上显示一个字符

  * @param  Line 行位置,范围:1~2

  * @param  Column 列位置,范围:1~16

  * @param  Char 要显示的字符

  * @retval 无

  */

void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)

{

       LCD_SetCursor(Line,Column);

       LCD_WriteData(Char);

}

/**

  * @brief  在LCD1602指定位置开始显示所给字符串

  * @param  Line 起始行位置,范围:1~2

  * @param  Column 起始列位置,范围:1~16

  * @param  String 要显示的字符串

  * @retval 无

  */

void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)

{

       unsigned char i;

       LCD_SetCursor(Line,Column);

       for(i=0;String[i]!='\0';i++)

       {

              LCD_WriteData(String[i]);

       }

}

/**

  * @brief  返回值=X的Y次方

  */

int LCD_Pow(int X,int Y)

{

       unsigned char i;

       int Result=1;

       for(i=0;i<Y;i++)

       {

              Result*=X;

       }

       return Result;

}

/**

  * @brief  在LCD1602指定位置开始显示所给数字

  * @param  Line 起始行位置,范围:1~2

  * @param  Column 起始列位置,范围:1~16

  * @param  Number 要显示的数字,范围:0~65535

  * @param  Length 要显示数字的长度,范围:1~5

  * @retval 无

  */

void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

{

       unsigned char i;

       LCD_SetCursor(Line,Column);

       for(i=Length;i>0;i--)

       {

              LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');

       }

}

/**

  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字

  * @param  Line 起始行位置,范围:1~2

  * @param  Column 起始列位置,范围:1~16

  * @param  Number 要显示的数字,范围:-32768~32767

  * @param  Length 要显示数字的长度,范围:1~5

  * @retval 无

  */

void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)

{

       unsigned char i;

       unsigned int Number1;

       LCD_SetCursor(Line,Column);

       if(Number>=0)

       {

              LCD_WriteData('+');

              Number1=Number;

       }

       else

       {

              LCD_WriteData('-');

              Number1=-Number;

       }

       for(i=Length;i>0;i--)

       {

              LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');

       }

}

/**

  * @brief  在LCD1602指定位置开始以十六进制显示所给数字

  * @param  Line 起始行位置,范围:1~2

  * @param  Column 起始列位置,范围:1~16

  * @param  Number 要显示的数字,范围:0~0xFFFF

  * @param  Length 要显示数字的长度,范围:1~4

  * @retval 无

  */

void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

{

       unsigned char i,SingleNumber;

       LCD_SetCursor(Line,Column);

       for(i=Length;i>0;i--)

       {

              SingleNumber=Number/LCD_Pow(16,i-1)%16;

              if(SingleNumber<10)

              {

                     LCD_WriteData(SingleNumber+'0');

              }

              else

              {

                     LCD_WriteData(SingleNumber-10+'A');

              }

       }

}

/**

  * @brief  在LCD1602指定位置开始以二进制显示所给数字

  * @param  Line 起始行位置,范围:1~2

  * @param  Column 起始列位置,范围:1~16

  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111

  * @param  Length 要显示数字的长度,范围:1~16

  * @retval 无

  */

void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

{

       unsigned char i;

       LCD_SetCursor(Line,Column);

       for(i=Length;i>0;i--)

       {

              LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');

       }

}

(4)控制AT24C02串行EEPROM的读写操作

#include <REGX52.H>

#include "I2C.h"

#define AT24C02_ADDRESS        0xA0

/**

  * @brief  AT24C02写入一个字节

  * @param  WordAddress 要写入字节的地址

  * @param  Data 要写入的数据

  * @retval 无

  */

void AT24C02_WriteByte(unsigned char WordAddress,Data)

{

       I2C_Start();

       I2C_SendByte(AT24C02_ADDRESS);

       I2C_ReceiveAck();

       I2C_SendByte(WordAddress);

       I2C_ReceiveAck();

       I2C_SendByte(Data);

       I2C_ReceiveAck();

       I2C_Stop();

}

/**

  * @brief  AT24C02读取一个字节

  * @param  WordAddress 要读出字节的地址

  * @retval 读出的数据

  */

unsigned char AT24C02_ReadByte(unsigned char WordAddress)

{

       unsigned char Data;

       I2C_Start();

       I2C_SendByte(AT24C02_ADDRESS);

       I2C_ReceiveAck();

       I2C_SendByte(WordAddress);

       I2C_ReceiveAck();

       I2C_Start();

       I2C_SendByte(AT24C02_ADDRESS|0x01);

       I2C_ReceiveAck();

       Data=I2C_ReceiveByte();

       I2C_SendAck(1);

       I2C_Stop();

       return Data;

}

(5)I2C总线通信协议

#include <REGX52.H>

//引脚定义

sbit I2C_SCL=P2^1;

sbit I2C_SDA=P2^0;

/**

  * @brief  I2C开始

  * @param  无

  * @retval 无

  */

void I2C_Start(void)

{

       I2C_SDA=1;

       I2C_SCL=1;

       I2C_SDA=0;

       I2C_SCL=0;

}

/**

  * @brief  I2C停止

  * @param  无

  * @retval 无

  */

void I2C_Stop(void)

{

       I2C_SDA=0;

       I2C_SCL=1;

       I2C_SDA=1;

}

/**

  * @brief  I2C发送一个字节

  * @param  Byte 要发送的字节

  * @retval 无

  */

void I2C_SendByte(unsigned char Byte)

{

       unsigned char i;

       for(i=0;i<8;i++)

       {

              I2C_SDA=Byte&(0x80>>i);

              I2C_SCL=1;

              I2C_SCL=0;

       }

}

/**

  * @brief  I2C接收一个字节

  * @param  无

  * @retval 接收到的一个字节数据

  */

unsigned char I2C_ReceiveByte(void)

{

       unsigned char i,Byte=0x00;

       I2C_SDA=1;

       for(i=0;i<8;i++)

       {

              I2C_SCL=1;

              if(I2C_SDA){Byte|=(0x80>>i);}

              I2C_SCL=0;

       }

       return Byte;

}

/**

  * @brief  I2C发送应答

  * @param  AckBit 应答位,0为应答,1为非应答

  * @retval 无

  */

void I2C_SendAck(unsigned char AckBit)

{

       I2C_SDA=AckBit;

       I2C_SCL=1;

       I2C_SCL=0;

}

/**

  * @brief  I2C接收应答位

  * @param  无

  * @retval 接收到的应答位,0为应答,1为非应答

  */

unsigned char I2C_ReceiveAck(void)

{

       unsigned char AckBit;

       I2C_SDA=1;

       I2C_SCL=1;

       AckBit=I2C_SDA;

       I2C_SCL=0;

       return AckBit;

}

  1. 传感器

#include <REGX52.H>

#include "OneWire.h"

//DS18B20指令

#define DS18B20_SKIP_ROM                    0xCC

#define DS18B20_CONVERT_T                 0x44

#define DS18B20_READ_SCRATCHPAD       0xBE

/**

  * @brief  DS18B20开始温度变换

  * @param  无

  * @retval 无

  */

void DS18B20_ConvertT(void)

{

       OneWire_Init();

       OneWire_SendByte(DS18B20_SKIP_ROM);

       OneWire_SendByte(DS18B20_CONVERT_T);

}

/**

  * @brief  DS18B20读取温度

  * @param  无

  * @retval 温度数值

  */

float DS18B20_ReadT(void)

{

       unsigned char TLSB,TMSB;

       int Temp;

       float T;

       OneWire_Init();//初始化

       OneWire_SendByte(DS18B20_SKIP_ROM);

       OneWire_SendByte(DS18B20_READ_SCRATCHPAD);

       TLSB=OneWire_ReceiveByte();

       TMSB=OneWire_ReceiveByte();

       Temp=(TMSB<<8)|TLSB;

       T=Temp/16.0;

       return T;

}

(7)单总线通信

#include <REGX52.H>

//引脚定义

sbit OneWire_DQ=P3^7;

/**

  * @brief  单总线初始化

  * @param  无

  * @retval 从机响应位,0为响应,1为未响应

  */

unsigned char OneWire_Init(void)

{

       unsigned char i;

       unsigned char AckBit;

       EA=0;

       OneWire_DQ=1;

       OneWire_DQ=0;

       i = 247;while (--i);            //Delay 500us

       OneWire_DQ=1;

       i = 32;while (--i);              //Delay 70us

       AckBit=OneWire_DQ;

       i = 247;while (--i);            //Delay 500us

       EA=1;

       return AckBit;

}

/**

  * @brief  单总线发送一位

  * @param  Bit 要发送的位

  * @retval 无

  */

void OneWire_SendBit(unsigned char Bit)

{

       unsigned char i;

       EA=0;

       OneWire_DQ=0;

       i = 4;while (--i);                //Delay 10us

       OneWire_DQ=Bit;

       i = 24;while (--i);              //Delay 50us

       OneWire_DQ=1;

       EA=1;

}

/**

  * @brief  单总线接收一位

  * @param  无

  * @retval 读取的位

  */

unsigned char OneWire_ReceiveBit(void)

{

       unsigned char i;

       unsigned char Bit;

       EA=0;

       OneWire_DQ=0;

       i = 2;while (--i);                //Delay 5us

       OneWire_DQ=1;

       i = 2;while (--i);                //Delay 5us

       Bit=OneWire_DQ;

       i = 24;while (--i);              //Delay 50us

       EA=1;

       return Bit;

}

/**

  * @brief  单总线发送一个字节

  * @param  Byte 要发送的字节

  * @retval 无

  */

void OneWire_SendByte(unsigned char Byte)

{

       unsigned char i;

       for(i=0;i<8;i++)

       {

              OneWire_SendBit(Byte&(0x01<<i));

       }

}

/**

  * @brief  单总线接收一个字节

  * @param  无

  * @retval 接收的一个字节

  */

unsigned char OneWire_ReceiveByte(void)

{

       unsigned char i;

       unsigned char Byte=0x00;

       for(i=0;i<8;i++)

       {

              if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}

       }

       return Byte;

}

(8)按键控制

#include <REGX52.H>

#include "Delay.h"

unsigned char Key_KeyNumber;

/**

  * @brief  获取按键键码

  * @param  无

  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下

  */

unsigned char Key(void)

{

       unsigned char Temp=0;

       Temp=Key_KeyNumber;

       Key_KeyNumber=0;

       return Temp;

}

/**

  * @brief  获取当前按键的状态,无消抖及松手检测

  * @param  无

  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下

  */

unsigned char Key_GetState()

{

       unsigned char KeyNumber=0;

      

       if(P3_1==0){KeyNumber=1;}

       if(P3_0==0){KeyNumber=2;}

       if(P3_2==0){KeyNumber=3;}

       if(P3_3==0){KeyNumber=4;}

      

       return KeyNumber;

}

/**

  * @brief  按键驱动函数,在中断中调用

  * @param  无

  * @retval 无

  */

void Key_Loop(void)

{

       static unsigned char NowState,LastState;

       LastState=NowState;                      //按键状态更新

       NowState=Key_GetState();           //获取当前按键状态

       //如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测

       if(LastState==1 && NowState==0)

       {

              Key_KeyNumber=1;

       }

       if(LastState==2 && NowState==0)

       {

              Key_KeyNumber=2;

       }

       if(LastState==3 && NowState==0)

       {

              Key_KeyNumber=3;

       }

       if(LastState==4 && NowState==0)

       {

              Key_KeyNumber=4;

       }

}

(9)蜂鸣器

#include <REGX52.H>

#include <INTRINS.H>

//蜂鸣器端口:

sbit Buzzer=P2^5;

/**

  * @brief  蜂鸣器私有延时函数,延时500us

  * @param  无

  * @retval 无

  */

void Buzzer_Delay500us()            //@12.000MHz

{

       unsigned char i;

       _nop_();

       i = 247;

       while (--i);

}

/**

  * @brief  蜂鸣器发声

  * @param  ms 发声的时长,范围:0~32767

  * @retval 无

  */

void Buzzer_Time(unsigned int ms)

{

       unsigned int i;

       for(i=0;i<ms*2;i++)

       {

              Buzzer=!Buzzer;

              Buzzer_Delay500us();

       }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值