西安电子科技大学
单片机大作业
学 院:电子工程学院 班 级:02121X班 姓 名:XXX 学 号:0212XXX 指导老师:XXX
温度控制系统设计
一、温度控制系统设计发展历史及意义
在工业企业中,如何提高温度控制对象的运行性能一直以来都是控制人员和现场技术人员努力解决的问题。这类控制对象惯性大,滞后现象严重,存在很多不确定的因素,难以建立精确的数学模型,从而导致控制系统性能不佳,甚至出现控制不稳定、失控现象。传统的继电器调温电路简单实用 ,但由于继电器动作频繁 ,可能会因触点不良而影响正常工作。控制领域还大量采用传统的PID控制方式,但PID控制对象的模型难以建立,并且当扰动因素不明确时,参数调整不便仍是普遍存在的问题。而采用数字温度传感器DS18B20,因其内部集成了A/D转换器,使得电路结构更加简单,而且减少了温度测量转换时的精度损失,使得测量温度更加精确。数字温度传感器DS18B20只用一个引脚即可与单片机进行通信,大大减少了接线的麻烦,使得单片机更加具有扩展性。由于DS18B20芯片的小型化,更加可以通过单跳数据线就可以和主电路连接,故可以把数字温度传感器DS18B20做成探头,探入到狭小的地方,增加了实用性。更能串接多个数字温度传感器DS18B20进行范围的温度检测。
二、DS18B20工作原理
DS18B20的读写时序和测温原理与DS1820相同,只是得到的温度值的位数因分辨率不同而不同,且温度转换时的延时时间由2s减为750ms。 DS18B20测温原理如图3所示。图中低温度系数晶振的振荡频率受温度影响很小,用于产生固定频率的脉冲信号送给计数器1。高温度系数晶振随温度变化其振荡率明显改变,所产生的信号作为计数器2的脉冲输入。计数器1和温度寄存器被预置在-55℃所对应的一个基数值。计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当计数器1的预置值减到0时,温度寄存器的值将加1,计数器1的预置将重新被装入,计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即为所测温度。斜率累加器用于补偿和修正测温过程中的非线性,其输出用于修正计数器1的预置值。
三、系统软件流程图
四、电路原理图
1.DS18B20温度传感器检测电路
温度采集通过数字化的温度传感器DS18B20,通过QD接向单片机的P3.0口。 DS18B20温度传感器电路如图5.3所示。
2.二极管显示报警电路
二极管显示报警电路如下图所示。通过单片机的P3.4和P3.5两个端口送出,采用的是高电平驱动,使其发光发出警告。
二极管显示电路
3.整体原理图
五、程序设计
1)读出温度子程序
读出温度子程序的主要功能是读出RAM中的9字节,在读出时需进行CRC校验,校验有错时不进行温度数据的改写,程序流程图如图5.10所示。
DS18B20的各个命令对时序的要求特别严格,所以必须按照所要求的时序才能达到预期的目的,同时,要注意读进来的是高位在后低位在前,共有12位数,小数4位,整数7位,还有一位符号位。
读出温度子程序的主要功能是读出RAM中的9字节,在读出时需进行CRC校验,校验有错时不进行温度数据的改写,程序流程图如图5.10所示。
DS18B20的各个命令对时序的要求特别严格,所以必须按照所要求的时序才能达到预期的目的,同时,要注意读进来的是高位在后低位在前,共有12位数,小数4位,整数7位,还有一位符号位。 2)写入子程序
写入子程序的流程图如5.11所示。
六、主要程序
#include
#define uchar unsigned char #define uint unsigned int
#define duan P0 #define wei P1 sbit DSPORT=P3^7;
void Delay1ms(uint y); void Delay5ms();
uchar Ds18b20Init();
void Ds18b20WriteByte(uchar dat); uchar Ds18b20ReadByte(); void Ds18b20ChangTemp(); void Ds18b20ReadTempCom(); int Ds18b20ReadTemp(); void DigDisplay();
void LcdDisplay(int temp);
uchar code segta[10]={0xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; unsigned char DisplayData[8];
void main() {
while(1) {
LcdDisplay(Ds18b20ReadTemp()); } }
void Delay1ms(uint y) {
uint x;
for( ; y>0; y--) {
for(x=110; x>0; x--); } }
/**************************************************************************
*****
* 函 数 名 : Ds18b20Init * 函数功能 : 初始化 * 输 入 : 无
* 输 出 : 初始化成功返回1,失败返回0
*******************************************************************************/
uchar Ds18b20Init() {
uchar i; DSPORT = 0; //将总线拉低480us~960us i = 70;
while(i--);//延时642us DSPORT = 1; //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低 i = 0;
while(DSPORT) //等待DS18B20拉低总线 {
Delay1ms(1); i++;
if(i>5)//等待>5MS {
return 0;//初始化失败 } }
return 1;//初始化成功 }
/*******************************************************************************
* 函 数 名 : Ds18b20WriteByte * 函数功能 : 向18B20写入一个字节 * 输 入 : com * 输 出 : 无
*******************************************************************************/
void Ds18b20WriteByte(uchar dat) {
uint i, j;
for(j=0; j<8; j++)
{
DSPORT = 0; //每写入一位数据之前先把总线拉低1us i++;
DSPORT = dat & 0x01; //然后写入一个数据,从最低位开始 i=6;
while(i--); //延时68us,持续时间最少60us DSPORT = 1; //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
dat >>= 1; } }
/*******************************************************************************
* 函 数 名 : Ds18b20ReadByte * 函数功能 : 读取一个字节 * 输 入 : com * 输 出 : 无
*******************************************************************************/
uchar Ds18b20ReadByte() {
uchar byte, bi; uint i, j;
for(j=8; j>0; j--) {
DSPORT = 0;//先将总线拉低1us i++;
DSPORT = 1;//然后释放总线 i++;
i++;//延时6us等待数据稳定
bi = DSPORT; //读取数据,从最低位开始读取
/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/ byte = (byte >> 1) | (bi << 7); i = 4; //读取完之后等待48us再接着读取下一个数 while(i--); } return byte; }
/*******************************************************************************
* 函 数 名 : Ds18b20ChangTemp * 函数功能 : 让18b20开始转换温度
* 输 入 : com * 输 出 : 无
*******************************************************************************/
void Ds18b20ChangTemp() {
Ds18b20Init(); Delay1ms(1);
Ds18b20WriteByte(0xcc); //跳过ROM操作命令 Ds18b20WriteByte(0x44); //温度转换命令
// Delay1ms(100); //等待转换成功,而如果你是一直刷着的话,就不用这个延时了 }
/*******************************************************************************
* 函 数 名 : Ds18b20ReadTempCom * 函数功能 : 发送读取温度命令 * 输 入 : com * 输 出 : 无
*******************************************************************************/
void Ds18b20ReadTempCom() {
Ds18b20Init(); Delay1ms(1);
Ds18b20WriteByte(0xcc); //跳过ROM操作命令 Ds18b20WriteByte(0xbe); //发送读取温度命令 }
/*******************************************************************************
* 函 数 名 : Ds18b20ReadTemp * 函数功能 : 读取温度 * 输 入 : com * 输 出 : 无
*******************************************************************************/
int Ds18b20ReadTemp() {
int temp = 0; uchar tmh, tml;
Ds18b20ChangTemp(); //先写入转换命令
Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令 tml = Ds18b20ReadByte(); //读取温度值共16位,先读低字节 tmh = Ds18b20ReadByte(); //再读高字节 temp = tmh; temp <<= 8; temp |= tml; return temp; }
/*******************************************************************************
* 函 数 名 : LcdDisplay()
* 函数功能 : LCD显示读取到的温度 * 输 入 : v * 输 出 : 无
*******************************************************************************/
void LcdDisplay(int temp) //lcd显示 {
float tp; if(temp< 0) //当温度值为负数 {
DisplayData[0] = 0x40;
//因为读取的温度是实际温度的补码,所以减1,再取反求出原码 temp=temp-1; temp=~temp; tp=temp;
temp=tp*0.0625*100+0.5;
//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
//算由?.5,还是在小数点后面。 } else
{
DisplayData[0] = 0x00;
tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量 //如果温度是正的那么,那么正数的原码就是补码它本身 temp=tp*0.0625*100+0.5;
//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
//算加上0.5,还是在小数点后面。 }
DisplayData[1] = segta[temp / 10000];
DisplayData[2] = segta[temp % 10000 / 1000];
DisplayData[3] = segta[temp % 1000 / 100] | 0x80; DisplayData[4] = segta[temp % 100 / 10]; DisplayData[5] = segta[temp % 10];
DigDisplay(); //扫描显示 }
void DigDisplay() {
uchar i,j; j=0x01;
for(i=0;i<8;i++) {
wei=j;
duan=DisplayData[i]; Delay5ms(); j=_crol_(j,1); } }
void Delay5ms() {
unsigned char j,k; for(j=10;j>0;j--) for(k=250;k>0;k--); }