|
本帖最后由 xiaos 于 2015-4-2 22:41 編輯
用放大用LM324比較差··不過(guò)溫度還是可以穩(wěn)定,用M8 AD10位 pwm10位溫度范圍為200-500
精確度1度··
因?yàn)槌绦虻脑蚣由弦ㄋ悦看紊郎氐皆O(shè)定值前15度就開(kāi)始整定··
有個(gè)缺點(diǎn)就是PID控制恒溫時(shí)的那幾度溫度升的很慢··
設(shè)置部分還沒(méi)寫(xiě)好
自己的思路是直接用那個(gè)可變電阻做設(shè)置
AD轉(zhuǎn)換采樣可變電阻來(lái)設(shè)定溫度
設(shè)置一按鍵為溫度設(shè)定
當(dāng)按了那按鍵后可變電阻設(shè)定溫度有效
沒(méi)按的話(huà)不管你怎么轉(zhuǎn)都不能調(diào)節(jié)溫度
那部分寫(xiě)完后整個(gè)代碼,發(fā)出來(lái)大家一起參考
發(fā)覺(jué)問(wèn)題還很多的。。希望大家多提下意見(jiàn),小弟初學(xué)的
還有如果要改的話(huà)可以不改那電路的引一條采樣跟控制線(xiàn)出來(lái)直接連上M8也可以的



- /*******************************
- project :A/D轉(zhuǎn)換數(shù)碼管顯示
- chip type : atmega8
- clock frequency:內(nèi)部RC(INT) 8MHz
- Author :周遠(yuǎn)峰
- ********************************/
- #include "iom8v.h"
- #include "macros.h"
- #define osccal 0x7d
- unsigned long adc_rel; //處理后世界轉(zhuǎn)換結(jié)果
- unsigned long adc_rl; //A/D轉(zhuǎn)換結(jié)
- unsigned int tmp; //設(shè)置的溫度參數(shù)
- unsigned char adc_mux; //A/D通道
- unsigned char led_buff[3]={0,0,0}; //顯示緩存
- signed int error0; //當(dāng)前偏差
- signed int error1; //上次偏差
- signed int error2; //上上次偏差
- signed char Kp; //比例常數(shù)
- signed char Ki; //積分常數(shù)
- signed char Kd; //微分常數(shù)
- signed int kk1; //當(dāng)前控制輸出
- 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
- //設(shè)置數(shù)據(jù)區(qū)位程序儲(chǔ)存器
- 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
- //設(shè)置數(shù)據(jù)區(qū)回到數(shù)據(jù)儲(chǔ)存器
- /*********************************************************
- 延時(shí)函數(shù)
- *********************************************************/
- void delay_us(int time) //微秒級(jí)延時(shí)
- {
- do
- time--;
- while (time>1);
- }
- void delay_ms(unsigned int time) //毫秒級(jí)延時(shí)
- {
- 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口內(nèi)部上拉
- DDRD|=0xf1;
- PORTD&=0x1f; //關(guān)閉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; //關(guān)閉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; //當(dāng)前
- 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函數(shù)
- ********************************************************/
- 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) //比設(shè)定低一定值時(shí)開(kāi)始PID
- {
- if((tmp+5)>adc_rel) //比設(shè)定高時(shí)關(guān)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); //選擇內(nèi)部2.56V為基準(zhǔn)AREF外加濾波電容
- ACSR=(1<<ACD); //關(guān)閉模擬比較器
- ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//128分頻
- }
- /*********************************************
-
- ADC中斷處理函數(shù)
-
- **********************************************/
- #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); //選擇內(nèi)部2.56V位基準(zhǔn)
- ADCSRA|=(1<<ADSC); //啟動(dòng)AD轉(zhuǎn)換
- if (i<2048)
- i++;
- else
- {
- adc_rel=adc_rl/2048;
- adc_rel=adc_rel*3/5;
- i=0;
- adc_rl=0;
- }
- }
- /******************************************************
-
- ADC數(shù)據(jù)轉(zhuǎn)壓縮BCD
-
- ******************************************************/
- void ADCtoBCD(unsigned int temp)
- {
- unsigned char i;
- for (i=0;i<3;i++)
- {
- led_buff[i]=seg_table[temp%10];/*temp%10求余數(shù)‘假設(shè)一個(gè)數(shù)是234那么234/10=23余4也就是查找4的段碼*/
-
- temp=temp/10;// 234/10=23因?yàn)椴惶幚硇?shù)實(shí)際就等于右移了
- }
-
- }
- /***************************************************************
- 主程序
- ***************************************************************/
- 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更新完畢就執(zhí)行數(shù)據(jù)處理
- {
- 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);
- }
- }
復(fù)制代碼
|
|