找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 4555|回復(fù): 4
收起左側(cè)

基于18b20的PID溫控單片機(jī)程序

[復(fù)制鏈接]
ID:587827 發(fā)表于 2019-7-21 19:01 | 顯示全部樓層 |閱讀模式
主控芯片采用STM32F103RCT6,用18b20作為溫度傳感器,可以通過(guò)串口發(fā)送命令和當(dāng)前溫度等信息。PI調(diào)節(jié),使用PWM控制固態(tài)繼電器繼而控制加熱器通斷。
/******************************************
/*********    無(wú)線遙控溫度控制            
/*********    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數(shù)據(jù)接口
sbit die=P1^0;

uchar tx[10];               //溫度結(jié)果儲(chǔ)存,0、1為整數(shù)位,其余小數(shù)
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參數(shù)
float e_k,e_k_1,e_k_2;      //偏差,此刻,上一刻,上上一刻

uchar cmd_flag;             //狀態(tài)標(biāo)志量,與接收命令有關(guān)
uchar run;                      //運(yùn)行狀態(tài),為1則啟動(dòng)溫控

//微秒級(jí)延時(shí)
void DelayUs(int num)
{
    while(num--) ;
}

//毫秒級(jí)延時(shí)
void DelayMs(uint di) //延時(shí)
{
    uint da,db;
    for(da=0;da<di;da++)
        for(db=0;db<100;db++);
}

//發(fā)送
void Print(uchar str)
{
    //TR0=0;
    SBUF=str;
    while(!TI);
    TI=0;
    //TR0=1;
}

//PID計(jì)算程序
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復(fù)位
    DelayUs(8);  //稍做延時(shí)
    dq = 0;    //單片機(jī)將dq拉低
    DelayUs(80); //精確延時(shí) 大于 480us
    dq = 1;    //拉高總線
    DelayUs(14);
    x=dq;      //稍做延時(shí)后 如果x=0則初始化成功 x=1則初始化失敗
    if(x)
    {
        x=0;
    }else
    {
        x=1;
    }
   
    DelayUs(20);
    return x;
}

//串口初始化程序
void Init_Uart()
{
    SCON = 0x52;            //8bit無(wú)奇偶校驗(yàn)
    TMOD = 0x20;            //Timer1設(shè)為8bit自動(dòng)重裝模式
    TCON=0x00;
    PCON=0X00;
    TH1 = TL1 = -(FOSC/12/32/BAUD); //定時(shí)器初值
    TR1 = 1;                //Timer1使能
        RI=0;
    TI=0;
    ES = 1;                 //串口中斷使能
    EA = 1;                 //總中斷使能
}

//定時(shí)器初始化程序
void InitTimer()        //5毫秒
{
    //AUXR &= 0x7F;     //定時(shí)器時(shí)鐘12T模式
    TMOD &= 0x01;       //設(shè)置定時(shí)器模式
    TL0 = 0x00;     //設(shè)置定時(shí)初值
    TH0 = 0xEE;     //設(shè)置定時(shí)初值
    TF0 = 0;        //清除TF0標(biāo)志
    TR0 = 1;        //定時(shí)器0開(kāi)始計(jì)時(shí)
    ET0 = 1;
}

//從DS18B20讀取一節(jié)數(shù)據(jù)
//返回值:讀到的數(shù)據(jù)
uchar ReadOneChar(void)
{
    uchar i=0;
    uchar dat = 0;
    for (i=8;i>0;i--)
    {
        dq = 0; // 給脈沖信號(hào)
        dat>>=1;
        dq = 1; // 給脈沖信號(hào)
        if(dq)
        dat|=0x80;
        DelayUs(4);
    }
    return(dat);
}

//對(duì)18b20寫一個(gè)字節(jié)
//參數(shù):數(shù)據(jù)
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); // 跳過(guò)讀序號(hào)列號(hào)的操作
    WriteOneChar(0x44); // 啟動(dòng)溫度轉(zhuǎn)換
    Init_DS18B20();
    WriteOneChar(0xCC); //跳過(guò)讀序號(hào)列號(hào)的操作
    WriteOneChar(0xBE); //讀取溫度寄存器

    a=ReadOneChar();  //讀低8位
    b=ReadOneChar(); //讀高8位

    tx[0] = (a/16+b*16)/10;      //整數(shù)部分
    tx[1] = (a/16+b*16)%10;

    Data_L=a&0X0F;
    for(num=3;num<7;num++)       //小數(shù)部分
   {
        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命令,溫度設(shè)定值上升
                if(temp_set<50)
                {
                    temp_set++;
                }else
                {
                    temp_set=50;
                }
                cmd_flag=0;
                break;
            case 'D':
            //down命令,溫度設(shè)定值下降
                if(temp_set>20)
                {
                    temp_set--;
                }else
                {
                    temp_set=20;
                }
                cmd_flag=0;
                break;
            case 'C':
            //close命令,關(guān)閉加熱
                run=0;
                //P1=0XF0;
                cmd_flag=0;
                break;
            case 'O':
            //open命令,開(kāi)啟加熱
                run=1;
                //P1=0X10;
                cmd_flag=0;
                break;
            default:
                cmd_flag=0;
                break;
            }
        }
}

//串口中斷函數(shù)
void Get()interrupt 4
{
    uchar dat;
    //P1=0X0C;
    if(RI)//接收到數(shù)據(jù)
    {
        die=0;
        RI=0;
        dat=SBUF;

        switch (cmd_flag)   //根據(jù)當(dāng)前狀態(tài)采取不同措施
        {
        case 0:
        //未接收到命令頭狀態(tài)
            if(dat=='$')
            //收到命令頭
            {
                cmd_flag=1;
            }
            break;
        case 1:
        //收到命令頭狀態(tài)
            cmd=dat;
            cmd_flag=2;
            break;
        case 2:
        //準(zhǔn)備收結(jié)束位
            if(dat=='/')
            {
                cmd_flag=3;
            }else
            {
                cmd_flag=0;
            }
            break;
        default:
        //無(wú)效狀態(tài)
            cmd_flag=0;
            break;
        }
    }
}

//定時(shí)中斷函數(shù)
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;
    }
   
}

//主函數(shù)
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)//判斷是否需要啟動(dòng)了加熱
        {
            die=!die;           //指示燈閃爍
            TR0=1;
            Print('>');         //運(yùn)行狀態(tài)
        }else
        {
            die=0;              //指示燈常亮
            //TR0=0;
            pwm_out=0;
            Print('|');         //暫停狀態(tài)
        }
        //輸出當(dāng)前溫度
        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');
        //輸出設(shè)定溫度
        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, 下載次數(shù): 60, 下載積分: 黑幣 -5

回復(fù)

使用道具 舉報(bào)

ID:202586 發(fā)表于 2019-7-25 19:45 來(lái)自觸屏版 | 顯示全部樓層
不錯(cuò),謝謝樓主分享
回復(fù)

使用道具 舉報(bào)

ID:401343 發(fā)表于 2019-7-28 22:44 | 顯示全部樓層
謝謝分享
回復(fù)

使用道具 舉報(bào)

ID:879424 發(fā)表于 2021-4-6 17:41 | 顯示全部樓層
能否詳細(xì)講一下PID的編程思路?
回復(fù)

使用道具 舉報(bào)

ID:332674 發(fā)表于 2021-4-12 13:25 | 顯示全部樓層
請(qǐng)問(wèn)樓主模塊是用的什么?求分享
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表