轉載至:http://blog.chinaunix.net/uid-20788517-id-3045170.html
在看芯片pdf文檔的時候總是容易被迷糊,總結一下,通過看時序圖瞭解到底是上升沿還是下降沿讀寫數據!
首先必須明白的幾個術語:
1. Read和Write:Read和Write均是指MCU的讀和寫。
2. Output和Input:在芯片官方文檔中大多會有input和ouput介紹,顯然是指器件的輸入和輸出。這裏和上面的Read與write相對應。對應關係是:
這是很顯然的對應關係,但是很不幸,由於沒有經過思考,一直以來我均誤以爲
輸入=讀,輸出=寫。這是完全沒有考慮到對象的因素,輸入(指器件的輸入)<==>寫(MCU的寫操作),輸出(指器件的輸出)<==>讀(MCU的讀操作)。
在芯片的pdf資料中,所給出的時序操作圖一般都是MCU來操作芯片的時序。
1) 所謂讀即是指MCU從器件的數據總線上根據一定的時序來讀取器件的數據。一般而言,MCU提供一個邊沿信號(上升沿或者下降沿均可)告訴器件可以發數據了,器件檢測到邊沿信號以後,立即在數據總線上更新數據,待數據穩定以後,MCU即可讀取數據。所以一般所說的上升沿(下降沿)開始讀數據是不準確地說法,上升沿(下降沿)這是數據總線上的數據發生改變,MCU並沒有在此時刻讀取數據,而是等待數據穩定之後纔開始讀取數據。
以DS1302的單字節讀時序爲例說明,要讀取DS1302數據,先必須寫1byte數據到DS1302,即是指(R/W,A0~A4,R/C,1這8位數據),然後再讀。所以我們應該看後半部分來解讀數據的read操作。
顯然在時鐘信號的下降沿數據總線上的數據發生改變,等待數據穩定之後,MCU將讀取該數據D0,接着MCU產生下一個下降沿,器件檢測到下降沿信號立即更新數據D1,等待數據穩定之後被MCU讀取。後面相同。
2)所謂寫即是指MCU向器件寫入數據,其操作是:先將數據放置在數據總線上,等待其穩定之後,MCU產生一個邊沿信號,將數據寫入器件。
以DS1302的單字節寫時序爲例說明,要向DS1302寫數據,,先必須寫1byte數據到DS1302,即是指(R/W,A0~A4,R/C,1這8位數據),然後再寫。所以上圖的16個脈衝下的操作均是寫操作,可以從第一位(R/W)分析起,當然也可以向讀操作一樣,只分析後半部分的操作。
寫操作必須先將數據準備在數據總線上,等待數據穩定之後,MCU產生一個邊沿信號,寫入數據到器件。從圖中可以看出,在起始狀態,數據總線上準備數據,穩定後遇到上升沿MCU將數據寫入到器件。寫完之後,數據總線上出現第二位數據A0,等待其穩定之後,MCU產生一個上升沿將A0寫入器件。
OK,總結完畢,可以簡單理解爲“寫穩讀變”。MCU在數據總線上的數據穩定之後,檢測邊沿信號寫數據到器件;MCU發出邊沿信號告訴器件發送數據,檢測到邊沿信號之後,器件改變(更新)數據,等待穩定之後MCU讀取數據。
對照上面的時序圖寫驅動函數:
- /*
- ** 函 數:single_byte_read
- ** 參 數: unsigned char commd--讀之前必須寫入的命令
- ** 返回值: unsigned char tempbyte--讀取的1byte數據
- ** 說 明: 這只是一個例子函數,對應上面的時序圖所寫的完整的讀1字節數據函數
- */
- unsigned char single_byte_read(unsigned char commd)
- {
- int i;
- unsigned char tempbit;
- unsigned char tempbyte;
- /* 初始化*/
- CE = 0;
- SCLK_OFF;
- /* 寫1byte 數據(R/W,addr,R/C,1):讀的地址命令*/
- /* 數據總線上先準備好數據,上升沿寫入數據到器件*/
- for(i=0;i<8;i++)
- {
- if(commd & 0x01)
- DataIO = 1; //數據總線上準備數據1
- else
- DataIO = 0; //數據總線上準備數據0
- commd=commd>>1;
- SCLK_ON; //上升沿來臨,MCU將數據寫入器件
- _NOP();
- SCLK_OFF; //再次拉低,爲下一個數據提供上升沿條件
- }
- /*寫完命令之後, 從器件讀1byte數據*/
- /*下降沿通知器件更新數據,等待其穩定之後讀取數據*/
- for(i=0;i<8;i++)
- {
- if(DataIO) //緊接上面寫命令的最後一個信號是下降沿信號,故此時第一位數據即是器件更新數據
- tempbit = 0x80;
- else
- tempbit = 0;
- tempbyte = tempbyte >> 1 | tempbit;
- SCLK_ON; //上升沿,爲下降沿提供條件
- _NOP();
- SCLK_OFF; //下降沿來臨,通知器件更新數據,在下一個循環中MCU讀取更新的數據.
- }
- return tempbyte;
- }
- /*
- ** 函 數:single_byte_write
- ** 參 數: unsigned char commd--寫數據之前必須先寫命令
- ** unsigned char data--寫的1byte數據
- ** 返回值: none
- ** 說 明: 這只是一個例子函數,對應上面的時序圖所寫的完整的寫1字節數據函數
- */
- void single_byte_write(unsigned char commd,unsigned char data)
- {
- int i;
-
- /* 初始化*/
- CE = 0;
- SCLK_OFF;
- /* 寫1byte 數據(R/W,addr,R/C,1):讀的地址命令*/
- /* 數據總線上先準備好數據,等待其數據穩定之後,MCU產生一個上升沿寫入命令到器件*/
- for(i=0;i<8;i++)
- {
- if(commd & 0x01)
- DataIO = 1; //數據總線上準備數據1
- else
- DataIO = 0; //數據總線上準備數據0
- commd=commd>>1;
- SCLK_ON; //上升沿來臨,MCU將數據寫入器件
- _NOP();
- SCLK_OFF; //再次拉低,爲下一個數據提供上升沿條件
- }
- /*寫完1byte命令之後, 再寫1byte數據*/
- /*與寫命令是一樣的,數據總線上先準備好數據,等待其數據穩定之後,MCU產生一個上升沿信號將數據寫入*/
- for(i=0;i<8;i++)
- {
- if(data & 0x01)
- DataIO = 1; //數據總線上準備數據1
- else
- DataIO = 0; //數據總線上準備數據0
- data=data>>1;
- SCLK_ON; //上升沿來臨,MCU將數據寫入器件
- _NOP();
- SCLK_OFF; //再次拉低,爲下一個數據提供上升沿條件
- }
- }