加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 一、為什么要用模擬 IIC
    • 二、實(shí)現(xiàn)模擬 IIC 的代碼封裝
    • 三、實(shí)現(xiàn)模擬 IIC 的簡要說明
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

I2C 驅(qū)動及其 Checksum在 BMS系統(tǒng)中的應(yīng)用

02/27 08:52
3611
閱讀需 11 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

各位好,從今天開始,我的 BMS 電池保護(hù)板系列開始聊一下軟件相關(guān)的話題。

首先要關(guān)注的,就是我們的主控芯片如何控制 AFE,如何從 AFE 中讀取到想要的信息,這就離不開 AFE 的通信接口。

AFE 的通信接口有很多種類,比如 Uart,IIC,SPI 等。其中 Uart 不多見,以 IIC 和 SPI 最為常見,因?yàn)檫@兩個(gè)通信協(xié)議是板級通信中最常用的,邏輯簡單,線路少。SPI 有一種菊花鏈模式,這個(gè)模式在分布式 BMS 系統(tǒng)中使用普遍,基本各個(gè)AFE 廠家都設(shè)計(jì)了相應(yīng)的隔離芯片,有保障他們的AFE 可以被更好得使用。我的 Demo 中選擇的 AFE的通信是 IIC 接口,因此這一篇文章主要講述 IIC 的實(shí)現(xiàn)。

一、為什么要用模擬 IIC

在我設(shè)計(jì)的 Demo 中,我選擇了使用 IO 口來模擬 IIC 總線,這種選擇經(jīng)歷了很久的思考。首先,這個(gè)行業(yè)的伙伴都應(yīng)該了解,早期的 STM32F1 系列 MCU,在 IIC 的硬件設(shè)計(jì)上出現(xiàn)過 bug,在中斷打斷 IIC 的時(shí)候會導(dǎo)致 IIC 總線無端掛起,或者有些標(biāo)志位無法置位,這是選擇模擬 IIC 的最初的原因。

隨后,經(jīng)過幾個(gè)項(xiàng)目的磨煉,這個(gè) IIC 使用模擬 IO 實(shí)現(xiàn)還是非選不可的,原因如下:

    在 BMS 項(xiàng)目中,MCU 并不需要特別快速的運(yùn)行,因?yàn)榭焖夙憫?yīng)的過流保護(hù)短路保護(hù)都有 AFE 的硬件直接操作,而讀取 AFE 采樣的數(shù)據(jù)也不需要很頻繁,想想,AFE 的 ADC 普遍的采樣頻率才 5Hz。從多陣列產(chǎn)品開發(fā)的角度,我們經(jīng)常會遇到更換 MCU 的情況,原因不乏成本,缺貨,或者看原廠不順眼等。那么如果使用硬件的 IIC 模式,面對各家的 MCU 的外設(shè)驅(qū)動,還需要一定的學(xué)習(xí)成本和移植風(fēng)險(xiǎn),所以模擬的 IIC 總線直接使用兩個(gè) IO 口和一個(gè)簡單的延時(shí)函數(shù)即可。

當(dāng)然,硬件 IIC 是有一定的好處的,除了通信的可靠性和容錯(cuò)性外,相對于模擬 IIC 最大的好處是,在單字節(jié)接收的過程中,我們可以利用中斷來讓 MCU 干些其他事情,也僅此而已。所以,如果你的系統(tǒng)運(yùn)行頻率很高,CPU 負(fù)荷比較高的情況下,肯定首選硬件 IIC。

二、實(shí)現(xiàn)模擬 IIC 的代碼封裝

封裝一個(gè)代碼,首先要將模塊的功能抽象出來,確定模塊的輸入輸出邏輯,從而確定如何封裝代碼成一個(gè)通用的庫,或者說利于移植的模塊。我個(gè)人在這一塊有一個(gè)整體的思路,就是按照 C++的面向?qū)ο缶幊趟枷雭硪?guī)劃這個(gè)類,雖然 C 無法寫成類的形式,但是大體的封裝思想是可以實(shí)現(xiàn)的。

