Логический анализатор выполнен на основе микроконтроллера STM32F103C8T6 (отладочная плата), вся информация выводится на TFT-дисплей SPI 320×240 (ILI9341C). Максимальное напряжение подаваемое на входы порта PB8-PB15 STM32F103C8T6 не должно превышать 5 В.
Логический анализатор позволяет отслеживать логическое состояние по 8-и каналом одновременно, а так же измерять временные параметры импульсов. Частотный диапазон от единиц герц до 400 кГц. Память на 3200 точек измерения (10 разверток экрана).
Анализатор имеет три режима работы:
- AUTO — автоматический режим синхронизации по кану № 0 (PB8)
- START_1 — режим ожидания, при появлении на входе № 0 лог. 1, анализатор производит один цикл измерения.
- START_0 — режим ожидания, при появлении на входе № 0 лог. 0, анализатор производит один цикл измерения.
Управление логическим анализатором осуществляется 5-ю кнопками:
- HOLD — остановка измерения, вывод на экран текущей информации, перезапуск измерения в режиме START_1 и START_0.
- SET — переключение режимов AUTO, START_1, START_0.
- UP и DOWN :
- выбор длительности развертки в режиме AUTO
- перемещение изображения импульсов в режиме HOLD по горизонтали
- SET_CURSOR — обнуление показаний измерителя временных интервалов.
Измерительный курсор (красная полоса) позволяющий оценивать логическое состояние одновременно по 8-и каналам (вывод на экран лог. состояния в двоичной и шестнадцатеричной системы счисления), курсор активен в режимах AUTO, START_1 и START_0, перемещение импульсов по горизонтали осуществляется кнопками UP и DOWN. Так при нажатии кнопки SET_CURSOR происходит обнуление показаний измерителя временных интервалов.
Сигналы шины I2C 100 кГц |
Сигналы шины I2C 100 кГц при минимальной длительности развертки |
Сигнал управления RGB (W2812) ленты 800 кГц |
Сигналы шины I2C 400 кГц при минимальной длительности развертки |
#include <SPI.h> #include <Adafruit_GFX_AS.h> // http://rcl-radio.ru/wp-content/uploads/2020/06/Adafruit_GFX.zip #include <Adafruit_ILI9341_STM.h> #include <EEPROM.h> #define TFT_CS PA0 #define TFT_DC PA1 #define TFT_RST PA2 // MOSI PA7 // SCK PA5 Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); byte data[3200],data_old[3200]; bool stopp=0; unsigned long times; int i,i2,i3,razv,delays,hh; byte w=1,w1,st,x,z,mn=8,sett; void setup() { Serial.begin(9600); EEPROM.init(0x801F000,0x801F800,0x400);// 1024 byte pinMode(PA3,INPUT_PULLUP);// HOLD pinMode(PB0,INPUT_PULLUP);// +++ pinMode(PB1,INPUT_PULLUP);// --- pinMode(PA4,INPUT_PULLUP);// SET pinMode(PB4,INPUT_PULLUP);// SET_CURSOR tft.begin();tft.setRotation(1);tft.fillScreen(ILI9341_BLACK); polos(); tft.setCursor(180, 5);tft.print("LOGIC ANALYZER"); tft.setCursor(180, 20);tft.print("RCL-RADIO.RU"); GPIOB-> regs-> CRH = 0x88888888; // INPUT PB8...PB15 razv = EEPROM.read(0); } void loop() { ////////// SET if(digitalRead(PA4)==LOW){sett++;w=1;w1=1;stopp=0;if(sett>2){sett=0;}delay(200);tft.fillRect(50,0,65,8,ILI9341_BLACK);polos();cif();tft.fillRect(50,10,80,25,ILI9341_BLACK);} //////////////////// HOLD ON OFF /////////////////////////////////////////// if(digitalRead(PA3)==LOW&&stopp==0){stopp=1;w1=1;polos();cif();tft.fillRect(50,10,80,25,ILI9341_BLACK);delay(300);i2=0;} if(digitalRead(PA3)==LOW&&stopp==1){stopp=0;w1=1;polos();cif();tft.fillRect(50,10,80,25,ILI9341_BLACK);delay(300);i2=0;} if(digitalRead(PB0)==LOW&&stopp==1){i2++;w1=1;if(i2>2880){i2=2880;}delay(1);} if(digitalRead(PB1)==LOW&&stopp==1){i2--;w1=1;if(i2<0){i2=0;}delay(1);} if(digitalRead(PB4)==LOW){i3=i2;w1=1;delay(200);} if(stopp==1&&w1==1){ tft.fillRect(0,10,60,8,ILI9341_BLACK);tft.setCursor(0, 10); //if(digitalRead(PB4)==LOW){i3=i2;delay(200);} if(((float)times/10/mn/320*mn)*(i2-i3)>1000){tft.print(((float)times/10000/mn/320*mn)*(i2-i3),1);tft.print(" mS ");} else{tft.print(((float)times/10/mn/320*mn)*(i2-i3),1);tft.print(" uS ");} } if(stopp==0){tft.fillRect(0,10,65,8,ILI9341_BLACK);} if(stopp==1){tft.fillRect(i2/10,235,4,3,ILI9341_BLACK);tft.fillRect(i2/10+2,235,30,3,ILI9341_GREEN);tft.fillRect(i2/10+32,235,4,3,ILI9341_BLACK);} if(stopp==0&&w1==1){tft.fillRect(0,235,320,3,ILI9341_BLACK);} tft.setCursor(0, 25); if(stopp==0){tft.fillRect(295,0,25,8,ILI9341_BLACK);tft.fillRect(0,25,65,8,ILI9341_BLACK);}else{tft.print("HOLD");} ///// SET = 0 ////////////////////////////////////////////////////////////// if(digitalRead(PB0)==LOW&&stopp==0){razv++;w=1;if(razv>12){razv=12;}EEPROM.update(0,razv);delay(300);} if(digitalRead(PB1)==LOW&&stopp==0){razv--;w=1;if(razv<0){razv=0;}EEPROM.update(0,razv);delay(300);} switch(razv){ case 0: mn=1;delays=500;break; case 1: mn=1;delays=200;break; case 2: mn=1;delays=100;break; case 3: mn=1;delays=50;break; case 4: mn=1;delays=25;break; case 5: mn=1;delays=12;break; case 6: mn=1;delays=5;break; case 7: mn=1;delays=2;break; case 8: mn=1;delays=1;break; case 9: mn=1;delays=0;break; case 10: mn=2;delays=0;break; case 11: mn=4;delays=0;break; case 12: mn=8;delays=0;break; } sinhr(); ///////////// измерение ////////////////////////// if(stopp==0&&delays>0){ times=micros(); i=0;while(i<3200){i++;delay_us(delays);data[i] = (GPIOB-> regs-> IDR & 0b1111111100000000) >> 8;} times=micros()-times;} if(stopp==0&&delays==0){ times=micros(); i=0;while(i<3200){i++;data[i] = (GPIOB-> regs-> IDR & 0b1111111100000000) >> 8;} times=micros()-times;} if(sett>0){stopp=1;} ////////////// end //////////////////////////////// if(w==1){w=0;polos(); tft.fillRect(0,0,65,8,ILI9341_BLACK);tft.setCursor(0, 0); if(times/10/mn>1000){tft.print((float)times/10/mn/1000,2);tft.print(" mS ");} else{tft.print((float)times/10/mn,1);tft.print(" uS ");} cif(); tft.setCursor(65, 0); if(sett==0){tft.print("AUTO ");} if(sett==1){tft.print("START_1");} if(sett==2){tft.print("START_0");} } i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 55-((data_old[i]>>0)&1)*15,i*mn-x, 55-((data_old[i+z]>>0)&1)*15, 0x000F); tft.drawLine(i*mn-x, 55-((data[i+i2]>>0)&1)*15,i*mn-x, 55-((data[i+z+i2]>>0)&1)*15, ILI9341_WHITE);}} i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 80-((data_old[i]>>1)&1)*15,i*mn-x, 80-((data_old[i+z]>>1)&1)*15, 0x000A); tft.drawLine(i*mn-x, 80-((data[i+i2]>>1)&1)*15,i*mn-x, 80-((data[i+z+i2]>>1)&1)*15, ILI9341_WHITE);}} i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 105-((data_old[i]>>2)&1)*15,i*mn-x, 105-((data_old[i+z]>>2)&1)*15, 0x000F); tft.drawLine(i*mn-x, 105-((data[i+i2]>>2)&1)*15,i*mn-x, 105-((data[i+z+i2]>>2)&1)*15, ILI9341_WHITE);}} i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 130-((data_old[i]>>3)&1)*15,i*mn-x, 130-((data_old[i+z]>>3)&1)*15, 0x000A); tft.drawLine(i*mn-x, 130-((data[i+i2]>>3)&1)*15,i*mn-x, 130-((data[i+z+i2]>>3)&1)*15, ILI9341_WHITE);}} i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 155-((data_old[i]>>4)&1)*15,i*mn-x, 155-((data_old[i+z]>>4)&1)*15, 0x000F); tft.drawLine(i*mn-x, 155-((data[i+i2]>>4)&1)*15,i*mn-x, 155-((data[i+z+i2]>>4)&1)*15, ILI9341_WHITE);}} i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 180-((data_old[i]>>5)&1)*15,i*mn-x, 180-((data_old[i+z]>>5)&1)*15, 0x000A); tft.drawLine(i*mn-x, 180-((data[i+i2]>>5)&1)*15,i*mn-x, 180-((data[i+z+i2]>>5)&1)*15, ILI9341_WHITE);}} i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 205-((data_old[i]>>6)&1)*15,i*mn-x, 205-((data_old[i+z]>>6)&1)*15, 0x000F); tft.drawLine(i*mn-x, 205-((data[i+i2]>>6)&1)*15,i*mn-x, 205-((data[i+z+i2]>>6)&1)*15, ILI9341_WHITE);}} i=10/mn;while(i<320){i++; for(x=0;x<mn;x++){if(x==0){z=1;}else{z=0;} tft.drawLine(i*mn-x, 230-((data_old[i]>>7)&1)*15,i*mn-x, 230-((data_old[i+z]>>7)&1)*15, 0x000A); tft.drawLine(i*mn-x, 230-((data[i+i2]>>7)&1)*15,i*mn-x, 230-((data[i+z+i2]>>7)&1)*15, ILI9341_WHITE);}} i=0;while(i<3199){i++;data_old[i]=data[i+i2];} if(stopp==1&&w1==1){w1=0; tft.fillRect(50,10,75,25,ILI9341_BLACK); if(mn<=2){tft.setCursor(65, 10);tft.print("0B");tft.print(data[i2+60/mn],BIN);} if(mn>2){tft.setCursor(65, 10);tft.print("0B");tft.print(data[i2+60/mn+1],BIN);} if(mn<=2){tft.setCursor(65, 25);tft.print("0X");tft.print(data[i2+60/mn],HEX);} if(mn>2){tft.setCursor(65, 25);tft.print("0X");tft.print(data[i2+60/mn+1],HEX);} tft.drawLine(60, 10,60, 230, ILI9341_RED); tft.drawLine(60, 20,125, 20, ILI9341_RED); } } void polos(){ tft.fillRect(0,210,320,25,0x000A); tft.fillRect(0,185,320,25,0x000F); tft.fillRect(0,160,320,25,0x000A); tft.fillRect(0,135,320,25,0x000F); tft.fillRect(0,110,320,25,0x000A); tft.fillRect(0,85,320,25,0x000F); tft.fillRect(0,60,320,25,0x000A); tft.fillRect(0,35,320,25,0x000F); } void sinhr(){ if(sett==0){ while(((GPIOB-> regs-> IDR & 0b0000000100000000) >> 8)==1){hh++;delay_us(1);if(hh>1000){hh=0;break;}} while(((GPIOB-> regs-> IDR & 0b0000000100000000) >> 8)==0){hh++;delay_us(1);if(hh>1000){hh=0;break;}} while(((GPIOB-> regs-> IDR & 0b0000000100000000) >> 8)==1){hh++;delay_us(1);if(hh>1000){hh=0;break;}} } if(sett==1){ while(((GPIOB-> regs-> IDR & 0b0000000100000000) >> 8)==0){zap();}} if(sett==2){ while(((GPIOB-> regs-> IDR & 0b0000000100000000) >> 8)==1){zap();}} } void cif(){ for(byte cc=0;cc<8;cc++){tft.setCursor(0, 45+cc*25);tft.print(cc);}} void zap(){ if(digitalRead(PA4)==LOW){sett++;w=1;w1=1;stopp=0;if(sett>2){sett=0;}delay(200);tft.fillRect(50,0,65,8,ILI9341_BLACK);polos();cif();tft.fillRect(50,10,80,25,ILI9341_BLACK);} if(digitalRead(PA3)==LOW&&stopp==1){stopp=0;w1=1;polos();cif();tft.fillRect(50,10,80,25,ILI9341_BLACK);delay(300);i2=0;} tft.setCursor(65, 0); if(sett==0){tft.print("AUTO ");} if(sett==1){tft.print("START_1");} if(sett==2){tft.print("START_0");} }