最近做課設,選了電力線通訊這種途徑,經過百度google等一番查詢,最終敲定了mi200e這塊國產芯片。
課設要求就是雙機通訊,互傳傳感器信息以及模擬一個時鍾
然后淘寶買了拆機的成品,我拿回來把mcu拆了然后飛出通訊端口和stm8交互。現在串口兩邊可以通訊了,下一步就是重新繪制一塊完整的pcb,然后制版,並實現響應功能。
先上ref:
http://search.eefocus.com/s?app_id=90&sub=1&q=mi200e
這是電路城搜索mi200e得出的結果,我主要參考第一篇,他在嘉立創還有發帖,點進去你就找得到了。
他使用stm8主控並繪制整塊pcb,我則使用以前的stm8核心小板。由於mi200e常規供電為5v,稍稍更改核心板為5v供電做好。
沒有拍當時做的圖片,上pcb和實物吧!
將右圖放大后,可看到兩塊綠板,這兩塊就是成品模塊,應用於智能抄表的。可看到左邊那塊上有一根小跳線,跳線右邊哪里原來是塊u,我用烙鐵把他拆了。
不然stm8沒法單獨和mi200e通訊。至於為什么要跳那根線,我在網上恰好查到他的原理圖,(應該是miartech官方的方案,然后抄的,原件絲印不同),mi200e的供電vdd受一個pmos控制,
所以直接將mos的g級接地。其實我買了兩種,一共買了四塊,連運費20+rmb。另一種的絲印是和原理圖隊上的。我后面會附上手頭的資料。
兩塊板子背面其實有排針,原來用於接220v的,我直接把他們並聯在一起,然后接了一根電源線。一方面因為我電源線緊張,另一方面固定在一塊紙板上方便調試。
這是原理圖,通訊接口是SPI,其中cs不能直接接地,因為數據是雙向互傳,並且不是單次傳輸。具體參考SPI接口flash的cs為什么不能直接接地吧。
我一開始想省io直接接地,結果調試的時候發現,自檢過不了。
至於rst引腳,我把它接到stm8的nrst恰好可以使用,雖然官方應用筆記里面說要低電平1s后拉高。留待后面再測試吧。
這樣就是4個io就能交互了。
然后我按照嘉立創那篇帖子里的方案做了,然后一直調試,發現他的程序我直接用不了,數據通。
然后我發現省略了crc校驗初步數據能夠發送,但是有毛病。
沒辦法,又看手冊,看應用筆記。以及對比另一個c51版本的程序
,這個程序從我給的鏈接里的第二篇可以下載到。但是這個只是驅動,應該就是這個產品用到的,但是沒給全程序。我猜嘉立創那篇帖主
也是參考這個改的,因為驅動大體一致。我同時看筆記,以及兩篇驅動,最后經過一番修改,然后下進去竟然就可以工作了。
程序限制它64字節,對於一般應用足夠了。
說一下這塊芯片的發送過程,兩個引導字節(一個字),一個固定字節,然后配置字節(速率和字長,字為單位)。到這里都是固定200/240bps速率(會因交流電頻率不同而不同),之后的速率可自行配置,
程序里設定的是1600/1920bps。然后是以字為單位的數據(這里就是串口透傳,由於是字對齊,所以必須是偶數字節,這里要注意!),最后一個字的CRC校驗。
附上一張筆記圖,看別人的代碼真是不容易啊。這里雙向能通訊了,后面再看要不要他程序的框架,如果要,還有更多細節要明白。
和硬件打交道,如果不懂的話,可能就是一個延時你就要消耗大把時間。所以需要日積月累!

