Взаимодействие с приборами и устройствами на уровне протокола, а также на физическом уровне. Используйте функцию I2C панели инструментов управления приборами для связи с датчиком температуры TMP102 и одновременно проанализируйте связь физического уровня I2C шины с помощью функции цифрового ввода-вывода с синхронизацией панели инструментов сбора данных.
Требуются инструментарий сбора данных и инструментарий управления приборами.
Может использоваться любое поддерживаемое устройство National Instruments™ DAQ с синхронизированными каналами DIO (например, NI Elvis II)
Адаптер хоста TotalPhase Aardvark I2C/SPI
TMP102 Цифровой датчик температуры с двухпроводным последовательным интерфейсом
Для TMP102 требуется источник питания 3,3 В. Используйте линейный LDO (LP2950-33) для генерации питания 3,3 В из линии питания 5 В устройства DAQ.
Альтернативные варианты включают в себя:
Используйте внешний источник питания.
Используйте аналоговый выходной канал устройства DAQ.

Подключите датчик и проверьте связь с ним с помощью объекта I2C из панели инструментов управления приборами.
aa = instrhwinfo('i2c', 'aardvark'); % Get information about connected I2C hosts tmp102 = i2c('aardvark',0,hex2dec('48')); % Create an I2C object to connect to the TMP102 tmp102.PullupResistors = 'both'; % Use host adaptor pull-up resistors fopen(tmp102); % Open the connection data8 = fread(tmp102, 2, 'uint8'); % Read 2 byte data % One LSB equals 0.0625 deg. C temperature = ... (double(bitshift(int16(data8(1)), 4)) +... double(bitshift(int16(data8(2)), -4))) * 0.0625; % Refer to TMP102 data sheet to calculate temperature from received data fprintf('The temperature recorded by the TMP102 sensor is: %s deg. C\n',num2str(temperature)); fclose(tmp102);
The temperature recorded by the TMP102 sensor is: 27.625 deg. C
Использовать избыточно дискретизированные синхронизированные цифровые каналы от NI Elvis (Dev4) для получения и анализа сообщений физического уровня по шине I2C.
Получение данных SDA на порт 0, линия 0 устройства DAQ. Получение данных SCL для порта 0, линия 1 устройства DAQ.
dd = daq("ni"); addinput(dd,"Dev4","port0\line0","Digital"); % sda addinput(dd,"Dev4","port0\line1","Digital"); % scl
Цифровые подсистемы на устройствах NI DAQ не имеют собственных часов; они должны совместно использовать часы с аналоговой подсистемой или импортировать часы из внешней подсистемы. Генерация 50% тактового цикла при частоте 1 МГц с использованием PulseGeneration и установите частоту сканирования на входе в соответствие.
pgChan = addoutput(dd,"Dev4","ctr1"),"PulseGeneration"); dd.Rate = 1e6; pgChan.Frequency = dd.Rate;
Часы генерируются на контакте 'pgChan.Terminal', обеспечивая синхронизацию с другими устройствами и просмотр часов на осциллографе. Выходной импульсный сигнал счетчика импортируется как тактовый сигнал.
disp(pgChan.Terminal); addclock(dd,"ScanClock","External",["Dev4/" pgChan.Terminal]);
PFI13
Получение данных в фоновом режиме из цифровых линий SDA и SCL.
Запуск сбора данных в фоновом режиме
Запуск операций I2C
Остановить получение данных после завершения I2C операций
start(dd, "continuous"); fopen(tmp102); data8 = fread(tmp102, 2, "uint8"); % One LSB equals 0.0625 deg. C temperature = (double(bitshift(int16(data8(1)), 4)) +... double(bitshift(int16(data8(2)), -4))) * 0.0625; fclose(tmp102); pause(0.1); stop(dd); myData = read(dd, "all");
Warning: Triggers and Clocks will not affect counter output channels.
Постройте график необработанных данных для просмотра полученных сигналов. Обратите внимание, что линии удерживаются на высоком уровне в периоды простоя. В следующем разделе показано, как найти биты условий запуска/остановки и использовать их для выделения областей, представляющих интерес в I2C связи.
figure("Name", "Raw Data"); subplot(2,1,1); plot(myData(:,1)); ylim([-0.2, 1.2]); ax = gca; ax.YTick = [0,1]; ax.YTickLabel = {'Low','High'}; title("Serial Data (SDA)"); subplot(2,1,2); plot(myData(:,2)); ylim([-0.2, 1.2]); ax = gca; ax.YTick = [0,1]; ax.YTickLabel = {'Low','High'}; title("Serial Clock (SCL)");

