本帖最后由 xiaos 于 2015-4-2 22:41 编辑
用放大用LM324比较差··不过温度还是可以稳定,用M8 AD10位 pwm10位温度范围为200-500
精确度1度··
因为程序的原因加上要慢慢整定所以每次升温到设定值前15度就开始整定··
有个缺点就是PID控制恒温时的那几度温度升的很慢··
设置部分还没写好
自己的思路是直接用那个可变电阻做设置
AD转换采样可变电阻来设定温度
设置一按键为温度设定
当按了那按键后可变电阻设定温度有效
没按的话不管你怎么转都不能调节温度
那部分写完后整个代码,发出来大家一起参考
发觉问题还很多的。。希望大家多提下意见,小弟初学的
还有如果要改的话可以不改那电路的引一条采样跟控制线出来直接连上M8也可以的
- /*******************************
- project :A/D转换数码管显示
- chip type : atmega8
- clock frequency:内部RC(INT) 8MHz
- Author :周远峰
- ********************************/
- #include "iom8v.h"
- #include "macros.h"
- #define osccal 0x7d
- unsigned long adc_rel; //处理后世界转换结果
- unsigned long adc_rl; //A/D转换结
- unsigned int tmp; //设置的温度参数
- unsigned char adc_mux; //A/D通道
- unsigned char led_buff[3]={0,0,0}; //显示缓存
- signed int error0; //当前偏差
- signed int error1; //上次偏差
- signed int error2; //上上次偏差
- signed char Kp; //比例常数
- signed char Ki; //积分常数
- signed char Kd; //微分常数
- signed int kk1; //当前控制输出
- signed int kk2; //上次控制输出
- #define NB -3
- #define NM -2
- #define NS -1
- #define ZO 0
- #define PS 1
- #define PM 2
- #define PB 3
- #pragma data:code
- //设置数据区位程序储存器
- const unsigned char seg_table[16]={0x40,0x79,0x24,0x30,0x19,0x90,0x80,0x78,0x00,0x10,0x08,0x81,0x44,0x21,0x04,0x8c};
- const unsigned char KP_table[49]={PB,PB,PM,PM,PS,ZO,ZO,PB,PB,PM,PS,PS,ZO,NS,PM,PM,PM,PS,ZO,NS,NS,PM,PM,PS,ZO,NS,NM,NM,PS,PS,ZO,NS,NS,NM,NM,PS,ZO,NS,NM,NM,NM,NB,ZO,ZO,NM,NM,NM,NB,NB};
- const unsigned char KI_table[49]={NB,NB,NM,NM,NS,ZO,ZO,NB,NB,NM,NS,NS,ZO,ZO,NB,NM,NS,NS,ZO,PS,PS,NM,NM,NS,ZO,PS,PM,PM,NM,NS,ZO,PS,PS,PM,PB,ZO,ZO,PS,PS,PM,PB,PB,ZO,ZO,PS,PM,PM,PB,PB};
- const unsigned char KD_table[49]={PS,NS,NB,NB,NB,NM,NS,PS,NS,NB,NM,NM,NS,ZO,ZO,NS,NM,NM,NS,NS,ZO,ZO,NS,NS,NS,NS,NS,ZO,ZO,ZO,ZO,ZO,ZO,ZO,ZO,PB,NS,PS,PS,PS,PS,PB,PB,PM,PM,PM,PS,PS,PB};
- #pragma data:data
- //设置数据区回到数据储存器
- /*********************************************************
- 延时函数
- *********************************************************/
- void delay_us(int time) //微秒级延时
- {
- do
- time--;
- while (time>1);
- }
- void delay_ms(unsigned int time) //毫秒级延时
- {
- while (time!=0)
- {
- delay_us(1000);
- time--;
- }
- }
- /************************************************************
- 中断显示初始化
- TIMER2 initialize - prescale:1024
- WGM: Normal
- desired value: 10mSec
- actual value: 9.984mSec (0.2%)
- *************************************************************/
- void timer2_init(void)
- {
- TCCR2 = 0x00; //stop
- ASSR = 0x00; //set async mode
- TCNT2 = 0xB2; //setup
- OCR2 = 0x4E;
- TCCR2 = 0x07; //start
- DDRB=0xff; //PC口为推挽1输出
- PORTB=0xff; //PC口内部上拉
- DDRD|=0xf1;
- PORTD&=0x1f; //关闭LED
- }
- /***********************************************
- 中断显示
- *************************************************/
- #pragma interrupt_handler timer2_ovf_isr:5
- void timer2_ovf_isr(void)
- {
- unsigned char i;
- static unsigned k;
- SEI();
- TCNT2 = 0xB2; //reload counter value
- for(i=0;i<3;i++)
- {
- PORTB=led_buff[i];
- PORTD|=(1<<(i+5));//待显示的位置1
- delay_ms(1);
- PORTD&=0x1f; //关闭LED
- }
- }
- /************************************************************
- PWM初始化,OC1A口输出
- *************************************************************/
- void timer1_init(void)
- {
- TCCR1B = 0x00; //stop
- TCNT1H = 0x00; //setup
- OCR1A = 200;
- TCCR1A = (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);//输出低电平
- TCCR1B = (1<<CS11)|(1<<CS10); //
- }
- /*****************************************************
- PID初始化
- ******************************************************/
- void pidcalc_init(void)
- {
- Kp=3;
- Ki=3;
- Kd=3;
- kk1=0; //当前
- kk2=100;
- error0=0;
- error1=0;
- error2=0;
- tmp=300;
- }
- void pidcalc_zizheng(void)
- {
- if (tmp>adc_rel)
- {
- if (kk2<500) kk2+=3;
- else kk2=500;
- }
- if ((tmp-1)>adc_rel)
- {
- if (kk2<500) kk2+=3;
- else kk2=500;
- }
- /*if ((tmp-2)>adc_rel)
- {
- if (kk2<600) kk2+=3;
- else kk2=600;
- }*/
- if (tmp<adc_rel)
- {
- if (kk2>10) kk2-=3;
- else kk2=10;
- }
- if ((tmp+1)<adc_rel)
- {
- if (kk2>10) kk2-=3;
- else kk2=10;
- }
- /*if ((tmp+2)<adc_rel)
- {
- if (kk2>10) kk2-=3;
- else kk2=10;
- }
- /*if (tmp>adc_rel)
- {
- if (Ki<200) Ki+=4;
- else Ki=400;
- }
- if (tmp<adc_rel)
- {
- if (Ki>0) Ki-=4;
- else Ki=0;
- } */
- }
- /*******************************************************
- PID函数
- ********************************************************/
- void pidcalc(void)
- {
- signed long KPP;
- signed long KII;
- signed long KDD;
- signed int i;
- signed char j;
- error0=tmp-adc_rel;
- j=error0-error1;
- i=7*(3+error0)+(3+j);
- if(i<49)
- {
- if (i>0)
- {
- Kp=KP_table[i];
- Ki=KI_table[i];
- Kd=KD_table[i];
- }
- } //输出
- if ((tmp-15)<adc_rel) //比设定低一定值时开始PID
- {
- if((tmp+5)>adc_rel) //比设定高时关PID
- {
- KPP=Kp*(error0-error1); //比例
- KII=error0*Ki; //积分
- KDD=Kd*(error0-(2*error1)+error2); //微分
- kk1=(KPP+KII+KDD)*4+kk2;
- if(kk1<0x3ef)
- {
- if (kk1>=10) OCR1A=kk1;
- else OCR1A=0;
- }
- else
- {
- OCR1A=0x3ff;
- }
- /*if((tmp-2)>adc_rel)
- {
- if(OCR1A<500) OCR1A+=20;
- else OCR1A=500;
- }*/
- }
- else
- {
- //if (tmp<adc_rel)
- // {
- /// if (OCR1A>50) OCR1A-=20;
- // else OCR1A=50;
- OCR1A=0;
- // }
- }
- }
- else
- {
- OCR1A=0x3ff;
- }
- error2=error1;
- error1=error0;
- }
- /***********************************************
- ADC初始化
- ************************************************/
- void adc_init(void)
- {
- DDRC=0x00;
- PORTC=0X00;
- ADCSRA=0X00;
- ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V为基准AREF外加滤波电容
- ACSR=(1<<ACD); //关闭模拟比较器
- ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//128分频
- }
- /*********************************************
-
- ADC中断处理函数
-
- **********************************************/
- #pragma interrupt_handler adc_isr:15
- void adc_isr(void)
- {
- static unsigned i;
- adc_rl+=ADC&0x3ff;
- ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V位基准
- ADCSRA|=(1<<ADSC); //启动AD转换
- if (i<2048)
- i++;
- else
- {
- adc_rel=adc_rl/2048;
- adc_rel=adc_rel*3/5;
- i=0;
- adc_rl=0;
- }
- }
- /******************************************************
-
- ADC数据转压缩BCD
-
- ******************************************************/
- void ADCtoBCD(unsigned int temp)
- {
- unsigned char i;
- for (i=0;i<3;i++)
- {
- led_buff[i]=seg_table[temp%10];/*temp%10求余数‘假设一个数是234那么234/10=23余4也就是查找4的段码*/
-
- temp=temp/10;// 234/10=23因为不处理小数实际就等于右移了
- }
-
- }
- /***************************************************************
- 主程序
- ***************************************************************/
- void main(void)
- {
- unsigned char i;
- unsigned int k;
- unsigned int adc_old;
- unsigned long adc_ol;
- unsigned int adc_o;
- DDRD=0xff;
- PORTD=0xf0;
- OSCCAL=osccal;
- TIMSK = 0x40; //timer interrupt sources
- adc_mux=0;
- adc_init();
- timer1_init();
- pidcalc_init();
- SEI();
- for(i=0;i<3;i++)
- led_buff[i]=seg_table[8];
- for(i=0;i<200;i++)
- timer2_init();
- adc_old=0;
- adc_rel=0;
- while(1)
- {
- if(adc_old!=adc_rel)//ADC更新完毕就执行数据处理
- {
- adc_old=adc_rel;
- pidcalc();
- pidcalc_zizheng();
- if(k<5)
- {
- k++;
- adc_ol+=adc_old;
- }
- else
- {
- adc_o=adc_ol/5;
- adc_ol=0;
- k=0;
- }
- }
- ADCtoBCD(adc_o);
- }
- }
复制代码
|