电路原理图如下:
程序说明:
A为传感器1的当前温度,B为传感器2的当前温度,C为设定的差值温度。
当满足:(A-B)>=C,时,继电器吸合,不满足条件时继电器断开。
/***********************************************************************
单品片机;60s2
板子; 双路温控继电器,两个温控探头,上面的温控探头是A面显示的温度, 下面的温控探头是B面显示的温度,
操作过程; 下完程序先设定C,先按加温度键,然后再按减温键,断一下电再上电,这样是为了设定掉电存储
板子功能; 当A的温度大于B的温度到设定值时,继电器A吸合,当再这个设定范围时,断开。有个问题,当B大于A时也会吸合
*************************************************************************/
单片机源程序如下:
#include<reg52.h>
#include<math.h>
#include "INTRINS.H"
#define uchar unsigned char
#define uint unsigned int
//数码管显示段码
code unsigned char duan[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88, 0x83, 0xC6, 0xBF,0x7f};
unsigned char dong[4] = { 0xFF, 0xFF, 0xFF, 0xFF}; //数码管显示缓冲区
uchar i = 0; //数码管扫描动态索引
uint time2,time3;
uchar gai = 0;
uchar mode = 1; //换页变量
/********************掉电存储*********************************************/
typedef unsigned char INT8U;
typedef unsigned int INT16U;
sfr IAP_DATA = 0xC2;
sfr IAP_ADDRH = 0xC3;
sfr IAP_ADDRL = 0xC4;
sfr IAP_CMD = 0xC5;
sfr IAP_TRIG = 0xC6;
sfr IAP_CONTR = 0xC7;
#define ENABLE_ISP 0x82 //系统工作时钟<20MHz 时,对IAP_CONTR 寄存器设置此值
union union_temp16
{
INT16U un_temp16;
INT8U un_temp8[2];
}my_unTemp16;
INT8U Byte_Read(INT16U add); //读一字节,调用前需打开IAP 功能
void Byte_Program(INT16U add, INT8U ch); //字节编程,调用前需打开IAP 功能
void Sector_Erase(INT16U add); //擦除扇区
void IAP_Disable(); //关闭IAP 功能
void Delay();
/******************************18b20*************************************************************/
bit flag1s = 0; //1s定时标志
extern bit Start18B20(); //18b20初始化函数
extern bit Get18B20Temp(int *temp); //18b20温度读取函数
/******************************第二路温控*************************************************/
bit flag1ss = 0; //1s定时标志
extern bit Start18B200(); //18b20初始化函数
extern bit Get18B20Tempp(int *tempp); //18b20温度读取函数
/*******************************************************************************************/
sbit wei1 = P2^3; //数码管的位断开关
sbit wei2 = P2^4;
sbit wei3 = P2^5;
sbit wei4 = P2^6;
bit d1 = 1; //换画面按键当前值
bit d2 = 1; //计数加按键当前值
bit d3 = 1; //计数减按键当前值
sbit s1 = P2^0; //计数加
sbit s2 = P2^1; //计数减
sbit s3 = P2^2; //换画面按钮
sbit out1 = P1^2; //高温启动
sbit out2 = P1^3; //低温启动
uchar T0RH = 0; //T0重载值的高字节
uchar T0RL = 0; //T0重载值的低字节
void peizhit0(uint ms); //配置t0定时器
void key(); //按键扫描函数
void main()
{
bit q1 = 1;
bit q2 = 1;
bit q3 = 1;
/***********************18b20***************************************/
int intT, decT; //温度值的整数和小数部分
bit res ;
int temp; //读取到的当前温度值
/***********************第二路18b20***************************************/
int intTT, decTT; //温度值的整数和小数部分
bit ress ;
int tempp; //读取到的当前温度值
Start18B20(); /*启动DS18B20*/
Start18B200(); /*启动DS18B20*/
/***********************开机读掉电存储内容******************************************************/
time2 = Byte_Read(0x03)*255+Byte_Read(0x02); //注意这是把高字节和低字节合在一起
time3 = Byte_Read(0x05)*255+Byte_Read(0x04); //读三的时间
EA = 1; //开总中断
peizhit0(1); //配置T0定时1ms
while(1)
{
/*********************第一个按键换页按键************************************/
if(d3 != q3)
{
q3 = d3;
if(d3 == 0)
{
mode = mode+1; //功能设置,4个参数,4个周期为一个循环
if(mode == 4)
{
mode = 1;
}
}
}
/*******************************第二个按键按下*************************/
if(d2 != q2)
{
q2 = d2;
if(d2 == 0)
{
if(mode ==2)
{
if(time2>0)
{
time2--;
}
}
else if(mode ==3)
{
if(time3>0)
{
time3--;
}
}
EA = 0;
Sector_Erase(0); //擦除0x01地址中的数据
Byte_Program(0x02,time2);
Byte_Program(0x03,time2>>8);
Byte_Program(0x04,time3);
Byte_Program(0x05,time3>>8);
EA = 1;
}
}
/*****************************第二个按键按下***************************/
if(d1 != q1)
{
q1 = d1;
if(d1 == 0)
{
if(mode ==2) // b
{
time2 = (time2+1)%999;
}
else if(mode ==3)
{
time3 = (time3+1)%999;//c
}
EA = 0;
Sector_Erase(0); //擦除0x01地址中的数据
Byte_Program(0x02,time2);
Byte_Program(0x03,time2>>8);
Byte_Program(0x04,time3);
Byte_Program(0x05,time3>>8);
EA = 1;
}
}
/***************第一层显示**************************/
if(mode == 1)
{
dong[0] = duan [10];
dong[1] = duan [intT/100%10];
dong[2] = duan [intT/10%10];
dong[3] = duan [intT%10];
}
/*************第二层显示**************************/
if(mode == 2)
{
dong[0] = duan [11];
dong[1] = duan [intTT/100%10];
dong[2] = duan [intTT/10%10];
dong[3] = duan [intTT%10];
}
/*************第三层显示**************************/
if(mode == 3)
{
dong[0] = duan [12];
dong[1] = duan [time3/100%10];
dong[2] = duan [time3/10%10];
dong[3] = duan [time3%10];
}
/*****************************温控部分**************************************************/
if (flag1s) //每秒更新一次温度
{
flag1s = 0;
gai++;
Start18B20(); // 注意 一定要随着温度读取函数一起每秒更新启动一次 不然就只能读取到刚上电那一瞬间的温度 启动DS18B20
res = Get18B20Temp(&temp); //读取当前温度
intT = temp*10 >> 4; // 注意在这个地方temp*10就是精确1位小数点,*100就是精确两位小数点 但是只能精确一位小数点 分离出温度值整数部分
decT = temp & 0xF; //分离出温度值小数部分
/*
if((intT <= time2) && (intT >= time3)) //注意 控制部分要放到 这个函数内 不然上电就会先比较 会有动作 放在这里就可以先读取再比较 稳定
{
out2 = 1;
out1 = 1;
}
if(intT >= time2)
{
out2 = 1;
//out1 = 0;
if(gai >= 3)
{
gai = 0;
out1 = ~out1;
}
}
if(intT <= time3)
{
out1 = 1;
//out2 = 0;
if(gai >= 3)
{
gai = 0;
out2 = ~out2;
}
}
*/
}
if (flag1ss) //每秒更新一次温度
{
flag1ss = 0;
Start18B200(); // 注意 一定要随着温度读取函数一起每秒更新启动一次 不然就只能读取到刚上电那一瞬间的温度 启动DS18B20
ress = Get18B20Tempp(&tempp); //读取当前温度
intTT = tempp*10 >> 4; // 注意在这个地方temp*10就是精确1位小数点,*100就是精确两位小数点 但是只能精确一位小数点 分离出温度值整数部分
decTT = tempp & 0xF; //分离出温度值小数部分
}
/*************************************************************/
if((intT-intTT) >= time3)
{
out2 = 0;
}
else
{
out2 = 1;
}
/************************************************************************/
}
}
/* 配置并启动T0,ms-T0定时时间 */
void peizhit0(uint ms)
{
unsigned long tmp; //临时变量
tmp = 11059200 / 12; //定时器计数频率 注意 因为晶振是11.0592,,12个震荡周期才是一个机器周期,所以,计数器加一所用的频率就是11059200/12
tmp = (tmp * ms) / 1000; //计算所需的计数值 注意 上面的计数时间单位是秒,所以除以1000就转化为ms了
tmp = 65536 - tmp; //计算定时器重载值
tmp = tmp + 18; //补偿中断响应延时造成的误差
T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节 注意 因为是char型所以这个数据如果不向左移动8位他就只能保存低位的8位数据,一个char型变量保存是从低8位先保存,保存完后如果有空间再保存高位,向右移动8位就是让它从高位开始保存,这个16位计数换成二进制是 1111 1000 1101 1110
T0RL = (unsigned char)tmp; //直接保存低字节数据
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x01; //配置T0为模式1
TH0 = T0RH; //加载T0重载值
TL0 = T0RL;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
}
/*按键扫描函数*/
void key()
{
static uchar saomiaozhi[3] = {1,1,1};
saomiaozhi[0] = (saomiaozhi[0]<<1) | s1;
saomiaozhi[1] = (saomiaozhi[1]<<1) | s2;
saomiaozhi[2] = (saomiaozhi[2]<<1) | s3;
if(saomiaozhi[0] == 0x00)
{
d1 = 0;
}
if(saomiaozhi[0] == 0xff)
{
d1 = 1;
}
if(saomiaozhi[1] == 0x00)
{
d2 = 0;
}
if(saomiaozhi[1] == 0xff)
{
d2 = 1;
}
if(saomiaozhi[2] == 0x00)
{
d3 = 0;
}
if(saomiaozhi[2] == 0xff)
{
d3 = 1;
}
}
/* T0中断服务函数,完成数码管、按键扫描与秒表计数 */
void t0() interrupt 1
{
static uchar c = 0;
static unsigned int tmr1s = 0;
static unsigned int tmr1ss = 0;
TH0 = T0RH; //重新加载重载值
TL0 = T0RL;
c++;
tmr1s++;
tmr1ss++;
if (tmr1s >= 1000) //定时1s
{
tmr1s = 0;
flag1s = 1;
}
if (tmr1ss >= 1000) //定时1s
{
tmr1ss = 0;
flag1ss = 1;
}
if(c >= 2)
{ c = 0;
key(); //按键扫描函数
}
P0 = 0xff;
switch (i)
{
case 0: wei1 = 0; wei2 = 1; wei3 = 1;wei4 = 1; i++; P0 = dong[0]; break;
case 1: wei1 = 1; wei2 = 0; wei3 = 1;wei4 = 1; i++; P0 = dong[1]; break;
case 2: wei1 = 1; wei2 = 1; wei3 = 0;wei4 = 1; i++; P0 = dong[2]; break;
case 3: wei1 = 1; wei2 = 1; wei3 = 0;wei4 = 1; i++; P0 = 0x7f; break;
case 4: wei1 = 1; wei2 = 1; wei3 = 1;wei4 = 0; i=0; P0 = dong[3]; break;
default: break;
}
}
/******************************掉电储存功能********************************************************/
//读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
INT8U Byte_Read(INT16U add)
{
IAP_DATA = 0x00;
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x01; //IAP/ISP/EEPROM 字节读命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址
//EA = 0;
IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
return (IAP_DATA);
}
//字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
void Byte_Program(INT16U add, INT8U ch)
{
IAP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x02; //IAP/ISP/EEPROM 字节编程命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址
IAP_DATA = ch; //要编程的数据先送进IAP_DATA 寄存器
//EA = 0;
IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
//擦除扇区, 入口:DPTR = 扇区地址
void Sector_Erase(INT16U add)
{
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x03; //IAP/ISP/EEPROM 扇区擦除命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址
//EA = 0;
IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
void IAP_Disable()
{
//关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
IAP_CONTR = 0; //关闭IAP 功能
IAP_CMD = 0; //清命令寄存器,使命令寄存器无命令,此句可不用
IAP_TRIG = 0; //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
IAP_ADDRH = 0;
IAP_ADDRL = 0;
}
void Delay()
{
INT8U i;
INT16U d=5000;
while (d--)
{
i=255;
while (i--);
}
}
全部资料51hei下载地址:
GYJ-0033_双路可编程温度控制系统相关程序.rar
(146.09 KB, 下载次数: 40)
双路可编程温度控制系统原理图及PCB图.pdf
(651.17 KB, 下载次数: 31)
|