C語(yǔ)言軟件iic虛擬總線中間層設(shè)計(jì)詳解
簡(jiǎn)介
mr-soft-iic 模塊為 mr-library 項(xiàng)目下的可裁剪模塊,以C語(yǔ)言編寫(xiě),可快速移植到各種平臺(tái)(主要以嵌入式mcu為主)。 mr-soft-iic 模塊通過(guò) io 模擬實(shí)現(xiàn) iic 協(xié)議。
IIC-協(xié)議
SPI 一般為一主多從設(shè)計(jì)。由2根線組成:CLK
(時(shí)鐘)、SDA
(數(shù)據(jù))。
接線方式
主機(jī) | 從機(jī) |
---|---|
CLK | CLK |
SDA | SDA |
主機(jī)從機(jī)一 一對(duì)應(yīng)相接。
總線
IIC 通過(guò)地址碼識(shí)別設(shè)備,一條 IIC 總線最多支持掛載127
個(gè)設(shè)備,通常速率為100kbit/s
和400kbit/s
,由于SDA
設(shè)置為開(kāi)漏模式,因此雙向通信時(shí)需外置上拉電阻。
工作本質(zhì)
我們可以看到CLK
和SDA
都有一個(gè)上拉電阻,而CLK
和SDA
都為開(kāi)漏(OUT-OD)下,所以只有一個(gè)下拉的MOS可以控制,因此只有下拉
和高阻
狀態(tài)。當(dāng)高阻
狀態(tài)時(shí)線上電平因?yàn)樯侠娮璧拇嬖谒詾閂CC,而下拉
狀態(tài)時(shí),因?yàn)镸OS對(duì)地,所以線上電平為GND。當(dāng)主機(jī)主動(dòng)控制時(shí),就可以完成寫(xiě)入的操作,當(dāng)需要讀取時(shí),只需置高阻,等待從機(jī)主動(dòng)拉低,即可完成雙向通信。
虛擬總線(中間層)設(shè)計(jì)
首先 IIC 總線的CLK
、SDA
這2條線是不會(huì)變動(dòng)的,所以我們可以把這部分單獨(dú)設(shè)計(jì)為iic-bus
,IIC總線需要知道當(dāng)前有哪個(gè)設(shè)備擁有IIC總線的使用權(quán),為了防止出現(xiàn)搶占還需要配置一個(gè)互斥鎖。
struct mr_soft_iic_bus { void (*set_clk)(mr_uint8_t level); // 操作 CLK 的函數(shù)指針 void (*set_sda)(mr_uint8_t level); // 操作 SDA 的函數(shù)指針 mr_uint8_t (*get_sda)(void); // 讀取 SDA 的函數(shù)指針 struct mr_soft_iic *owner; // 當(dāng)前該總線的所有者 mr_uint8_t lock; // 互斥鎖 };
IIC設(shè)備唯一獨(dú)有的只有設(shè)備addr,所以我們把這部分定義為iic-device
。IIC設(shè)備還需要知道自己歸屬于哪條IIC總線。
struct mr_soft_iic { mr_uint8_t addr; // 設(shè)備地址 struct mr_soft_iic_bus *bus; // 該設(shè)備歸屬的總線 };
當(dāng)創(chuàng)建了一條iic-bus
,一個(gè)iic-device
后我們需要一個(gè)掛載函數(shù),即將iic-device
掛載到iic-bus
上
void mr_soft_iic_attach(struct mr_soft_iic *iic, struct mr_soft_iic_bus *iic_bus) { iic->bus = iic_bus; }
那么由于是虛擬總線設(shè)計(jì),當(dāng)我們要開(kāi)始傳輸前需要先去獲取總線。
mr_err_t mr_soft_iic_bus_take(struct mr_soft_iic *iic) { mr_uint8_t iic_bus_lock; mr_base_t level; /* check iic-bus owner */ if(iic->bus->owner != iic) { /* check mutex lock */ do { iic_bus_lock = iic->bus->lock; } while (iic_bus_lock != MR_UNLOCK); /* lock mutex lock */ iic->bus->lock = MR_LOCK; /* exchange iic-bus owner */ iic->bus->owner = iic; } else { /* lock mutex lock */ iic->bus->lock = MR_LOCK; } return MR_EOK; }
當(dāng)我們使用完畢后需要釋放總線
mr_err_t mr_soft_iic_bus_release(struct mr_soft_iic *iic) { /* check spi-bus owner */ if(iic->bus->owner == iic) { iic->bus->lock = MR_UNLOCK; return MR_EOK; } return -MR_ERROR; }
到此其實(shí)虛擬總線已經(jīng)設(shè)計(jì)完畢,設(shè)備需要使用僅需通過(guò)掛載 、獲取、釋放 三步操作即可,其余操作交由中間層處理。 為調(diào)用接口的統(tǒng)一,設(shè)計(jì)iic-msg
struct mr_soft_iic_msg { mr_uint8_t read_write; // 讀寫(xiě)模式:IIC_WR/ IIC_RD mr_uint8_t addr; // 寫(xiě)入/讀取 地址 mr_uint8_t *buffer; // 數(shù)據(jù)地址 mr_size_t size; // 數(shù)據(jù)數(shù)量 };
然后通過(guò)transfer
函數(shù)統(tǒng)一調(diào)用接口。
mr_err_t mr_soft_iic_transfer(struct mr_soft_iic *iic, struct mr_soft_iic_msg msg) { mr_err_t ret; /* check msg */ if(msg.read_write > IIC_RD) return -MR_ERROR; if(msg.addr == MR_NULL) return -MR_EINVAL; if(msg.buffer == MR_NULL || msg.size == MR_NULL) return MR_EOK; /* take iic-bus */ ret = mr_soft_iic_bus_take(iic); if(ret != MR_EOK) return ret; /* send iic device and register address */ mr_soft_iic_bus_start(iic->bus); mr_soft_iic_bus_send(iic->bus, iic->addr << 1); mr_soft_iic_bus_send(iic->bus, msg.addr); if(msg.read_write == IIC_WR) { /* send iic start and device write cmd */ mr_soft_iic_bus_start(iic->bus); mr_soft_iic_bus_send(iic->bus, iic->addr << 1); /* send */ while(msg.size) { mr_soft_iic_bus_send(iic->bus,*msg.buffer); ++ msg.buffer; -- msg.size; } /* send iic stop */ mr_soft_iic_bus_stop(iic->bus); } else { /* send iic start and device write cmd */ mr_soft_iic_bus_start(iic->bus); mr_soft_iic_bus_send(iic->bus, iic->addr << 1 | 0x01); /* receive */ while(msg.size) { *msg.buffer = mr_soft_iic_bus_receive(iic->bus, (msg.size == 0)); ++ msg.buffer; -- msg.size; } /* send iic stop */ mr_soft_iic_bus_stop(iic->bus); } /* release iic-bus */ mr_soft_iic_bus_release(iic); return MR_EOK; }
使用示例
/* -------------------- 配置 -------------------- */ /* 創(chuàng)建一條 iic 總線 */ struct mr_soft_iic_bus iic_bus; /* 適配 iic 總線接口 */ void set_clk(mr_uint8_t level) { GPIO_WriteBit(GPIOA,GPIO_Pin_0,level); } void set_sda(mr_uint8_t level) { GPIO_WriteBit(GPIOA,GPIO_Pin_1,level); } mr_uint8_t get_sda(void) { return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1); } /* 配置 iic 總線 */ struct mr_soft_iic_bus iic_bus; iic_bus.set_clk = set_clk; iic_bus.set_sda = set_sda; iic_bus.get_sda = get_sda; iic_bus.lock = MR_UNLOCK; iic_bus.owner = MR_NULL; /* 創(chuàng)建一個(gè) iic 設(shè)備 */ struct mr_soft_iic iic_device; /* 配置 iic 設(shè)備 */ iic_device.addr = 0x31; // iic 設(shè)備地址 /* -------------------- 使用 -------------------- */ int main(void) { /* 需要發(fā)送的數(shù)據(jù) */ mr_uint8_t buffer[10]={0,1,2,3,4,5,6,7,8,9}; /* 初始化 gpio */ GPIO_InitTypeDef GPIO_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 掛載 iic 設(shè)備到 iic 總線 */ mr_soft_iic_attach(&iic_device,&iic_bus); /* 創(chuàng)建 iic 消息 */ struct mr_soft_iic_msg iic_msg; iic_msg.addr = 0x55; // 寫(xiě)入/讀取 地址 iic_msg.buffer = buffer; // 數(shù)據(jù)地址 iic_msg.size = 10; // 數(shù)據(jù)數(shù)量 iic_msg.read_write = IIC_WR; // 只寫(xiě)模式 /* 發(fā)送消息 */ mr_soft_iic_transfer(&iic_device,iic_msg); }
剩余底層代碼位于開(kāi)源代碼中,請(qǐng)下載開(kāi)源代碼。
開(kāi)源代碼倉(cāng)庫(kù)鏈接 gitee.com/chen-fanyi/…
路徑:master/mr-library/ device / mr_soft_iic
請(qǐng)仔細(xì)閱讀README.md ?。。。?!
以上就是C語(yǔ)言軟件iic虛擬總線中間層設(shè)計(jì)詳解的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言軟件iic虛擬總線中間層的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++使用遞歸和非遞歸算法實(shí)現(xiàn)的二叉樹(shù)葉子節(jié)點(diǎn)個(gè)數(shù)計(jì)算方法
這篇文章主要介紹了C++使用遞歸和非遞歸算法實(shí)現(xiàn)的二叉樹(shù)葉子節(jié)點(diǎn)個(gè)數(shù)計(jì)算方法,涉及C++二叉樹(shù)的定義、遍歷、統(tǒng)計(jì)相關(guān)操作技巧,需要的朋友可以參考下2017-05-05基于Matlab實(shí)現(xiàn)嗅覺(jué)優(yōu)化算法的示例代碼
嗅覺(jué)劑優(yōu)化是一種新穎的優(yōu)化算法,旨在模仿氣味分子源尾隨的藥劑的智能行為。本文將利用Matlab實(shí)現(xiàn)這一智能優(yōu)化算法,需要的可以參考一下2022-05-05基于Qt實(shí)現(xiàn)簡(jiǎn)易GIF播放器的示例代碼
這篇文章主要介紹了如何利用Qt設(shè)計(jì)一個(gè)簡(jiǎn)易GIF播放器,可以播放GIF動(dòng)畫(huà)。其基本功能有載入文件、播放、暫停、停止、快進(jìn)和快退,感興趣的可以了解一下2022-06-06C++學(xué)習(xí)之虛函數(shù)表與多態(tài)詳解
這篇文章主要為大家詳細(xì)介紹了C++中虛函數(shù)表與多態(tài)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定的幫助,感興趣的小伙伴可以了解一下2023-03-03C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單計(jì)算器程序
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單計(jì)算器程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02C++11正則表達(dá)式詳解(regex_match、regex_search和regex_replace)
正則表達(dá)式(regular expression)是計(jì)算機(jī)科學(xué)中的一個(gè)概念,又稱(chēng)規(guī)則表達(dá)式,下面這篇文章主要介紹了C++11正則表達(dá)式(regex_match、regex_search和regex_replace)的相關(guān)資料,需要的朋友可以參考下2022-09-09C++基礎(chǔ) class、struct、union詳細(xì)
這篇文章主要 給大家介紹的是C++基礎(chǔ) class、struct、union,主要由三部分組成,分別是、類(lèi)class、結(jié)構(gòu)體struct、共用體union,需要的朋友可以參考一下2021-09-09