原理图看贴子:
http://bbs.mydigit.cn/read.php?tid=1856713&ds=1#tpc 源代码开放了,随便有空就玩玩的,也没有太多注释,也没有整理下,压缩包里面有HEX和代码
下载方式选用内部8M晶振,无分频~ 编译器是ICCAVR V7.22 - June 25th 2009
看了的给个M币支持就好了~ 版主,给个专家或者精吧,哈。。。
原贴还有PCB免费送,付邮费就行~ 已经有人订了几块了,共12块~
#include <iom48v.h>
#include <macros.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define mclk 8000000
#pragma data:code
flash table[]={0xf9,0x90,0x5d,0xd5,0xb4,0xe5,0xed,0xd0,0xfd,0xf5};//0~9, verson2
//const table[]={0x77,0x24,0x3B,0x3E,0x6C,0x5E,0x5F,0x34,0x7F,0x7E};//"0~9" " -" " C" 0x80--"." version1
//const table1[]={0x08,0x80,0x7d,0x53,0x6f,0x67} ; //"-"".""A""C""W""V" +1000 point LED1 +2000 point LED2 +3000 point LED3
flash table1[]={0x04,0x02,0xfc,0x69,0xbd,0xb9};//version2
//const table2[] ={}; //version2 E1 E2 E3
uchar set_t,stop,set_hot;// , stop;//set_t=1,set initial temperature, set_t=0,normal work; stop=1 ,L1 don't work,else work
uchar EPROMH,EPROML, StateTVI; //StateTVI 温度电压电流
volatile uint Tem_Iron,Tem_Iron_Next,Tem_Ironset,Tem_IN4148,VoltageIn,CurrentIn,PowerIn, Ad_data,Time_temp,Time_temp1,Tem_Iron_show,Tem_IN4148_show,VoltageIn_show,CurrentIn_show; //
static uchar delay_10,delay_100,delay_500;
volatile int pwmval ,pwmval_show , pTerm, dTerm, iTerm,K_pwm,i2;
//#define LED1 (1<<4) //PORTC
//#define LED2 (1<<5)//
//#define LED3 (1<<3)//最高位version1
#define LED1 (1<<3) //PORTC version2
#define LED2 (1<<4)//
#define LED3 (1<<5)//最高位
#define KEY_MENU (1<<1) //PORTB
#define KEY_UP (1<<0)
#define KEY_DOWN (1<<7)
#define StartShowTime 800 // //ms,startshowtime for Tem_Iron start show time
#define IronTypeShowTime 400 //ms show IronType,when start Iron power,it should short than StartShowTime
#define LED1POINT 1000
#define LED2POINT 2000
#define LED3POINT 3000
#define A_SHOW 4000
#define C_SHOW 5000
#define W_SHOW 6000
#define V_SHOW 7000
#define N 10// AD采样次数
#define Td 810 //设定温度基准,代表0 报氏度的值 5个单位1.C
#define Tem_Setvalue 340
uchar Trg;
uchar Cont;
uchar Release;
uchar cnt_plus,cnt_plus1;
typedef enum
{ A1321=0x01,
A1322=0x02,
// A1323=0x03,
//T12=0x04,
CurrentShort=0x10,
NoCurrent=0x11,
IronTemErr=0x12,//电烙铁温度检测错误A1322 检测到没有温度,小于0X30珹1321检测到温度不升高
}IronType;
IronType Iron_type ;
typedef struct
{
int dState; // Last position input
int iState; // Integrator state
int iGain, // integral gain
pGain, // proportional gain
dGain; // derivative gain
} SPid;
//SysConfig config; //系统参数
SPid pid; // PID 控制结构
//#ifdef ATMEGA8 //for atmega8 and mega48 compatible
//#else
void delay(uint ms)
{
uint i,j;
for(i=0;i<ms;i++)
{
for(j=0;j<1141;j++);
}
}
void RTEEPROMwrite(int location, unsigned char databyte) //写EEPROM,读写砸8ms以上的延时
{
unsigned char savedSREG;
while(EECR&(1<<EEWE));
EEAR = location; // set address
EEDR = databyte; // set data
savedSREG = SREG; // keep setting so it can be restored
CLI(); // disable interrupts
EECR |= BIT(EEMWE); // set "write enable" bit
EECR |= BIT(EEWE); // set "write" bit
SREG = savedSREG; // restore SREG
EEAR = 0;
}
unsigned char RTEEPROMread(int location) //读EEPROM
{
unsigned char savedSREG;
while(EECR&(1<<EEWE));
savedSREG = SREG; // keep setting so it can be restored
CLI();
EEAR = location; // set address
EECR |= BIT(EERE); // set "read enable" bit
EEAR = 0;
SREG = savedSREG;
return (EEDR);
}
/*void uart_init(uint baud)
{
UCSR0B=0x00;
UCSR0A=0x00; //控制寄存器清零
UCSR0C=0x06;
//选择UCSRC,异步模式,禁止
// 校验,1位停止位,8位数据位
baud=mclk/16/baud-1 ; //波特率最大为65K
UBRR0L=baud;
UBRR0H=baud>>8; //设置波特率
UCSR0B=(1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0);
//接收、发送使能,接收中断使能
SREG=BIT(7); //全局中断开放
DDRD|=0X02; //配置TX为输出(很重要)
}
void uart_sendB(uchar data)
{
while(!(UCSR0A&(BIT(UDRE0)))) ;
UDR0=data;
while(!(UCSR0A&(BIT(TXC0))));
UCSR0A|=BIT(TXC0);
}
//串口发送字符串
void uart_SendString(uchar*s)
{
while (*s++)
{
uart_sendB(*s);
}
}
void uart_rx()
{
UCSR0B&=~BIT(RXCIE0);
rdata=UDR0;
flag=1;
UCSR0B|=BIT(RXCIE0);
}
*/
void timer1_init(void) //time1 setup
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Ph. correct PWM top=03FFh
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
/*TCCR1A=0x13;//OC1B输出比较输出模式,比较匹配时输出取反;比较匹配时,OC1A/OC1B清零
TCCR1B=0x03;//10位相位修正的PWM ,OC1B输出 64分频
TCNT1H=0x02;
TCNT1L=0x8E;
ICR1H=0x03;
ICR1L=0xE8;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
TIMSK1 = 0x04;//使能OCIE1B*/
/*TCCR1A = 0x00; //相位频率可调
TCCR1B = 0x00; // WGM: 9 TOP=ICRn;内部时钟1分频
TCCR1B = 0x00; //stop
TCNT1 = 0x00; //setup
OCR1A = 0x03E8;//初始电压240V
OCR1B = 0x03E8;//初始电流10A
ICR1 = 0x07D0; // 2000Hz
TCCR1A =0xA0; /*相位频率可调*/
//TCCR1B =0x11; // WGM: 9 TOP=ICRn;内部时钟1分频*/
TCCR1A = (1<<WGM11); //相位修正PWM模式,TOP值定义为ICR1
TCCR1B = (1<<WGM13);
//OC1A比较匹配时OC1A电平取反
//OC1B升序比较匹配时清0,降序比较匹配置1
TCCR1A |= (1<<COM1A0)|(1<<COM1B1);
TCCR1B |= (1<<CS11);//|(1<<CS10); //无分频
OCR1A = 200; //输出比较寄存器OCR1A赋初值
OCR1B = 200; //输出比较寄存器OCR1B赋初值
// OCR1C = 200; //输出比较寄存器OCR1C赋初值
ICR1 = 1000; //配置输入捕捉寄存器1,确定为TOP值,决定PWM分辨率
TIMSK1 = 0x04;//使能OCIE1B*/
}
void timer2_init(void)
{
OCR2A=0x14;// f=8M/1024/OCR2A(20)=391HZ 2.6ms
TCCR2A=0x02;//CTC工作模式
TCCR2B=0x07;//1024
TIMSK2|=0x02;//使能计数器达到TOP时中断
}
void ledshow(uint value)
{uchar Ledvalue[3],i,pointbit;
static uchar ledbit;
if(value>999) //+1000 point LED1 +2000 point LED2 +3000 point LED3 +4000" A "+5000 "C"+6000"W "+7000"V"
{ pointbit=value/1000;
value=value-pointbit*1000;
}
else
pointbit=0;
if(ledbit>=3)
ledbit=0;
for(i=0;i<3;i++)
{
Ledvalue
=value%10; value=value/10; } switch(ledbit++) {case 0:PORTC=PORTC|LED1|LED2|LED3; if(pointbit>0) {if(pointbit==1) PORTD=~(table[Ledvalue[0]]|table1[1]); if(pointbit==4) PORTD=~table1[2];//A if current mode point LED3 if(pointbit==5) PORTD=~table1[3];//C if(pointbit==6) PORTD=~table1[4];//W if(pointbit==7) PORTD=~table1[5];//V } else PORTD=~table[Ledvalue[0]]; PORTC&=~ LED1; break; case 1: PORTC=PORTC|LED1|LED2|LED3; if(pointbit==2) PORTD=~(table[Ledvalue[1]]|table1[1]); else PORTD=~table[Ledvalue[1]]; PORTC&=~LED2; break; case 2: PORTC=PORTC|LED1|LED2|LED3; if(pointbit==3||pointbit==4) PORTD=~(table[Ledvalue[2]]|table1[1]); //if current mode point LED3 else PORTD=~table[Ledvalue[2]]; PORTC&=~LED3; break; case 3: //delay(500); break; } }void KeyRead( void ) { uchar ReadData = PINB^0xff; // 1 读键值 ,保存到ReadData里面 Trg = ReadData & (ReadData ^ Cont); // 2 得到按下触发值 Release= (ReadData ^ Trg ^ Cont); // 3 得到释放触发值 Cont = ReadData; // 4 得到所有未释放的键值 } void Key_Process(void){ uint TEM1temp; if(Release&KEY_MENU){ if (StateTVI<=4) //StateTVI 0:烙铁温度 1:环境温度 2、电压 3、电流 4、功率 StateTVI++ ; if(StateTVI>4) StateTVI=0; // TEM1temp=Tem_IN4148; // EPROMH=(TEM1temp>>8)&0xff; // EPROML=TEM1temp&0xff; // RTEEPROMwrite(0x07,EPROMH); // RTEEPROMwrite(0x08,EPROML); } if(Cont&KEY_UP){ if((cnt_plus>50)&(StateTVI==0))//50ms代表按键是连续地按下并且在烙铁显示温度的时候才能改变 { cnt_plus=0; if(Tem_Ironset>=100&&Tem_Ironset<480) Tem_Ironset++; else Tem_Ironset=480; } } if(Cont&KEY_DOWN){ if((cnt_plus>50)&&(StateTVI==0)) //20ms代表按键是连续地按下 { cnt_plus=0; if(Tem_Ironset>100&&Tem_Ironset<=480) Tem_Ironset--; else Tem_Ironset=100; } } if((Release&KEY_DOWN)||(Release&KEY_UP)&&(StateTVI==0) ) //非设置的情况下,如果检测到上或者下按键,保存信息到EEPROM { TEM1temp=Tem_Ironset; EPROMH=(TEM1temp>>8)&0xff; EPROML=TEM1temp&0xff; RTEEPROMwrite(0x05,EPROMH); RTEEPROMwrite(0x06,EPROML); Time_temp=0; // 让设置好的参数显示长一点 } } /*void SwithStateTVI_Test(void){ switch(StateTVI) { case 0:{if((Time_temp<StartShowTime)||(Cont&KEY_DOWN)||(Cont&KEY_UP)&&(StateTVI==0)) ledshow(Tem_Ironset); else ledshow(Tem_Iron); }break; case 1:{ ledshow(Tem_IN4148); }break; case 2:{ ledshow(VoltageIn); }break; case 3: { ledshow(CurrentIn); } break; case 4 : { ledshow(PowerIn); } break; }}*/void SwithStateTVI(void){ switch(StateTVI) { case 0:{ if(Time_temp1<IronTypeShowTime) ledshow ( Iron_type); else if((Time_temp<StartShowTime)||(Cont&KEY_DOWN)||(Cont&KEY_UP)&&(StateTVI==0)||(Tem_Iron-Tem_Ironset)<=10||(Tem_Ironset-Tem_Iron)<=8) ledshow(Tem_Ironset); else ledshow(Tem_Iron_show); // ledshow((Tem_Iron*4/5+(Td-Tem_IN4148)*10/26)); }break; case 1:{ if(Td>=Tem_IN4148)//只显示大于0度的 ledshow((Td-Tem_IN4148_show)*10/26*10+C_SHOW); else ledshow(0+C_SHOW); //ledshow(pwmval_show); }break; case 2:{ // ledshow(set_hot); ledshow(VoltageIn_show*50/186+LED2POINT); //实际值为37.23 }break; case 3: { ledshow(CurrentIn_show*100/225+A_SHOW);//CurrentIn<655,or overflow } break; case 4 : { ledshow((VoltageIn_show*10/37)*(CurrentIn_show*100/225)/100+W_SHOW); } break; }} uint filter_adc(void) //ADC+中位值平均滤波法{ uint value_buf[N],temp; uchar count,i,j; unsigned long sum=0; ADCSRA =0X80; //控制寄存器0x82,4分频;0x83,8分频;0x85,32分频;0x86,64分频;0x87,128分频 for (count=0;count<N;count++) { ADCSRA |=BIT(ADSC); //启动AD转换 while(!(ADCSRA &(BIT(ADIF)))); //判断AD转换是否结束 value_buf[count]=ADC; } for(j=0;j<N-1;j++) for(i=0;i<N-j;i++) if(value_buf>value_buf[i+1]) //+1 { temp=value_buf; value_buf=value_buf[i+1]; //+1 value_buf[i+1]=temp; } for(count=1;count<N-1;count++) //连续采样N个数据,去掉一个最大值和一个最小值 sum += value_buf[count]; return sum/(N-2); //然后计算N-2个数据的算术平均值 } uint mega48_ad0(void) //T1 Tem_Iron{ uint addata; ADMUX=0x00;//选ADC0为输入 //ADCSRA=0X80;//启动ADC,置位使能 //ADCSRA|=BIT(ADSC);//置位,开始转换 //while(!(ADCSRA&(BIT(ADIF)))); //addata=ADCL; // addata=addata+ADCH*256; addata=filter_adc(); return addata;} uint mega48_ad1(void) //T2 Tem_IN4148{ uint addata; ADMUX=0x01;//选ADC1为输入 // ADCSRA=0X80;//启动ADC,置位使能 //ADCSRA|=BIT(ADSC);//置位,开始转换 //while(!(ADCSRA&(BIT(ADIF)))); // addata=ADCL; // addata=addata+ADCH*256; addata=filter_adc(); return addata;} uint mega48_ad2(void) //I{ uint addata; ADMUX=0x02;//选ADC2为输入 // ADCSRA=0X80;//启动ADC,置位使能 //ADCSRA|=BIT(ADSC);//置位,开始转换 //while(!(ADCSRA&(BIT(ADIF)))); // addata=ADCL; // addata=addata+ADCH*256; addata=filter_adc(); return addata;} uint mega48_ad7(void) //V{ uint addata; ADMUX=0x07;//选ADC7为输入 // ADCSRA=0X80;//启动ADC,置位使能 //ADCSRA|=BIT(ADSC);//置位,开始转换 //while(!(ADCSRA&(BIT(ADIF)))); // addata=ADCL; // addata=addata+ADCH*256; addata=filter_adc(); return addata; } #pragma interrupt_handler timer1_compb_isr:13void timer1_compb_isr(void){ //ledshow(210); //SwithStateTVI();} #pragma interrupt_handler timer2_ovf_isr:12void timer2_ovf_isr(void) { int error; if(Time_temp<StartShowTime) { Time_temp++;} if(Time_temp1<IronTypeShowTime) { Time_temp1++; } cnt_plus++;//for key cnt_plus1++;//for ad Ad_data=mega48_ad0(); KeyRead(); Key_Process(); i2--; if (cnt_plus1>=10) {delay_10=1; cnt_plus1=0; } else delay_10=0; if(Iron_type==A1322) { Tem_Iron=(Ad_data-23)*5/4+(Td-Tem_IN4148)*10/26; //1 Ad_data-23 去掉失调电压,烙铁电压=采集电压+冷端温度补偿 if(Tem_Iron>500) Tem_Iron=0; //开机的时候,有可能Temp_Iron小于零,导致不正常,所以先置0 }//for A1322 23是运放的失调电压,(Td-Tem_IN4148)*10/26 是实际温度,冷端补偿 if(Iron_type==A1321) { if(Ad_data>=500) Tem_Iron=Ad_data-500;//for A1321 else Tem_Iron=0; //20130516 解决开机乱显示大于加热温度问题 } ///if(Iron_type==CurrentShort) // Tem_Iron=480;//把温度设置到最高,关掉PWM // if(Iron_type==NoCurrent) // ledshow(000); Ad_data=mega48_ad1();//AD1采样环境温度 Tem_IN4148=Ad_data; //Tem_IN4148+((unsigned long)addata*5*1000000/1024/41/48); Ad_data=mega48_ad7();//AD7采样电压 VoltageIn=Ad_data; Ad_data=mega48_ad2();//AD2极样电流 CurrentIn=Ad_data; pwmval_show=pwmval; delay_500++; if(delay_500>=60) { delay_500=0; Tem_Iron_show=Tem_Iron;//让显示的温度电压电流跳动缓慢一点 Tem_IN4148_show=Tem_IN4148; VoltageIn_show=VoltageIn; CurrentIn_show=CurrentIn; } //if(((unsigned long)addata*5*1000000/1024/41/48)<Tem_Iron) // open_mosft();//(m1*5(5V电压VREF)/1024)/(470/10+1)/0.000041 open 电烙铁 // sprintf("pwmvalue=%x,Tem_Iron=%",pwmval); // uart_sendB((pwmval>>8)&&0xff); // uart_sendB((pwmval)&&0xff); // uart_sendB((Tem_Iron>>8)&&0xff); // uart_sendB((Tem_Iron)&&0xff); // SwithStateTVI_Test(); SwithStateTVI(); } int UpdatePID(int error, int position)//Position为现有的测试值{ /*功能: PID计算*/ pTerm = pid.pGain * error; // calculate the proportional term // calculate the integral state with appropriate limiting pid.iState += error; // Maximum and minimum allowable integrator state if (pid.iState < 0) pid.iState = 0; if (pid.iState > 1000) pid.iState = 1000; //else if (pid.iState < pid.iMin) pid.iState = pid.iMin; // iTerm = (pid.iGain * pid.iState); // calculate the integral term if(Iron_type==A1321) iTerm =Tem_Ironset*3-500;//固定积分I,保证低温的时候不过会冲太大 380度时取500,280度时取200 else if (Iron_type==A1322) iTerm=Tem_Ironset*2-250; dTerm = pid.dGain * (pid.dState - position) ; pid.dState = position; pwmval =pTerm + iTerm+dTerm; if (pwmval<0) return 0; else if (pwmval>1000) return 1000; else return pwmval;}void main(void){ uint TEM1temp; DDRC=0xF8; PORTC|=(LED1|LED2|LED3);//先关闭LED PORTC&=0xF8;//ADC高阻输入 DDRD=0xFF; PORTD=0xFF;//LED关闭 DDRB =0x74;//0x7b; /* output */// PORTB OUTPUT BIT 0 1 7 INPUT BIT 2 OUTPUT PB6 OUT PORTB = 0x7F; /* all off */ //LED PB6 "1 " OFF LED HEAT INDICAT CLI(); timer1_init(); MCUCR = 0x00; //uart_init(9600); SEI();//打开全局中断使能 pid.pGain =40; // Set PID Coefficients 比例常数 Proportional Const pid.iGain = 0; //积分常数 Integral Const pid.dGain = 0; //微分常数 Derivative Const EPROMH=RTEEPROMread(0x05); EPROML=RTEEPROMread(0x06); Tem_Ironset=((EPROMH<<8)|EPROML);//读EEPROM if(Tem_Ironset>480)Tem_Ironset=400; if(Tem_Ironset<100)Tem_Ironset=100; StateTVI=0; KeyRead(); delay(100); if((Cont&KEY_MENU)&&(Cont&KEY_DOWN)) set_t=1; else set_t=0; if(set_t==1) { Tem_Ironset=Tem_Setvalue;//如果设置,恢复340摄氏度 TEM1temp=Tem_Ironset; EPROMH=(TEM1temp>>8)&0xff; EPROML=TEM1temp&0xff; RTEEPROMwrite(0x05,EPROMH); RTEEPROMwrite(0x06,EPROML); } stop=0;//启动烙铁 set_hot=0; /*电烙铁自动识别函数,利用电流大小来识别*/OCR1B=0;//全开烙铁delay(400);//延时100msVoltageIn=mega48_ad7();//AD2极样电压CurrentIn=mega48_ad2();Ad_data=VoltageIn*6/CurrentIn;//算出来数值为欧姆if(Ad_data>2&&Ad_data<=11) // 更改下规则,以11欧为分界线,大于11欧为标准 //450-2A 900--4A A1321瞬间电流有4.6A,大于Ad_data>1000Iron_type=A1321;else if(Ad_data>11&&Ad_data<=30) Iron_type=A1322; //A1322实际测试大概最大启动电流在(19V时大概2A左右澹?else if(Ad_data<=2)Iron_type=CurrentShort;elseIron_type=NoCurrent;//小于100即0.4A 算是断路/*电烙铁自动识别函数,利用电流大小来识别*/ timer2_init();//将显示初使化放在电烙铁自动识别之后,以免出现不识别的现象 while(1) {int error; error = (int)Tem_Ironset-(int)Tem_Iron; if(error>40) //设置的温度比实际的温度是否是大于n度 { //全功率加热 500ms pwmval=1000; } else if(error<-40) { //不加热 pwmval=0; } else //如果是在n度范围内,则运行PID计算 { if(Iron_type==A1321) pid.pGain =Tem_Ironset/3-43; // 380C时取80,280度时取50 else if (Iron_type==A1322) pid.pGain=Tem_Ironset/4-20; pwmval = UpdatePID(error, Tem_Iron); if(pwmval<0) pwmval=0; else if(pwmval>1000) pwmval=1000; } OCR1B=1000-pwmval; // printf("test it%d ",pwmval); /* if (!stop) { if(Tem_Iron>300) { set_hot=1; pwmval=500; } if(set_hot==1) { if(Tem_Iron<Tem_Ironset) pwmval++; else pwmval--; } else { if(Tem_Iron<Tem_Ironset) pwmval=1000; else pwmval=0; } } */ /*if(Tem_Iron<Tem_Ironset) OCR1B=0;//1000-pwmval;//OCR1B越小,占空比越小,加热功率越大elseOCR1B=1000;*/ }}
[ 此帖被rogerllg在2016-10-28 10:31重新编辑 ]