欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標(biāo)題:
小白菜的IIC學(xué)習(xí)之路
[打印本頁]
作者:
jiujiu
時(shí)間:
2014-12-19 02:38
標(biāo)題:
小白菜的IIC學(xué)習(xí)之路
一,為了那“可惡”的目的
2011 年初,小白菜的工作比較清閑了,于是小白菜就開始IIC 學(xué)習(xí)之路。
之前在用 IIC 總線(口線模擬)時(shí),總感覺IIC 移植時(shí)不夠簡(jiǎn)介易懂,使用時(shí),函數(shù)不
能夠適應(yīng)所有IIC 操作,于是小白菜想改寫一下IIC 總線操作,使之成為真正的萬能IIC 總
線驅(qū)動(dòng)。于是小白菜找到目標(biāo)了:
一是編寫一個(gè)移植性極其好的 IIC 總線操作,只需要簡(jiǎn)單的改動(dòng)就能完成移植。
二是編寫兩個(gè)函數(shù),一個(gè)是向器件發(fā)送數(shù)據(jù)函數(shù),一個(gè)是從器件中讀取數(shù)據(jù)函數(shù)。并且
這兩個(gè)函數(shù)真正適應(yīng)所有不同的IIC 器伯的操作。
二,過程抽象
為了達(dá)到以上的目的,小白菜需要先對(duì) IIC 進(jìn)行一次抽象。
1 單片機(jī)向器件發(fā)送數(shù)據(jù)時(shí)的抽象過程
(這里的抽象指的是抽象出不依賴具體器件的 IIC 操作)
發(fā)送時(shí)的流程:
(1) MCU 啟動(dòng)總線
(2) 發(fā)送器件IIC 地址 接收 ACK 信號(hào)
(3) 發(fā)送寄存器地址1 接收 ACK 信號(hào) [發(fā)送寄存器地址2 接收 ACK 信號(hào)]
有些器件可能沒有寄存器地址(小白菜還沒有遇到過),所以該步可能不需要。
(4) 發(fā)送數(shù)據(jù)1 接收 ACK 信號(hào)
發(fā)送數(shù)據(jù)2 接收 ACK 信號(hào)
發(fā)送數(shù)據(jù)3 接收 ACK 信號(hào)
……
(5) MCU 關(guān)閉總線,發(fā)送完成。
我們來具體的分析一下,
第(1)步啟動(dòng)總線,
第(2)步發(fā)送 1B 數(shù)據(jù)(IIC 地址),接收一個(gè)ACK 信號(hào)
第(3)步發(fā)送 1B 數(shù)據(jù)(寄存器地址1),接收一個(gè)ACK 信號(hào),發(fā)送1B 數(shù)據(jù)(寄存器地址2),
接收一個(gè)ACK 信號(hào)
第(4)步發(fā)送 1B 數(shù)據(jù)(數(shù)據(jù)1),接收一個(gè)ACK 信號(hào),發(fā)送1B 數(shù)據(jù)(數(shù)據(jù)2),接收一個(gè)
ACK 信號(hào)……
第(5)步關(guān)閉總線
寫到這里,有些人可能看出來了,其實(shí)發(fā)送時(shí)不論數(shù)據(jù)或地址,都是一個(gè)相同過程,啟
動(dòng)總線后,MCU 發(fā)送一個(gè)字節(jié),等一個(gè)ACK 信號(hào),再發(fā)送一個(gè)字節(jié),等一個(gè)ACK 信號(hào),
發(fā)送……,哎、發(fā)送完了,得了,關(guān)閉總線。
繼續(xù)進(jìn)行抽象,我們可以把第(2)、(3)、(4)步進(jìn)行合并,得到IIC 寫操作抽象:
第(1)步啟動(dòng)總線,
第(2) (3) (4)步發(fā)送 1B 數(shù)據(jù),接收一個(gè)ACK 信號(hào),直到發(fā)送完成
第(5)步關(guān)閉總線
到這里之后,似乎是大功告成了,但是小白菜一想,這么多數(shù)據(jù),參數(shù)肯定是用指針+
數(shù)據(jù)字節(jié)數(shù)還進(jìn)行傳遞,可是像讀寫EEPROM 這樣的器件,地址就丙三字節(jié),但一次寫入
的數(shù)據(jù)可能有很多個(gè)字節(jié),于是小白菜把(2) (3) 合在一起,把數(shù)據(jù)發(fā)送部分(4)單獨(dú)拿出來。
小白菜得到了最終的 IIC 寫操作的抽象
第(1)步啟動(dòng)總線,
第(2) (3)步發(fā)送 1B 數(shù)據(jù),接收一個(gè)ACK 信號(hào),直到發(fā)送完成(發(fā)送地址)
第(4)步發(fā)送 1B 數(shù)據(jù),接收一個(gè)ACK 信號(hào),直到發(fā)送完成 (發(fā)送數(shù)據(jù))
第(5)步關(guān)閉總線
小白菜據(jù)此寫出了函數(shù)名及形參和流程圖(就是上面的抽象,所以嘛,就不寫了)。
extern uint8 IIC_MCU_Send_Str(uint8 *PAddr, uint8 AddrNum, uint8 *PDataAddr, uint16 DataNum)
*PAddr :I 第1 批發(fā)送的數(shù)據(jù)的首地址。這部分IC 地址以及子地址。PAddr[0]中存放IIC
地址,后面的存放子地址。
AddrNum :IIC 以及子地址的字節(jié)數(shù)。不可為0.
*PDataAddr :第2 批發(fā)送的數(shù)據(jù)的首地址。這部分是發(fā)送的數(shù)據(jù)。
DataNum :第2 批要發(fā)送的字節(jié)數(shù)(最大為65536 個(gè)字節(jié))。為0 時(shí)不發(fā)送這一部分。
2 單片機(jī)從有寄存器的IIC 器件讀取數(shù)據(jù)時(shí)的抽象過程:
發(fā)送時(shí)的流程:
(1) MCU 啟動(dòng)總線
(2) 發(fā)送器件IIC 地址 接收 ACK 信號(hào)
(3) 發(fā)送寄存器地址1 接收 ACK 信號(hào) [發(fā)送寄存器地址2 接收 ACK 信號(hào)]
有些器件可能沒有寄存器地址(小白菜還沒有遇到過),所以該步可能不需要。
(4) MCU 重新啟動(dòng)總線
(5) 發(fā)送器件IIC 地址(最低位置1 以表明是讀操作) 接收 ACK 信號(hào)
(6) 接收數(shù)據(jù)1 發(fā)送 ACK 信號(hào)
接收數(shù)據(jù)2 發(fā)送 ACK 信號(hào)
接收數(shù)據(jù)3 發(fā)送 ACK 信號(hào)
……
(7) 接收最后一字節(jié)數(shù)據(jù) 發(fā)送非ACK 信號(hào)
(8) MCU 關(guān)閉總線,接收完成。
根據(jù)該流程,我們可以清楚地得到讀取時(shí)的抽象:
第(1)步 MCU 啟動(dòng)總線
第(2) (3) 步發(fā)送 1B 數(shù)據(jù),接收一個(gè)ACK 信號(hào),直到發(fā)送完成(發(fā)送地址)
第(4) 步 MCU 重新啟動(dòng)總線
第(5) 步發(fā)送器件IIC 地址(最低位置1 以表明是讀操作) 接收 ACK 信號(hào)
第(6) 步接收前面的字節(jié),發(fā)送ACK 信號(hào)
第(7) 步接收最后一字節(jié)數(shù)據(jù),發(fā)送非ACK 信號(hào)
第(8) 步 MCU 關(guān)閉總線,接收完成。
雖然這里步驟多了,但是,函數(shù)參數(shù)也用不了幾個(gè),首先要知道地址吧,還要知道數(shù)據(jù)讀出
來后存放在哪里吧,小白菜想了想,這個(gè)函數(shù)的參數(shù)和寫操作函數(shù)的參數(shù)一樣就行了,
于是小白菜據(jù)寫出了函數(shù)名及形參和流程圖(就是上面的抽象,所以嘛,你懂得)
extern uint8 IIC_MCU_Rcv_Str(uint8 *PAddr, uint8 AddrNum, uint8 *PDataAddr, uint16
DataNum)
*PAddr :發(fā)送的數(shù)據(jù)的首地址。這部分IC 地址以及子地址。PAddr[0]中存放IIC 地址,
后面的存放子地址。
AddrNum :IIC 以及子地址的字節(jié)數(shù)。不可為0.
*PDataAddr :存放所接收數(shù)據(jù)的首地址
DataNum :要接收的字節(jié)數(shù)。
三 奮筆疾書 + 代碼移植
小白菜開始了寫代碼了。因?yàn)槭切“撞寺铮砸婚_始也不知道哪些地方在移植時(shí)需要
修改,于是就開始先寫代碼,可能在寫的時(shí)候就能知道了。寫啊寫,寫啊寫,終于讓小白菜
寫完了。
寫著寫著還真讓小白菜找出了哪里需要移植了。口線需要更改吧,不同的單片機(jī),頭
文件不一樣吧,還得有延時(shí)函數(shù)需要改吧……
于是小白菜把在移植時(shí)需要更改的地方做了一個(gè)“表”,放在H 文件中的“移植修改”
部分。這樣,在修改時(shí)就可以只修改H 文件中的一個(gè)地方,就能快速的完成移植。
現(xiàn)在想想,小白菜有的時(shí)候也不是那么菜嘛(偷笑 ing)。
到現(xiàn)在為止,小白菜的目的已經(jīng)達(dá)到了。突然,后背一涼,心里一個(gè)想法冒出來了,
剛寫完的代碼還沒測(cè)試就飄飄然了!哎,被勝利沖昏了頭腦。于是小白菜自已測(cè)試了一番,
Bug 還真是有,改改更健康~~
四使用說明
4.1 移植修改
移植修改都在 H 文件中的移植修改部分。下面進(jìn)行具體說明。
//----------------------------------------------------------------------------//
// 編號(hào):1
// 名稱:
// 功能:?jiǎn)纹瑱C(jī)寄存器頭文件,例如reg51.h
//----------------------------------------------------------------------------//
#include "ATT703x.H"
4.1.1 這部分是請(qǐng)您把使用的單片機(jī)的頭文件包含進(jìn)來。大蝦們用過MCU 多了,知道不同
的MCU,其寄存器定義是不一樣滴,不是所有的51 單片機(jī)都用Reg51.H 或Reg52.H 頭文
件的。
//----------------------------------------------------------------------------//
// 編號(hào):2
// 名稱:SDA, SCL
// 功能:模擬I2C 數(shù)據(jù)傳送位
//----------------------------------------------------------------------------//
#if defined(IIC_IO_ENABLE)
sbit SDA = P0^0; // 模擬I2C 數(shù)據(jù)傳送位。
sbit SCL = P2^6; // 模擬I2C 時(shí)鐘控制位。
#endif
4.1.2 SDA 和SCL 口線定義。這里就是您用的口線,如果您告訴我您不知道怎么改,好吧,
你贏了……
//----------------------------------------------------------------------------//
// 編號(hào):3
// 名稱:IIC_Delay_1US()
// 功能:精確的1 微秒延時(shí)函數(shù)。請(qǐng)根據(jù)您所用的單片機(jī)來正確設(shè)置。
// :如果您的系統(tǒng)中有精確的微妙級(jí)延時(shí)函數(shù),那么您可以直接使用。
// :例如,您的延時(shí)函數(shù)是Delay_1us(),那么您可以使用下句
// :#define IIC_Delay_1us() Delay_1us()
// :來實(shí)現(xiàn)延時(shí)。
//----------------------------------------------------------------------------//
#defineIIC_Delay_500ns() _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
#define IIC_Delay_1US() IIC_Delay_500ns();IIC_Delay_500ns();
4.1.3 軟件延時(shí)函數(shù),這里是標(biāo)準(zhǔn)IIC,不是快速IIC。1us 的延時(shí)怎么做呢?當(dāng)然是nop 函
數(shù)了。如果您不知道一個(gè)nop 的執(zhí)行時(shí)間,那么說明您需要好好看看手冊(cè)了。
4.1.4 好多單片機(jī)都需要設(shè)置時(shí)鐘,設(shè)置GPIO 狀態(tài),所以在使用IIC 之前,請(qǐng)一定確保MCU
先初始化完畢。
4.2 函數(shù)說明
4.2.1 MCU 向IIC 器件發(fā)送多字節(jié)數(shù)據(jù)函數(shù)
//----------------------------------------------------------------------------//
// MCU 向IIC 器件發(fā)送多字節(jié)數(shù)據(jù)函數(shù)(對(duì)外提供服務(wù))
//函數(shù)名稱:IIC_MCU_Send_Str
//函數(shù)功能:MCU 向IIC 從器件發(fā)送多字節(jié)數(shù)據(jù)。本函數(shù)是寫IIC 從器件的抽象函數(shù)。
//入口參數(shù):
// *PAddr: IIC 地址以及子地址。PAddr[0]中存放IIC 地址,后面的存放子地址。
// AddrNum : IIC 以及子地址的字節(jié)數(shù)。不可為0.
//
// *PDataAddr: 第 2 批發(fā)送的數(shù)據(jù)的首地址。這部分是發(fā)送的數(shù)據(jù)。
// DataNum : 第 2 批要發(fā)送的字節(jié)數(shù)(最大為65536 個(gè)字節(jié))。為0 時(shí)不發(fā)送這一部分。
//出口參數(shù):0 = 操作成功,1 = 操作出錯(cuò)。
//重要說明:這是一個(gè)從啟動(dòng)IIC 總線到發(fā)送數(shù)據(jù)再到最后結(jié)束總線為止的完整的發(fā)送過程。
// 數(shù)據(jù)發(fā)送的順序是先發(fā)送PAddr[0],最后發(fā)送PAddr[AddrNum - 1],然后發(fā)送
// PDataAddr[0],最后發(fā)送PDataAddr[DataNum - 1]。
// 一般地,PAddr 用于發(fā)送器件IIC 地址和子地址,PDataAddr 用于發(fā)送數(shù)據(jù)。
// 本函數(shù)對(duì)有無子地址的IIC 器件都適用。
//----------------------------------------------------------------------------//
extern uint8 IIC_MCU_Send_Str(uint8 *PAddr, uint8 AddrNum, uint8 *PDataAddr, uint16
DataNum)
應(yīng)用示例:
從 0x00 字節(jié)地址開始寫AT24C02,寫入10 個(gè)字節(jié)數(shù)(這里不考慮頁寫等待,因?yàn)楹?br /> IIC 寫無關(guān)),這10B 數(shù)據(jù)存放在unsigned char Buf[10]中,寫入時(shí)要求Buf[0]寫入0x00 字節(jié)
地址,Buf[1]寫入0x01 字節(jié)地址……。
A2、A1、A0 全接地。(有人說我沒說明WP 的接法……我只有一個(gè)問題,你是來砸場(chǎng)
子的么!!!)
首先組織 IIC 地址,設(shè)置一數(shù)組unsigned char Addr[2],其中Addr[0] = 0xA0,Addr[1] = 0x00;
Addr [0]中存放的是(二進(jìn)制表示) 1 0 1 0 A2 A1 A0 0(LSB)
Addr [1]中存放的是(二進(jìn)制表示) a7 a6 a5 a4 a3 a2 a1 a0(LSB)
調(diào)用時(shí) IIC_MCU_Send_Str(Addr, 2, Buf, 10);
您還應(yīng)當(dāng)查看一下函數(shù)的返回值,是0 表示操作成功,否則操作失敗。
4.2.1 MCU 從有子地址的IIC 器件中接收多字節(jié)函數(shù)
//----------------------------------------------------------------------------//
// MCU 從有子地址的IIC 器件中接收多字節(jié)函數(shù)(對(duì)外接口)
//函數(shù)名稱:IICMCURcvStr
//函數(shù)功能:本函數(shù)用于有子地址的IIC 器件的讀操作。
//入口參數(shù):
// *PAddr: IIC 地址以及子地址。PAddr[0]中存放IIC 地址,后面的存放子地址。
// AddrNum : IIC 以及子地址的字節(jié)數(shù)。為0 時(shí)出錯(cuò).
// *PDataAddr:存放所接收數(shù)據(jù)的首地址
// DataNum : 要接收的字節(jié)數(shù)。合法值1-65535。為0 時(shí)出錯(cuò)。
//
//出口參數(shù):0 = 操作成功,1 = 操作出錯(cuò)。
//重要說明:
// 讀取的第一個(gè)數(shù)據(jù)存放在PDataAddr[0]中,第一個(gè)存放在PDataAddr[1]中……
// 有子地址的IIC 器件的讀操作是:
// MCU 先啟動(dòng)總線,然后發(fā)送器件的IIC 地址和需要操作的子地址
//(這一部分就是*PAddr),之后重新啟動(dòng)總線,再次發(fā)送器件的IIC 地址且最低位置1 以表
明是讀
// 操作,等待應(yīng)答后便開始接收數(shù)據(jù)(這一部分是*PDataAddr),最后關(guān)閉總線。
//----------------------------------------------------------------------------//
extern uint8 IIC_MCU_Rcv_Str(uint8 *PAddr, uint8 AddrNum, uint8 *PDataAddr, uint16
DataNum)
讀取的第一個(gè)數(shù)據(jù)存放在 PDataAddr[0]中,第一個(gè)存放在PDataAddr[1]中……
應(yīng)用示例:
從 0x00 字節(jié)地址開始讀AT24C02,讀10 個(gè)字節(jié)數(shù)并且存放在unsigned char Buf[10]中,
A2、A1、A0 全接地。(有人說我沒說明WP 的接法……還提這個(gè)問題!!)
首先組織 IIC 地址,設(shè)置一數(shù)組unsigned char Addr[2],其中Addr[0] = 0xA0,Addr[1] = 0x00;
Addr [0]中存放的是(二進(jìn)制表示) 1 0 1 0 A2 A1 A0 0(LSB)
Addr [1]中存放的是(二進(jìn)制表示) a7 a6 a5 a4 a3 a2 a1 a0(LSB)
調(diào)用時(shí) IIC_MCU_Rcv_Str (Addr, 2, Buf, 10);
這樣,Buf[0]是讀取到的0x00 字節(jié)地址的數(shù)據(jù),Buf[1]是0x01 字節(jié)地址的數(shù)據(jù)……
您還應(yīng)當(dāng)查看一下函數(shù)的返回值,是 0 表示操作成功,否則操作失敗。
五 最后的廢話
好吧,有人會(huì)說這個(gè)實(shí)現(xiàn)的有點(diǎn)羅嗦,不如直接以IIC 地址,寄存器地址做參數(shù)來的方
便;雖然有時(shí)候我也這么覺得。
但是、但是、但是什么呢?下期見!
3htech
我是一顆小白菜
程序下載:
IIC.rar
(94 KB, 下載次數(shù): 53)
2014-12-19 02:37 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
作者:
qq704661078
時(shí)間:
2015-1-31 21:25
樓下高手,謝謝分享!!
作者:
fontex
時(shí)間:
2015-2-7 09:02
只能說謝謝。
作者:
xsynet
時(shí)間:
2015-2-10 11:20
只能說謝謝了
作者:
xsynet
時(shí)間:
2015-2-10 11:20
樓主強(qiáng)大,學(xué)習(xí)了
作者:
496111160
時(shí)間:
2015-2-21 16:47
只能說謝謝。
作者:
496111160
時(shí)間:
2015-2-21 16:53
學(xué)習(xí)一下,看看效果
作者:
fuermalin
時(shí)間:
2015-2-23 19:50
謝謝樓主
學(xué)習(xí)一下
作者:
1101459202
時(shí)間:
2016-3-6 08:57
謝謝樓主
學(xué)習(xí)一下
作者:
davedoff86
時(shí)間:
2016-9-29 13:16
好用, 學(xué)習(xí)了
作者:
lyseg
時(shí)間:
2017-4-4 12:03
謝謝分享!!
作者:
insurace
時(shí)間:
2019-7-16 10:03
感謝樓主
作者:
jemery1030
時(shí)間:
2019-7-17 20:00
感謝再感謝。
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1