.NET Micro Framework 和.NET Compact Framework不同,并不是.NET Framework的子集,而是更貼近硬體底層,它提供了許多諸如GPIO、PWM、SPI、I2C和OneWire等硬體操作類庫。由此可以讓普通的軟體開發人員相對平滑的過度到硬體開發領域,也足以讓以前相對封閉的硬體系統通過二次開發的方式擴充硬體子產品成為一種流行(随着物聯網技術的深入發展,未來軟體不僅需要組态化,硬體其實更需要組态化)。
由于非硬體研發出身,最早接觸I2C接口是在2007年初次接觸.NET Micro Framework的時候,當時并沒有和實際的硬體打交道,而是從軟體層面封裝了一個可以進行I2C總線虛拟通信的模拟器(參見博文《.Net MicroFramework研究—帶I2C總線的模拟器》),後來在2008年為TI DM355的晶片移植.NET Micro Framework,我的任務就是I2C、USB等硬體驅動的開發。在TI DM355上有一個紅外遙控接收器單元(MSP430單片)和DM355通過I2C接口進行通信,進而讓.NET Micro Framework可以接收遙控器的按鍵資訊。
後續在Cortex-M3平台,所接觸的子產品都是SPI接口的,I2C接口的反而沒有,是以相關接口一直沒有調試。最近有一個客戶在使用物聯網智能網關時候,發現引出的IO不夠,需要擴充幾路AD,推薦了一個基于PCF8591晶片的AD/DA轉換子產品,是以我才得以再次深入研究I2C接口。
如下是.NET Micro Framework的I2C接口類庫:
public class I2CDevice : IDisposable
{
public I2CDevice.ConfigurationConfig;
protectedbool m_disposed;
publicI2CDevice(I2CDevice.Configurationconfig);
public static I2CDevice.I2CReadTransaction CreateReadTransaction(byte[] buffer);
public static I2CDevice.I2CWriteTransaction CreateWriteTransaction(byte[] buffer);
public void Dispose();
public int Execute(I2CDevice.I2CTransaction[] xActions, int timeout);
public class Configuration
{
publicreadonly ushortAddress;
publicreadonly intClockRateKhz;
publicConfiguration(ushort address, int clockRateKhz);
}
public sealed class I2CReadTransaction : I2CDevice.I2CTransaction{}
public class I2CTransaction
{
publicreadonly byte[]Buffer;
protectedI2CTransaction(byte[] buffer);
}
public sealed class I2CWriteTransaction : I2CDevice.I2CTransaction{}
}
I2C的讀寫操作通過定義I2CDevice.I2CTransaction數組,可以實作批量操作。
物聯網智能網關基于STM32F207/STM32F407晶片,其I2C接口即支援主模式也支援從模式(I2C接口類僅支援主模式),總線速度支援兩種,标準速度(高達100KHz)和快速(400KHz),I2C位址支援7位和10位兩種(驅動隻支援7位位址)。
PCF8591晶片是8位A/D和D/A轉換器,4路模拟輸入,1路模拟輸出。其I2C位址是可以進行硬體編碼的(3個位址引腳A0、A1和A2),其位址編碼規則如下:

對I2C來說,一般讀操作的時候位址的最低位為1,寫操作的時候位址的最低位為0。我們選用的子產品,看原理圖可知,A2、A1和A0管腳都被直接連接配接到GND,是以這部分都是0,是以對讀位址來說是0x91,寫位址是0x90。.NET Micro Framework底層I2C驅動實作的時候,位址會自動左移,最低位是不算位址的一部分的(是以才說是7位位址支援),是以我們在填寫I2C子產品位址的時候,要填寫的是讀位址(或寫位址)右移一位的數字,也就是0x48。
總線頻率我們理論上可以選擇10K到400K,這裡我們選擇100K。
下面我們詳細介紹一下PCF8591是如何進行AD讀取和DA輸出的。
讀AD操作:
寫DA操作
控制字的定義如下:
對AD0~AD3通道來說,我們常用的控制字的值為0x0,0x1,0x2,0x3。
對DA來說,我們常用的控制字的值為0x40。
注意:如果我們循環讀取AD0至AD3,由于讀周期讀取的AD轉換值,其實是上一次的轉換結果,是以我們讀取AD1的時候,其實是讀取的AD0,依次類推(上電第一次讀取的值是0x80)。
有了以上知識,我們就可以進行程式設計了,核心代碼如下:
public static void Main()
{
I2CDeviceI2CBus = new I2CDevice(new I2CDevice.Configuration(0x48, 100));
byte[]bytAD = new byte[4];
bytebytDA = 0;
while(true)
{
for(byte i = 0; i < 4; i++)
{
byte[]bytWData = new byte[1]{ i };
byte[]bytRData = new byte[1];
I2CDevice.I2CTransaction[] i2c = newI2CDevice.I2CTransaction[2];
i2c[0] = I2CDevice.CreateWriteTransaction(bytWData);
i2c[1] = I2CDevice.CreateReadTransaction(bytRData);
I2CBus.Execute(i2c, 100);
bytAD[i - 1 < 0 ? 3 : i- 1] = bytRData[0];
}
Debug.Print("AD0=" + ShowData(bytAD[0]) + " AD1=" + ShowData(bytAD[1]) + " AD2=" + ShowData(bytAD[2]) + " AD3=" + ShowData(bytAD[3]));
byte[]bytWData1 = new byte[2]{ 0x40, bytDA };
I2CDevice.I2CTransaction[] i2c1 = newI2CDevice.I2CTransaction[1];
i2c1[0] = I2CDevice.CreateWriteTransaction(bytWData1);
I2CBus.Execute(i2c1, 100);
Debug.Print("DA0=" + ShowData(bytDA));
bytDA += 10;
Thread.Sleep(1000);
}
}
PCF8591子產品和物聯網智能網關接線有四根,分别是VCC、GND、SCL和SDA,VCC可以接5V或3.3V(我們接3.3V)、SCL接PB6,SDA接PB7。程式部署運作的效果圖如下:
通過旋轉子產品的上的模拟開關,我們會發現AD3的值可以由0向255變化。
注意:為了正常運作本執行個體,物聯網智能網關固件版本需要更新到V1.7.15以上,TinyBooter也需要同步更新。
固件下載下傳位址:
http://www.sky-walker.com.cn/MFRelease/firmware/MFv42_YF_Wisteria207.rar----------------------------------------------------
源碼下載下傳:
http://www.sky-walker.com.cn/MFRelease/Sample/PCF859IT_I2C.rarMF簡介:
http://blog.csdn.net/yefanqiu/article/details/5711770MF資料:
http://www.sky-walker.com.cn/News.asp?Id=25