![]() #include "stm32f10x.h" #include "usart.h" #include "rtc.h" #include "IO.h" #include "ds18b20.h" #include "adc.h" #include "exti.h" #include "timer.h" //#include "uart2.h" #include "control.h" #define Phz (u32)3*Pmax //功率頻率值上限實際為3*Pmax/100;為了減少誤差,放大100倍 此計算為500微歐采樣電阻值 #define USART_IAP_LEN 10*1024+3 //定義最大接收字節數 10K+3字節 固件更新分3次接收 //IO方向設置 //#define DS18B20_IO_IN() {GPIOB->CRL&=0XFFFFFF0F;GPIOB->CRL|=0x00000080;} //PB1 CRL控制的是低8位 CRH控制的是高8位 //#define DS18B20_IO_OUT() {GPIOB->CRL&=0XFFFFFF0F;GPIOB->CRL|=0x00000030;} ////////////////////////////////////////////////////////////////////////////////// //XXXX智能插座主程序 //author:WEN BO RUI (WEN K) //Q:406650447 //修改日期:2014/5/16 //版本:V1.0 //Copyright(C) 沈陽XXXX公司 2014-2024 //All rights reserved ////////////////////////////////////////////////////////////////////////////////// //u8 USART1_RX_BUF[USART_IAP_LEN] __attribute__ ((at(0X20001000)));//接收緩沖,最大USART_IAP_LEN個字節,起始地址為0X20001000. u8 USART1_RX_BUF[USART_IAP_LEN]; //串口1數據接收緩沖字節 u8 rtcbuffer[8]={0}; //實時時鍾數組 u16 flashBUF[512]; //定義FLASH存儲參數緩存;共512*2=1024個字節,1K字節存儲。因為STM32內部FLASH存取為半字(u16)讀寫,參數為功率和定時組合 u8 Param[204]; //204定義一個8位的參數數組,用於讀取、寫入參數到FLASH的轉化; u8 TEMPBUF[206]; //臨時緩沖區數組 u8 T50F=0,T1000F=0,VDIF=0; //定時器T3定時100毫秒和1秒標志位,語音按鍵標志位 u8 t3count=0; //T3定時器計數器 u8 SREF=0,NREFLAG=0,GettimeF=0; //SREF串口接收服務器數據標志位;NREFLAG為恢復出廠狀態標志位;GettimeF校時功能位 u8 overload = 0; //overload過載標志位,當等於1時表示過載,斷繼電器電源 u8 CRCF,HELLOF =0;; //數據累加和 u32 PSUM; //累積功率 u32 Pmax; //最大使用功率設置上限 u32 Pvio; //用於語音播放時時功率轉換 u16 ADCValue; u16 j1=0,pj=0; u16 m,n; u16 flashCN; //u16 aplen1,iaplen2,iaplen3; //三段IAP長度 float ADtemp,ADJDQ; //檢測繼電器狀態變量 u8 TEMH,TEML,TEM,V5H,V5L; //溫度 電壓檢測值 struct { vu8 powstaF; //開關狀態位,增加此變量可以用於服務器對繼電器狀態查詢時返回開關狀態,開關工作方式(off auto on) vu8 runF; vu8 pv1; //u8 pv1,pv2,pv3,pv4; //32位的功率變為4個8位的 vu8 pv2; vu8 pv3; vu8 pv4; // vu8 yearTH; //上次清零功率時的時間 // vu8 yearTL; // vu8 monT; // // vu8 dateT; // vu8 hourT; // vu8 minT; // vu8 secT; // vu8 timT; //時區 }sta; struct { u8 Time1;u8 Time2;u8 Time3;u8 Time4; u8 Time5;u8 Time6;u8 Time7;u8 Time8; }work; //定時操作結構體 void COM1SEND (u8 com1) { USART_SendData(USART1,com1); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); } void send1() { COM1SEND(0x1e); COM1SEND(0xba); COM1SEND(0x00); COM1SEND(0x00); COM1SEND(CRCF); } //向串口發送一個字符串,strlen為該字符串長度 //void send_string_com1(u8 *str,u8 strlen) //{ // u8 k=0; // for(k=0;k<strlen;k++) // { // COM1SEND(*(str + k)); // } //} //CRC8校驗函數 #define POLY 0xB2 unsigned crc8_slow(unsigned crc, unsigned char *data, size_t len) { unsigned char *end; if (len == 0) return crc; crc ^= 0xff; end = data + len; do { crc ^= *data++; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; } while (data < end); return crc ^ 0xff; } void HELLO(void) //WIFI上電准備完成后發送消息給服務器 { u8 i; u8 inbuf1[32]={"hahahahahahahahahahahahahah00000"}; CRCF = 0; TEMPBUF[0] = 0x24; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa1; for(i=3;i<35;i++) { TEMPBUF=inbuf1[i-3]; } TEMPBUF[35] = 0x00; TEMPBUF[36] = 0x10; TEMPBUF[37] = 0x00; TEMPBUF[38] = 0x11; CRCF=crc8_slow(CRCF,TEMPBUF,39); send1(); //發送1e ba 00 00 crc for(i=0;i<39;i++) { COM1SEND(TEMPBUF); } CRCF = 0; } void IDEL(void) //WIFI每分鍾發送一次給服務器,防止鏈接斷開 { u8 i; u8 idel1[7] = {0x04,0x00,0xa2,0x00,0x00,0x00,0x00}; //鏈接數據 CRCF = 0; CRCF=crc8_slow(CRCF,idel1,7); //CRC8校驗 send1(); for(i=0;i<7;i++) { COM1SEND (idel1); } } void SHUTDOWN(void) //發送斷電信息給服務器 { u8 i; u8 shut1[7] = {0x04,0x00,0xa3,0x00,0x00,0x00,0x00}; //斷電數據 CRCF = 0; CRCF=crc8_slow(CRCF,shut1,7); //CRC8校驗 send1(); for(i=0;i<7;i++) { COM1SEND (shut1); } } //********************************************* //函數名: ONE_LINE(U16 COM_data) //功能說明:發送一個一線串口命令 //入口參數:COM_data 為語音地址或者命令 //出口參數:無 //********************************************* void ONE_LINE(u16 COM_data) { u8 i; u8 high_data; //高八位 u8 low_data; //低八位 low_data = COM_data &0x00ff; high_data = (COM_data>>8) & 0x00ff; //while(!BUSY) //判斷非忙,再發地址數據 { DATA = 0; delay_ms(5); //拉低數據線5毫秒 for(i=0;i<8;i++) //發送高八位 { if(high_data &0x80) //數據位為 1 { DATA = 1; delay_us(600); //延時 600us DATA = 0; delay_us(200); //延時 200us } else //數據位為 0 { DATA = 1; delay_us(200); //延時 200us DATA = 0; delay_us(600); //延時 600us } high_data <<=1; //循環左移一位 } for(i=0;i<8;i++) //發送低八位 { if(low_data &0x80) //數據位為 1 { DATA = 1; delay_us(600); //延時 600us DATA = 0; delay_us(200); //延時 200us } else //數據位為 0 { DATA = 1; delay_us(200); //延時 200us DATA = 0; delay_us(600); //延時 600us } low_data <<=1; //循環左移一位 } DATA =1; } } //*************寫參數到內部FLASH函數**************/ void FLASHWR() { u8 i,j = 0; for(i=0;i<193;i+=2) //串口接收的數據存入16位的數組,准備寫入FLASH { flashBUF[j] = ((Param&&0xff)<<8)+Param[i+1]; j++; } j = 0; flashBUF[101] = PSUM; //當前功率累加值送入FLASH緩存,准備保存 小端在前 flashBUF[102] = PSUM>>16; //當前功率累加值送入FLASH緩存,准備保存 FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR); FLASH_ErasePage(0x800fc00); //先擦后寫,FLASH存參數地址為從0x800fc00開始的1K字節; for(flashCN=0;flashCN<128;flashCN++) //256字節數據 { FLASH_ProgramHalfWord((0x800fc00 +flashCN*2),flashBUF[flashCN]); //flash 為一個字節存儲,16位數據必須地址加2 } FLASH_Lock(); } //**************返回服務器全部參數設置狀態函數*********************/ void STAall() { u8 i; TEMPBUF[0] = 0xcb; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0xff; TEMPBUF[4] = 0xff; TEMPBUF[5] = sta.powstaF; //開關狀態位 TEMPBUF[6] = sta.runF; //運行方式位 TEMPBUF[7] = Param[10]; //虛擬值 TEMPBUF[8] = Param[4]; //限制使用功率上限值 TEMPBUF[9] = Param[5]; TEMPBUF[10] = Param[6]; TEMPBUF[11] = Param[7]; TEMPBUF[12] = PSUM; //數據封裝小端模式,低位在前 TEMPBUF[13] = PSUM>>8; TEMPBUF[14] = PSUM>>16; TEMPBUF[15] = PSUM>>24; TEMPBUF[16] = Param[193]; //上次功率清零時間 TEMPBUF[17] = Param[194]; TEMPBUF[18] = Param[195]; TEMPBUF[19] = Param[196]; TEMPBUF[20] = Param[197]; TEMPBUF[21] = Param[198]; TEMPBUF[22] = Param[199]; for(i=11;i<193;i++) //本次設定值返回 { TEMPBUF[i+12] = Param; } TEMPBUF[205] = Param[8]; //最后一個字節聲音提示與否 CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,206); //CRC8校驗 send1(); // for(i=0;i<206;i++) //本次設定值返回 { COM1SEND(TEMPBUF); } CRCF = 0; } //**************軟復位程序,用於固件更新重啟單片機**********************/ void SoftReset(void) //軟復位程序 { __set_FAULTMASK(1); // 關閉所有中端 NVIC_SystemReset(); // 復位 以上兩個函數位於 core_cm3.h 文件中 } //********************主函數開始**********************/ int main(void) { //u8 inbuf1[10]={"opencloner"}; //u8 inbuf1[22]={"感謝使用XXXX智能插座\n"}; u8 i,j,Tchange,WifiF; u8 FproV=0x78; //掉電時FLASH 寫保護標識,防止多次寫入 u8 FproT=0x78; //每天時間到了寫次Flash,寫保護標識,防止多次寫入 u16 COM1F; //接收服務器數據狀態查詢字節 short TEM18B20; u8 vdio[10]; //語音播報功率值時各個位置上的數值 //SCB->VTOR = FLASH_BASE | 0x1400; //使用IAP更新功能, VTOR寄存器存放的是新的中斷向量表的起始地址復位從0x8001400開始 delay_init(); //延時函數初始化 IO_Init(); //GPIO初始化 NVIC_Configuration(); //設置NVIC中斷分組2:2位搶占優先級,2位響應優先級 //uart2_Init(115200); //串口2初始化 RTC_Init(); //RTC初始化 EXTIX_Init(); //外部中斷初始化 Adc_Init(); //ADC初始化 uart_init(115200); DS18B20_Init(); TIM3_Init(249,7199); //10Khz的計數頻率,計數到250為25ms Tout= ((249+1)*( 7199+1))/72=25000us=25ms // RTC_Set(2014,6,10,10,36,10); //測試用,實際代碼中要去掉 for(flashCN=0;flashCN<128;flashCN++) //上電后讀取參數 { flashBUF[flashCN]= *(u16*)(0x800f800 + flashCN*2); //讀取FLASH數據 } if(flashBUF[102] == 0xffff) //第一次上電讀出,累積置零 { flashBUF[101] = 0; flashBUF[102] = 0; } j = 0; PSUM =(flashBUF[102]<<16)+flashBUF[101]; //累積功率送PSUM 小端在前(低位在前) for(i=0;i<102;i++) { Param[j] = flashBUF>>8; //高8位在前 Param[j+1] = flashBUF; j+=2; } j = 0; //清j if((Param[7]==0xff)||(Param[6]==0xff)||(Param[5]==0xff)) { // Pmax = 1100; //如果功率使用上限為0XFF。認為沒有設置,自動設置為默認為1100W(美國功率限制) // Pmax = 2200; //自動設置為默認為2200W(中國功率限制) Pmax = 2500; //考慮用戶使用心理,設置可稍高些 Param[7] = 0; //功率設定值送給對應數組,留保存 Param[6] = 0; Param[5] = Pmax>>8; Param[4] = Pmax; //最低位在前 } else { Pmax = (Param[7]<<24)+(Param[6]<<16)+(Param[5]<<8)+Param[4];//最大使用上限讀出來 } // Pmax = 300; //測試用,實際代碼中要去掉 // Param[192]=0x08; //測試用,實際代碼中要去掉 // Param[131]=0x07; //測試用,實際代碼中要去掉 // Param[183]=0x06; //測試用,實際代碼中要去掉 // Param[11]=0x05; //測試用,實際代碼中要去掉 while(1) { //****************以下WiFi模塊初始化完成程序*****暫時可以不用,上電一直循環發送HELLO給服務器***************************************** // if((WifiRDY==0)&&(WifiF==0)) //WifiRDY為wifi模塊的READY引腳,接STM32 IO引腳 ,上拉輸入 // { //當為低電平時WIFI模塊上電正常 // WifiF = 1; //發送一次后不再發送 // HELLO(); //發送給服務器進行握手, // } // if(WifiRDY) //WifiRDY=1表示高電平;表示WIFI模塊斷了;這時清WifiF,為了下一次握手 // { // WifiF = 0; //清WifiF // } //****************以下恢復出廠狀態處理程序************************************************* if(NREFLAG) //如果恢復出廠狀態標志位被置高了 { NREFLAG = 0; TEMPBUF[0] = 0x01; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa5; TEMPBUF[3] = 0x03; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,4); //CRC8校驗 send1(); for(i=0;i<4;i++) { COM1SEND(TEMPBUF); //過載信息發給服務器 } for(i=0;i<128;i++) //將0xffff,准備寫入FLASH { flashBUF = 0xffff; } flashBUF[101] = 0; //功率參數直接清零 flashBUF[102] = 0; FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR); FLASH_ErasePage(0x800fc00); //先擦后寫,FLASH存參數起始地址 for(flashCN=0;flashCN<128;flashCN++) //256字節數據 { FLASH_ProgramHalfWord((0x800fc00 +flashCN*2),flashBUF[flashCN]); //flash 為一個字節存儲,16位數據必須地址加2 } FLASH_Lock(); delay_ms(10); for(flashCN=0;flashCN<128;flashCN++) //延時一段時間后讀取參數 { flashBUF[flashCN]= *(u16*)(0x800f800 + flashCN*2); //讀取FLASH數據 } j = 0; for(i=0;i<102;i++) { Param[j] = flashBUF>>8; //高8位在前 Param[j+1] = flashBUF; j+=2; } j = 0; } //****************以下接收服務器指令處理程序*********************************************** switch(SREF) { case 0xB1: //SERVER_WELCOME 服務器歡迎數據 當前固定為 "opencloner"+時間 { SREF = 0; //暫無內容返回(PLUG主動發HELLO給服務器,服務器返回這個數據包,PLUG不在發送數據) HELLOF = 1; //服務器收到插座的HELLO,返回相應值,職位HELLOF,插座不再發HELLO函數 STAall(); //返回所有狀態 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); } break; case 0xB2: //SERVER_INQUIRY狀態查詢(PLUG收到查詢請求后需要根據數據位標識碼返回PLUG_STATUS) { SREF = 0; COM1F = (USART1_RX_BUF[3]<<8)+USART1_RX_BUF[2]; //兩個字節的Mask標志位,低位在前高位在后;如0x01;接收的位01,00 switch(COM1F) { case 0xffff: //所有狀態查詢 (已OK) { STAall(); //返回所有狀態 }break; case 0x01: //開關狀態查詢,開還是關(已OK) { TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x01; TEMPBUF[4] = 0x00; TEMPBUF[5] = sta.powstaF; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } }break; case 0x02: //開關運行方式查詢,一直開。自動,一直關 { TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x02; TEMPBUF[4] = 0x00; TEMPBUF[5] = sta.runF; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } }break; case 0x03: //開關狀態和運行方式查詢,一直開。自動,一直關(已OK) { TEMPBUF[0] = 0x04; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x03; TEMPBUF[4] = 0x00; TEMPBUF[5] = sta.powstaF; TEMPBUF[6] = sta.runF; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,7); //CRC8校驗 send1(); for(i=0;i<7;i++) { COM1SEND(TEMPBUF); } }break; case 0x04: //虛擬設定值 (已OK) { //位於flashBUF[5]的高8位--->Param[10] TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x04; TEMPBUF[4] = 0x00; TEMPBUF[5] = Param[10]; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } }break; case 0x08: //限制功率上限值 (具體值及相應功能程序未完成) { TEMPBUF[0] = 0x06; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x08; TEMPBUF[4] = 0x00; TEMPBUF[5] = Param[4]; TEMPBUF[6] = Param[5]; TEMPBUF[7] = Param[6]; TEMPBUF[8] = Param[7]; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,9); //CRC8校驗 send1(); for(i=0;i<9;i++) { COM1SEND(TEMPBUF); } }break; case 0x10: //當前累積電量查詢 (已OK) { TEMPBUF[0] = 0x06; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x10; TEMPBUF[4] = 0x00; TEMPBUF[5] = PSUM; TEMPBUF[6] = PSUM>>8; TEMPBUF[7] = PSUM>>16; TEMPBUF[8] = PSUM>>24; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,9); //CRC8校驗 需加上數據長度兩字節和標志位1字節 send1(); for(i=0;i<9;i++) { COM1SEND(TEMPBUF); } }break; case 0x20: //定時數據狀態 (具體值及相應功能程序也已經完成) { TEMPBUF[0] = 0x7b; //123個字節 TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x20; TEMPBUF[4] = 0x00; for(i=11;i<132;i++) //定時數據從Param[11]到Param[131] { TEMPBUF[i-6]= Param; } CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,126); //CRC8校驗需加上數據長度兩字節和標志位1字節 send1(); for(i=0;i<126;i++) { COM1SEND(TEMPBUF); } }break; case 0x40: //溫度設定狀態返回是否有效位+溫控數據 (已OK) { TEMPBUF[0] = 0x33; //51個字節 TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x40; TEMPBUF[4] = 0x00; for(i=132;i<184;i++) //定時數據從Param[11]到Param[131] { TEMPBUF[i-127]= Param; } CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,54); //CRC8校驗 需加上數據長度兩字節和標志位1字節 send1(); for(i=0;i<54;i++) { COM1SEND(TEMPBUF); } }break; case 0x80: //???沒明白是什么意思時間設定有效否,返回是否有效位 { //位於flashBUF[92]的高8位字節--->Param[184] 暫定時區設定 TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x80; TEMPBUF[4] = 0x00; TEMPBUF[5] = Param[184]; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } }break; case 0x100: //聲音設定有效否 (已完成) { //位於flashBUF[4]的高8位字節--->Param[8] TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x00; TEMPBUF[4] = 0x10; TEMPBUF[5] = Param[8]; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } }break; case 0x200: //是否時間自動校正 { //時間自動校正位於flashBUF[97]的高8位字節--->Param[192] TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x00; TEMPBUF[4] = 0x20; TEMPBUF[5] = Param[192]; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } }break; } USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); } break; case 0xB3: //SERVER_SWITCH(服務器發送此指令進行開關操作, plug收到后返回PLUG_STATUS(數據位mask=01)) { SREF = 0; if(USART1_RX_BUF[2]==1) { sta.powstaF = 1; //繼電器狀態查詢時返回開關狀態 1表示吸合 0斷開 AUTO = 1; //開繼電器 TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x01; TEMPBUF[4] = 0x00; TEMPBUF[5] = sta.powstaF; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } } if(!USART1_RX_BUF[2]) { sta.powstaF = 0; //繼電器狀態查詢時返回開關狀態 1表示吸合 0斷開 AUTO =0; //關繼電器 TEMPBUF[0] = 0x03; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa4; TEMPBUF[3] = 0x01; TEMPBUF[4] = 0x00; TEMPBUF[5] = sta.powstaF; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,6); //CRC8校驗 send1(); for(i=0;i<6;i++) { COM1SEND(TEMPBUF); } } USART_ITConfig(USART1,USART_IT_RXNE, ENABLE); } break; case 0xB4: //SERVER_SETUP(參數設置) { SREF = 0; for(i=0;i<193;i++) //串口接收的數據存入16位的數組,准備寫入FLASH { Param = USART1_RX_BUF; } STAall(); //發送所有參數給服務器 Pmax = (Param[7]<<24)+(Param[6]<<16)+(Param[5]<<8)+Param[4];//最大使用上限讀出來 //FLASHWR(); //參數寫入FLASH USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啟串口中斷 } break; case 0xB5: //SERVER_UPGRADE(固件升級,暫未調試) { SREF = 0; if(USART1_RX_BUF[2]==0x01) //第一段升級程序,一共三段 { // USART1_RX_BUF[1023]=0x01; //測試用,正常程序屏蔽掉 // USART1_RX_BUF[1024]=0x02; //測試用,正常程序屏蔽掉 // USART1_RX_BUF[1025]=0x03; //測試用,正常程序屏蔽掉 // USART1_RX_BUF[1026]=0x04; //測試用,正常程序屏蔽掉 // USART1_RX_BUF[2049]=0x05; //測試用,正常程序屏蔽掉 // USART1_RX_BUF[2050]=0x06; //測試用,正常程序屏蔽掉 // USART1_RX_BUF[3073]=0x09; //測試用,正常程序屏蔽掉 // USART1_RX_BUF[3074]=0x0a; //測試用,正常程序屏蔽掉 //iaplen1 = USART1_RX_BUF[0]; //長度取過來,暫時未用 //第一段寫入地址為0x08008800~0x0800afff(10k字節) for(i=0;i<10;i++) //寫10次 { FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR); m=0; FLASH_ErasePage(0x8008800+i*1024); //先擦后寫,每次擦除一頁地址(1K);擦10K;FLASH存參數起始地址 for(n=0;n<1024;n+=2) //串口接收的數據存入16位的數組,准備寫入FLASH { flashBUF[m] = (USART1_RX_BUF[n+4+i*1024]<<8)+USART1_RX_BUF[n+3+i*1024]; m++; } m = 0; for(flashCN=0;flashCN<512;flashCN++) //10k字節數據,分10次寫入,每次寫1K,因為RAM不夠 { FLASH_ProgramHalfWord((0x8008800 +flashCN*2+i*1024),flashBUF[flashCN]);//flash 為一個字節存儲,16位數據必須地址加2 } FLASH_Lock(); } } if(USART1_RX_BUF[2]==0x02) //第二段升級程序,一共三段 { //iaplen2 = USART1_RX_BUF[0]; //長度取過來 //第二段寫入地址為0x0800b000~0x0800d7ff(10k字節) for(i=0;i<10;i++) //寫10次 { FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR); m=0; FLASH_ErasePage(0x800b000+i*1024); //先擦后寫,每次擦除一頁地址(1K);擦10K;FLASH存參數起始地址 for(n=0;n<1024;n+=2) //串口接收的數據存入16位的數組,准備寫入FLASH { flashBUF[m] = (USART1_RX_BUF[n+4+i*1024]<<8)+USART1_RX_BUF[n+3+i*1024]; m++; } m = 0; for(flashCN=0;flashCN<512;flashCN++) //10k字節數據,分10次寫入,每次寫1K,因為RAM不夠 { FLASH_ProgramHalfWord((0x800b000 +flashCN*2+i*1024),flashBUF[flashCN]);//flash 為一個字節存儲,16位數據必須地址加2 } FLASH_Lock(); } for(m=0;m<USART_IAP_LEN;m++) //第二次接收完后把串口緩存全部置為0xff,防止第三次接收后 { //接收的不是整K的長度,寫到FLASH的值不定 USART1_RX_BUF[m]=0xff; } } if(USART1_RX_BUF[2]==0x03) //第三段升級程序,一共三段 { //iaplen3 = USART1_RX_BUF[0]; //長度送過來 //第3段寫入地址為0x0800d800~0x0800fbff(9k字節) for(i=0;i<9;i++) //寫9次 { FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR); m=0; FLASH_ErasePage(0x800d800+i*1024); //先擦后寫,每次擦除一頁地址(1K);擦10K;FLASH存參數起始地址 for(n=0;n<1024;n+=2) //串口接收的數據存入16位的數組,准備寫入FLASH { flashBUF[m] = (USART1_RX_BUF[n+4+i*1024]<<8)+USART1_RX_BUF[n+3+i*1024]; m++; } m = 0; if(i==8) //最后一次寫入時,置一個更新標志位存到FLASH { flashBUF[511]=0x7777; //地址0x0800fbff存入0x77,以便IAP判斷 } for(flashCN=0;flashCN<512;flashCN++) //9k字節數據,分9次寫入,每次寫1K,因為RAM不夠 { FLASH_ProgramHalfWord((0x800d800 +flashCN*2+i*1024),flashBUF[flashCN]);//flash 為一個字節存儲,16位數據必須地址加2 } FLASH_Lock(); } TEMPBUF[0] = 0x01; //第三次寫完后發送准備固件更新消息 TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa5; TEMPBUF[3] = 0x04; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,4); //CRC8校驗 send1(); for(i=0;i<4;i++) //准備固件更新信息返回服務器 { COM1SEND(TEMPBUF); } SoftReset(); //接收和存儲完固件更新文件后軟復位程序,轉IAP程序開始更新, } USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); } break; case 0xB6: //SERVER_TIME,用於回應plug的PLUG_TIME指令。 { SREF = 0; COM1F = (USART1_RX_BUF[4]<<8)+USART1_RX_BUF[3]; //USART1_RX_BUF[1]是標志位0XB6;USART1_RX_BUF[2]接收的是時區, //所以時間從USART1_RX_BUF[3]開始 3,4為年份需合並成16位的格式 GettimeF = 1; //低字節在前,高字節在后,如2014年=07DE,接收順序為DE 07 RTC_Set(COM1F,USART1_RX_BUF[5],USART1_RX_BUF[6],USART1_RX_BUF[7],USART1_RX_BUF[8],USART1_RX_BUF[9]); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); } break; case 0xB7: //SERVER_IDLE,用於回應plug的PLUG_IDLE,無實際意義。 { SREF = 0; USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); } break; case 0xB8: //用於接收手機端設置的一些定時參數。 { SREF = 0; for(i=0;i<193;i++) //串口接收的數據存入16位的數組,准備寫入FLASH { Param = USART1_RX_BUF; } STAall(); //發送所有參數給服務器 Pmax = (Param[7]<<24)+(Param[6]<<16)+(Param[5]<<8)+Param[4];//最大使用上限讀出來 TEMPBUF[0] = 0x01; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa5; TEMPBUF[3] = 0x05; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,4); //CRC8校驗 send1(); COM1SEND(0x01); COM1SEND(0x00); COM1SEND(0xa5); //返回服務器PLUG_ALERM 返回05 告知本地設置改變 COM1SEND(0x05); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); } break; default: { USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); }break; } //****************以下過載報警程序******************************************** if(overload) //過載標志 { overload = 0; AUTO = 0; //關掉繼電器 TEMPBUF[0] = 0x01; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa5; TEMPBUF[3] = 0x01; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,4); //CRC8校驗 send1(); COM1SEND(0x01); COM1SEND(0x00); COM1SEND(0xa5); //返回服務器PLUG_ALERM 返回01 告知過載 COM1SEND(0x01); } //****************以下語音模塊處理程序,地址1~9存放的數字1~9語音,地址10存放“0”語音,******************************************* if(VDIF == 1) //語音按鍵標志位等於1播放當前時刻 { // // ONE_LINE(0x0B); //地址11存放的”當前時刻“語句 // delay_ms(180); //經驗時間,等待BUSY變成1 // while(BUSY); //一直等待上個語句播放完成 ONE_LINE(0x02); //播放下一條語句 delay_ms(180); while(BUSY); //一直等待上個語句播放完成 ONE_LINE(0x01); VDIF = 0; } if(VDIF == 2) //語音按鍵標志位等於2播放當前已消耗功率 { vdio[0] = PSUM/1000000000; //最高位(第10位)數值 Pvio = PSUM-vdio[0]*1000000000; vdio[1] = Pvio/100000000; //(第9位)數值 Pvio = Pvio-vdio[1]*100000000; vdio[2] = Pvio/10000000; //(第8位)數值 Pvio = Pvio-vdio[2]*10000000; vdio[3] = Pvio/1000000; //(第7位)數值 Pvio = Pvio-vdio[3]*1000000; vdio[4] = Pvio/100000; //(第6位)數值 Pvio = Pvio-vdio[4]*100000; vdio[5] = Pvio/10000; //(第5位)數值 Pvio = Pvio-vdio[5]*10000; vdio[6] = Pvio/1000; //(第4位)數值 Pvio = Pvio-vdio[6]*1000; vdio[7] = Pvio/100; //(第3位)數值 Pvio = Pvio-vdio[7]*100; vdio[8] = Pvio/10; //(第2位)數值 Pvio = Pvio-vdio[8]*10; vdio[9] = Pvio%10; //(第1位)數值 ONE_LINE(0x0c); //地址12存放的“已使用功率“語音 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); if(vdio[0]) //最高位不為0;從最高位播放 { for(i=0;i<10;i++) { ONE_LINE(vdio); //播放最高位 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else //最高位為0,判斷第9位,以此類推 { if(vdio[1]) //最9位不為0;從9位播放 { for(i=1;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { if(vdio[2]) //最8位不為0;從8位播放 { for(i=2;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { if(vdio[3]) //最7位不為0;從7位播放 { for(i=3;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { if(vdio[4]) //最6位不為0;從6位播放 { for(i=4;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { if(vdio[5]) //最5位不為0;從5位播放 { for(i=5;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { if(vdio[6]) //最4位不為0;從4位播放 { for(i=6;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { if(vdio[7]) //最3位不為0;從3位播放 { for(i=7;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { if(vdio[8]) //最2位不為0;從2位播放 { for(i=8;i<10;i++) { ONE_LINE(vdio); //播放 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } else { ONE_LINE(vdio[9]); //播放第一位 delay_ms(180); //經驗時間,等待BUSY變成1 while(BUSY); } } } } } } } } } VDIF = 0; //清播放標志位 } //***************以下電壓采集及斷電處理程序25毫秒檢測一次*********************************************** if(T50F) //目前25毫米取一次AD采樣值,用以判斷是否斷電 { //小於4.75V認為出現斷電或異常,保存參數,送出警告 T50F = 0; ADCValue = Get_Adc_Average(ADC_Channel_1 ,3); //采集3次取平均值 為了減少損耗時間 ADtemp = (float)ADCValue*(3.3/4096); V5H = ADtemp; V5L = (ADtemp-V5H)*100; if(ADtemp<=1.87) //小於4.75V認為出現斷電或異常,保存參數,送出警告 { //正常時1.90,差0.03V SHUTDOWN(); //發送斷電信息給服務器 if(FproV==0x78) //Fprotect==0x78,才寫入一次FLASH, { //防止斷電延遲時間過長,多次寫入FLASH // FLASHWR(); //參數寫入FLASH FproV = 0; //寫入一次后不再寫入,重上電后恢復。 } } } //***************以下讀取時間,溫度,繼電器工作狀態檢測,定時處理及發送程序******************************************** if(T1000F) //定時1秒時間讀次時間,溫度並發送給服務器 { //清除標志位 T1000F = 0; //****************以下開啟校時模式程序********************************************** if((Param[192]==1)&&(GettimeF==0)) //是否需要校時,接收到服務器的校時數據后,置位GettimeF ,不再發送申請命令 { // TEMPBUF[0] = 0x01; TEMPBUF[1] = 0x00; TEMPBUF[2] = 0xa6; TEMPBUF[3] = Param[184]; CRCF = 0; CRCF=crc8_slow(CRCF,TEMPBUF,4); //CRC8校驗 send1(); COM1SEND(0x01); COM1SEND(0x00); COM1SEND(0xa6); COM1SEND(Param[184]); } //****************以下獲取溫度程序********************************************** TEM18B20=DS18B20_Get_Temp(); //獲取溫度 if(TEM18B20<0) { TEM18B20=-TEM18B20; //轉為正數 TEM = 1; //表示負溫度 } else { TEM = 0; } TEMH = TEM18B20/10; //顯示正數部分 TEML = TEM18B20%10; //顯示小數部 //******繼電器工作方式檢測 ADCValue = Get_Adc_Average(ADC_Channel_7 ,5); //ADC 7通道采集5次繼電器控制端電壓 ADJDQ = (float)ADCValue*(3.3/4096); if(ADJDQ>3.2) //大於3.2V工作在自動運行的吸合狀態 { if(WifiRDY==0) //WiFi正常 { LEDR = 0; //wifi正常且繼電器有輸出,紅燈亮 LEDG = 1; } if(WifiRDY) //WiFi異常 { LEDR = ~LEDR; //wifi異常且繼電器有輸出,紅燈閃 LEDG = 1; } sta.powstaF = 1; //繼電器狀態查詢時返回開關狀態 1表示吸合 0斷開 sta.runF = 1; //繼電器運行方式 1表示自動運行 } if(ADJDQ<0.2) //小於0.2V工作在自動運行的斷開狀態 { if(WifiRDY==0) //WiFi正常 { LEDR = 1; //wifi正常且繼電器無輸出,綠燈亮 LEDG = 0; } if(WifiRDY) //WiFi異常 { LEDR = 1; //wifi異常且繼電器無輸出,綠燈閃 LEDG = ~LEDG; } sta.powstaF = 0; //增加此變量可以用於服務器對繼電器狀態查詢時返回開關狀態 sta.runF = 1; //繼電器運行方式 1表示自動運行 } if((ADJDQ>2.8)&&(ADJDQ<3.1)) //工作在一直吸合狀態 LED指示燈為橙色 { LEDR=LEDG=0; //橙色 sta.powstaF = 1; //增加此變量可以用於服務器對繼電器狀態查詢時返回開關狀態 sta.runF = 0; //繼電器運行方式 0常閉狀態 } if((ADJDQ>0.3)&&(ADJDQ<0.6)) //工作在一直斷開狀態 { sta.powstaF = 0; //增加此變量可以用於服務器對繼電器狀態查詢時返回開關狀態 sta.runF = 2; //繼電器運行方式 2表示常開狀態 } //RTC讀取及處理 RTC_Get(); //獲取時間 rtcbuffer[0]=calendar.w_year/0xff; //年份的高8位 rtcbuffer[1]=calendar.w_year; //年份的低8位 rtcbuffer[2]=calendar.w_month; rtcbuffer[3]=calendar.w_date; rtcbuffer[4]=calendar.hour; if(calendar.min!=rtcbuffer[5]) //如果分鍾變了; { Tchange = 1; //每分鍾發次IDEL();給服務器,防止鏈接斷開 } rtcbuffer[5]=calendar.min; rtcbuffer[6]=calendar.sec; rtcbuffer[7]=calendar.week; if((rtcbuffer[4]==0x13)&&(FproT==0x78)) //每天19點寫一次FLASH,保護參數。 { FLASHWR(); FproT = 0; } if(Tchange) //每分鍾發次IDEL();給服務器,防止鏈接斷開 { Tchange = 0; IDEL(); } //**********定時開關檢測*************************** if(Param[11]==1) //定時開關使能 { timeJC(work.Time1,12); //Param[12]~Param[26] timeJC(work.Time2,27); //Param[27]~Param[41] timeJC(work.Time3,42); //Param[42]~Param[56] timeJC(work.Time4,57); //Param[57]~Param[71] timeJC(work.Time5,72); //Param[72]~Param[86] timeJC(work.Time6,87); //Param[87]~Param[101] timeJC(work.Time7,102); //Param[102]~Param[116] timeJC(work.Time8,117); //Param[117]~Param[131] } //**********溫度開關簡單模式使能******************** if(Param[132]==1) { Tsimple(133); } //**********溫度開關編程模式使能******************** if(Param[132]==2) { Tprog(136); Tprog(142); Tprog(148); Tprog(154); Tprog(160); Tprog(166); Tprog(172); Tprog(178); } // sta.pv4 = PSUM; //低8位 // sta.pv3 = PSUM>>8; // sta.pv2 = PSUM>>16; // sta.pv1 = PSUM>>24; // for(i=0;i<8;i++) // { // COM1SEND (rtcbuffer); // } // COM1SEND(V5H); // COM1SEND(V5L); // COM1SEND((j1>>8)); // COM1SEND(j1); // COM1SEND(PSUM>>24); // COM1SEND(PSUM>>16); // COM1SEND(PSUM>>8); // COM1SEND(PSUM); if(!HELLOF) //如果服務器未返回值一直發送HELLO函數 { HELLO(); } COM1SEND((j1>>8)); COM1SEND(j1); COM1SEND(PSUM>>24); COM1SEND(PSUM>>16); COM1SEND(PSUM>>8); COM1SEND(PSUM); // COM1SEND (PSUM); // COM1SEND (PJ); // COM1SEND (overload); // COM1SEND (FproV); //讀Flash,用於測試 // COM1SEND (FproT); //讀Flash,用於測試 // COM1SEND (aj); //讀Flash,用於測試 COM1SEND (*(u8*)(0x8008800)); //讀Flash,用於測試 COM1SEND (*(u8*)(0x8008801)); COM1SEND (*(u8*)(0x8008bfc)); //讀Flash,用於測試 COM1SEND (*(u8*)(0x8008bfd)); //讀Flash,用於測試 COM1SEND (*(u8*)(0x8008bfe)); COM1SEND (*(u8*)(0x8008bff)); //讀Flash,用於測試 COM1SEND (*(u8*)(0x8008ffe)); //讀Flash,用於測試 COM1SEND (*(u8*)(0x8008fff)); //讀Flash,用於測試 COM1SEND (*(u8*)(0x80093fe)); //讀Flash,用於測試 COM1SEND (*(u8*)(0x80093ff)); COM1SEND (*(u8*)(0x800fbfe)); COM1SEND (*(u8*)(0x800fbff)); } } } void USART1_IRQHandler(void) //串口1中斷服務程序 { static u8 receY=0,i=0; static u16 j=0,LEN = 0; static u8 Rav[7]; //static u8 k=0; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷 { USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中斷標志 if((i<7)&&(receY==0)) //接受完數據包頭1E BA 00 00 和CRC 和數據長度(7個字節) { Rav=USART_ReceiveData(USART1); //讀取接收到的首字節數據 if((Rav[0]==0x1E)) //首字節為0X00; { i++; // if((Rav[1]==0xBA)) { if((Rav[2]==0x00)) { if((Rav[3]==0x00)) { if(i == 7) { i = 0; receY = 1; //是要接收的數據包 LEN = Rav[6]; LEN=(LEN<<8)+Rav[5]+2; //獲得數據長度值 數據包長度需加2,因為緊跟着的標識位沒算數據長度而且后續接收j先加1了 //LEN = ((Rav[5]&0x00ff)<<8)+Rav[6]+2; //而且數據長度的低字節當receY有效時,緊接着又送一遍到USART_RX_BUF[0] // for(k=0;k<7;k++) // { // Rav = 0xaf; // } } } } } if(i==7){i = 0;} //i加到5,確沒有被清零,表明接收到錯誤數據,自動清零 } } if(receY) //開始接收數據包 { USART1_RX_BUF[j]=USART_ReceiveData(USART1); if(j<LEN) { j++; } if(j==LEN) //接收完成,開始處理數據 { SREF = USART1_RX_BUF[1]; //標識位送REVF USART1_RX_BUF[0] = LEN-3; //為了得到固件更新時每次的數據長度 減去開頭重復接收的一個數據,標識位及包標識位 j = 0; //這樣USART1_RX_BUF[0]為數據長度,USART1_RX_BUF[1]為標識 receY = 0; //USART1_RX_BUF[2]為第幾包,后面為更新的數據 LEN = 0; USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); //關閉接收中斷 } } } if(USART_GetFlagStatus(USART1,USART_FLAG_ORE) == SET) //溢出 { USART_ClearFlag(USART1,USART_FLAG_ORE); //讀SR USART_ReceiveData(USART1); //讀DR } USART_ReceiveData(USART1); } //外部中斷5-9服務程序 void EXTI9_5_IRQHandler(void) { //static u16 j1; j1++; pj++; if(j1==130) //1300個脈沖對應1W 6毫歐時為1300;500微歐為110個脈沖 { j1 = 0; PSUM++; //一個脈沖到來時1W功率 } EXTI_ClearITPendingBit(EXTI_Line9); //清除LINE9上的中斷標志位 } //外部中斷10-15服務程序 void EXTI15_10_IRQHandler(void) { static u8 av; av++; if(av == 1) { VDIF = 1; } if(av == 2) { av = 0; VDIF = 2; } EXTI_ClearITPendingBit(EXTI_Line13); //清除LINE13上的中斷標志位 } //定時器3中斷服務程序 void TIM3_IRQHandler(void) //TIM3中斷 25毫秒中斷 { static u8 Pcount,nrecount; if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查TIM3更新中斷發生與否 { T50F = 1; t3count++; Pcount++; //功率判斷開始計時,1秒 LEDG = ~LEDG; if(Pcount==39) //1秒到了 { Pcount = 0; if((pj*100) >Phz) //判斷PJ的計數值是否超過預設功率上限對應的參數 { overload = 1; //超過則認為過載 } pj = 0; //清除該計數為了下一次判斷 } if(NRE==0) //出廠設置鍵被按下 { nrecount++; if(nrecount>121) { nrecount = 0; NREFLAG = 1; //置高恢復出廠狀態標志位 } } else nrecount = 0; //按鍵未按下或時間不到抬起了,清計數器 if(t3count==200) //5秒時間 { t3count = 0; T1000F = 1; LEDR = ~LEDR; } TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中斷標志 } } |