学会阅读硬件的原理图、数据手册大全
參考: 郭天祥:https://www.bilibili.com/video/BV1DW411a7mz?p=8
韋東山:https://www.bilibili.com/video/BV1ga4y1Y7PL?p=4
https://www.bilibili.com/video/BV17g411F7oR?spm_id_from=333.999.0.0
洋桃電子:https://www.bilibili.com/video/BV1eW411J7cf?p=2&spm_id_from=pageDriver
目錄
- 硬件接口的四大類
- 1. GPIO和門電路
- 2. 協議類
- 3. 類似內存的接口(ram-like)
- 4. 模擬電路
- GPIO與門電路
- 1. GPIO的應用
- 2. GPIO引腳操作
- 2.1 設置引腳為GPIO功能
- 2.2 設置引腳方向
- 2.3 設置/讀取引腳數值
- 3. 二極管
- 4. 三極管
- 4.1 NPN三極管
- 4.2 PNP三極管
- LED電路與操作
- 1. LED實物
- 2. LED電路
- 同步與異步
- 1. 概念
- 1.1 同步信號示例
- 1.2 異步信號示例
- 2. 差別
- 使用一線傳輸雙向數據
- 1. 面臨的問題
- 2. 解決方法
- 3. 雙向傳輸示例
- 如何高效閱讀英文數據手冊?
- 類似內存的接口(2440開發板為例)
- SDRAM
- NOR FLASH
- 網卡
- 不同位寬外設的接線
- 時序的閱讀及內存控制器的設置
- 1602液晶驅動顯示
- 閱讀手冊
- LCD1602.h
- LCD1602.c
- IIC總線AT24C02芯片實驗(E2PROM)
- IIC總線協議
- 24C02芯片手冊閱讀
- 編寫代碼
硬件接口的四大類
參考書籍:
- 《微機原理》:側重于計算機結構
- 《數字電子技術基礎 》:側重于門電路
1. GPIO和門電路
GPIO:general peripheral input/ouput,通用的外設輸入、輸出接口。
這類電路通常只使用一個引腳:
- 可以設置為輸出
- 可以輸出高、低電平
- 比如用來控制LED
- 也可以設置為輸入
- 可以讀取引腳電平,判斷當前是高電平還是低電平
- 比如用來判斷按鍵是否被按下
- 可以接上各類晶體管(二極管、三極管等)實現邏輯運算
門電路:與門、或門、非門
2. 協議類
比如:UART、I2C、SPI、Nand、TFT LCD。
如果兩個設備之間要傳輸的數據比較復雜,可以約定一些規則。這類接口被稱為"協議類"接口。
當然可以只使用一條GPIO引腳來傳輸復雜的數據,比如紅外遙控器、溫度傳感器等。也可使用多條線路來傳輸數據,比如UART、I2C、SPI等。比如TFT LCD的接口線將近30條。
例子:
-
I2C接口
- 硬件連接
- I2C協議
3. 類似內存的接口(ram-like)
比如:Nor Flash、SDRAM、DDR、網卡DM9000等。
- 內存:可以讀寫某個地址上的數據,所以必定有這些信號
- 地址總線
- 數據總線
- 讀/寫信號
- 片選(cs):ram-like接口上可以接多個設備,互相之間不能干擾,選中哪個設備哪個設備才能響應
- 很多設備也采用類似內存的接口,比如Nor Flash、8080接口的LCD
- 例子
4. 模擬電路
數字電路上傳輸的電壓值只有2類取值,比如
- 2.xV到3.3V,抽象為邏輯值1
- 0V到1.xV,抽象為邏輯值0
模擬電路上傳輸的電壓可以是各種各樣的,比如以下兩個電路:
- ADC電路中:可以讀取滑動電阻器上的觸點電壓值
- DAC電路中:可以輸出不同的電壓值,用來控制LED的亮度(數字電路里LED只有亮、滅兩個狀態)
讀取滑動電阻器上的觸點電壓值
- DAC電路中:可以輸出不同的電壓值,用來控制LED的亮度(數字電路里LED只有亮、滅兩個狀態)
GPIO與門電路
1. GPIO的應用
GPIO可以設置為輸出、輸入:
-
輸出功能
-
LED
-
發射紅外信號
-
控制電機
-
蜂鳴器
-
數碼管
-
-
輸入功能
- 按鍵
- 接收紅外信號
- 人體感應
-
實現各類協議
- 讀取溫濕度傳感器數據
- 其實UART等也是使用GPIO來實現的
2. GPIO引腳操作
怎么用一個GPIO來控制LED?換句話說,怎么讓一個GPIO輸出高、低電平?
2.1 設置引腳為GPIO功能
芯片內部有很多模塊,比如GPIO、UART(串口)。
一個引腳,可以接到模塊A,也可以接到模塊B,比如上圖中的引腳gpio0_0,可以接到GPIO group 0,也可以接到UART。
可以設置某些寄存器(比如io_mux),選擇引腳的功能。
2.2 設置引腳方向
假設一個引腳被設置成了GPIO功能,那么它是用作輸出,還是輸入?
在GPIO模塊內部,一般都有一個方向選擇寄存器,里面每一位用來控制一個引腳的方向。
比如GPIO group 0中有一個gpio0_dir_reg寄存器,
- 它的bit 0寫入1,表示gpio0_0被設置為輸出
- 它的bit 0寫入0,表示gpio0_0被設置為輸入
2.3 設置/讀取引腳數值
一個GPIO引腳被設置成輸出,那么怎樣設置它的輸出電平?
一個GPIO引腳被設置成輸入,那么怎樣讀取它的輸入電平?
在GPIO模塊內部,一般都有一個數據寄存器,里面每一位用來控制一個引腳的輸出電平。
比如GPIO group 0中有一個gpio0_data_reg寄存器,
- 寫數據
- 它的bit 0寫入1,表示gpio0_0輸出高電平
- 它的bit 0寫入0,表示gpio0_0輸出低電平
- 讀數據
- 如果bit 0等于1,表示gpio0_0為高電平
- 如果bit 0等于0,表示gpio0_0為低 電平
3. 二極管
參考資料:圖文詳解二極管原理
-
二極管的箭頭表示正向電流的方向
-
二極管的電流具有單向性
-
假設正極、負極之間的電壓為V
- 當V大于某個閾值(比如0.7V),二極管就導通,導通時電阻約等于0
- 當V<0,二極管不會導通,電阻無窮大
-
內部結構:由PN節組成,P代表正極(positive),N代表負極(negative)
-
二極管中流動的是電子,電流方向是從正極到負極,電子流動的方向是從負極到正極
-
使用二極管
- 比如:使用二極管防止電源接反是燒壞電路
4. 三極管
參考資料:三極管工作原理分析精辟透徹看后你就懂
可以使用二極管的特性制作成三極管,組成開關電路。
三極管實物圖:
三極管可以分為:NPN三極管、PNP三極管。
4.1 NPN三極管
- 擴散
- 物質會從濃度大的地方擴散到濃度低的地方
- 比如墨水滴入水中,墨水會四處散開
- 比如臭味會四處散開
- 電子也會有擴散作用
- 三極管原理
- 當be之間的PN節加上正向電壓,電子從e極的’N’大量往‘P’移動(所以e被稱為發射極)
- 電子在’P’大量聚集,一部分通過b極流走,另一部分通過c極擴散出去(c起收集作用,所以被稱為集電極)
- 電子流動方向如圖中紅色箭頭所示
- 電流方向與電子流動方向相反:be之間電流從b到e,ce之間電流從c到e
- 三極管的使用
- 當Vcon等于0.7V左右,be之間的PN節打通,c極相當于直接連接e,V2=0
- 當Vcon等于0V,be之間的PN節沒打通,c極相當于斷開,V2=V
- 所以,可以用Vcon來控制V2
4.2 PNP三極管
- 擴散
- 物質會從濃度大的地方擴散到濃度低的地方
- 比如墨水滴入水中,墨水會四處散開
- 比如臭味會四處散開
- 電子也會有擴散作用
- 三極管原理
- 當eb之間的PN節加上正向電壓,空穴從e極的’N’大量往‘P’移動(所以e被稱為發射極)
- 空穴在’P’大量聚集,一部分通過b極流走,另一部分通過c極擴散出去(c起收集作用,所以被稱為集電極)
- 空穴流動方向如圖中紅色箭頭所示
- 電流方向與空穴流動方向相同:eb之間電流從e到b,ec之間電流從e到c
- 三極管的使用
- 當Vcon為高電壓(比如3.3V),eb之間的PN節打通,c極相當于直接連接e,V2=Vcon
- 當Vcon等于0V,eb之間的PN節沒打通,c極相當于斷開,V2=0
- 所以,可以用Vcon來控制V2
流從e到b,ec之間電流從e到c
- 三極管的使用
- 當Vcon為高電壓(比如3.3V),eb之間的PN節打通,c極相當于直接連接e,V2=Vcon
- 當Vcon等于0V,eb之間的PN節沒打通,c極相當于斷開,V2=0
- 所以,可以用Vcon來控制V2
LED電路與操作
1. LED實物
2. LED電路
- 方式1
- 芯片引腳輸出高電平,LED被點亮
- 芯片引腳輸出低電平,LED被熄滅
- 缺點:芯片引腳的驅動能力可能不夠,LED亮度低
- 方式2
- 芯片引腳輸出低電平,LED被點亮
- 芯片引腳輸出高電平,LED被熄滅
- 缺點:電流進入芯片過大時,可能燒毀芯片
- 方式3
- 芯片引腳輸出高電平,三極管導通,LED被點亮
- 芯片引腳輸出低電平,三極管不導通,LED被熄滅
- 方式4
- 芯片引腳輸出低電平,第一個三極管不導通,第二個三極管導通,LED被點亮
- 芯片引腳輸出高電平,第一個三極管導通,第二個三極管不導通,LED被熄滅
三極管導通,第二個三極管不導通,LED被熄滅
同步與異步
1. 概念
同步(synchronous)、異步(asynchronous),使用生活例子來說就是:
- 同步:朋友打電話說到我家吃飯,我在家里等他們
- 異步:朋友沒有提前打招呼,突然就到我家來了
1.1 同步信號示例
在電子產品中,使用同步信號進行傳輸時,一般涉及兩個信號:
- 時鐘信號:用來通知對方要讀取數據了
- 數據信號:用來傳輸數據
比如:
- 時鐘信號:打電話,起約定作用
- 數據信號:傳輸數據
1.2 異步信號示例
使用異步信號傳輸數據時,雙方遵守相同的約定:
-
起始信號:發送方可以通知接收方"注意了,我要開始傳輸數據了"
-
數據的表示
- 怎么表示邏輯1
- 怎么表示邏輯0
以紅外遙控器解碼器為例,它向單片機發出的數據格式如下:
-
起始信號:解碼器發出一個9ms的低電平、4.5ms的高電平,用來同時對方說"開始了"
-
表示一位數據
- 邏輯1:0.56ms的低電平+1.69ms的高電平
- 邏輯0:0.56ms的低電平+0.56ms的高電平
-
接收方、發送方都遵守這樣的約定,就可以使用一條線傳輸數據
2. 差別
| 信號線 | 多:時鐘信號、數據信號 | 少:只需要數據信號 |
| 速率 | 可變,提高時鐘信號頻率即可 | 雙方提前約定 |
| 抗干擾能力 | 強 | 弱 |
使用一線傳輸雙向數據
1. 面臨的問題
兩個設備之間,只使用一條數據線,能否傳輸雙向的數據?
- A發出高電平,B發出低電平
- 電路可能被損壞
- 電路上到底是高電平還是低電平?不能確定
- 問題在于:有兩個設備試圖同時驅動電路
2. 解決方法
不讓雙方同時驅動電路,或者即使同時驅動也沒關系:
- 不讓雙方同時驅動電路:雙方無法約定時間,此方法不可行
- 即使同時驅動也沒關系:可行,電路如下:
真值表如下:
| 0 | 0 | 1(由上拉電阻決定) |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 0 |
從真值表和電路圖我們可以知道:
- 當某一個芯片不想影響SDA線時,那就不驅動這個三極管
- 想讓DATA輸出高電平,雙方都不驅動三極管(SDA通過上拉電阻變為高電平)
- 想讓DATA輸出低電平,就驅動三極管
芯片內部的三極管,被稱為open collector,開集,也就是在芯片內部三極管的集電極是開放的。
芯片內部不驅動三極管是,集電極的電平由外面的上拉電阻決定。
這種電路實現了:
- 雙方設備即使同時想輸出不同的電平:
- 電路也不會被損壞
- 電平也是確定的
3. 雙向傳輸示例
-
初始狀態:一開始,雙方都不驅動三極管,DATA為高
-
起始信號和回應:A想傳輸數據給B,發出開始信號、得到回應信號
- A檢測DATA線,高表示對方沒有占用數據線
- A驅動三極管,使得DATA為低,用來通知B:我就要傳輸數據了
- A釋放三極管,DATA變為高
- B驅動三極管,使得DATA為低,用來通知A:好的,我準備好了(這是一個回應信號)
- B釋放三極管,DATA變為高
-
傳輸:A發送數據給B,比如傳輸2位數據0、1
- 雙方都使用同一套數據表示方法,比如使用60US來傳輸一位數據,數值由DATA電平決定
- 在第1個60us,A設置DATA為低;在同一時間,B讀取DATA電平得到數據0
- 在第2個60us,A設置DATA為高;在同一時間,B讀取DATA電平得到數據1
-
結束:A釋放三極管,DATA變為高電平
- 在第2個60us,A設置DATA為高;在同一時間,B讀取DATA電平得到數據1
-
結束:A釋放三極管,DATA變為高電平
-
這時候,B也可以使用一樣的方法給A傳輸數據
如何高效閱讀英文數據手冊?
博文參照鏈接
全英文的數據手冊少則十幾頁,多則上百頁也有,加上我們又是如此的愛國(英文水平差的借口),所以在閱讀全英文數據手冊的時候,根本做不到面面俱到,當然也是完全沒有必要,學會善用Ctrl+F搜索關鍵詞,按需所取,閱讀我們關注的部分即可。
我以一個DC-DC BUCK芯片舉例,列出了很多關鍵詞,其他的數據手冊也是同樣的道理。
▉ Title
首先是Title,這也是廠家秀肌肉的地方,會告訴你一些最重要的芯片信息,比如TPS56120x系列、輸入電壓范圍4.5~17V、最大輸出電流1A、同步降壓、封裝是6Pin的SOT-23等。
▉ Feature
如果你是選型,以上參數符合要求,你就會接著往下去看,feature展示了更多的參數,比如輸出電壓范圍、靜態功耗、關閉功耗、精度和頻率等。
▉ Description description
可以讓我們對這個芯片有個大概的了解。
▉ Table of Contents
有的數據手冊會有目錄,可以先了解大致有那些內容,幫助我們尋找關鍵字。
▉Pin Configuration and Functions
可以了解芯片的管腳排布,每個管腳對應的信號名,建立原理圖封裝時需要參考下方這個圖。
通過pin functions了解每個管腳的功能描述,以及設計電路時有什么需要注意的。
▉ Absolute Maximum
Absolute Maximum即絕對最大值,加在芯片上的參數(電壓、溫度、ESD等級等)絕對不能超過這個值,否則芯片會損壞。
▉ Electrical Characteristics
硬件工程師必關注的電氣參數,每個芯片的電氣參數也是不盡相同的。
▉ Typical Characteristics
典型的參數,指的是芯片廠商在特定的參數下,測量得出的一些芯片特性,比如下面的不同輸出電壓和開關頻率之間的關系,DC-DC效率和輸出電流之間的關系等等,這個是為了讓我們更好的了解芯片的性能。
▉ Functional Block Diagram
功能框圖非常重要,透過外部的管腳了解內部的組成,可以更好的理解芯片,如SW管腳接了兩個MOS管,這是為什么能輸出占空比的原因?OVP和UVP都是通過比較器來實現的等等。
▉ Feature Description
對芯片的某一些特性進行描述,讓我們更好的理解這個芯片的相關特性,如下DC-DC的如軟啟動、電流保護、UVLO等功能都有詳細的描述。
▉ Typical Application
對于芯片類的數據手冊來說,典型應用就是參考電路圖。
▉ Layout Guide
對于芯片類如DC-DC,還有layout指導。
▉ Packaging Information
package信息,指的是一盒里面的數量,如下可以看見QTY3000和QTY250的型號是不一樣的。
一個系列不同的型號多在后綴有差別,可能是封裝不同、package QTY的不同等,所以在order的時候需要寫完整的芯片型號。
▉ Package Outline
封裝尺寸信息,在建立PCB封裝時會用到。
▉ Example Layout
根據提供的參考layout建立我們自己的PCB封裝。
列了這么多關鍵詞,并不是教大家如何閱讀DC-DC數據手冊,而是在闡明一個點:不同的人看數據手冊的側重點是不一樣的,硬件工程師更關注電氣參數、封裝信息、參考設計等,軟件工程師更關注寄存器、協議等,提取關鍵字,高效的閱讀數據手冊,找到對我們有幫助的內容才是最重要的。
類似內存的接口(2440開發板為例)
SDRAM
2440芯片手冊講到片選地址映射圖:
NOR FLASH
網卡
不同位寬外設的接線
為什么NOR FLASH地址線從ADDR1開始?SDARM地址是從ADDR2開始的?
如果CPU要讀取32位數據,那么內存控制器會去讀兩次16位數據存起來,一次性交給CPU。
時序的閱讀及內存控制器的設置
例如查詢2440芯片手冊內存控制配置方法:
再查詢相應的外設手冊:
1602液晶驅動顯示
閱讀手冊
1602代表:顯示16個字符,可以顯示兩行。如下圖所示:
發現使用上表中的數值芯片不能正常驅動,查看原廠家芯片英文資料,實踐可以正常使用,具體數值如下圖所示:
LCD1602.h
#ifndef __LCD1602_H__ #define __LCD1602_H__//用戶調用函數: void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endifLCD1602.c
#include <REGX52.H>//引腳配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0//main函數入口 void main() {LCD_Init();while(1);}//函數定義: /*** @brief LCD1602延時函數,12MHz調用可延時1ms* @param 無* @retval 無*/ void LCD_Delay() {unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i); }/*** @brief LCD1602寫命令* @param Command 要寫入的命令* @retval 無*/ void LCD_WriteCommand(unsigned char Command) {LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }/*** @brief LCD1602寫數據* @param Data 要寫入的數據* @retval 無*/ void LCD_WriteData(unsigned char Data) {LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }/*** @brief LCD1602設置光標位置* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @retval 無*/ void LCD_SetCursor(unsigned char Line,unsigned char Column) {if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));} }/*** @brief LCD1602初始化函數* @param 無* @retval 無*/ void LCD_Init() {LCD_WriteCommand(0x38);//八位數據接口,兩行顯示,5*7點陣LCD_WriteCommand(0x0c);//顯示開,光標關,閃爍關LCD_WriteCommand(0x06);//數據讀寫操作后,光標自動加一,畫面不動LCD_WriteCommand(0x01);//光標復位,清屏 }/*** @brief 在LCD1602指定位置上顯示一個字符* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @param Char 要顯示的字符* @retval 無*/ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) {LCD_SetCursor(Line,Column);LCD_WriteData(Char); }/*** @brief 在LCD1602指定位置開始顯示所給字符串* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param String 要顯示的字符串* @retval 無*/ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) {unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);} }/*** @brief 返回值=X的Y次方*/ int LCD_Pow(int X,int Y) {unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result; }/*** @brief 在LCD1602指定位置開始顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~65535* @param Length 要顯示數字的長度,范圍:1~5* @retval 無*/ void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');} }/*** @brief 在LCD1602指定位置開始以有符號十進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:-32768~32767* @param Length 要顯示數字的長度,范圍:1~5* @retval 無*/ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) {unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');} }/*** @brief 在LCD1602指定位置開始以十六進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~0xFFFF* @param Length 要顯示數字的長度,范圍:1~4* @retval 無*/ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}} }/*** @brief 在LCD1602指定位置開始以二進制顯示所給數字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數字,范圍:0~1111 1111 1111 1111* @param Length 要顯示數字的長度,范圍:1~16* @retval 無*/ void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');} }IIC總線AT24C02芯片實驗(E2PROM)
IIC總線協議
24C02芯片手冊閱讀
前面講了,器件前四位地址固定為1010,后三位在開發板里全部接地,因此器件地址確定為:0X1010 000.
編寫代碼
IIC.h
#ifndef __I2C_H__ #define __I2C_H__void I2C_Start(void); void I2C_Stop(void); void I2C_SendByte(unsigned char Byte); unsigned char I2C_ReceiveByte(void); void I2C_SendAck(unsigned char AckBit); unsigned char I2C_ReceiveAck(void);#endifIIC.c
#include <REGX52.H>sbit I2C_SCL=P2^1; sbit I2C_SDA=P2^0;/*** @brief I2C開始* @param 無* @retval 無*/ void I2C_Start(void) {I2C_SDA=1;I2C_SCL=1;//前后要保證間隔4.7us,郭天祥老師在這里寫了個delay空函數(下同)I2C_SDA=0;I2C_SCL=0; }/*** @brief I2C停止* @param 無* @retval 無*/ void I2C_Stop(void) {I2C_SDA=0;I2C_SCL=1;I2C_SDA=1; }/*** @brief I2C發送一個字節* @param Byte 要發送的字節* @retval 無*/ void I2C_SendByte(unsigned char Byte) {unsigned char i;//單片機節省空間 不用inttemp = Byte;for(i=0;i<8;i++){temp = temp<<1;I2C_SDA = CY;//溢出位//I2C_SDA=Byte&(0x80>>i); 這種方法沒看懂I2C_SCL=1;I2C_SCL=0;//低電平可改變數據 下一循環送入新的數據} }/*** @brief I2C接收一個字節* @param 無* @retval 接收到的一個字節數據*/ unsigned char I2C_ReceiveByte(void) {unsigned char i,k,Byte=0x00;I2C_SDA=1;for(i=0;i<8;i++){I2C_SCL=1;j = I2C_SDA;k = (k<<1)|j;//if(I2C_SDA){Byte|=(0x80>>i);}I2C_SCL=0;}return k; }/*** @brief I2C發送應答* @param AckBit 應答位,0為應答,1為非應答* @retval 無*/ void I2C_SendAck(unsigned char AckBit) {I2C_SDA=AckBit;I2C_SCL=1;I2C_SCL=0; }/*** @brief I2C接收應答位* @param 無* @retval 接收到的應答位,0為應答,1為非應答*/ unsigned char I2C_ReceiveAck(void) {unsigned char AckBit;I2C_SDA=1;I2C_SCL=1;AckBit=I2C_SDA;I2C_SCL=0;return AckBit; }AT24C02.h
#ifndef __AT24C02_H__ #define __AT24C02_H__void AT24C02_WriteByte(unsigned char WordAddress,Data); unsigned char AT24C02_ReadByte(unsigned char WordAddress);#endifAT24C02.c
#include <REGX52.H> #include "I2C.h"#define AT24C02_ADDRESS 0xA0//地址高四位固定是1010為a 后三位為000 寫位為0/*** @brief AT24C02寫入一個字節* @param WordAddress 要寫入字節的地址* @param Data 要寫入的數據* @retval 無*/ void AT24C02_WriteByte(unsigned char WordAddress,Data) {I2C_Start();I2C_SendByte(AT24C02_ADDRESS);//發送器件地址寫I2C_ReceiveAck(); //收到應答I2C_SendByte(WordAddress); //要寫入字節的地址 自己隨便定I2C_ReceiveAck(); //收到應答I2C_SendByte(Data); //發送(寫入)數據I2C_ReceiveAck(); //收到應答I2C_Stop(); }/*** @brief AT24C02讀取一個字節* @param WordAddress 要讀出字節的地址* @retval 讀出的數據*/ unsigned char AT24C02_ReadByte(unsigned char WordAddress) {unsigned char Data;I2C_Start();I2C_SendByte(AT24C02_ADDRESS);//偽寫I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_Start();I2C_SendByte(AT24C02_ADDRESS|0x01);//代表要讀數據I2C_ReceiveAck();Data=I2C_ReceiveByte(); //讀到數據I2C_SendAck(1);I2C_Stop();return Data; }總結
以上是生活随笔為你收集整理的学会阅读硬件的原理图、数据手册大全的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020 数学建模 A题
- 下一篇: Notification的学习,4.0前