|
主控芯片采用STM32F103RCT6,用18b20作为温度传感器,可以通过串口发送命令和当前温度等信息。PI调节,使用PWM控制固态继电器继而控制加热器通断。
/******************************************
/********* 无线遥控温度控制
/********* MCU:STC89C52
* ******* 温度传感器:18b20
* 控制方法:PID控制
* 串口命令格式'\0x04'+命令+'\0x05'
*****************************************/
#include <reg51.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define FOSC 11059200L //晶振频率
#define BAUD 9600 //串口波特率
#define PWMPERIOD 100 //周期,*5ms
#define OPEN 1
#define CLOSE 0
sbit pwm_out=P1^2; //pwm输出口
sbit dq = P0^1; //18b20数据接口
sbit die=P1^0;
uchar tx[10]; //温度结果储存,0、1为整数位,其余小数
uchar temp_now;
//float temp_now_dec;
float temp_set;
uchar cmd;
uchar time_length;
uchar duty_ratio;
//float duty;
float kp,ki,kd; //pid参数
float e_k,e_k_1,e_k_2; //偏差,此刻,上一刻,上上一刻
uchar cmd_flag; //状态标志量,与接收命令有关
uchar run; //运行状态,为1则启动温控
//微秒级延时
void DelayUs(int num)
{
while(num--) ;
}
//毫秒级延时
void DelayMs(uint di) //延时
{
uint da,db;
for(da=0;da<di;da++)
for(db=0;db<100;db++);
}
//发送
void Print(uchar str)
{
//TR0=0;
SBUF=str;
while(!TI);
TI=0;
//TR0=1;
}
//PID计算程序
void CalculatePID()
{
char u_add;
e_k_2=e_k_1;
e_k_1=e_k;
e_k=temp_set-temp_now;
//u_add=(kp+ki+kd)*e_k-(kp+2*kd)*e_k_1+kd*e_k_2;
u_add=kp*e_k-kp*e_k_1;
// duty=duty-u_add;
// if(duty>1)
// {
// duty=1;
// }else if(duty<0)
// {
// duty=0;
// }
// duty_ratio=PWMPERIOD*duty;
duty_ratio=u_add+duty_ratio;
if(duty_ratio>=PWMPERIOD)
{
duty_ratio=PWMPERIOD;
}
Print('D');
Print(duty_ratio/100+48);
Print(duty_ratio%100/10+48);
Print(duty_ratio%10+48);
Print('\n');
}
//ds18b20初始化程序
//返回值:1初始化成功,0失败
uchar Init_DS18B20(void)
{
uchar x=0;
dq = 1; //dq复位
DelayUs(8); //稍做延时
dq = 0; //单片机将dq拉低
DelayUs(80); //精确延时 大于 480us
dq = 1; //拉高总线
DelayUs(14);
x=dq; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
if(x)
{
x=0;
}else
{
x=1;
}
DelayUs(20);
return x;
}
//串口初始化程序
void Init_Uart()
{
SCON = 0x52; //8bit无奇偶校验
TMOD = 0x20; //Timer1设为8bit自动重装模式
TCON=0x00;
PCON=0X00;
TH1 = TL1 = -(FOSC/12/32/BAUD); //定时器初值
TR1 = 1; //Timer1使能
RI=0;
TI=0;
ES = 1; //串口中断使能
EA = 1; //总中断使能
}
//定时器初始化程序
void InitTimer() //5毫秒
{
//AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0x01; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0xEE; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
}
//从DS18B20读取一节数据
//返回值:读到的数据
uchar ReadOneChar(void)
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
dq = 0; // 给脉冲信号
dat>>=1;
dq = 1; // 给脉冲信号
if(dq)
dat|=0x80;
DelayUs(4);
}
return(dat);
}
//对18b20写一个字节
//参数:数据
void WriteOneChar(unsigned char dat)
{
uchar i=0;
for (i=8; i>0; i--)
{
dq = 0;
dq = dat&0x01;
DelayUs(2);
dq = 1;
dat>>=1;
}
}
//读取温度
void ReadTemperature(void)
{
uchar a=0;
uchar b=0;
uchar Data_L=0;
uchar num=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
a=ReadOneChar(); //读低8位
b=ReadOneChar(); //读高8位
tx[0] = (a/16+b*16)/10; //整数部分
tx[1] = (a/16+b*16)%10;
Data_L=a&0X0F;
for(num=3;num<7;num++) //小数部分
{
Data_L=Data_L*10;
tx[num]=Data_L/16;
Data_L=Data_L%16;
}
temp_now=(uchar)(tx[0*10+tx[1]);
//temp_now_dec=tx[0]*10+tx[1]+tx[3]*0.1+tx[4]*0.01;
}
//处理命令
void DealCMD()
{
if(cmd_flag==3)
{
switch (cmd)
{
case 'U':
//up命令,温度设定值上升
if(temp_set<50)
{
temp_set++;
}else
{
temp_set=50;
}
cmd_flag=0;
break;
case 'D':
//down命令,温度设定值下降
if(temp_set>20)
{
temp_set--;
}else
{
temp_set=20;
}
cmd_flag=0;
break;
case 'C':
//close命令,关闭加热
run=0;
//P1=0XF0;
cmd_flag=0;
break;
case 'O':
//open命令,开启加热
run=1;
//P1=0X10;
cmd_flag=0;
break;
default:
cmd_flag=0;
break;
}
}
}
//串口中断函数
void Get()interrupt 4
{
uchar dat;
//P1=0X0C;
if(RI)//接收到数据
{
die=0;
RI=0;
dat=SBUF;
switch (cmd_flag) //根据当前状态采取不同措施
{
case 0:
//未接收到命令头状态
if(dat=='$')
//收到命令头
{
cmd_flag=1;
}
break;
case 1:
//收到命令头状态
cmd=dat;
cmd_flag=2;
break;
case 2:
//准备收结束位
if(dat=='/')
{
cmd_flag=3;
}else
{
cmd_flag=0;
}
break;
default:
//无效状态
cmd_flag=0;
break;
}
}
}
//定时中断函数
void Time()interrupt 1
{
time_length++;
if(time_length>=PWMPERIOD)
{
ReadTemperature();
if(run)
{
pwm_out=OPEN;
time_length=0;
CalculatePID();
}
}else if (time_length>=duty_ratio)
{
pwm_out=CLOSE;
}
}
//主函数
int main()
{
IP=0x10;
InitTimer();
Init_Uart();
Init_DS18B20();
time_length=0;
duty_ratio=0;
e_k=0;
e_k_1=0;
e_k_2=0;
// duty=0;
temp_set=30;
time_length=0;
kp=1;
ki=0;
kd=0;
run=1;
while(1)
{
DealCMD();
if(run)//判断是否需要启动了加热
{
die=!die; //指示灯闪烁
TR0=1;
Print('>'); //运行状态
}else
{
die=0; //指示灯常亮
//TR0=0;
pwm_out=0;
Print('|'); //暂停状态
}
//输出当前温度
Print('N');
// Print('=');
// Print(temp_now/10+48);
// Print(temp_now%10+48);
// Print('.');
// Print((int)(temp_now_dec*10)+48);
// Print((int)(temp_now_dec*100)%10+48);
Print(tx[0+'0');
Print(tx[1+'0');
Print('.');
Print(tx[3+'0');
Print(tx[4+'0');
Print(',');
//Print('\n');
//输出设定温度
Print('S');
// Print('=');
Print((int)temp_set/10+48);
Print((int)temp_set%10+48);
Print('\r');
Print('\n');
DelayMs(200);
}
return 0;
}
|
-
-
USER.7z
84.56 KB, 下载次数: 60, 下载积分: 黑币 -5
|