哈哈,今天终于实现了白光控制器的基本功能。
此次是技术预览版,故只有基本功能,其它功能将在后期陆续加入。
目前实现功能:
1、烙铁温度读取;
2、PWM加热;
3、PID控温;
4、单按键控制加热与否。
由于刚刚才实现基本功能,还没有加上冷端补偿;手上51板的按键都在P1口,所以也只加了一个按键,没有加入温度调整;PID还没有调好,升温较慢;手上只有NMOS管,且自举电路有问题,另在1N4148上端与地之间并了一0.02uF电容。
源程序及电路图下载
/* 白光控制器技术预览版
* elecfun
* 2011-3-20
* 实现基本功能
*/
#include "STC_NEW_8051.H"
#include <intrins.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "LCD1602.H"
#define FOSC 11187107
#define BAUD 1200
#define BG_ON P1&=~(1<<3)
#define BG_OFF P1|=(1<<3)
#define BG_CPL P1^=(1<<3)
#define PORT_KEY P1 //按键接口
#define KEY_ON 0x20 //按键位置
#define TTNUM 10
unsigned char idata tArr[TTNUM];
unsigned char ptArr;
unsigned char keyOne,keyAll; //按键
bit isWork=0;
unsigned char pwm; //系统PWM值
unsigned int t;
unsigned int intT=1;
struct PID {
unsigned int SetPoint; // 设定目标 Desired Value
double Proportion; // 比例常数 Proportional Const
double Integral; // 积分常数 Integral Const
double Derivative; // 微分常数 Derivative Const
unsigned int LastError; // 上次误差
unsigned int PrevError; // 上上次误差
unsigned int SumError; // 累积误差
};
struct PID spid;
//PID计算
unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )
{
int dError,Error;
Error = pp->SetPoint - NextPoint; // 偏差
pp->SumError += Error; // 积分
dError = pp->LastError - pp->PrevError; // 当前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion * Error // 比例项
+ pp->Integral * pp->SumError // 积分项
+ pp->Derivative * dError); // 微分项
}
//读按键值
void KeyRead( void )
{
unsigned char readData;
PORT_KEY |= (KEY_ON);
readData = PORT_KEY^0xff; //读端口值,并取反
keyOne = readData & (readData ^ keyAll); //只在第一次按下时为按键值,以后为0
keyAll = readData; //长按、短按都为按键值
}
void Delayms(unsigned int dm)
{
unsigned int d1,d2;
for (d1=0; d1<dm; d1++)
for (d2 = 0; d2<666; d2++)
;
}
unsigned char GetADCResult(unsigned char ch)
{
ADC_CONTR = ADC_POWER | ADC_SPEEDL | ch | ADC_START;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));//等待完成
return ADC_RES; //返回8位值
}
//ADC初始化
void InitADC()
{
P1ASF = 1<<7;
P1M0 = 1<<7; //ADC7设置为开漏输入,其它为准双向
P1M1 = 1<<7;
ADC_RES = 0;
ADC_CONTR = ADC_POWER | ADC_SPEEDL;
Delayms(2);
}
//串口初始化
void InitUart()
{
SCON = 0x5a;
TMOD = 0x20; //T18位自动重载
TH1 = TL1 = -(FOSC/12/32/BAUD);
TR1 = 1;
}
//串口发送字符
void SendData(unsigned char dat)
{
while (!TI);
TI = 0;
SBUF = dat;
}
//串口发送字符串
void SendString(unsigned char *s)
{
while (*s++)
{
SendData(*s);
}
}
//读取温度,取平均值
void GetTemp(void)
{
unsigned char i;
unsigned int tAll=0;
for (i=0; i<TTNUM; i++)
{
tAll += tArr[i];
}
t = tAll / TTNUM;
Delayms(2);
tArr[ptArr] = GetADCResult(7);
if (++ptArr >= TTNUM)
{
ptArr = 0;
}
}
//PWM初始化
void InitPWM(void)
{
EA = 1;
CCON = 0x00; //初始化PCA寄存器
CMOD = 0x00; //时钟12分频,禁止溢出中断
CL = 0; //初始化PCA计数器
CH = 0;
CCAP0H = CCAP0L = 0x80; //占空比00%
CCAPM0 = 0x63; //8位PWM,由低变高产生中断
CR = 1; //PCA时钟开始工作
}
//PWM中断函数,读取温度并计算PID值
void PCA_Int(void) interrupt 7 //PCA中断
{
CR = 0;
EA = 0;
intT++;
if (intT>20)
{
intT=0;
GetTemp();
pwm = PIDCalc(&spid, t);
if (pwm == 0)
{
pwm = 1;
}
}
EA = 1;
CF = 0;
CCF0 = 0;
CR = 1;
}
void main(void)
{
float tt;
unsigned int td,tp;
unsigned char arr[10];
InitADC();
InitUart();
Init_LCD1602();
BG_OFF;
InitPWM();
spid.Proportion = 2.0; //比例常数
spid.Integral = 0.0; //积分
spid.Derivative = 0.0; //微分
spid.SetPoint = 225; //目标
isWork=0;
while(1)
{
KeyRead();
if (keyOne & KEY_ON)
{
isWork = ~isWork;
}
//此处为温度转换公式,计算得出,可能不准确
tt = 3.55 * t + 15.8;
sprintf(arr, "%5.1f", tt);
LCD1602_DispString(0, 0, arr); //显示当前温度
sprintf(arr, "%3u", spid.SetPoint);
LCD1602_DispString(8, 0,arr); //显示设定温度
sprintf(arr, "%3u%%",(unsigned int)(pwm*100/255)); //显示当前PWM
LCD1602_DispString(8, 1, arr);
if (isWork)
{
CCAP0H = CCAP0L = pwm;
CR = 1;
LCD1602_DispString(0,1,"ON ");
} else {
pwm = 1;
CCAP0H = CCAP0L = pwm;
LCD1602_DispString(0,1,"OFF");
}
}
}