Извлеките I2C сигналы физического уровня на линиях SDA и SCL.
sda = myData(:,1)'; scl = myData(:,2)';
Найдите все поднимающиеся и падающие границы часов.
sclFlips = xor(scl(1:end-1), scl(2:end)); sclFlips = [1 sclFlips 1]; sclFlipIndexes = find(sclFlips==1);
Вычисление тактовых периодов из тактовых индексов
sclFlipPeriods = sclFlipIndexes(1:end)-[1 sclFlipIndexes(1:end-1)];
При проверке убедитесь, что периоды простоя имеют высокий уровень вероятности нежелательной почты для более чем 100 нас. Поскольку скорость сканирования = 1MS/s, каждый образец представляет 1 нас. idlePeriodIndices указать периоды активности в пределах I2C связи.
idlePeriodIndices = find(sclFlipPeriods>100);
Увеличьте изображение первого периода активности на шине I2C. Для удобства просмотра включите 30 образцов активности простоя в переднюю и конечную часть каждого графика.
range1 = sclFlipIndexes(idlePeriodIndices(1)) - 30 : sclFlipIndexes(idlePeriodIndices(2) - 1) + 30; figure("Name", "I2C Communication Data"); subplot(2,1,1); plot(sda(range1)); ylim([-0.2, 1.2]); ax = gca; ax.YTick = [0,1]; ax.YTickLabel = {'Low','High'}; title("Serial Data (SDA)"); subplot(2,1,2); plot(scl(range1)); ylim([-0.2, 1.2]); ax = gca; ax.YTick = [0,1]; ax.YTickLabel = {'Low','High'}; title("Serial Clock (SCL)");