首先我們確定,要模擬 IIC 通信總線,需要兩個(gè) IO,這兩個(gè) IO 的通信速率不必太高,因?yàn)?IIC 一般的通信速率才 400Khz,現(xiàn)在有一些 1Mhz 的。其次,我們需要一個(gè)延時(shí)函數(shù),來控制總線的時(shí)鐘延時(shí),這個(gè)延時(shí)最好使用定時(shí)器來實(shí)現(xiàn),這樣可以調(diào)整出比較好的 IIC 波形,但是這樣會引入一個(gè)復(fù)雜的 TIMER 模塊,因此我選擇了代碼延時(shí),只需要確定好主時(shí)鐘調(diào)試一次即可。有了上面的兩個(gè) IO 口和延時(shí)函數(shù),我們就可以通過控制兩個(gè)引腳的高低和時(shí)序來模擬 IIC 通信了。現(xiàn)在,我們已經(jīng)有了足夠的輸入來對模擬 IIC 這個(gè)類進(jìn)行構(gòu)造函數(shù)的編寫。那么,進(jìn)一步的,我們確定 IIC 這個(gè)類的方法和屬性。我們可以把 IIC 總線通信的一些錯(cuò)誤和狀態(tài)作為屬性來定義,可以讓調(diào)用者通過調(diào)用類的屬性來獲取總線的狀態(tài),是空閑,還是忙狀態(tài)。也可以通過屬性來獲取上一次通信的結(jié)果。其次,對于方法就比較明確了,我們需要查詢忙狀態(tài)的方法,需要最基本的向設(shè)備-地址的讀寫操作,然后再在上層實(shí)現(xiàn)多字節(jié)的讀寫操作。

OK,看一下代碼吧

下面是硬件相關(guān)的定義,定義了兩個(gè)引腳和兩個(gè)延時(shí)函數(shù),因?yàn)樵?IIC 通信中,有控制時(shí)鐘的延時(shí)和控制時(shí)序的延時(shí)。

//===========硬件相關(guān)的定義==================================================
#include "cw32l031.h"#include "cw32l031_gpio.h"// I2C的引腳定義#define I2C_SDA_PIN     GPIO_PIN_0#define I2C_SCL_PIN     GPIO_PIN_1
//I2C 的軟件延時(shí),這個(gè)需要根據(jù)系統(tǒng)時(shí)鐘進(jìn)行調(diào)整#define    I2C_DELAY_INIT()        u8 _counter = 0;#define    I2C_DELAY()             for( _counter = 0; _counter < 20;  ) {_counter++; }    //100K 重新測試#define    I2C_DELAY_SHORT()       for( _counter = 0; _counter < 10;  ) {_counter++; }    //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

然后,我們需要定義一些類的屬性,在這里其實(shí)就是一些關(guān)于通信模塊的設(shè)置,比如通信的重發(fā)嘗試次數(shù),比如 IIC 總線的狀態(tài)和錯(cuò)誤標(biāo)志等,這里我們直接使用宏定義來設(shè)定,沒有在提供變量給調(diào)用者進(jìn)行實(shí)例化的時(shí)候進(jìn)行構(gòu)建,因?yàn)檫@在 C語言中就相當(dāng)于脫褲子放屁。

//===============IIC 軟件層相關(guān)(2023.11.11整理)======================================// I2C的一些錯(cuò)誤宏定義#define    I2C_SUCCESS                 0#define    I2C_ARBITRATION_LOST        0x11#define    I2C_NACK                    0x12#define    I2C_TIMEOUT                 0x13#define    I2C_WRITEFAIL               0x14#define    I2C_CRC                     0x15#define    I2C_OTHER                   0x16