1 #include "stm8s.h" 2 #include "config.h" 3 #include "MI200E.h" 4 #include "PLCProcess.h" 5 6 unsigned char g_cStatusReg; 7 unsigned char g_cRecModCfgReg; 8 unsigned short PLC_Word_Rec_Overtime; 9 unsigned char g_bRecv_Pkg_Flag; 10 unsigned char g_CRC_H,g_CRC_L; 11 unsigned char g_cPkg_Length = 0; 12 unsigned char g_Pkg_Indication_Byte = 0; 13 unsigned char g_cTrans_Step; 14 unsigned char g_cRecv_Step; 15 unsigned char g_cRecByte_H; 16 unsigned char g_cRecByte_L; 17 unsigned char g_cSend_Data_Length; 18 unsigned char g_cSend_Byte_Cnt; 19 unsigned char g_cRecv_Byte_Cnt; 20 unsigned char g_Send_Buf[64]; 21 unsigned char g_Recv_Buf[64]; 22 23 24 void PLC_Send_Frame(unsigned char cWRData_H, unsigned char cWRData_L) 25 { 26 PLC_Write_Reg(PLCAddrWRSR,(g_cStatusReg&0x7F)); //Clear TI;Write Status Register:0x02 27 MI200E_SCK_0; 28 MI200E_CS_0; 29 Write_SPI(PLCAddrWRTB0); //Write Sending Byte Register 0:0x04 30 Write_SPI(cWRData_H); 31 Write_SPI(cWRData_L); 32 MI200E_SCK_0; 33 MI200E_CS_1; 34 } 35 36 void PLC_RD_Recv_Word(void) 37 { 38 MI200E_SCK_0; 39 MI200E_CS_0; 40 Write_SPI(PLCAddrRDRB0); //Read Receiving Byte Register 0:0x84 41 g_cRecByte_H = Read_SPI(); 42 g_cRecByte_L = Read_SPI(); 43 MI200E_SCK_0; 44 MI200E_CS_1; 45 } 46 47 unsigned char PLC_Clear_EPF(void) 48 { 49 unsigned char cStatusByte; 50 51 cStatusByte = PLC_Read_Reg(PLCAddrRDSR); //Read Status Register:0x82 52 PLC_Write_Reg(PLCAddrWRSR, (cStatusByte&0xF5)); //Clear EPF Flag & CRC_Flag;Write Status Register:0x02 53 return(cStatusByte); 54 } 55 56 57 void PLC_Transmit_Process(unsigned char* ptrData_Buffer) 58 { 59 unsigned char cStatusByte; 60 61 cStatusByte = PLC_Read_Reg(PLCAddrRDSR); //Read status register 62 if((cStatusByte&0x80) != 0x80) 63 { 64 return; 65 } 66 g_cStatusReg = cStatusByte;//**confirmed 67 switch(g_cTrans_Step) 68 { 69 case 0: 70 //Write Mode Cfg Reg, Code Length = 32, Data Rate = 200 bps; 71 PLC_Write_Reg(PLCAddrWRMR, 0x0D); //**0x0d changed to 0x0c;diff:carriar freq:76.5->57.6khz 72 PLC_Send_Frame(0xFF, 0xFF); //First 2 Byte:0xFF 0xFF 73 //Baud=1600bps + length(unit in words) 74 g_Pkg_Indication_Byte = (0x00 + g_cSend_Data_Length/2 + 2);//**why finially +2?? 75 g_cTrans_Step = 1; 76 break; 77 case 1: 78 //Initial CRC Bit;Write Status Register:0x02 79 PLC_Write_Reg(PLCAddrWRSR,(g_cStatusReg & 0xFD)); 80 //Send Header Byte:0x1a & Packet Indication Byte 81 PLC_Send_Frame(0x1A, g_Pkg_Indication_Byte); 82 g_cTrans_Step = 2; 83 break; 84 case 2: 85 //Write mode configuration; 86 PLC_Write_Reg(PLCAddrWRMR,0x01);//0b0000 00--1600/1920bps 01--76.8khz**00 57.6k 87 //Send 0x1f,0xff as MiarTech's PLC AMR Applications 88 PLC_Send_Frame(0x1F,0xFF);//**the word?? 89 g_cTrans_Step = 3; 90 g_cSend_Byte_Cnt = 0; 91 break; 92 case 3://Send Data(Unit in Word:16 Bytes) 93 if(g_cSend_Byte_Cnt >= (g_cSend_Data_Length - 2)) 94 { 95 g_cTrans_Step = 4; 96 } 97 PLC_Send_Frame(*ptrData_Buffer,*(ptrData_Buffer + 1)); 98 g_cSend_Byte_Cnt = g_cSend_Byte_Cnt + 2;//point to the next word 99 delay_us(80);//delay 50us and read crc 100 g_CRC_H = PLC_Read_Reg(PLCAddrRD_CRC_H); 101 g_CRC_L = PLC_Read_Reg(PLCAddrRD_CRC_L); 102 break; 103 case 4://Send CRC Code:16 Bytes 104 PLC_Send_Frame(g_CRC_H, g_CRC_L); 105 g_cTrans_Step = 5; 106 break; 107 case 5://transmit finished 0x81 108 PLC_Write_Reg(PLCAddrWRMR, 0x81); //Write mode configuration, 109 g_cRecByte_H = 0; 110 g_cRecByte_L = 0; 111 g_cRecv_Step = 0x00; 112 PlcRunMode = PLCRX; 113 UartRunMode = IDLE; 114 break; 115 default: 116 break; 117 } 118 } 119 120 121 void PLC_Receive_Process(unsigned char* ptrData_Buffer) 122 { 123 unsigned char cStatusByte; 124 unsigned char CRC_Correct_Flag; 125 // unsigned char temp,i; 126 // static unsigned short cnt; 127 128 129 if(g_cRecv_Step == 0x10)//Receive Process Initialization OK 130 { 131 g_cRecModCfgReg = PLC_Read_Reg(PLCAddrRDRR); //Read Receiving Mode Configuration Register(0x83) 132 cStatusByte = PLC_Read_Reg(PLCAddrRDSR); 133 if(g_cRecModCfgReg != 0x00) //Have Received Spread Spectrum&Packet Length 134 { 135 PLC_Write_Reg(PLCAddrWRRR,0x00); //Clear Receiving Mode Configuration Byte 136 g_cPkg_Length = (0x3f & g_cRecModCfgReg); //Packet Length = g_cRecModCfgReg[5:0] 137 g_cRecv_Step = 0x01; 138 PLC_Word_Rec_Overtime = 0; 139 } 140 if(((cStatusByte & 0x30) != 0x30)||(PLC_Word_Rec_Overtime > 500)) //Receive Overtime >=1 Second 141 { 142 CRC_Correct_Flag = PLC_Clear_EPF(); 143 g_cRecv_Step = 0x00; 144 return; 145 } 146 } 147 else if(g_cRecv_Step == 0x00) 148 { //0x81 149 PLC_Write_Reg(PLCAddrWRMR, 0x81);//bit[0]--bit[3] 00--1600/1920bps 01--76.8khz 150 cStatusByte = PLC_Read_Reg(PLCAddrRDSR); 151 g_cStatusReg = cStatusByte; 152 if((g_cStatusReg & 0x20 ) == 0x20)//Read Carrier Detected Flag 153 { 154 if((g_cStatusReg & 0x10) == 0x10)//Read Frame Indicate Flag 155 { 156 //Clear Receiving Mode Configuration Byte 157 //PLC_Write_Reg(PLCAddrWRRR, 0x00);//datasheet?? 158 g_bRecv_Pkg_Flag = 0;//*(*? 159 g_cRecv_Step = 0x10; 160 PLC_Word_Rec_Overtime = 0; 161 } 162 } 163 } 164 else 165 { 166 cStatusByte = PLC_Read_Reg(PLCAddrRDSR); 167 g_cStatusReg = cStatusByte; 168 169 //Carrier Detected & Frame Indicate Flag is not Correct 170 if(((cStatusByte & 0x30) != 0x30)||(PLC_Word_Rec_Overtime > 500)) 171 { 172 g_cRecv_Step = 0x00; 173 CRC_Correct_Flag = PLC_Clear_EPF(); 174 return; 175 } 176 else 177 { 178 if((cStatusByte & 0x40) == 0x40)//Read Received Interrupt Flag.RI = 1:Received OK 179 { 180 PLC_Word_Rec_Overtime = 0; 181 // if(cnt == 0) 182 { 183 PLC_Write_Reg(PLCAddrWRSR,((g_cStatusReg & 0xBF)|0x02)); //Clear RI Flag & Set MI200_CRC 184 } 185 switch( g_cRecv_Step ) 186 { 187 case 0x01: //Read 0x1f,0xff as MiarTech's PLC AMR Applications 188 { 189 // cnt ++; 190 // if(cnt > 20) 191 // { 192 // cnt = 0; 193 // g_cRecv_Step = 0x00; 194 // return; 195 // } 196 // temp = PLC_Read_Reg(PLCAddrRDSR); 197 // if((temp&0x70) != 0x70) 198 // return; 199 // cnt = 0; 200 // 201 PLC_RD_Recv_Word(); 202 if((g_cRecByte_H == 0x1F) && (g_cRecByte_L == 0xFF)) 203 { 204 g_cRecv_Step = 0x02; 205 g_cRecv_Byte_Cnt = 0; 206 } 207 else 208 { 209 g_cRecv_Step = 0x00; 210 CRC_Correct_Flag = PLC_Clear_EPF(); 211 return; 212 } 213 } 214 break; 215 case 0x02: //read user data 216 { 217 // if(cnt == 0) 218 // { 219 // PLC_Write_Reg(PLCAddrWRSR,((g_cStatusReg & 0xBF )|0x02)); //Clear RI Flag & Set MI200_CRC 220 // } 221 // cnt ++; 222 // if(cnt > 20) 223 // { 224 // cnt = 0; 225 // g_cRecv_Step = 0x00; 226 // return; 227 // } 228 // temp = PLC_Read_Reg(PLCAddrRDSR); 229 // if((temp&0x70) != 0x70) 230 // return; 231 // cnt = 0; 232 233 if(g_cRecv_Byte_Cnt == (g_cPkg_Length - 3)) //1 for amr;1 for crc 234 { 235 g_cRecv_Step = 0x03; 236 } 237 PLC_RD_Recv_Word(); 238 239 *(ptrData_Buffer + g_cRecv_Byte_Cnt) = g_cRecByte_H; 240 *(ptrData_Buffer + g_cRecv_Byte_Cnt + 1) = g_cRecByte_L; 241 242 g_cRecv_Byte_Cnt++ ; 243 } 244 break; 245 case 0x03: //讀取CRC數據 246 // cnt ++; 247 // if(cnt > 20) 248 // { 249 // cnt = 0; 250 // g_cRecv_Step = 0x00; 251 // return; 252 // } 253 // temp = PLC_Read_Reg(PLCAddrRDSR); 254 // if((temp&0x70) != 0x70) 255 // return; 256 // cnt = 0; 257 258 PLC_RD_Recv_Word(); 259 CRC_Correct_Flag = PLC_Clear_EPF(); 260 g_bRecv_Pkg_Flag = 1; 261 if ((CRC_Correct_Flag & 0x02) != 0x00) //CRC Flag Bit = 1;CRC is Correct 262 { 263 //串口發送 264 UartRunMode = TX; 265 unsigned char txlen; 266 txlen = (g_cPkg_Length-2)*2; 267 UsatrTxSub(g_Recv_Buf,txlen); 268 UartRunMode = IDLE; 269 } 270 g_cRecv_Step = 0x04; 271 break; 272 default: 273 break; 274 } 275 } 276 } 277 } 278 } 279 280 281 /******************************************************************************* 282 ** End Of File 283 *******************************************************************************/
主要修改的就是,這個文件了。后面有什么進展還會更新!
10/14日更新!
期間參照它的工程做了修改,重畫原理圖pcb,然后做手工板。
做了兩塊,對齊的一般但是能用,只是兩塊板硬件調試都花了很長時間。
第一塊是花原理圖的時候中間有個電容連線錯了,參照成品一個原件一個原件對,找了很久。由於畫圖的時候,他在原理圖邊上,沒注意它。
第二塊是焊接一個電容,它可能被我燙壞了,造成mi200e經常開機過不了自檢,也是圖省事全部原件基本都是直接拆的成品上的,最后還是電容一個一個換下來才找到問題。
這里吸取教訓,小電容再也不用拆機的!
上圖:
實物:
top layer:(其實這面畫的是bottom layer)
做出來有兩個缺陷,一是該也不該用核心板,該是說方便更換,不該就是焊接很難受,布線也不好看,還變大了,不然可以小不少。
二就是oled,原來考慮是top layer就做最終頂層的,但是尋思直插放另一面合適,最終就把bottom當了頂層。這就導致oled必須換個方向插,
進而就得讓它支出來。
目前串口透傳OK!距離尚未測試。
按鍵掃描OK!
OLED顯示OK!
DS18b20(暫定傳感器)程序寫了,尚未測試,拿出以前的18b20插的時候引腳斷了,因為生銹了。233
剩下的就是小結構以及模擬一個時鍾
更新:2018年11月13日14:05:17
課設快結束了,器件程序調試了好幾次,最終基本實現了功能。
調試時遇到主要BUG:
發送的數據不能是奇數字節,不然無法正常通信->改為偶數之后正常
原B板存在MI200E初始化失敗情況,反復初始化之后一旦正確就一直正確-> 嘗試過原件替換,無果。重新做了一塊板,問題解決!
限於mcu的flash只有8k,導致程序寫不下了,所以功能做了調整。
最終(暫定)功能:
A端:獨立顯示時間,讀取18b20溫度通過電力線發給B
B端:獨立顯示時間,通過電力線讀取數據並顯示溫度,可以更改時間,可以校准A的時間。
尚有未完善的問題:如何用定時器精確微秒級延時供18b20使用
網上參考了很多方案,自己也調試了許多,效果都不理想。
最終使用原子的匯編延時,較准確。
這個問題留待后期解決。
由於沒有銅柱,我簡單打印了一個外殼(圖里沒有體現)。2333