В качестве простого примера проанализируйте метрики условий запуска и остановки и I2C вычисление скорости передачи битов.
Длительность условия запуска определяется как время, необходимое для снижения вероятности нежелательной почты после снижения ПДД.
Продолжительность состояния остановки определяется как время, необходимое для повышения ПДД после повышения вероятности нежелательной почты.
Скорость передачи битов вычисляется путем изменения времени между 2 возрастающими фронтами синхронизации.
Условие запуска: сначала низкий уровень SDA, затем низкий уровень вероятности нежелательной почты
sclLowIndex = sclFlipIndexes(idlePeriodIndices(1)); sdaLowIndex = find(sda(1:sclLowIndex)==1, 1, "last") + 1; % +1, flip is next value after last high startConditionDuration = (sclLowIndex - sdaLowIndex) * 1/s.Rate; fprintf('sda: %s\n', sprintf('%d ', sda(sdaLowIndex-1:sclLowIndex))); % Indexes point to next change, hence sclLowIndex includes flip to low fprintf('scl: %s\n', sprintf('%d ', scl(sdaLowIndex-1:sclLowIndex))); % subtract 1 from sdaLowIndex to see sda value prior to flip fprintf('Start condition duration: %d sec.\n\n', startConditionDuration); % count 5 pulses, 5 us.
sda: 1 0 0 0 0 0 0 scl: 1 1 1 1 1 1 0 Start condition duration: 5.000000e-06 sec.
Условие остановки: сначала высокий уровень вероятности нежелательной почты, затем высокий уровень ПДД
% flip prior to going into idle is the one we want sclHighIndex = sclFlipIndexes(idlePeriodIndices(2)-1); sdaHighIndex = find(sda(sclHighIndex:end)==1, 1, 'first') + sclHighIndex - 1; stopConditionDuration = (sdaHighIndex - sclHighIndex) * 1/s.Rate; fprintf('sda: %s\n', sprintf('%d ',sda(sclHighIndex-1:sdaHighIndex))); fprintf('scl: %s\n', sprintf('%d ',scl(sclHighIndex-1:sdaHighIndex))); fprintf('Stop condition duration: %d sec.\n\n', stopConditionDuration);
sda: 0 0 0 0 0 0 1 scl: 0 1 1 1 1 1 1 Stop condition duration: 5.000000e-06 sec.
Скорость передачи: Обратное время между 2 растущими краями на линии SCL
startConditionIndex = idlePeriodIndices(1); firstRisingClockIndex = startConditionIndex + 2; secondRisingClockIndex = firstRisingClockIndex + 2; clockPeriodInSamples = sclFlipIndexes(secondRisingClockIndex) - sclFlipIndexes(firstRisingClockIndex); clockPeriodInSeconds = clockPeriodInSamples * 1/s.Rate; bitRate = 1/clockPeriodInSeconds; fprintf('DAQ calculated bit rate = %d; Actual I2C object bit rate = %dKHz\n', ... bitRate,... tmp102.BitRate);
DAQ calculated bit rate = 1.000000e+05; Actual I2C object bit rate = 100KHz
sclFlipIndexes вектор был создан с использованием XOR и, следовательно, содержит как растущие, так и падающие края. Начните с переднего края и используйте шаг два, чтобы пропустить опускающиеся края.
% idlePeriodIndices(1)+1 is first rising clock edge after start condition. % Use a step of two to skip falling edges and only look at rising edges. % idlePeriodIndices(2)-1 is the index of the rising edge of the stop condition. % idlePeriodIndices(2)-3 is the last rising clock edge in the bit stream to be % decoded. bitStream = sda(sclFlipIndexes(idlePeriodIndices(1)+1:2:idlePeriodIndices(2)-3)); fprintf('Raw bit stream extracted from I2C physical layer signal: %s\n\n', sprintf('%d ', bitStream));
Raw bit stream extracted from I2C physical layer signal: 1 0 0 1 0 0 0 1 0 0 0 0 1 1 0 1 1 0 1 0 1 0 0 0 0 0 1
ADR_RW = {'W', 'R'};
ACK_NACK = {'ACK', 'NACK'};
address = bitStream(1:7); % 7 bit address
fprintf('\nDecoded Address: %d%d%d%d%d%d%d(0x%s) %d(%s) %d(%s)\n', ...
address,...
binaryVectorToHex(address),...
bitStream(8),...
ADR_RW{bitStream(8)+1},...
bitStream(9),...
ACK_NACK{bitStream(9)+1});
for iData = 0:1
startBit = 10 + iData*9;
endBit = startBit + 7;
ackBit = endBit + 1;
data = bitStream(startBit:endBit);
fprintf('Decoded Data%d: %s(0x%s) %d(%s)\n', ...
iData+1,...
sprintf('%d', data),...
binaryVectorToHex(data),...
bitStream(ackBit),...
ACK_NACK{bitStream(ackBit)+1});
end
Decoded Address: 1001000(0x48) 1(R) 0(ACK) Decoded Data1: 00011011(0x1B) 0(ACK) Decoded Data2: 10100000(0xA0) 1(NACK)
Два uint8 байты были прочитаны, с использованием fread, из шины I2C в переменную data8. Шестнадцатеричное преобразование этих значений должно соответствовать результатам декодирования шины, показанному выше.
fprintf('Data acquired from I2C object: 0x%s\n', dec2hex(data8)'); fprintf('Temperature: %2.2f deg. C\n\n', temperature);
Data acquired from I2C object: 0x1BA0 Temperature: 27.63 deg. C