#define    I2C_MAX_ATTEMPTS            1000   //嘗試次數(shù)

最后,我們需要給調(diào)用者提供一個(gè)可以調(diào)用的列表,從類的角度看,無非就是構(gòu)造函數(shù),析構(gòu)函數(shù)和幾個(gè)方法屬性。這里我們只有一個(gè)充當(dāng)構(gòu)造函數(shù)的初始化函數(shù)和兩個(gè)方法:讀方法和寫方法。

// I2C對外接口的聲明void i2c_init(void); //I2C的初始化函數(shù)
//多字節(jié)的讀寫u8 i2c_write(u8 addr, u8 reg_addr, u8* txBuff, int count);u8 i2c_read( u8 addr, u8 reg_addr, u8* rxBuff, int count);

好啦,有了以上的一個(gè)頭文件,我們就可以使用這個(gè) IIC 模塊,使用的步驟很簡單,先確定 IO 口,然后確定延時(shí)函數(shù),最后在我們的初始化過程中將 i2c_init()調(diào)用一下,就可以在我們的系統(tǒng)中使用讀寫方法了。我建了一個(gè)微信群,供大家來討論 BMS 相關(guān)技術(shù),為了保證討論質(zhì)量,請先加我的個(gè)人微信,備注 “BMS” ,我來拉大家入群。

三、實(shí)現(xiàn)模擬 IIC 的簡要說明

當(dāng)我們定義好模擬 IIC 模塊的外觀后,也就是對外接口后,我們就需要思考如何在這個(gè)封裝層下來實(shí)現(xiàn)邏輯,其實(shí)這是一種自頂向下的設(shè)計(jì)模式。咱們先把 IO 的拉高拉低變換成總線上的一些狀態(tài),對于 SCL 引線還好,他負(fù)責(zé)產(chǎn)生時(shí)鐘,可以直接拉高拉低,而對于 SDA 引線就稍微復(fù)雜一些,因?yàn)樗丝梢岳呃偷妮敵鐾?,還需要從總線上讀取電平。

GPIO_TypeDef* m_I2C_PORT = CW_GPIOA; //定義I2C的IO指針,默認(rèn)為GPIOB
//I2C的一些信號狀態(tài),不同的硬件需要重新定義#define i2cSetSDA_highZ()    (m_I2C_PORT->ODR |= I2C_SDA_PIN)#define i2cGetSDA()          ((m_I2C_PORT->IDR & I2C_SDA_PIN) ? 1 : 0)#define i2cSetSCL_highZ()    (m_I2C_PORT->ODR |= I2C_SCL_PIN)#define i2cGetSCL()          ((m_I2C_PORT->IDR & I2C_SCL_PIN) ? 1 : 0)#define i2cClearSDA()        (m_I2C_PORT->ODR &= (~I2C_SDA_PIN))#define i2cClearSCL()        (m_I2C_PORT->ODR &= (~I2C_SCL_PIN))

以上,我們將 IO 的狀態(tài)轉(zhuǎn)換成了 IIC 總線上的多態(tài)端口。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險(xiǎn)等級 參考價(jià)格 更多信息
ADG1211YRUZ 1 Rochester Electronics LLC QUAD 1-CHANNEL, SGL POLE SGL THROW SWITCH, PDSO16, LEAD FREE, MO-153-AB, TSSOP-16
$5.96 查看
AD8361ARMZ 1 Analog Devices Inc LF to 2.5 GHz TruPwr&trade; Detector

ECAD模型

下載ECAD模型
$10.05 查看
LSM6DS33TR 1 STMicroelectronics iNEMO 6DoF inertial measurement unit (IMU), for consumer electronics

ECAD模型

下載ECAD模型
$2.48 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

多年硬件從業(yè)經(jīng)驗(yàn),專注分享從研發(fā)到供應(yīng)鏈,再到精益制造過程中的經(jīng)驗(yàn)和感悟!