基于STM8的程控加热器

这是我在创新的考核任务,来回顾复习一下整个过程并总结一些错误

设计制作一个程控加热器,能根据预定的温度--时间曲线进行加热,其示意图如下图所示。

基本要求

(1)能显示设定温度和实际工作温度;

(2)可用键盘设定控制温度,温控误差要求小于±2℃;

(3)温度低于30℃时,风扇停止工作,加热器开始加热;当温度高于70℃,应切断加热器,并接通风扇开始散热。

(4)到达预定温度、上下限温度时能声光报警;

(5)自制直流电源

发挥部分

(1)能显示加热功率和风扇转速;

(2)加热功率程控可调;

(3)具有程控加热功能,能按预定的加热曲线进行加热;

(4)温控误差要求小于±1℃

(5)其他。

设计思路

显示:OLED显示屏

温度设定:按键

数据获取:ds18b20,霍尔元器件

数据处理:PID算法

数据输出:PWM1,PWM2

加热:水泥电阻

温控主要流程:用ds18b20获得水泥电阻的实时温度,再对实际温度与设定温度进行比较并进行数据处理,来对风扇和水泥电阻输出PWM实现控制

DS18B20时序

/*******************************************************************************
* 函 数 名         : Ds18b20Init
* 函数功能    : 初始化
* 输    入         : 无
* 输    出         : 初始化成功返回1,失败返回0
*******************************************************************************/


u8 Ds18b20Init()
{
u8 i;
        GPIO_DeInit(GPIOA);
        
        GPIO_WriteLow(GPIOA, GPIO_PIN_1);
        Delay_us(600);
        
        GPIO_WriteHigh(GPIOA, GPIO_PIN_1);
        Delay_us(10);                                //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
GPIO_Init(GPIOA, GPIO_PIN_1, GPIO_MODE_IN_PU_NO_IT);
        
        
while(GPIO_ReadInputPin(GPIOA, GPIO_PIN_1)) //等待DS18B20拉低总线


          
{
Delay_ms(1);
i++;
if(i>5)//等待>5MS
{
return 0;//初始化失败
}

}
        
        return 1;//初始化成功
}


/*******************************************************************************
* 函 数 名         : Ds18b20WriteByte
* 函数功能    : 向18B20写入一个字节
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/


void Ds18b20WriteByte(u8 dat)
{
u16 j;
        GPIO_Init(GPIOA, GPIO_PIN_1, GPIO_MODE_OUT_PP_HIGH_FAST);


for(j=0; j<8; j++)
{
                GPIO_WriteLow(GPIOA, GPIO_PIN_1);

                Delay_us(1);

if((dat&0x01))
                {
                    GPIO_WriteHigh(GPIOA, GPIO_PIN_1);
                }
                else 
                {
                    GPIO_WriteLow(GPIOA, GPIO_PIN_1);
                }

                dat >>= 1;

                Delay_us(60);
GPIO_WriteHigh(GPIOA, GPIO_PIN_1);

Delay_us(1);
                
}
}
/*******************************************************************************
* 函 数 名         : Ds18b20ReadByte
* 函数功能    : 读取一个字节
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/



u8 Ds18b20ReadByte()
{
u8 byte, bi;
u16  j;
        
for(j=8; j>0; j--)
{
                GPIO_Init(GPIOA, GPIO_PIN_1, GPIO_MODE_OUT_PP_HIGH_FAST);
//先将总线拉低1us
GPIO_WriteLow(GPIOA, GPIO_PIN_1);
                Delay_us(1);
                
GPIO_WriteHigh(GPIOA, GPIO_PIN_1);//然后释放总线
Delay_us(6);

//延时6us等待数据稳定

                GPIO_Init(GPIOA, GPIO_PIN_1, GPIO_MODE_IN_PU_NO_IT);
if(GPIO_ReadInputPin(GPIOA, GPIO_PIN_1))      
                {
                    bi = 0x01;
                }  //读取数据,从最低位开始读取
                else bi = 0x00;
                /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
byte = (byte >> 1) | (bi << 7);
                Delay_us(60);
                
}
return byte;
}
/*******************************************************************************
* 函 数 名         : Ds18b20ChangTemp
* 函数功能    : 让18b20开始转换温度
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/


void  Ds18b20ChangTemp()
{
Ds18b20Init();
Delay_ms(1);
Ds18b20WriteByte(0xcc); //跳过ROM操作命令  
Ds18b20WriteByte(0x44);     //温度转换命令

   
}
/*******************************************************************************
* 函 数 名         : Ds18b20ReadTempCom
* 函数功能    : 发送读取温度命令
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/


void  Ds18b20ReadTempCom()
{
Ds18b20Init();
Delay_ms(1);
Ds18b20WriteByte(0xcc); //跳过ROM操作命令
Ds18b20WriteByte(0xbe); //发送读取温度命令

}

/*******************************************************************************
* 函 数 名         : Ds18b20ReadTemp
* 函数功能    : 读取温度
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/


int Ds18b20ReadTemp()
{
int temp = 0;
u8 tmh, tml;
Ds18b20ChangTemp(); //先写入转换命令
Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令
tml = Ds18b20ReadByte(); //读取温度值共16位,先读低字节
tmh = Ds18b20ReadByte(); //再读高字节
temp = tmh;
temp <<= 8;
temp |= tml;
return temp;
}
这个代码一步一步照着时序码的,还是花了一些时间弄这个...最后读出的数据很快很准确,还是挺高兴的~

PID

粗略理解了PID之后便写了以下代码

emm当时还修改了I的计算方式,以为自己的更好

因为I是以过去的误差来决定未来的功率大小,而经典算法中的I是不断累加的,我就认为不断累加之后巨大的值对温控稳定状态会造成很大的误差,于是我将一直累加改成一段时间累加,最后第一次运行的结果是+-0.2的波动

后来我在改进代码的时候重新用累加写了一下I,发现效果更好...这与我的判断不符,猛然惊醒。对于有风扇的温控,当我在温度接近稳定时,只需要维持稳定即可,所以到这时的I很大可以迅速抵消风吹造成的温度下降。

那对于没风扇的加热器呢?没风扇最大的问题就是温度过冲,所以加热曲线实现的时间必须变长。

一些问题:

由于stm8K103不能用sprintf函数造成了一些困扰,于是我自己写了一个int转字符串函数

判断无符号数<0是我犯过很蠢的错误之一~~

猜你喜欢

转载自blog.csdn.net/qq_40589292/article/details/80600896
今日推荐