原程序中在TACTL中都使用了TACLR清除TAR計數(shù),但此方式是錯誤的,它同時置位了分頻等參數(shù),應改為TAR=0的方式,在閥門動作開始時使用,以使每次閥門動作時間準確。 基本測試完成的程序代碼: /******************************************************************** * * * 太陽能熱水器自動上水控制 * * V10.1 * * yajou 2008-09-25 * ********************************************************************* 更新內容: * 1. DS18B20的CRC校驗; * 2. 增基本定時器定時1s,每5秒采集顯示溫度數(shù)據(jù) * 3. P1.2中斷進行電源電壓判斷 * 4. V10.0 增加在V3.4版的太陽能熱水器閥控功能 * 5. V10.1 開關閥動作前先判斷閥門狀態(tài) * ********************************************************************* <<>> * P1.2: 欠壓判斷 * P1.6: 上水按鍵 * P1.7: 停止按鍵 * P2.0: DS18B20溫度信號線 * P2.2: 開閥到位 * P2.3: 關閥到位 * P6.3: Beep 完成一個操作后鳴叫,錯誤連叫3聲 * P6.7: LED 上水開閥時長亮,開閥完成上水時瞬閃(長時間滅,瞬間亮),* 水滿后關閥時長亮,結束后滅。 * ********************************************************************/ #include //系統(tǒng)文件夾內找 #include "main.h" //當前文件夾內找 int main(void) { Sys_Init(); //DS18B20初始化,開始溫度轉換--------- while(Ds18b20_Init() && (--i) ); //2008.10.14修改:&改為&& Ds18b20_WriteByte(SkipROM); Ds18b20_WriteByte(Convert); Delayms(900); //ReleaseDQ(); //寄生電源時要拉高DQ //------------------------------------ while(1) { if(enable_tmptest) { enable_tmptest = 0; if(TempCal(&wendu_fuhao, &wendu_zhensu, &wendu_yusu)) i_tmp++; //測溫錯誤計次加1 else i_tmp = 0; } Display(); LPM3; //進入低功耗模式n,n:0~4。 } } /******************************************************** * Display * ********************************************************/ void Display(void) { uchar temp_wendu_zhensu; if(wendu_fuhao) LCDMEM[0] = digit[10]; //顯示"-" else LCDMEM[0] = digit[12]; //不顯示 LCDMEM[3] = digit[wendu_zhensu%10]; LCDMEM[3] |= 0x10; //小數(shù)點 temp_wendu_zhensu = wendu_zhensu / 10; LCDMEM[2] = digit[temp_wendu_zhensu%10]; LCDMEM[1] = digit[temp_wendu_zhensu/10]; LCDMEM[4] = (digit[wendu_yusu/10] & 0x0f)<<4; //取低位放在高位,低位為標志符 LCDMEM[5] = (digit[wendu_yusu/10] & 0xf0)>>4; //取高位放在低位 LCDMEM[5] |= (digit[wendu_yusu%10] & 0x0f)<<4; LCDMEM[6] = (digit[wendu_yusu%10] & 0xf0)>>4; if(enable_famenoperate == 0) LCDMEM[2] |= BIT4 ; //顯示"閥門關" else LCDMEM[2] &= ~BIT4 ;//不顯示"閥門關" if(i_tmp > 5) { i_tmp = 5; LCDMEM[5] |= BIT0; //顯示"插卡錯" } } /***************************************************************************** * SYS初始化 * *****************************************************************************/ void Sys_Init(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer /*時鐘初始化 //MCLK:2031616Hz*/ FLL_CTL0 |= XCAP14PF; // Configure load caps SCFI0 |= FN_2; //頻率范圍 SCFQCTL =30; //N,如不設置默認=31 SCFI0 |= FLLD_2; //D=2,PUC后的默認值=2 //FLL_CTL1 |= FLL_DIV_4; //4分頻,P1.5輸出:f=32768/4 FLL_CTL0 |= DCOPLUS;//在MCLK前分頻 f=D*(N+1)*faclk,2*(30+1)*32768=2031616Hz /*LCD初始化*/ LCDCTL = LCDON + LCD4MUX + LCDP0; // STK LCD 4Mux, S0-S15 BTCTL = BTFRFQ1; // STK LCD freq, 基本定時器輸出fLCD=fACLK/64 P5SEL = 0xFC; // Common and Rxx all selected,公共極和 Rxx 選擇 for(i=0;i<12;i++) //清顯示 LCDMEM = digit[12]; _EINT(); //打開全局中斷控制,若不需要打開,可以屏蔽本句 /*基本定時器初始化*/ IE2 |= BTIE; //打開基本定時器中斷 BTCTL |= BTDIV + BTIP1+ BTIP2; // 1s interrupt /*外部中斷初始化*/ P1IES = BIT2 + BIT6 + BIT7; //P1.2,P1.6,P1.7中斷為1->0 P2IES = BIT2 + BIT3; //P2.2,P2.3中斷為1->0 P1IE = BIT2 + BIT6 + BIT7; //允許P1.2,P1.6中斷,P1.7中斷,欠壓-開閥-關閥 P2IE = BIT2 + BIT3; //允許P2.2,P2.3中斷,開閥到位-關閥到位 /*定時器A初始化*/ TACTL = TASSEL0 + TACLR +ID0; //時鐘用ACLK, clear TAR,二分頻 TACTL |= MC0; //選擇模式,Up to CCR0 // TACTL |= TAIE; //Timer_A interrupt enable,這句不能加,加了運行出錯 CCTL0 &= ~CCIE; //禁止CCR0 interrupt,開關閥中斷中打開 CCR0 = 65535; //預置值,二分頻后定時為4s /*端口初始化*/ P6DIR |= BIT3 + BIT4 + BIT5 + BIT7;//蜂鳴器+閥門控制信號P6.4&P6.5+LED P6OUT = 0x00; TingZhi();//閥門初始化為停 } /***************************************************************************** 基本定時器中斷函數(shù) * *****************************************************************************/ #pragma vector=BASICTIMER_VECTOR __interrupt void BasTimer() { static uchar times; if(enable_guanfajishi) //開閥上水后進行關閥延時計時,以防溢水信號失效 { n_guanfa++; if(n_guanfa > 15) //(>3600)1h后 { LPM3_EXIT; //退出中斷后退出低功耗模式。 enable_guanfajishi = 0; n_guanfa = 0; Guanfa(); //關閥門 TAR = 0; //Timer_A 清除原計時 CCTL0 = CCIE; //允許CCR0 interrupt Ledon(); //開LED enable_famenoperate = 2; //閥門狀態(tài)為關動作中 enable_LED = 0; //關瞬閃 } } if(enable_LED) //瞬閃LED:開閥停止后打開此瞬閃,關閥信號中斷時關閉此瞬閃 { Ledon(); Delayms(20); Ledoff(); } times++; if(times > time_yanshi) { times = 0; enable_tmptest = 1; //允許溫度測試 LPM3_EXIT; //退出中斷后退出低功耗模式。 } } /***************************************************************************** 定時器A中斷函數(shù) * 中斷源:CC0 * *****************************************************************************/ #pragma vector=TIMERA0_VECTOR //定時4s,防止閥門到位信號失效 __interrupt void TimerA0() { CCTL0 &= ~CCIE; //禁止CCR0 interrupt CCR0 = 65535; //預置值,4s LPM3_EXIT; //退出中斷后退出低功耗模式。 TingZhi(); //閥門動作停止 if(enable_famenoperate == 3) //判斷之前是開閥還是關閥動作 { //之前為開閥 enable_famenoperate = 1;//閥門狀態(tài)為開 enable_LED = 1; //開瞬閃 } else if(enable_famenoperate == 2) { //之前為關閥 enable_famenoperate = 0;//閥門狀為關 } } /***************************************************************************** 端口1中斷函數(shù) * 多中斷中斷源:P1IFG.0~P1IFG7 * 進入中斷后應首先判斷中斷源,退出中斷前應清除中斷標志,否則將再次引發(fā)中斷 * *****************************************************************************/ #pragma vector=PORT1_VECTOR __interrupt void Port1() { if((P1IFG&BIT2) == BIT2) //處理P1IN.2中斷 { P1IFG &= ~BIT2; //清除中斷標志 P1IES ^= BIT2; //P1.2中斷為0->1和1->0切換 P1DIR&=~BIT2; //P1.2為輸入方式 if(P1IN&BIT2 ) //判斷P1.2電平高低 { LCDMEM[0] &= ~BIT4; IE2 |= BTIE;//打開基本定時器中斷 } else { LCDMEM[0] |= BIT4 ; //顯示"換電池" IE2 &= ~BTIE; //關閉基本定時器中斷 } } else if((P1IFG&BIT6) ==BIT6) //處理P1IN.6中斷,開閥上水 { P1IFG &= ~BIT6; //清除中斷標志 //在此先判斷閥門狀態(tài),如為關才開閥 if((P2IN&BIT2 == BIT2) && ~(P2IN&BIT3)) //P2.2開閥到位線為1,P2.3關閥到位線為0,關閥狀態(tài) { if(wendu_zhensu < 20) { LPM3_EXIT; //退出中斷后退出低功耗模式。 Kaifa(); //開閥 TAR = 0; //Timer_A 清除原計時 CCTL0 = CCIE; //允許CCR0 interrupt Ledon(); //亮LED enable_famenoperate = 3; //閥門狀態(tài)為開動作中 enable_guanfajishi = 1; //開閥上水后進行關閥延時計時,以防溢水信號失效 }else { for(i = 0; i < 3; i++) //溫度高不能上水,鳴叫3聲 { BeepOn(); //要先退出LPM3嗎??? Delayms(100); BeepOff(); Delayms(100); } } } } else if((P1IFG&BIT7) ==BIT7) //處理P1IN.7中斷,關閥 { P1IFG &= ~BIT7; //清除中斷標志 //在此先判斷閥門狀態(tài),如為開才關閥 if((~P2IN&BIT2) && (P2IN&BIT3 == BIT3)) //P2.2開閥到位線為0,P2.3關閥到位線為1,開閥狀態(tài) { LPM3_EXIT; //退出中斷后退出低功耗模式。 Guanfa(); //關閥 TAR = 0;//Timer_A 清除原計時 CCTL0 = CCIE; //允許CCR0 interrupt Ledon(); //開LED enable_famenoperate = 2; //閥門狀態(tài)為關動作中 enable_guanfajishi = 0; //關閉關閥延時計時 n_guanfa = 0; //關閥延時計時清零 enable_LED = 0; //關瞬閃 } } } /***************************************************************************** 端口2中斷函數(shù) * *****************************************************************************/ #pragma vector=PORT2_VECTOR __interrupt void Port2() { LPM3_EXIT; //退出中斷后退出低功耗模式。若退出中斷后要保留低功耗模式,將本句屏蔽 CCTL0 &= ~CCIE; //禁止CCR0 interrupt CCR0 = 65535; //預置值,4s if((P2IFG&BIT2) == BIT2) //處理P2IN.2中斷,開閥到位 { P2IFG &= ~BIT2; //清除中斷標志 TingZhi(); enable_famenoperate = 1;//閥門狀態(tài)為開 enable_LED = 1; //開瞬閃 } else if((P2IFG&BIT3) == BIT3)//處理P2IN.3中斷,關閥到位 { P2IFG &= ~BIT3; //清除中斷標志 TingZhi(); enable_famenoperate = 0;//閥門狀為關 } } /******************************************************** * DS18B20初始化 * ********************************************************/ uchar Ds18b20_Init(void) //存在返0,否則返1 { uchar temp = 1; uchar uttime = ReDetectTime; //超時時間 while(outtime-- && temp) { IoOut_DQ(); Delayms(2); //2ms ReleaseDQ(); Delayus(2); PullDownDQ(); Delayus(600); //614us(480-960) ReleaseDQ(); Delayus(70); //73us(>60) IoIn_DQ(); temp = ReadDQ(); Delayus(500); //us } return temp; } /******************************************************** * 寫bit2DS18B20 * ********************************************************/ void Ds18b20_WriteBit(uchar bitdata) { IoOut_DQ(); if(bitdata) { PullDownDQ(); Delayus(2); //2us(>1us) ReleaseDQ(); //(上述1-15) Delayus(85); //86us(45- x,總時間>60) }else { PullDownDQ(); Delayus(85); //86us(60-120) } ReleaseDQ(); Delayus(2); //2us(>1us) } /******************************************************** * 寫B(tài)yte DS18B20 * ********************************************************/ void Ds18b20_WriteByte(uchar chrdata) { uchar ii; for(ii = 0; ii < 8; ii++) { Ds18b20_WriteBit(chrdata & 0x01); chrdata >>= 1; } } /******************************************************** * 寫 DS18B20 * ********************************************************/ //void Ds18b20_Write(uchar *p_readdata, uchar bytes) //{ // while(bytes--) // { // Ds18b20_WriteByte(*p_readdata); // p_readdata++; // } //} /******************************************************** * 讀bit From DS18B20 * ********************************************************/ uchar Ds18b20_ReadBit(void) { uchar bitdata; IoOut_DQ(); PullDownDQ(); Delayus(2); //2us( >1us) ReleaseDQ(); Delayus(8); //8us( <15us) IoIn_DQ(); bitdata = ReadDQ(); Delayus(85); //85us(上述總時間要>60us) return bitdata; } /******************************************************** * 讀Byte DS18B20 * ********************************************************/ uchar Ds18b20_ReadByte(void) { uchar ii,chardata; for(ii = 0; ii < 8; ii++) { chardata >>= 1; if(Ds18b20_ReadBit()) chardata |= 0x80; } return chardata; } /******************************************************** * 讀 DS18B20 ROM * ********************************************************/ //bit Ds18b20_ReadRom(uchar *p_readdata) //成功返0,失敗返1 //{ // uchar ii = 8; // if(Ds18b20_Init()) return 1; // Ds18b20_WriteByte(ReadROM); // while(ii--) // { // *p_readdata = Ds18b20_ReadByte(); // p_readdata++; // } // return 0; //} /******************************************************** * 讀 DS18B20 EE * ********************************************************/ uchar Ds18b20_ReadEE(uchar *p_readdata) //成功返0,失敗返1 { uchar ii = 9; if(Ds18b20_Init()) return 1; Delayus(1); Ds18b20_WriteByte(SkipROM); Delayus(1); Ds18b20_WriteByte(ReadScr); Delayus(1); while(ii--) { *p_readdata = Ds18b20_ReadByte(); p_readdata++; } return 0; } /******************************************************** * 溫度采集計算 * ********************************************************/ uchar TempCal(uchar *p_fuhao,uchar*p_wendu_zhensu,uchar *p_wendu_yusu) //成功返0,失敗返1 (溫度范圍-55 --- +128) { uchar temp[9],ii,crc_data = 0; uint tmp = 0; uchar tmp_ys = 0; *p_fuhao = 0; //讀暫存器和CRC值----------------------- if(Ds18b20_ReadEE(temp)) return 1; //CRC校驗------------------------------ for(ii = 0; ii < 9; ii++) crc_data = CrcTable[crc_data^temp[ii]]; if(crc_data == 0) { tmp = temp[1]; // tmp <<= 8; // tmp |= temp[0]; //組成溫度的兩字節(jié)合并 //溫度正負數(shù)處理----------------------- if(temp[1] >>= 4) //溫度為負 { tmp = ~tmp + 1; *p_fuhao = 1; //返回值,1為負0為正 } //溫度計算----------------------------- tmp_ys =tmp % 16; //取十進制溫度的余數(shù) tmp_ys = (tmp_ys * 10) / 16; //十進制溫度的小數(shù)*10(取小數(shù)點后一位) *p_wendu_zhensu = tmp / 16; *p_wendu_yusu = tmp_ys; } //開始溫度轉換------------------------- while(Ds18b20_Init() & (--ii) ); Ds18b20_WriteByte(SkipROM); Ds18b20_WriteByte(Convert); return 0; } /******************************************************** * 閥門動作停止 * ********************************************************/ void TingZhi(void) { TingZ(); Ledoff(); BeepOn(); Delayms(100); BeepOff(); } 頭文件main.h /******************************************************** * 命令字定義 * ********************************************************/ #define uchar unsigned char #define uint unsigned int /***精確定時方法*****/ #define CPU_F ((double)2031616) //8000000為 MCLK=8MHZ的意思* #define Delayus(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define Delayms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) /***調用此程序時實參必是數(shù)字,而不能使用變量作為實參。 Delayus(1); //這是產生1微秒的延時 Delayms(1); //這是產生1毫秒的延時 Delayus(3.5); //延時3.5毫秒,還是可以這樣呢 Delayms(3.5); //延時3.5毫秒…是不是很實用? ***精確定時方法*****/ //設置重復檢測次次數(shù),超出次數(shù)則超時 #define ReDetectTime 20 /***ds18b20命令***/ #define SkipROM 0xCC #define MatchROM 0x55 #define ReadROM 0x33 #define SearchROM 0xF0 #define AlARMSearch 0xEC #define Convert 0x44 #define WriteScr 0x4E #define ReadScr 0xBE #define CopyScr 0x48 #define RecallEE 0xB8 #define ReadPower 0xB4 /***P2.0接DS18B20的DQ,//P2.1為DQ的上拉電源***/ #define ReleaseDQ() P2OUT |= BIT0 //上拉/釋放總線 #define PullDownDQ() P2OUT &= ~BIT0 //下拉總線 //#define vcc() P2OUT |= BIT1 #define ReadDQ() P2IN&BIT0 #define IoIn_DQ() P2DIR&=~BIT0 #define IoOut_DQ() P2DIR|=BIT0 #define time_yanshi 5 //每5秒采集并顯示溫度 /***開關閥門控制部分***/ #define Ledon() P6OUT |= BIT7 //點亮批示燈P6.7 #define Ledoff() P6OUT &= ~BIT7 //熄滅批示燈P6.7 #define BeepOn() P6OUT |= BIT3 //蜂鳴器on,開關閥結束時鳴叫提示P6.3 #define BeepOff() P6OUT &= ~BIT3 //蜂鳴器off //#define KF0() P6OUT &= ~BIT4 //開閥IO輸出為0 P6.4 //#define KF1() P6OUT |= BIT4 //開閥IO輸出為1 //#define GF0() P6OUT &= ~BIT5 //關閥0 P6.5 //#define GF1() P6OUT |= BIT5 //關閥1 #define Kaifa() P6OUT |= BIT46OUT &= ~BIT5 //開閥 #define Guanfa() P6OUT &= ~BIT46OUT |= BIT5 //關閥 #define TingZ() P6OUT &= ~BIT46OUT &= ~BIT5 //停止 //#define KFdw (P2IN & BIT2)>>2 //開閥到位P2.2 //#define GFdw (P2IN & BIT3)>>3 //關閥到位P2.3 /******************************************************** * 函數(shù) * ********************************************************/ void Display(void); //顯示 void Sys_Init(void); //系統(tǒng)初始化 uchar Ds18b20_Init(void); //DS18B20初始化,存在返0,否則返1 void Ds18b20_WriteBit(uchar bitdata); //寫bit2DS18B20 void Ds18b20_WriteByte(uchar chrdata); //寫B(tài)yte DS18B20 void Ds18b20_Write(uchar *p_readdata, uchar bytes); //寫 DS18B20 uchar Ds18b20_ReadBit(void); //讀bit From DS18B20 uchar Ds18b20_ReadByte(void); //讀Byte DS18B20 uchar Ds18b20_ReadRom(uchar *p_readdata); //讀 DS18B20 ROM:成功返0,失敗返1 uchar Ds18b20_ReadEE(uchar *p_readdata); //讀 DS18B20 EE :成功返0,失敗返1 uchar TempCal(uchar *p_fuhao,uchar*p_wendu_zhensu,uchar *p_wendu_yusu); //成功返0,失敗返1 (溫度范圍-55 --- +128) //void Kaifa(void); //void Guanfa(void); //void TingZ(void); void TingZhi(void); /******************************************************** * 變量 * ********************************************************/ uchar wendu_zhensu = 0; uchar wendu_yusu = 0; uchar wendu_fuhao = 0; uchar i,i_tmp; //i_tmp:測溫錯誤計次 uchar enable_tmptest = 1; //允許溫度測試 1允許,0禁止 const uchar digit[13]= { 0xAF, // "0" LCD segments a+b+c+d+e+f 0xA0, // "1" b+c 0xCB, // "2" a+b+g+e+d 0xE9, // "3" a+b+c+d+g 0xE4, // "4" b+c+f+g 0x6D, // "5" a+c+d+f+g 0x6F, // "6" a+c+d+e+f+g 0xA8, // "7" a+b+c 0xEF, // "8" a+b+c+d+e+f+g 0xED, // "9" a+b+c+d+f+g 0x40, // "-" 0x4f, // "E" 0x00 /* 不顯示 */ }; const uchar CrcTable [256]={ 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205, 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80, 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53}; //開關閥門控制部分 uchar enable_famenoperate = 0; //閥門操作狀態(tài),0為關,1為開,2為關閥動作中,3為開閥動作中 uchar enable_LED; //LED瞬閃允許標志 uchar enable_guanfajishi; //標志位:開閥上水后進行關閥延時計時,以防溢水信號失效 uint n_guanfa; //關閥延時計時 |