标题:
单片机数字温度控制器Proteus仿真设计带源码
[打印本页]
作者:
我不是我
时间:
2017-7-17 21:37
标题:
单片机数字温度控制器Proteus仿真设计带源码
用DS18B20进行温度转换,用AT89C51单片机读取温度,并根据温度值,控制1602显示和直流电机转动,采用占空比调速,带有ISIS仿真文件,可直接使用。
proteus仿真原理图如下:
0.png
(19.5 KB, 下载次数: 117)
下载附件
2017-7-18 01:42 上传
0.png
(56.08 KB, 下载次数: 79)
下载附件
2017-7-18 01:42 上传
单片机源程序如下:
/******************************/
/* 数字温度控制器 */
/******************************/
#include <reg51.h>
//引脚定义
sbit RS=P2^0;//1602LCD RS
sbit RW=P2^1;//1602LCD RW
sbit E=P2^2;//1602LCD E
sbit Moto1=P2^3;//直流电机控制端
sbit Moto2=P2^4;//直流电机控制端
sbit DQ=P2^5;//DS18B20 DQ
#define uchar unsigned char
#define uint unsigned int //宏定义
#define LcdData P0 //1602的D0~D7
#define CWD Moto1=1;Moto2=0 //正转
#define CCWD Moto1=0;Moto2=1 //反转
#define Stop Moto1=1; Moto2=1 //停止
//全局变量定义
uchar HPulseNum;//高电平数(PWM波高电平持续长度)
uchar LPulseNum;//低电平数(PWM波低电平持续长度)
uint NumChange; //周期
bit TempFlag;//正负温度标志:温度为正Temp_Flag=0,否则为1
uint Temp;//温度值
//直流电机转向状态 0为CWD(顺时针方向) 1为CCWD(逆时针方向)
uchar MotoStatus; //电机状态
bit PulseStatus;//PWM波状态,0高电平 1低电平
//函数申明(共11个函数)
/*****************************************************/
void Delayms(uint xms);//ms级延时函数
void WriteLcd(uchar Dat,bit x);//写1602LCD指令、数据函数
void InitLcd(void);//初始化1602LCD函数
void StatusLCD(void);//1602LCD显示状态函数
void InitT0(void);//初始化定时器T0函数
void Delayus(uchar xus);//us级延时函数
bit Init_DS18B20(void);//初始化DS18B20函数
uchar Read_DS18B20(void);//读DS18B20函数
void Write_DS18B20(uchar Dat);//写DS18B20函数
void GetTemp();//取温度函数
void MotoControl();
/*****************************************************/
uchar FirstLine[16]={" C STOP"}; //用于1602LCD第一行显示的数组
uchar SecondLine[16]={"TG! H/L: 0%"}; //用于1602LCD第二行显示的数组
//ms级延时函数
void Delayms(uint xms)//1ms左右延时
{
uint i,j;
for(i=xms; i>0; i--)
for(j=110; j>0; j--);
}
//写1602LCD指令、数据函数
void WriteLcd(uchar Dat,bit x)
{
E=0;
LcdData=Dat;
RS=x;//写指令时x=0,写数据时x=1
RW=0;
E=1;
Delayms(1);
E=0;
}
//初始化1602LCD函数
void InitLcd(void)
{
WriteLcd(0x38,0);//功能设定(38H)
WriteLcd(0x0C,0);//显示开、关设定(0CH)
WriteLcd(0x06,0);//输入模式设定(06H)
WriteLcd(0x01,0);//清除显示(01H)
}
//1602LCD显示状态函数
void StatusLCD(void)
{
if(TempFlag) FirstLine[0]='-';//如果温度值为负,显示负符号
else FirstLine[0]=' ';//否则不显示温度符号
if(Temp<1000) FirstLine[1]=' ';//如果温度值小于100,百位显示空白(不显示0)
else FirstLine[1]=Temp/1000+0x30;//取温度百位并转换成ASCII码
if(Temp<100) FirstLine[2]=' ';//如果温度值小于10,十位显示空白(不显示0)
else FirstLine[2]=Temp%1000/100+0x30;//取温度十位并转换成ASCII码
FirstLine[3]=Temp%100/10+0x30;//取温度个位并转换成ASCII码
FirstLine[4]='.';//显示小数点
FirstLine[5]=Temp%10+0x30;//取温度十分位并转换成ASCII码
FirstLine[6]=0xDF;//显示℃中C前面的小圆
if(NumChange!=0)
{
if(MotoStatus==1)//顺时针时显示CWD
{
FirstLine[9]=' ';
FirstLine[10]='C';
FirstLine[11]='W';
FirstLine[12]='D';
}
if(MotoStatus==2)//逆时针时显示CCWD
{
FirstLine[9]='C';
FirstLine[10]='C';
FirstLine[11]='W';
FirstLine[12]='D';
}
}
else
{
FirstLine[9]='S';
FirstLine[10]='T';
FirstLine[11]='O';
FirstLine[12]='P';
}
if((TempFlag)|(Temp<250))//如果温度为负或小于25度,温度过低
SecondLine[1]='L';//改写1602LCD第二行显示内容
if((!TempFlag)&(Temp>=250)&(Temp<=300))//如果温度为正且在25℃~30℃之间,温度正常
SecondLine[1]='G';//改写1602LCD第二行显示内容
if((!TempFlag)&(Temp>300))//如果温度为正且大于30度,温度过高
SecondLine[1]='H';//改写1602LCD第二行显示内容
//占空比小于100%时,不显示百位
if(NumChange<100)
SecondLine[8]=' ';
else
//取占空比百位并转换成ASCII码
SecondLine[8]=NumChange/100+0x30;
//占空比小于10%时,不显示十位
if(NumChange<10)
SecondLine[9]=' ';
else
//取占空比十位并转换成ASCII码
SecondLine[9]=NumChange%100/10+0x30;
//取占空比个位并转换成ASCII码
SecondLine[10]=NumChange%10+0x30;
}
//us级延时函数
void Delayus(uchar xus)//晶振为12MHz,延时时间为2i+5 us
{
while(--xus);
}
//初始化DS18B20函数
bit Init_DS18B20(void)
{
bit x;
DQ=1;
DQ=0;
Delayus(250);
DQ=1;
Delayus(27);
if(!DQ) x=0;
else x=1;
Delayus(250);
DQ=1;
return x;
}
//读DS18B20函数
uchar Read_DS18B20(void)
{
uchar i=0,Dat=0;
for(i=0;i<8;i++)
{
DQ=1;
DQ=0;
Dat>>=1;
DQ=1;
if(DQ) Dat |= 0x80;
DQ=1;
Delayus(30);
}
return Dat;
}
//写DS18B20函数
void Write_DS18B20(uchar Dat)
{
uchar i=0;
for(i=0;i<8;i++)//循环8次,写入一个字节
{
DQ=1;//未发送前的状态
Dat >>= 1;//将要传送的最低位放入CY
DQ=0;//将总线拉低,产生写时序
DQ=CY;//将要传送的位状态送到总线上
Delayus(30);//延时50us,即保持总线状态,待DS18B20采样
DQ=1;//恢复期,总线置1
}
}
//取温度函数
void GetTemp(void)//获取温度函数
{
uchar a=0,b=0;
TR0=0;
Init_DS18B20();
Write_DS18B20(0xcc);//跳过ROM
Write_DS18B20(0x44);//开启温度转换
Init_DS18B20();
Write_DS18B20(0xcc);//跳过ROM
Write_DS18B20(0xbe);//读暂存器
a=Read_DS18B20();//读取高速暂存字节0,温度低8位
b=Read_DS18B20();//读取高速暂存字节1,温度高8位
Temp=b;
Temp<<=8;
Temp=Temp|a;//将高、低位温度编码合在一起
if(b>=8)//判断温度值是否为负,如果温度高字节大于等于8说明温度值为负
{
Temp=~Temp+1;//将补码转换成原码
TempFlag=1;//温度标志为1,表示温度为负
}
else
{
TempFlag=0;//温度标志为0,表示温度为正
}
Temp=Temp*0.0625*10+0.5;//将温度编码转换成温度值 放大10倍 加0.5是为了四舍五入
TR0=1;
}
//初始化外部中断INT0和定时器T0
void InitT0(void)
{
EA=1;
ET0=1;
TMOD=0x02;//T0工作于定时、方式2
TH0=256-250;//250us定时
TL0=256-250;
TR0=1;//启动定时器
}
//T0定时器中断服务函数
void T0Serv() interrupt 1
{
if(!PulseStatus)//如果当前处于PWM波高电平段 PulseStatus:PWM波状态,0高电平 1低电平
{
if(HPulseNum--!=0)//如果高电平段延时计数不为0
{
if(MotoStatus!=0)//如果MotoStatus!=0(为0是停止状态)
{
if(MotoStatus==1)
{
CWD;//顺时针驱动直流电机
}
else//MotoStatus=1(逆时针)
{
CCWD;//逆时针驱动直流电机
}
}
}
else//高电平段延时计数为0
{
PulseStatus=!PulseStatus;//取反PWM波电平状态
LPulseNum=100-NumChange; //装载低电平段延时计数,为低电平段延时做准备
}
}
else//当前处于PWM波低电平段
{
//如果低电平段延时计数不为0
if(LPulseNum--!=0)
{
Stop;//停止驱动直流电机
}
//低电平段延时计数为0
else
{
PulseStatus=!PulseStatus; //取反PWM波电平状态
HPulseNum=NumChange; //装载高电平段延时计数,为高电平段延时做准备
}
}
}
void MotoControl()
{
if((!TempFlag)&(Temp>300)) //正的温度且大于30℃
{
MotoStatus=1;
NumChange=Temp-300;
if(NumChange>=100) NumChange=100;//控制上限
}
if((!TempFlag)&(Temp<=300)&(Temp>=250))
{
MotoStatus=0;
NumChange=0;
}
if((Temp<250)|(TempFlag))
{
……………………
…………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
任务5 数字温度控制器.rar
(71.55 KB, 下载次数: 66)
2017-7-17 21:34 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
LIuwEI.
时间:
2018-10-30 16:35
为什么仿真不对 有错误?
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1