|
本帖最后由 gq2352100 于 2019-4-15 19:08 編輯
寫了一個(gè)溫度控制程序,DS18B20采集,LCD1602顯示,根據(jù)當(dāng)前溫度和設(shè)定溫度的誤差輸出5檔PWM,但是不知道為什么,用 keil DEBUG的時(shí)候,一旦運(yùn)行到初始化定時(shí)器后,就不會(huì)再繼續(xù)運(yùn)行下面的代碼,而是一直循環(huán)STARTUP.A51里面的兩行,一直到左上R0寄存器減1到0就會(huì)復(fù)位,從頭執(zhí)行程序。如圖:
就是圖中標(biāo)記的這兩行
找了半天不知道問(wèn)題所在,請(qǐng)各位大佬幫幫忙,感激萬(wàn)分。
單片機(jī)代碼貼上:
- //這是主程序
- #include < reg52.h >
- #include < intrins.h >
- #include < ds18b20.h >
- #include < lcd1602.h >
- #include < fuzzy.h >
- #include < pwm.h >
- #define uchar unsigned char
- #define uint unsigned int
- void init_time()
- {
- TMOD=0x01; //T0都是定時(shí)方式1
- TH0=0xFC; //T1 10us初值
- TL0=0x18;
- TR0=1;
- ET0=1;
- EA=1;
- time=0;
- zkb=50;
- }
- void main()
- {
- lcd_display();
- delayms(500);
- ow_reset();
- if(presence==0)
- {
- Ok_Menu ();
- delayms(500);
- init_time();
- while(1)
- {
- temperature_trans();
- fuzzy();
- pwmchange();
- c_display();
- temperature_display();
- }
- //下面是DS18B20程序
-
- #include < reg52.h >
- #include < intrins.h >
- #define uchar unsigned char
- #define uint unsigned int
- sbit DQ = P0^0; //定義DS18B20端口DQ
- bit presence=1; //ds18b20應(yīng)答信號(hào) 0允許,1禁止
- unsigned char data temp_data[2] = {0x00,0x00} ; //用于存儲(chǔ)16位溫度
- /*us級(jí)延時(shí),延時(shí)時(shí)間約4+2*i*/
- void delayus(uchar us)
- {
- while(--us);
- }
- /*ms級(jí)別 */
- void delayms(uint ms)
- {
- uint i;
- uchar j;
- for(i=0;i<ms;i++)
- for(j=0;j<250;j++)
- {
- _nop_(); //一個(gè)機(jī)器周期,1us
- _nop_(); //適用于精度高的
- _nop_();
- _nop_();
- }
- }
- /*復(fù)位,每次讀寫之前都要進(jìn)行復(fù)位*/
- /**********************************/
- bit ow_reset(void)
- {
- DQ = 1 ; //DQ復(fù)位
- delayus(8) ; //稍做延時(shí)
- DQ = 0; //拉低約600us
- delayus(250);
- DQ = 1;//產(chǎn)生上升沿,延時(shí)約15~60us
- delayus(20);
- presence=DQ;
- delayus(250);
-
- return(presence); //等待應(yīng)答信號(hào) 0允許,1禁止
- }
- /*讀取數(shù)據(jù)一位 */
- //---------------------------------
- bit Read_bit()
- {
- uint i = 0;
- bit b = 0;
- DQ = 0; //產(chǎn)生讀時(shí)隙
- i++; //維持低電平至少1us
- DQ = 1; //1us以上后拉高
- delayus(2); //延時(shí)8us,DO下降沿15內(nèi)ds18b20輸出的數(shù)據(jù)才有效
- b = DQ; //讀取數(shù)據(jù)
- delayus(40); //每個(gè)讀時(shí)隙至少持續(xù)60us
- return(b);
- }
- /*讀取一個(gè)字節(jié) */
- //------------------------------------
- uchar Read_byte()
- {
- uchar byte_read = 0;
- uchar i, j;
- for(i=0; i<8; i++)
- {
- j = Read_bit();
- byte_read = (j<<i) | byte_read; //低位讀起
- }
- return(byte_read);
- }
- //-----------------------------------------
- /*寫一個(gè)字節(jié) */
- void Write_byte(uchar byte_to_write)
- {
- uchar i = 0;
- uchar j = 0;
- bit write_bit = 0;
- for(j=0; j<8; j++)
- {
- write_bit = (byte_to_write & 0x01);
- if(write_bit == 1) //寫1
- {
- DQ = 0; //產(chǎn)生寫時(shí)隙
- delayus(3); //延時(shí)15us
-
- DQ = 1; //寫1
- delayus(40); //延時(shí),寫時(shí)隙不得低于60us
- }
- else
- {
- DQ = 0; //產(chǎn)生寫時(shí)隙
- delayus(50); //延時(shí),保持低約60us~120us
- DQ = 1;
- i++;
- }
- byte_to_write = byte_to_write >> 1;
- }
- }
- //-----------------------------------
- /*讀取溫度,啟動(dòng)溫度轉(zhuǎn)換*/
- /*啟動(dòng)溫度轉(zhuǎn)換*/
- void start_convert()
- {
- ow_reset(); // 發(fā)出復(fù)位脈沖,每次操作都從復(fù)位開始
- delayms(1);
- Write_byte(0xcc); //skip room命令,跳過(guò)序列號(hào)命令字
- Write_byte(0x44); //啟動(dòng)溫度轉(zhuǎn)換命令
- }
- /*讀取溫度值*/
- void read_tempreture()
- {
- ow_reset(); // 發(fā)出復(fù)位脈沖,每次操作都從復(fù)位開始
- delayms(1);
- Write_byte(0xcc); //跳過(guò)rom命令
- Write_byte(0xbe); //讀取暫存器命令
- temp_data[0] = Read_byte(); //存儲(chǔ)溫度低字節(jié)值 (整數(shù)部分低四位和小數(shù)部分) 先從低字節(jié)讀取
- temp_data[1] = Read_byte(); //存儲(chǔ)溫度高字節(jié)值 (其中高五位為符號(hào)位)
- }
- //下面是LCD1602程序
- #include < reg52.h >
- #include < ds18b20.h >
- #define uchar unsigned char
- #define uint unsigned int
- #define lcddata P2
- sbit LCDRS=P1^7; //液晶數(shù)據(jù)選擇命令端
- sbit LCDRW=P1^6; //液晶讀寫命令端
- sbit LCDEN=P1^5; //液晶使能端
- uint cc,cc2; //變量cc中保存讀出的溫度值
- float cc1;
- uchar flag; //正負(fù)標(biāo)志
- uchar cdis2[ ] = "+00.00"; //將來(lái)測(cè)得的溫度修改各位即可
- uchar code cdis5[ ] = "Temp: ";
- uchar code cdis0[ ] = "CHECKING...";
- uchar code cdis1[ ] = " DS18B20 OK " ;
- uchar code cdis3[ ] = " DS18B20 ERR0R " ;
- uchar code cdis4[ ] = " PLEASE CHECK " ;
- void delaylcd(uint z)
- {uchar x,y;
- for(x=z;x>0;x--)
- {for(y=110;y>0;y--);
- }
- }
- /*寫命令to lcd */
- /**********************************/
- void write_com(uchar com)//寫命令
- {
- LCDRW=0; //低電平為寫
- LCDRS=0; //低電平為命令選擇
- lcddata=com;
- delaylcd(5);
- LCDEN=1;
- delaylcd(5);
- LCDEN=0;
- }
- /*lcd1602初始化 */
- /**********************************/
- void lcd_init(void)
- {
- LCDRW=0; //低電平為寫
- LCDEN=0;
- write_com(0x38); //使用8位數(shù)據(jù)開關(guān),顯示兩行,使用5*7字形
- write_com(0x0c); //顯示器開,光標(biāo)關(guān),字符不閃爍 0x0e 光標(biāo)開
- write_com(0x06); //字符不動(dòng),光標(biāo)自動(dòng)右移動(dòng)一位
- write_com(0x01); //清屏
- }
- /*寫數(shù)據(jù)to lcd */
- /**********************************/
- void write_data(uchar date)
- {
- LCDRW=0; //低電平為寫
- LCDRS=1; //高電平為數(shù)據(jù)選擇
- lcddata=date;
- delaylcd(5);
- LCDEN=1;
- delaylcd(5);
- LCDEN=0;
- }
- /*設(shè)定顯示位置 */
- /********************************/
- void lcd_pos(uchar pos)
- { //第一行第幾列直接寫pos為幾,第二行pos從0x40開始
- write_com(pos|0x80); //數(shù)據(jù)指針=80+地址變量
- }
- //--------------------------------------
- /* CHECKING...顯示 */
- void lcd_display()
- {
- uchar m ;
- lcd_init() ; //初始化LCD
- lcd_pos(0) ; //設(shè)置顯示位置為第一行的第1個(gè)字符
- m = 0 ;
- while(cdis0[m] != '\0')
- { //顯示字符
- write_data(cdis0[m]) ;
- m++ ;
- }
- }
- //--------------------------------------
- /* DS18B20 OK 顯示菜單 */
- void Ok_Menu ()
- {
- uchar m ;
- lcd_init() ; //初始化LCD
-
- lcd_pos(0) ; //設(shè)置顯示位置為第一行的第1個(gè)字符
- m = 0 ;
- while(cdis1[m] != '\0')
- { //顯示字符
- write_data(cdis1[m]) ;
- m++ ;
- }
- }
- //------------------------------------
- /*Temp: ℃顯示 */
- void c_display()
- {
- uchar m;
- lcd_init() ;
- lcd_pos(0);
- m=0;
- while(cdis5[m]!='\0')
- {
- write_data(cdis5[m]);
- m++;
- }
- lcd_pos(12);
- write_data(0xDF); //°
- lcd_pos(13);
- write_data('C');
- }
- //------------------------------------
- /*采集溫度轉(zhuǎn)換成LCD顯示的格式 */
- void temperature_trans()
- {
- EA=0; //DS18B20讀寫數(shù)據(jù)按照嚴(yán)格的時(shí)序,最好不要被打斷,故把所有中斷關(guān)閉
- start_convert(); //啟動(dòng)溫度轉(zhuǎn)換
- delayms(100);
- read_tempreture();
- //讀取溫度
- cc=temp_data[1]*256+temp_data[0];
- if(temp_data[1]>0xF8)
- {flag=1;cc=~cc+1;}
- else
- flag=0; //高5位全1負(fù),全0正
- cc1=cc*0.0625; //浮點(diǎn)數(shù)溫度
- cc2=cc1*100;
- cdis2[1]=cc2/1000+0x30;
- if(cdis2[1]==0x30)
- cdis2[1]=0x20;
- cdis2[2]=cc2/100%10+0x30;
- cdis2[4]=cc2%100/10+0x30;
- cdis2[5]=cc2%10+0x30;
- if(flag==1)
- cdis2[0]='-';
- else
- cdis2[0]='+';
- EA=1;
-
-
- }
- //------------------------------------
- /*溫度顯示 */
- void temperature_display()
- {
- uchar m;
- lcd_pos(6); //設(shè)置顯示位置為第一行的第6個(gè)字符
- m=0;
- while(cdis2[m]!='\0')
- { //顯示字符
- write_data(cdis2[m]) ;
- m++;
- }
- }
- //下面是根據(jù)采集溫度和設(shè)定溫度差值查表得輸出的程序
- #include <reg52.h>
- #include <lcd1602.h>
- #define uint unsigned int
- float set_temp=20.0000; //設(shè)置溫度
- uchar u;
- uchar e_f;
-
- void fuzzy()
- {
-
- float e=cc1-set_temp; //算出誤差
- unsigned int code ely[ ]={0,1,2,3,4};
- unsigned int code uly[ ]={0,1,2,3,4};
- e_f=(e/5*10+5)/10; //誤差轉(zhuǎn)換成0-4整數(shù)
- if(e_f<0)
- {e_f=0;}
- if(e_f>4)
- e_f=4;
- u=uly[e_f]; //差表得到控制輸出,改變PWM占空比
- }
- //下面是PWM的程序
- #include<reg52.h>
- #include<fuzzy.h>
- #include<lcd1602.h>
- #define uint unsigned int
- #define uchar unsigned char
- uchar time; //計(jì)數(shù)
- uchar zkb; //占空比
- sbit pwm=P1^0; //P1^0口輸出方波
- void pwmchange() //根據(jù)算法輸出調(diào)節(jié)占空比,5個(gè)檔位
- {
- EA=0;
- if(u==0)
- {zkb=0;}
- else if(u==1)
- {zkb=25;}
- else if(u==2)
- {zkb=50;}
- else if(u==3)
- {zkb=75;}
- else if(u==4)
- {zkb=100;}
- EA=1;
- }
- //----------------------------------------------
- //------------------------------------------
- void time_1() interrupt 1
- {
- TH0=0xFC; //T1 10us初值
- TL0=0x18;
- if(time<zkb)
- pwm=1; //方波翻轉(zhuǎn)
- else
- if(time>=zkb)
- pwm=0;
- time++;
- if(time==100) //100份 最大100%
- time=0;
- }
復(fù)制代碼
|
|