8051 W77E516 Dual Uart 應用問題 |
缺席
|
typenew
一般會員 發表:8 回覆:17 積分:5 註冊:2004-03-26 發送簡訊給我 |
各位前輩好,小弟最近使用Winbond W77E516的雙UART做應用。 目前整個系統架構如下: A. PC = 傳送資料用,使用VC win32 SDK來寫一簡單AP。 B. Winbond W77E516 = 傳輸的中繼站,當PC透過UART傳一Byte 給予W77E516,W77E516再從另一UART給予另一顆8051。 C. 8051 base MCU only one uart ( Crystal = 11.0592 BaudRate = 19200 ) ------------------------- --------------------------------------- ------------------------- | | ---------------> | | ---------------> | | | PC | <--------------- |UART0 W77E516 UART1 | <--------------- | 8051 | | | UART | | UART | | ------------------------- --------------------------------------- ------------------------- 所以W77E516的角色,就有點像延長線,只是把A與C的資料做By pass而已,問題就來了,當A送資料過去,C要回傳ACK回來,會有資料不正確的情況發生。如果把W77E516拿掉,也就是PC端跟8051直接連接,就都沒有問題。惟獨把W77E516加上就會發生問題。 以下是小弟所寫的Code,請參閱。謝謝。 Main.c [code cpp] #include #include "def.h" #include "mpu.h" //#include "W77E516.h" BYTE data _data0; BYTE data _data1; //=================================================================== // F: UART_WriteData() //=================================================================== extern void UART_WriteDataToSerial1(BYTE Data); extern void UART_WriteDataToSerial0(BYTE Data); extern void InitUART(void); extern void DelayX1ms(unsigned int count); extern void DelayX10ms(unsigned int count); //============================== // // ISP_Trigger() //============================== void ISP_Trigger() { T_P2_6 = 0; T_P2_7 = 0; DelayX10ms(6); Reset = 1; DelayX10ms(16); Reset = 0; T_P2_6 = 0; T_P2_7 = 0; DelayX10ms(16); T_P2_6 = 1; T_P2_7 = 1; } void InitVar() { Reset = 0; } void main(void) { InitVar(); InitUART(); ISP_Trigger(); while(1); } #if 1 ////////////////////////////////////// // UART Interrupt /////////////////////////////////////// //=================================================================== // F: UART_S() //=================================================================== void UART_S0(void) interrupt 4 { EA = 0; // disable all interrupt if (_testbit_(TI) == 0) // check if translate command { _data0 = SBUF; // recieve UAR RI = 0; // clear UART recieve interrupt SBUF1 = _data0; while (TI_1 == 0); TI_1 = 0; } // if TI EA = 1; // release EA bit } ////////////////////////////////////// // UART Interrupt /////////////////////////////////////// //=================================================================== // F: UART_S() //=================================================================== void UART_S1(void) interrupt 7 { EA = 0; // disable all interrupt if (_testbit_(TI_1) == 0) // check if translate command { _data1 = SBUF1; // recieve UAR RI_1 = 0; // clear UART recieve interrupt SBUF = _data1; while (TI == 0); TI = 0; } // if TI EA = 1; // release EA bit } [/code] |
阿信
版主 發表:111 回覆:983 積分:813 註冊:2005-03-10 發送簡訊給我 |
|
wjhsu
初階會員 發表:9 回覆:32 積分:48 註冊:2004-06-13 發送簡訊給我 |
你應該是用Keil吧?
_testbit_()的用法是使用8051原始的JBC指令, 去測試位元, 如果為1, 就先清除它, 然後再跳到指定的地方執行, 所以你要不要試試下面的方式.... p.s. 我沒有用過Wxxx的8051, 所以假設第二組的UART行為和標準的UART一樣, [code cpp] //=================================================================== // F: UART_S() //=================================================================== void UART_S0(void) interrupt 4 { if (_testbit_(RI)) //如果是接收中斷, 先清除RI旗標 SBUF1 = SBUF; else //傳送中斷, 清除TI旗標 TI = 0; } ////////////////////////////////////// // UART Interrupt /////////////////////////////////////// //=================================================================== // F: UART_S() //=================================================================== void UART_S1(void) interrupt 7 { if (_testbit_(RI_1)) //如果是接收中斷, 先清除RI_1旗標 SBUF = SBUF1; else //傳送中斷, 清除TI_1旗標 TI_1 = 0; } [/code] |
typenew
一般會員 發表:8 回覆:17 積分:5 註冊:2004-03-26 發送簡訊給我 |
感謝 阿信大的回覆,關於轉換器,是否有可以介紹的呢?
關於並聯的事,之前有想過利用Jump的方式來做切換,馬上就被上頭打槍了,要用Dual Uart也是上頭決定,小弟也只能乖乖的聽話Coding了。 小弟在補充一下PC的AP寫法。 假設是用"abcd" 字串 當PC收到"abcd"字串會馬上送出一樣"abcd"字串給予Target,使用此方式做HandShake,傳送方式如下,但是這樣傳送方式會有問題。 [code cpp] WriteComData("abcd",4); //====================================== // WriteComData() //====================================== void WriteComData(PCHAR Str,UINT Len) { DWORD WriteLen; static OVERLAPPED o; PurgeComm(hCom,PURGE_TXCLEAR); // clear input buffer WriteFile(hCom,Str,Len,&WriteLen,&o); // WriteLen can't be NULL in WIN98 while (!HasOverlappedIoCompleted(&o)) Sleep(0); if (!Duplex) // 半雙工 ReadComData(Str,Len); }[/code] 如果將WriteComData("abcd",4); 修改成如下: [code cpp] WriteComData("a",1); Sleep(1); WriteComData("b",1); Sleep(1); WriteComData("d",1); Sleep(1); WriteComData("c",1); [/code] 就可以了,目前只能猜測是因為PC送出的中斷太快導致Winxxxx那顆來不及處理,但是這樣的方法,如果之後要傳送的資料是幾萬Byte那每一Byte都要加這樣的Delay會讓整個系統變很慢。 所以今天小弟又修改Firmware code,利用一塊Buffer先把資料都接收完,再把資料從另一個Uart送出,殘念,一樣不行。下面就是修改過後的Firmware。 請參閱,謝謝。 [code cpp] void UART_S1(void) interrupt 7 { EA = 0; // disable all interrupt if (_testbit_(TI_1) == 0) // check if translate command { _data[index] = SBUF1; index ; if(index == 4) mode = 1; RI_1 = 0; // clear UART recieve interrupt } // if TI EA = 1; // release EA bit } void main(void) { InitVar(); InitUART(); ISP_Trigger(); while(1) { if(mode) { EA = 0; while(index) { SBUF = _data[4-index]; while (TI == 0); TI = 0; index--; } EA = 1; mode = 0; } } } [/code] ===================引 用 阿信 文 章=================== 程式看起來,好像沒什麼問題。 不過你說會發生問題是什麼樣的問題,狀況呢? 如果是要做延長的功能,我想使用一些專用的轉換器會比較適合。 如果是要抓取PC與8051通訊的資料,可以用並聯,兩條都拉到RX。 如果是要修改傳輸的資料,那就要用示波器看了, 看你接收到的資料與發射的資料是否相同。 也有可能是延遲的問題。 |
阿信
版主 發表:111 回覆:983 積分:813 註冊:2005-03-10 發送簡訊給我 |
|
typenew
一般會員 發表:8 回覆:17 積分:5 註冊:2004-03-26 發送簡訊給我 |
不好意思最近因為都再作相關的實驗,沒注意到已經有前輩回復了,關於Delay的問題,小弟前幾天有作一個實驗就是,接收時,是接收到AP所要傳送的數Byte之後再作傳送的動作,舉例:如果AP是要一次傳送4byte給予Firmware,那再Firmware中就是接收到4 byte之後再送出去給Target端;此時發現AP如果不加Delay會接收不完整的資料。
經過這幾天的實驗,小弟認為是因為Target端的Firmware code在搞怪,因為Target端是一直透過Uart1在送handshake字串給予Wxxxx那顆,所以Uart1收到資料會馬上關掉所有中斷,那如果剛剛好AP透過Uart 0要送資料過來,但是剛好Uart1 在動作,所以有可能被檔掉,這需要再作進一步的實驗才可得知。 因為Schedule壓力下,所以小弟只好先把可以動的code作整合,以應付上頭的要求。如果有進一步的實驗結果小弟會在上來分享心得。 關於wjhsu大的程式,其實之前就有試過了,是不能動的,小弟有一個懷疑,是那段code邏輯上有問題。當有資料傳送過來給Firmware的確會進入interrupt routine中,只是單純把RI清掉,並沒有把資料搬出來,這是小弟利用keil c 模擬的結果。 如果以上小弟的看法有任何問題,請各位前輩不吝指教。謝謝。 ===================引 用 阿信 文 章=================== 問題點應該還是在Delay, 就是在接收跟發射之間程式不能等太久, 也就是不能用while (TI_1 == 0);讓程式空等, 要在下一筆資料接收到前完成發射。 你用wjhsu大大的程式試試看吧! |
wjhsu
初階會員 發表:9 回覆:32 積分:48 註冊:2004-06-13 發送簡訊給我 |
你好,
if (_testbit_(RI)) SBUF1 = SBUF; -->完整地說, 應該是: 如果RI=1, 就清除它, 然後把 "SBUF的值讀入, 再複製給SBUF1", 所以應該是有把資料搬出來.... 剛看了一下你的附檔, 有些問題想提出一下: 1. 你有把INT0 Enable (IE = 0xD1), 但沒看到 INT0的中斷函式, 不知它會不會在過程中, 發生中斷? 2. 假設Baud Rate=9600, 系統頻率=11.059MHz, 4T的m.c. 就算PC"連續"送出字元, UART0每次中斷的間隔至少有約1.0417ms, 約2880個m.c, 看來你其它地方也沒做什麼事, 速度應該沒什麼問題, 不過, 在中斷裏應該儘早離開, 所以用while (TI == 0); 不是很好,.會阻擋其它的中斷 3. EA在進入主迴圈前設為1就好了, 應該不需在二個中斷函式裏Disable, 理由同上 4. 既然是handshake, 那Target應該是在收到資料後才回傳, 為什麼 "Target端是一直透過Uart1在送handshake字串給予Wxxxx那顆"?? 另外, 請問一下, 你有試過PC端不經過W77E516, 直接與Target通訊,可以正常的收發資料嗎?? |
阿信
版主 發表:111 回覆:983 積分:813 註冊:2005-03-10 發送簡訊給我 |
>關於wjhsu大的程式,其實之前就有試過了,是不能動的
怎麼樣的不能動? 有用示波器看波形、時序嗎? 中斷不能等發射完畢 發射時應該要確認前一筆已發完 下面的程式碼試看看, 旗標我用byte,可以改成bit, 另外buffer只有一個可能會有問題, 基本上如果要穩的話應該要有4個才對。 程式碼使用全形空白,要換成半形。 UART1的程式一樣。 [code cpp] BYTE data _fgTx0; BYTE data _fgTx0A; BYTE data _fgTx1; BYTE data _fgTx1A; void UART_S0(void) interrupt 4 { if (_testbit_(RI)) //接收中斷0 _data0 = SBUF; //存資料 if (_fgTx1==0) { //檢查TX1發射中 SBUF1=_data0; //不在發射中,直接發射 fgTx1=1; //設定發射中旗標 } else _fgTx1A=1; //發射中,設定等待旗標 if (_testbit_(TI)) //發射中斷0 _fgTx0=0; //清除發射中旗標 if (_fgTx0A) { //如果有資料等待中,發射資料 SBUF1=_data0; //發射資料 _fgTx0A=0; //清除等待旗標 _fgTx0=1; //設定發射中旗標 } } } [/code] |
typenew
一般會員 發表:8 回覆:17 積分:5 註冊:2004-03-26 發送簡訊給我 |
wjhsu 大你好,感謝大大的回覆。
1 . INT0 有Enable 此外部中斷,是加上一顆按紐,按下去會拉成LOW,形成Falling edge產生中斷。 2 . 其實小弟也是這樣想應該是沒問題的阿。 3. 目前小弟是將Uart1 的中斷函式中EA 有關的都Mark掉了,還是一樣不行,還沒試過將兩個都關掉,小弟會修改加以測試。 4. 應該是說Target 會一直送出4 byte字串透過Wxxx那顆傳給PC端,Target是ISP firmware,此ISP firmware是會一直變動Baud rate去Match PC端的Baudrate,其用意在於,如果客戶的板子( Target 端 ) 要Update firmware 但是他的Crystal是不固定的,那剛剛好客戶的MCU是焊死在板子上,依照以前的慣例是一定要知道客戶的Crystal才可以燒進入ISP firmware,但是在上述的情形是不可行的,那才會有現在進化的版本可以自動去調整Baud Rate的Firmware,才會有一直送出4 byte的handshake的資料給予Host端,直到Host端收到是真正正確的4 byte資料。 5. 關於不透過Wxxx那顆,直接用 PC連接,小弟有實驗過,是可行的,所以很納悶透過Wxxxx那顆Dual Uart應該是可行的。 不好意思 囉唆那麼多。希望小弟的表達有清楚。謝謝 ===================引 用 wjhsu 文 章=================== 你好, if (_testbit_(RI)) SBUF1 = SBUF; -->完整地說, 應該是: 如果RI=1, 就清除它, 然後把 "SBUF的值讀入, 再複製給SBUF1", 所以應該是有把資料搬出來.... 剛看了一下你的附檔, 有些問題想提出一下: 1. 你有把INT0 Enable (IE = 0xD1), 但沒看到 INT0的中斷函式, 不知它會不會在過程中, 發生中斷? 2. 假設Baud Rate=9600, 系統頻率=11.059MHz, 4T的m.c. 就算PC"連續"送出字元, UART0每次中斷的間隔至少有約1.0417ms, 約2880個m.c, 看來你其它地方也沒做什麼事, 速度應該沒什麼問題, 不過, 在中斷裏應該儘早離開, 所以用while (TI == 0); 不是很好,.會阻擋其它的中斷 3. EA在進入主迴圈前設為1就好了, 應該不需在二個中斷函式裏Disable, 理由同上 4. 既然是handshake, 那Target應該是在收到資料後才回傳, 為什麼 "Target端是一直透過Uart1在送handshake字串給予Wxxxx那顆"?? 另外, 請問一下, 你有試過PC端不經過W77E516, 直接與Target通訊,可以正常的收發資料嗎?? |
typenew
一般會員 發表:8 回覆:17 積分:5 註冊:2004-03-26 發送簡訊給我 |
感謝 阿信 大的回覆。
關於示波器,小弟是沒有拉出來看,真的不好意思。小弟會這樣推測不能動的原因是,將wjhsu 大的程式copy拿去compile並燒入MCU中,發現不能動,後來小弟在中斷函式中加入燈號顯示,就是將沒有用到的Port Pin ,麻煩硬體人員加上Led燈。 wjhsu大的code 範例加入燈號 [code cpp] void UART_S0(void) interrupt 4 { if (_testbit_(RI)) //如果是接收中斷, 先清除RI旗標 { SBUF1 = SBUF; P1_0 = 0; //燈號亮 } else //傳送中斷, 清除TI旗標 TI = 0; } [/code] 發現連燈都沒亮。那小弟利用Keil c 模擬來單步執行,才發現_testbit_(RI)的確會清掉RI不過,都不會為TRUE故不會進入執行SBUF1 = SBUF;搬資料的動作,改成下面這樣 就會亮,不過這樣跟以前寫的就一樣了,一樣的問題還是會出現。 [code cpp] if (_testbit_(TI)) //如果是傳送中斷, 先清除TI旗標 { SBUF1 = SBUF; RI = 0; P1_0 = 0; //燈號亮 } [/code] 不知道小弟這樣Debug方式是不是不足以證明,煩請 阿信大指教。謝謝。 關於 阿信大所提供的方式,小弟會再作進一步實驗,有任何消息,會再作進一步更新,謝謝。 ===================引 用 阿信 文 章=================== >關於wjhsu大的程式,其實之前就有試過了,是不能動的 怎麼樣的不能動? 有用示波器看波形、時序嗎? 中斷不能等發射完畢 發射時應該要確認前一筆已發完 下面的程式碼試看看, 旗標我用byte,可以改成bit, 另外buffer只有一個可能會有問題, 基本上如果要穩的話應該要有4個才對。 程式碼使用全形空白,要換成半形。 UART1的程式一樣。 [code cpp] BYTE data _fgTx0; BYTE data _fgTx0A; BYTE data _fgTx1; BYTE data _fgTx1A; void UART_S0(void) interrupt 4 { if (_testbit_(RI)) //接收中斷0 _data0 = SBUF; //存資料 if (_fgTx1==0) { //檢查TX1發射中 SBUF1=_data0; //不在發射中,直接發射 fgTx1=1; //設定發射中旗標 } else _fgTx1A=1; //發射中,設定等待旗標 if (_testbit_(TI)) //發射中斷0 _fgTx0=0; //清除發射中旗標 if (_fgTx0A) { //如果有資料等待中,發射資料 SBUF1=_data0; //發射資料 _fgTx0A=0; //清除等待旗標 _fgTx0=1; //設定發射中旗標 } } } [/code] |
wjhsu
初階會員 發表:9 回覆:32 積分:48 註冊:2004-06-13 發送簡訊給我 |
|
typenew
一般會員 發表:8 回覆:17 積分:5 註冊:2004-03-26 發送簡訊給我 |
wjhsu 前輩你好,這陣子才忙完,才有空上來回覆實驗結果,小弟有下載sample code做實驗,發現還是不行。
後來,小弟利用其他方式來解,發現小弟想的方法可行,也許方法不好,請見諒。 所以現在上來將小弟所寫的source code 分享一下。 [code cpp] //global var. char data OnLineBuffer[16] ; BYTE data front; BYTE data rear; // F: UART_WriteData() //=================================================================== void UART_WriteData(BYTE Data) { SBUF = Data; while (TI == 0); TI = 0; } //=================================================================== // F: UART_ReadData1() //=================================================================== BYTE UART_ReadData1(void) { while (RI_1 == 0); RI_1 = 0; return SBUF1; } //=================================================================== // // F: InitUART() //=================================================================== void InitUART(void) { IE = 0x91; SCON = 0x50; // SCON: mode 1, 8-bit UART, enable rcvr SCON1 = 0x50; TMOD = 0x20; TH1 = 0xFC; //Baud Rate : 28800 Hz Crystal : 22.1184MHz TL1 = 0xFD; PCON = PCON | 0x80; WDCON = WDCON | 0x80; TCON = 5; TR1 = 1; // TR1: timer 1 run ET0 = 0; } void main(void) { /*----------------Init UART ------------------*/ InitUART(); while(1) { UART_WriteData(UART_ReadData1()); } }[/code] Uart0 Interrupt Subroutine [code cpp] //=================================================================== // F: UART_S() //=================================================================== void UART_S(void) interrupt 4 { BYTE temp; // loop index if (_testbit_(TI) == 0) // check if translate command { rear = (rear 1) % MAXSIZE; OnLineBuffer[rear] = SBUF; // recieve UART RI = 0; // clear UART recieve interrupt front = (front 1) % MAXSIZE; UART_WriteData1(OnLineBuffer[front]); } // if TI }[/code] 小弟解釋一下,此顆8052會有雙Uart,之前所寫的code是用兩個Uart的中斷來接收,發現會有Data不正確的問題,現在上面的code就是改為Uart0的中斷有開啟,Uart1 的中斷關掉,Uart1改用Polling的方式來接收Target端的資料 ( 註: Target 端 = 待燒IC Target端只會回傳三四Byte的Handshake資料 ),另外利用一個Circular queue來Buffer Data,這樣修改之後發現就可以把之前的問題解決都不需要像之前一樣當要傳送大量連續資料(例如一次256Byte)要切成每一個Byte然後每一個Byte之間要加Delay。 ===================引 用 wjhsu 文 章=================== 我有一個附檔放在下面文章中, 如果你有空的話, 看要不要看一下... 要先確認, 1. ConnectToTarget()的程序是否符合你說的, Target自動調整BaudRate的動作 2. 巨集常數N 的值, 要與PC每次傳送 與 等待回應的資料長度一樣,現假設為4個Byte http://delphi.ktop.com.tw/board.php?cid=31&fid=130&tid=95337 |
helper197
一般會員 發表:8 回覆:10 積分:3 註冊:2008-08-20 發送簡訊給我 |
大大您好 想跟您請問一下 , 我已經實做出kerl C的軟體環境模擬與測試 在 Port 1(來源方) 也在硬體透過 Max232 實做出來了 但是 Port 2(PC 端) 怎麼都通不了 = =a 希望您指點一下 1. Port 1 我發現他需要把 INT0 (P3.2) 至能 Port 1 才會順利工作 = =a 我也不知道餵啥 2. W77E516 -> Max232 -> PC(RS232) 兩個 (分別使用 Max232 的 兩組 TxRx) 結線方式都跟 Port 1一模一樣 還有對調過來源方的設備 都很正常通訊 麻煩您囉 感謝 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |