帮我写一个基于51的pid温度控制系统的程序,采用ds18b20作为温度传感器,数码管显示,通过按键设置期望的温度
时间: 2024-03-23 12:38:44 浏览: 143
C51单片机实现DS18B20温度数据的采集,通过串口传至上位机以及PID控制温度软件设计源代码.zip
5星 · 资源好评率100%
好的,下面是一个基于51单片机的PID温度控制系统的程序,使用DS18B20作为温度传感器,数码管显示温度和设定温度,通过按键设置期望的温度:
```c
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define DQ P2_7
sbit D1 = P0^0; // 数码管D1
sbit D2 = P0^1; // 数码管D2
sbit D3 = P0^2; // 数码管D3
sbit D4 = P0^3; // 数码管D4
sbit KEY_UP = P3^1; // 上键
sbit KEY_DOWN = P3^0; // 下键
float temperature = 0; // 当前温度
float setpoint = 40; // 设定温度
float kp = 2.0; // 比例系数
float ki = 0.5; // 积分系数
float kd = 1.0; // 微分系数
float error = 0.0, error_sum = 0.0, error_diff = 0.0;
float last_error = 0.0, output = 0.0;
void delayms(uint ms) // 延时函数
{
uint i, j;
for (i = 0; i < ms; i++)
{
for (j = 0; j < 120; j++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
void ds18b20_init() // 初始化DS18B20
{
DQ = 1;
delayms(10);
DQ = 0;
delayms(80);
DQ = 1;
delayms(10);
}
uchar ds18b20_read_byte() // 读取一个字节
{
uchar i, j, value = 0;
for (i = 0; i < 8; i++)
{
DQ = 0;
_nop_();
_nop_();
value >>= 1;
if (DQ)
{
value |= 0x80;
}
_nop_();
_nop_();
DQ = 1;
}
return value;
}
void ds18b20_write_byte(uchar value) // 写入一个字节
{
uchar i;
for (i = 0; i < 8; i++)
{
DQ = 0;
_nop_();
_nop_();
if (value & 0x01)
{
DQ = 1;
}
value >>= 1;
_nop_();
_nop_();
DQ = 1;
}
}
float ds18b20_read_temperature() // 读取温度
{
uchar tl, th;
float temp = 0.0;
ds18b20_init();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0x44);
delayms(100);
ds18b20_init();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0xBE);
tl = ds18b20_read_byte();
th = ds18b20_read_byte();
temp = th;
temp <<= 8;
temp |= tl;
temp /= 16.0;
return temp;
}
void display(uint num) // 数码管显示
{
uchar digit[4] = {0};
digit[0] = num % 10;
digit[1] = num % 100 / 10;
digit[2] = num % 1000 / 100;
digit[3] = num / 1000;
if (digit[3])
{
D1 = 1;
}
else
{
D1 = 0;
}
D2 = 1;
P1 = digit[2];
delayms(5);
D2 = 0;
if (digit[3] || digit[2])
{
D3 = 1;
}
else
{
D3 = 0;
}
D4 = 1;
P1 = digit[1];
delayms(5);
D4 = 0;
P1 = digit[0];
}
void main()
{
EA = 1; // 开全局中断
TMOD = 0x01; // 定时器0工作在模式1
TH0 = 0xFC; // 定时器0初值为65536-50000=15536
TL0 = 0x00;
TR0 = 1; // 启动定时器0
ET0 = 1; // 开定时器0中断
ds18b20_init(); // 初始化DS18B20
while (1)
{
if (KEY_UP == 0) // 上键按下
{
setpoint += 1.0;
delayms(10);
}
if (KEY_DOWN == 0) // 下键按下
{
setpoint -= 1.0;
delayms(10);
}
temperature = ds18b20_read_temperature(); // 读取温度
error = setpoint - temperature; // 计算误差
error_sum += error; // 累计误差
error_diff = error - last_error; // 计算误差变化率
output = kp * error + ki * error_sum + kd * error_diff; // 计算输出
if (output < 0.0) // 输出不能为负数
{
output = 0.0;
}
// 控制温度,这里用printf代替实际控制操作
printf("Temperature: %.2f, Setpoint: %.2f, Output: %.2f\n", temperature, setpoint, output);
temperature += output;
display((uint)(temperature * 10)); // 显示温度
}
}
void timer0_isr() interrupt 1 // 定时器0中断服务程序
{
TH0 = 0xFC; // 定时器0初值为65536-50000=15536
TL0 = 0x00;
}
```
这个程序使用了定时器0来实现一个简单的延时,从而避免了使用延时函数的问题。在主循环中,通过读取上下按键来设置设定温度,然后使用PID算法计算控制输出来控制温度,使用DS18B20读取温度值,并通过数码管显示温度和设定温度。控制输出不能为负数,因此在计算输出时需要进行判断。注意,在使用DS18B20时需要正确连接电路,以及正确初始化和读取传感器。
阅读全文