与协议层以及物理层的仪器和设备进行通信。利用仪器控制工具箱的I2C特性与TMP102温度传感器通信,同时利用数据采集工具箱的时钟数字IO特性分析物理层I2C总线通信。
需要数据采集工具箱和仪器控制工具箱。
任何支持金宝app的国家仪器™DAQ设备都可以使用带时钟的DIO通道(例如,Ni Elvis II)
TotalPhase Aardvark I2C/SPI主机适配器
TMP102数字温度传感器,两线串行接口
TMP102需要3.3 V电源。使用线性LDO (LP2950-33)从DAQ设备的5v电源线生成3.3 V电源。
其他选项包括:
使用外部电源。
使用DAQ设备的模拟输出通道。
连接传感器并使用仪器控制工具箱中的I2C对象验证与它的通信。
aa = instrhwinfo (“i2c”,“豚”);%获取已连接的I2C主机信息tmp102 = i2c (“豚”0 hex2dec (48岁的));%创建连接到TMP102的I2C对象tmp102。PullupResistors =“两个”;%使用主适配器上拉电阻fopen (tmp102);%打开连接data8 = fread(tmp102,2,“uint8”);%读取2字节数据%一个LSB等于0.0625°。C温度=...(双(bitshift (int16 (data8 (1)), 4)) +...双(BitsHift(INT16(DATA8(2)),-4)))* 0.0625;%根据收到的数据计算温度,请参阅TMP102数据表流(TMP102传感器记录的温度为:%s deg. C\n'num2str(温度));文件关闭(tmp102);
TMP102传感器记录的温度为:27.625℃
使用NI Elvis的过采样时钟数字通道(Dev4
)来获取和分析I2C总线上的物理层通信。
在数据采集设备的0行0端口上获取SDA数据。在DAQ设备的第1行端口0上获取SCL数据。
dd =采集(“倪”);addinput (dd,“dev4”,“port0 \ line0”,“数字”);%SDA.addinput (dd,“dev4”,“port0 \ line1”,“数字”);%scl.
NI DAQ设备上的数字子系统没有自己的时钟;它们必须与模拟子系统共享时钟,或者从外部子系统导入时钟。产生50%占空比时钟在1 MHz使用PulseGeneration
计数器输出,并设置输入扫描速率匹配。
pgchan = addoutput(dd,“dev4”,“ctr1”),“脉冲变量”);dd.Rate = 1 e6;pgChan。频率= dd.Rate;
时钟在pgChan上生成。终端引脚,允许与其他设备同步,并在示波器上查看时钟。计数器输出脉冲信号作为时钟信号输入。
disp (pgChan.Terminal);addclock (dd,“ScanClock”,“外部”,[“dev4 /”pgChan.Terminal]);
PFI13
在后台从SDA和SCL数字线路获取数据。
在后台模式下启动DataAcquisition
启动I2C操作
I2C操作完成后,停止DataAcquisition
开始(dd,“连续”);fopen (tmp102);data8 = fread(tmp102,2,“uint8”);%一个LSB等于0.0625°。C温度= (double(bitshift(int16(data8(1)), 4)) +...双(BitsHift(INT16(DATA8(2)),-4)))* 0.0625;文件关闭(tmp102);暂停(0.1);停止(DD);mydata =读(DD,“全部”);
警告:触发器和时钟不会影响计数器输出通道。
绘制原始数据以查看所获取的信号。请注意,在空闲时段内,线路仍然很高。下一节显示如何查找开始/停止条件位并使用它们隔离I2C通信中的感兴趣区域。
图(“姓名”,“原始数据”);次要情节(2,1,1);绘图(MyData(:,1));ylim ([-0.2, 1.2]);甘氨胆酸ax =;ax.ytick = [0,1];ax.yticklabel = {“低”,“高”};标题(“串行数据(SDA)”);次要情节(2,1,2);情节(myData (:, 2));ylim ([-0.2, 1.2]);甘氨胆酸ax =;ax.ytick = [0,1];ax.yticklabel = {“低”,“高”};标题(“串行时钟(sci)”);
提取SDA和SCL线路上的I2C物理层信号。
sda = mydata(:,1)';scl = mydata(:,2)';
找出所有上升和下降的时钟边缘。
sclFlips = xor(scl(1:end-1), scl(2:end));sclFlips = [1 sclFlips 1];sclFlipIndexes =找到(sclFlips = = 1);
从时钟指数计算时钟周期
sclFlipPeriods = sclFlipIndexes(1:end-1) -[1 sclFlipIndexes(1:end-1)];
通过检查,观察到闲置期间SCL高超过100 us。由于扫描速率= 1MS/s,每个样品代表1个us。idlePeriodIndices
表示I2C通信中活动的周期。
idlePeriodIndices =找到(sclFlipPeriods > 100);
放大I2C总线上的第一期活动。为了便于观察,将30个空闲活动样本包含在每个图的前部和末端。
range1 = sclFlipIndexes(idlePeriodIndices(1)) - 30: sclFlipIndexes(idlePeriodIndices(2) - 1) + 30;图(“姓名”,“I2C通信数据”);次要情节(2,1,1);情节(sda (range1));ylim ([-0.2, 1.2]);甘氨胆酸ax =;ax.ytick = [0,1];ax.yticklabel = {“低”,“高”};标题(“串行数据(SDA)”);次要情节(2,1,2);情节(sci (range1));ylim ([-0.2, 1.2]);甘氨胆酸ax =;ax.ytick = [0,1];ax.yticklabel = {“低”,“高”};标题(“串行时钟(sci)”);
作为一个简单的例子,分析启动和停止条件度量和I2C比特率计算。
启动条件持续时间定义为SDA降低后SCL降低所需的时间。
停止条件持续时间定义为SCL升高后SDA升高所花费的时间。
比特率是通过取两个上升时钟边缘之间的时间的倒数来计算的。
启动条件:先SDA低,再SCL低
sclLowIndex = sclFlipIndexes (idlePeriodIndices (1));sdaLowIndex = find(sda(1:sclLowIndex)== 1,1,“最后一次”) + 1;% +1,翻转是最后一个高之后的下一个值startConditionDuration = (sclLowIndex - sdaLowIndex) * 1/s.Rate;流(“sda: % s \ n”sprintf ('%d',SDA(SdalowIndex-1:ScllowIndex))));%索引指向下一个变化,因此sclLowIndex包括翻转到低流('scl:%s \ n'sprintf ('%d'sci (sdaLowIndex-1: sclLowIndex)));%从sdaLowIndex中减去1以查看翻转前的sda值流('开始条件持续时间:%d sec。\ n \ n',StartConditionDuration);%数5次脉冲,5次脉冲。
sda: 1 00000 scl: 1 1 1 1 1 1 0启动条件持续时间:5.000000e-06秒。
停止条件:先SCL高,然后SDA高
进入idle之前的% flip是我们想要的sclHighIndex = sclFlipIndexes (idlePeriodIndices (2) 1);sdaHighIndex = sda(sclHighIndex:end)== 1,1,“第一”) + sclHighIndex - 1;stopConditionDuration = (sdaHighIndex - sclHighIndex) * 1/s.Rate;流(“sda: % s \ n”sprintf ('%d'sda (sclHighIndex-1: sdaHighIndex)));流('scl:%s \ n'sprintf ('%d'sci (sclHighIndex-1: sdaHighIndex)));流('停止条件持续时间:%d秒\n\n', stopConditionDuration);
sda: 00000 1 scl: 0 1 1 1 1 1 1停止条件持续时间:5.000000e-06秒
比特率:SCL线上两个上升边之间的时间的倒数
startConditionIndex = idlePeriodIndices (1);firstRisingClockIndex = startConditionIndex + 2;second drisingclockindex = firstRisingClockIndex + 2;clockPeriodInSamples = sclFlipIndexes(secondRisingClockIndex) - sclFlipIndexes(firstRisingClockIndex);clockPeriodInSeconds = clockPeriodInSamples * 1/s rate;比特率= 1 / clockPeriodInSeconds;流('DAQ计算比特率= %d;实际I2C对象比特率= %dKHz\n',...比特率,...tmp102.bitrate);
DAQ计算比特率= 1.000000e+05;实际I2C对象比特率= 100KHz
的sclFlipIndexes
矢量是使用异或创建的,因此包含上升和下降边缘。从上升边开始,用两步跳过下降边。
% idlePeriodIndices(1)+1是启动条件后的第一个上升时钟边。用两步跳过下降边,只看上升边。%IdlePiodIndics(2)-1是停止条件的上升沿的索引。% idlePeriodIndices(2)-3是位流中最后一个上升的时钟边缘%解码。Bitstream = SDA(SCLFLIPINDEXES(IDLEPEIDINDICES(1)+1:2:IDLEPEIDINDICES(2)-3));流('从I2C物理层信号提取的原始比特流:%s\n\n'sprintf ('%d'比特流));
从I2C物理层信号提取的原始比特流:1 0 0 1 0 0 1 0 0 1 1 0 1 1 0 1 1 0 1 0 0 1
adr_rw = {' W ',“R”};ACK_NACK = {'ACK',“纳”};地址=比特流(1:7);%7位地址流(“\ nDecoded地址:% d % d % d % d % d % d % d (0 x % s) % d (% s) % d (% s) \ n ',...地址,...binaryvectortohex(地址),...比特流(8),...ADR_RW{比特流(8)+ 1},...比特流(9),...ACK_NACK{比特流(9)+ 1});为iData = 0:1 startBit = 10 + iData*9;endBit = startBit + 7;ackBit = endBit + 1;data =比特流(startBit: endBit);流('解码数据%d: %s(0x%s) %d(%s)\n',...iData + 1,...sprintf ('%d'数据),...BinaryVectortohex(数据),...比特流(Ackbit),...ACK_NACK{比特流(ackBit) + 1});结束
Decoded Address: 1001000(0x48) 1(R) 0(ACK) Decoded Data1: 00011011(0x1B) 0(ACK) Decoded Data2: 10100000(0xA0) 1(NACK)
两个uint8
字节被读取,使用从文件中读
,从I2C总线进入变量data8
.这些值的十六进制转换应该与上面显示的总线解码的结果相匹配。
流('从I2C对象获取的数据:0x%s\n'dec2hex (data8) ');流(温度:%2.2f deg. C\n\n'、温度);
从I2C对象获取的数据:0x1BA0温度:27.63℃