I2C实验
參考:I2C 總線協議詳解
作者:一只青木呀
發布時間:2020-09-21 11:41:25
網址:https://blog.csdn.net/weixin_45309916/article/details/108705297
目錄
- I2C 簡介
- I2C 協議
- I2C協議有關術語
- 1、起始位
- 2、停止位
- 3、數據傳輸
- 4、應答信號
- 5、I2C 寫時序(主機向從機)
- 6、I2C 讀時序(主機向從機)
- 7、I2C 多字節讀寫時序
- I.MX6U I2C 簡介
- AP3216C 簡介
- 硬件原理分析
- 實驗程序編寫
- 編譯下載驗證
- 編寫Makefile 和鏈接腳本
- 編譯下載
I2C 是最常用的通信接口,眾多的傳感器都會提供I2C 接口來和主控相連,比如陀螺儀、加速度計、觸摸屏等等。所以I2C 是做嵌入式開發必須掌握的,I.MX6U 有4 個I2C 接口,可以通過這4 個I2C 接口來連接一些I2C 外設。I.MX6U-ALPHA 使用I2C1 接口連接了一個距離傳感器AP3216C,本章我們就來學習如何使用I.MX6U 的I2C 接口來驅動AP3216C,讀取AP3216C 的傳感器數據。
I2C 簡介
I2C 是很常見的一種總線協議, I2C 是 NXP 公司設計的, I2C 使用兩條線在主控制器和從機之間進行數據通信。一條是 SCL(串行時鐘線),另外一條是 SDA(串行數據線),這兩條數據線需要接上拉電阻,總線空閑的時候 SCL 和 SDA 處于高電平。 I2C 總線標準模式下速度可以達到 100Kb/S,快速模式下可以達到 400Kb/S。 I2C 總線工作是按照一定的協議來運行的,接下來就看一下 I2C 協議。
I2C 協議
I2C 是支持多從機的,也就是一個 I2C 控制器下可以掛多個 I2C 從設備,這些不同的 I2C從設備有不同的器件地址,這樣 I2C 主控制器就可以通過 I2C 設備的器件地址訪問指定的 I2C設備了,一個 I2C 總線連接多個 I2C 設備如下圖所示:
上圖中 SDA 和 SCL 這兩根線必須要接一個上拉電阻,一般是 4.7K。其余的 I2C 從器件都掛接到 SDA 和 SCL 這兩根線上,這樣就可以通過 SDA 和 SCL 這兩根線來訪問多個 I2C設備。
I2C協議有關術語
1、起始位
顧名思義,也就是 I2C 通信起始標志,通過這個起始位就可以告訴 I2C 從機,“我”要開始進行 I2C 通信了。在 SCL 為高電平的時候, SDA 出現下降沿就表示為起始位,如下圖所示:
2、停止位
停止位就是停止 I2C 通信的標志位,和起始位的功能相反。在 SCL 位高電平的時候, SDA出現上升沿就表示為停止位,如下圖所示:
3、數據傳輸
I2C 總線在數據傳輸的時候要保證在 SCL 高電平期間, SDA 上的數據穩定,因此 SDA 上的數據變化只能在 SCL 低電平期間發生,如下圖所示:
4、應答信號
當 I2C 主機發送完 8 位數據以后會將 SDA 設置為輸入狀態,等待 I2C 從機應答,也就是等到 I2C 從機告訴主機它接收到數據了。應答信號是由從機發出的,主機需要提供應答信號所需的時鐘,主機發送完 8 位數據以后緊跟著的一個時鐘信號就是給應答信號使用的。從機通過將 SDA 拉低來表示發出應答信號,表示通信成功,否則表示通信失敗。
5、I2C 寫時序(主機向從機)
主機通過 I2C 總線與從機之間進行通信不外乎兩個操作:寫和讀, I2C 總線單字節寫時序如下圖所示:
上圖就是 I2C 寫時序,我們來看一下寫時序的具體步驟:
- 1)、開始信號。
- 2)、發送 I2C 設備地址,每個 I2C 器件都有一個設備地址,通過發送具體的設備地址來決定訪問哪個 I2C 器件。這是一個 8 位的數據,其中高 7 位是設備地址,最后 1 位是讀寫位,為1 的話表示這是一個讀操作,為 0 的話表示這是一個寫操作。
- 3)、 I2C 器件地址后面跟著一個讀寫位,為 0 表示寫操作,為 1 表示讀操作。
- 4)、從機發送的 ACK 應答信號。
- 5)、重新發送開始信號。
- 6)、發送要寫寫入數據的寄存器地址。
- 7)、從機發送的 ACK 應答信號
- 8)、發送要寫入寄存器的數據。
- 9)、從機發送的 ACK 應答信號。
- 10)、停止信號。
6、I2C 讀時序(主機向從機)
I2C 總線單字節讀時序如下圖所示:
I2C 單字節讀時序比寫時序要復雜一點,讀時序分為 4 大步,第一步是發送設備地址,第二步是發送要讀取的寄存器地址,第三步重新發送設備地址,最后一步就是 I2C 從器件輸出要讀取的寄存器值,我們具體來看一下這步。
- 1)、主機發送起始信號。
- 2)、主機發送要讀取的 I2C 從設備地址。
- 3)、讀寫控制位,因為是向 I2C 從設備發送數據,因此是寫信號。
- 4)、從機發送的 ACK 應答信號。
- 5)、重新發送 START 信號。
- 6)、主機發送要讀取的寄存器地址。
- 7)、從機發送的 ACK 應答信號。
- 8)、重新發送 START 信號。
- 9)、重新發送要讀取的 I2C 從設備地址。
- 10)、讀寫控制位,這里是讀信號,表示接下來是從 I2C 從設備里面讀取數據。
- 11)、從機發送的 ACK 應答信號。
- 12)、從 I2C 器件里面讀取到的數據。
- 13)、主機發出 NO ACK 信號,表示讀取完成,不需要從機再發送 ACK 信號了。
- 14)、主機發出 STOP 信號,停止 I2C 通信。
7、I2C 多字節讀寫時序
有時候我們需要讀寫多個字節,多字節讀寫時序和單字節的基本一致,只是在讀寫數據的時候可以連續發送多個自己的數據,其他的控制時序都是和單字節一樣的。
I.MX6U I2C 簡介
I.MX6U 提供了4 個I2C 外設,通過這四個I2C 外設即可完成與I2C 從器件進行通信,I.MX6U 的I2C 外設特性如下:
①、與標準I2C 總線兼容。
②、多主機運行
③、軟件可編程的64 中不同的串行時鐘序列。
④、軟件可選擇的應答位。
⑤、開始/結束信號生成和檢測。
⑥、重復開始信號生成。
⑦、確認位生成。
⑧、總線忙檢測
I.MX6U 的I2C 支持兩種模式:標準模式和快速模式,標準模式下I2C 數據傳輸速率最高是100Kbits/s,在快速模式下數據傳輸速率最高為400Kbits/s。
我們接下來看一下I2C 的幾個重要的寄存器,首先看一下I2Cx_IADR(x=1~4)寄存器,這是I2C 的地址寄存器,此寄存器結構如圖26.1.2.1 所示:
寄存器I2Cx_IADR 只有ADR(bit7:1)位有效,用來保存I2C 從設備地址數據。當我們要訪問某個I2C 從設備的時候就需要將其設備地址寫入到ADR 里面。接下來看一下寄存器I2Cx_IFDR,這個是I2C 的分頻寄存器,寄存器結構如圖26.1.2.2 所示:
寄存器I2Cx_IFDR 也只有IC(bit5:0)這個位,用來設置I2C 的波特率,I2C 的時鐘源可以選擇IPG_CLK_ROOT=66MHz,通過設置IC 位既可以得到想要的I2C 波特率。IC 位可選的設置如圖26.1.2.3 所示:
不像其他外設的分頻設置一樣可以隨意設置,圖26.1.2.3 中列出了IC 的所有可選值。比如現在I2C 的時鐘源為66MHz,我們要設置I2C 的波特率為100KHz,那么IC 就可以設置為0X15,也就是640 分頻。66000000/640=103.125KHz≈100KHz。
接下來看一下寄存器I2Cx_I2CR,這個是I2C 控制寄存器,此寄存器結構如圖26.1.2.4 所示:
寄存器I2Cx_I2CR 的各位含義如下:
IEN(bit7):I2C 使能位,為1 的時候使能I2C,為0 的時候關閉I2C。
IIEN(bit6):I2C 中斷使能位,為1 的時候使能I2C 中斷,為0 的時候關閉I2C 中斷。
MSTA(bit5):主從模式選擇位,設置IIC 工作在主模式還是從模式,為1 的時候工作在主模式,為0 的時候工作在從模式。
MTX(bit4):傳輸方向選擇位,用來設置是進行發送還是接收,為0 的時候是接收,為1 的時候是發送。
TXAK(bit3):傳輸應答位使能,為0 的話發送ACK 信號,為1 的話發送NO ACK 信號。
RSTA(bit2):重復開始信號,為1 的話產生一個重新開始信號。
接下來看一下寄存器I2Cx_I2SR,這個是I2C 的狀態寄存器,寄存器結構如圖26.1.2.5 所示:
寄存器I2Cx_I2SR 的各位含義如下:
ICF(bit7):數據傳輸狀態位,為0 的時候表示數據正在傳輸,為1 的時候表示數據傳輸完成。
IAAS(bit6):當為1 的時候表示I2C 地址,也就是I2Cx_IADR 寄存器中的地址是從設備地址。
IBB(bit5):I2C 總線忙標志位,當為0 的時候表示I2C 總線空閑,為1 的時候表示I2C 總線忙。
IAL(bit4):仲裁丟失位,為1 的時候表示發生仲裁丟失。
SRW(bit2):從機讀寫狀態位,當I2C 作為從機的時候使用,此位用來表明主機發送給從機的是讀還是寫命令。為0 的時候表示主機要向從機寫數據,為1 的時候表示主機要從從機讀取數據。
IIF(bit1):I2C 中斷掛起標志位,當為1 的時候表示有中斷掛起,此位需要軟件清零。
RXAK(bit0):應答信號標志位,為0 的時候表示接收到ACK 應答信號,為1 的話表示檢測到NO ACK 信號。
最后一個寄存器就是I2Cx_I2DR,這是I2C 的數據寄存器,此寄存器只有低8 位有效,當要發送數據的時候將要發送的數據寫入到此寄存器,如果要接收數據的話直接讀取此寄存器即可得到接收到的數據。
關于I2C 的寄存器就介紹到這里,關于這些寄存器詳細的描述,請參考《I.MX6ULL 參考手冊》第1462 頁的31.7 小節。
AP3216C 簡介
I.MX6U-ALPHA 開發板上通過I2C1 連接了一個三合一環境傳感器:AP3216C,AP3216C是由敦南科技推出的一款傳感器,其支持環境光強度(ALS)、接近距離(PS)和紅外線強度(IR)這三個環境參數檢測。該芯片可以通過IIC 接口與主控制相連,并且支持中斷,AP3216C 的特點如下:
①、I2C 接口,快速模式下波特率可以到400Kbit/S
②、多種工作模式選擇:ALS、PS+IR、ALS+PS+IR、PD 等等。
③、內建溫度補償電路。
④、寬工作溫度范圍(-30°C ~ +80°C)。
⑤、超小封裝,4.1mm x 2.4mm x 1.35mm
⑥、環境光傳感器具有16 位分辨率。
⑦、接近傳感器和紅外傳感器具有10 位分辨率。
AP3216C 常被用于手機、平板、導航設備等,其內置的接近傳感器可以用于檢測是否有物體接近,比如手機上用來檢測耳朵是否接觸聽筒,如果檢測到的話就表示正在打電話,手機就會關閉手機屏幕以省電。也可以使用環境光傳感器檢測光照強度,可以實現自動背光亮度調節。
AP3216C 結構如圖26.1.3.1 所示:
AP3216 的設備地址為0X1E,同幾乎所有的I2C 從器件一樣,AP3216C 內部也有一些寄存器,通過這些寄存器我們可以配置AP3216C 的工作模式,并且讀取相應的數據。AP3216C 我們用的寄存器如表26.1.3.1 所示:
在表26.1.3.1 中,0X00 這個寄存器是模式控制寄存器,用來設置AP3216C 的工作模式,一般開始先將其設置為0X04,也就是先軟件復位一次AP3216C。接下來根據實際使用情況選擇合適的工作模式,比如設置為0X03,也就是開啟ALS+PS+IR。從0X0A~0X0F 這6 個寄存器就是數據寄存器,保存著ALS、PS 和IR 這三個傳感器獲取到的數據值。如果同時打開ALS、PS 和IR 則讀取間隔最少要112.5ms,因為AP3216C 完成一次轉換需要112.5ms。關于AP3216C的介紹就到這里,如果要想詳細的研究此芯片的話,請大家自行查閱其數據手冊。
本章實驗中我們通過I.MX6U 的I2C1 來讀取AP3216C 內部的ALS、PS 和IR 這三個傳感器的值,并且在LCD 上顯示。開機會先檢測AP3216C 是否存在,一般的芯片是有個ID 寄存器,通過讀取ID 寄存器判斷ID 是否正確就可以檢測芯片是否存在。但是AP3216C 沒有ID 寄存器,所以我們就通過向寄存器0X00 寫入一個值,然后再讀取0X00 寄存器,判斷讀出得到值和寫入的是否相等,如果相等就表示AP3216C 存在,否則的話AP3216C 就不存在。本章的配置步驟如下:
1、初始化相應的IO
初始化I2C1 相應的IO,設置其復用功能,如果要使用AP3216C 中斷功能的話,還需要設置AP3216C 的中斷IO。
2、初始化I2C1
初始化I2C1 接口,設置波特率。
3、初始化AP3216C
初始化AP3216C,讀取AP3216C 的數據。
硬件原理分析
本試驗用到的資源如下:
①、指示燈LED0。
②、RGB LCD 屏幕。
③、AP3216C
④、串口
AP3216C 是在I.MX6U-ALPHA 開發板底板上,原理圖如圖26.2.1 所示:
從圖26.2.1 可以看出AP3216C 使用的是I2C1,其中I2C1_SCL 使用的UART4_TXD 這個IO、I2C1_SDA 使用的是UART4_R XD 這個IO。
實驗程序編寫
本實驗對應的例程路徑為:開發板光盤-> 1、裸機例程-> 17_i2c。
本章實驗在上一章例程的基礎上完成,更改工程名字為“ap3216c”,然后在bsp 文件夾下創建名為“i2c”和“ap3216c”的文件夾。在bsp/i2c 中新建bsp_i2c.c 和bsp_i2c.h 這兩個文件,在bsp/ap3216c 中新建bsp_ap3216c.c 和bsp_ap3216c.h 這兩個文件。bsp_i2c.c 和bsp_i2c.h 是I.MX6U 的I2C 文件,bsp_ap3216c.c 和bsp_ap3216c.h 是AP3216C 的驅動文件。在sp_i2c.h 中輸入如下內容:
1 #ifndef _BSP_I2C_H 2 #define _BSP_I2C_H 3 /*************************************************************** 4 Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 5 文件名: bsp_i2c.h 6 作者: 左忠凱 7 版本: V1.0 8 描述: IIC驅動文件。 9 其他: 無 10 論壇: www.openedv.com 11 日志: 初版V1.0 2019/1/15 左忠凱創建 12 ***************************************************************/ 13 #include "imx6ul.h" 14 15 /* 相關宏定義*/ 16 #define I2C_STATUS_OK (0)第16 到22 行定義了一些I2C 狀態相關的宏。第27 到31 行定義了一個枚舉類型i2c_direction,此枚舉類型用來表示I2C 主機對從機的操作,也就是讀數據還是寫數據。第36 到44 行定義了一個結構體i2c_transfer,此結構體用于I2C 的數據傳輸。剩下的就是一些函數聲明了,總體來說bsp_i2c.h 文件里面的內容還是很簡單的。接下來在文件bsp_i2c.c 里面輸入如下內容:
/*************************************************************** Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名: bsp_i2c.c 作者: 左忠凱 版本: V1.0 描述: IIC驅動文件。 其他: 無 論壇: www.openedv.com 日志: 初版V1.0 2019/1/15 左忠凱創建 ***************************************************************/ 1 #include "bsp_i2c.h" 2 #include "bsp_delay.h" 3 #include "stdio.h" 4 5 /* 6 * @description : 初始化I2C,波特率100KHZ 7 * @param – base : 要初始文件bsp_i2c.c中一共有8 個函數,我們依次來看一下這些函數的功能,首先是函數i2c_init,此函數用來初始化I2C,重點是設置I2C 的波特率,初始化完成以后開啟I2C。第2 個函數是i2c_master_repeated_start,此函數用來發送一個重復開始信號,發送開始信號的時候也會順帶發送從設備地址。第3 個函數是i2c_master_start,此函數用于發送一個開始信號,發送開始信號
的時候也順帶發送從設備地址。第4 個函數是i2c_check_and_clear_error,此函數用于檢查并清除錯誤。第5 個函數是i2c_master_stop,用于產生一個停止信號。第6 和第7 個函數分別為i2c_master_write 和i2c_master_read,這兩個函數分別用于完成向I2C 從設備寫數據和從I2C 從設備讀數據。最后一個函數是i2c_master_transfer,此函數就是用戶最終調用的,用于完成I2C
通信的函數,此函數會使用前面的函數拼湊出I2C 讀/寫時序。此函數就是按照26.1.1 小節講解的I2C 讀寫時序來編寫的。
I2C 的操作函數已經準備好了,接下來就是使用前面編寫I2C 操作函數來配置AP3216C 了,配置完成以后就可以讀取AP3216C 里面的傳感器數據,在bsp_ap3216c.h 輸入如下所示內容:
1 #ifndef _BSP_AP3216C_H 2 #define _BSP_AP3216C_H第15 到26 行定義了一些宏,分別為AP3216C 的設備地址和寄存器地址,剩下的就是函數聲明。接下來在bsp_ap3216c.c 中輸入如下所示內容:
/*************************************************************** Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名: bsp_ap3216c.c 作者: 左忠凱文件bsp_ap3216c.c 里面共有4 個函數,第1 個函數是ap3216c_init,顧名思義,此函數用于初始化AP3216C,初始化成功的話返回0,如果初始化失敗就返回其他值。此函數先初始化所使用到的IO,比如初始化I2C1 的相關IO,并設置其復用為I2C1。然后此函數會調用i2c_init來初始化I2C1,最后初始化AP3216C。第2 個和第3 個函數分別為ap3216c_writeonebyte 和
ap3216c_readonebyte,這兩個函數分別是向AP3216C 寫入數據和從AP3216C 讀取數據。這兩個函數都通過調用bsp_i2c.c 中的函數i2c_master_transfer 來完成對AP3216C 的讀寫。最后一個函數就是ap3216c_readdata,此函數用于讀取AP3216C 中的ALS、PS 和IR 傳感器數據。
最后在main.c 中輸入如下代碼:
/************************************************************** Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名: main.c 作者: 左忠凱 版本: V1.0 描述: I.MX6U開發板裸機實驗18 IIC實驗 其他: IIC是最常用的接口,ALPHA開發板上有多個IIC外設,本實驗就 來學習如何驅動I.MX6U的IIC接口,并且通過IIC接口讀取板載 AP3216C的數據值。 論壇: www.openedv.com 日志: 初版V1.0 2019/1/15 左忠凱創建 **************************************************************/ 1 #include "bsp_clk.h" 2 #include "bsp_delay.h" 3 #include "bsp_led.h" 4 #include "bsp_beep.h" 5 #include "bsp_key.h" 6 #include "bsp_int.h" 7 #include "bsp_uart.h" 8 #include "bsp_lcd.h" 9 #include "bsp_rtc.h" 10 #include "bsp_ap3216c.h" 11 #include "stdio.h" 12 13 /* 14 * @description : main函數 15 * @param : 無 16 * @return : 無第38 行調用ap3216c_init 來初始化AP3216C,如果AP3216C 初始化失敗的話就會進入循環,會在LCD 上不斷的閃爍字符串“AP3216C Check Failed!”和“Please Check!”,直到AP3216C初始化成功。
第53 行調用函數ap3216c_readdata 來獲取AP3216C 的ALS、PS 和IR 傳感器數據值,獲取完成以后就會在LCD 上顯示出來。
文件main.c 里面的內容總體上還是很簡單的,實驗程序的編寫就到這里。
編譯下載驗證
編寫Makefile 和鏈接腳本
修改Makefile 中的TARGET 為ap3216c,然后在在INCDIRS 和SRCDIRS 中加入“bsp/i2c”和“bsp/ap3216c”,修改后的Makefile 如下:
1 CROSS_COMPILE ?= arm-linux-gnueabihf- 2 TARGET ?= ap3216c 3 4 /* 省略掉其它代碼...... */ 5 6 INCDIRS := imx6ul \ 7 stdio/in第2 行修改變量TARGET 為“ap3216c”,也就是目標名稱為“ap3216c”。
第21 和22 行在變量INCDIRS 中添加I2C 和AP3216C 的驅動頭文件(.h)路徑。
第39 和40 行在變量SRCDIRS 中添加I2C 和AP3216C 驅動文件(.c)路徑。
鏈接腳本保持不變。
編譯下載
使用Make 命令編譯代碼,編譯成功以后使用軟件imxdownload 將編譯完成的ap3216c.bin文件下載到SD 卡中,命令如下:
chmod 777 imxdownload //給予imxdownload 可執行權限,一次即可 ./imxdownload ap3216c.bin /dev/sdd //燒寫到SD 卡中,不能燒寫到/dev/sda 或sda1 里面!燒寫成功以后將SD 卡插到開發板的SD 卡槽中,然后復位開發板。程序運行以后LCD界面如圖26.4.2.1 所示:
圖26.4.2.1 中顯示出了AP3216C 的三個傳感器的數據,大家可以用手遮住或者靠近AP3216C,LCD 上的三個數據就會變化。
總結
- 上一篇: NXP(I.MX6uLL) UART串口
- 下一篇: 2021 常用的 7 款 MySQL 客