| Ваш IP: 3.230.119.106 | Online(12) - гости: 6, боты: 6 | Загрузка сервера: 0.74 ::::::::::::

STM32 — осциллограф (Arduino IDE)

На рисунке показана схема простого осциллографа (пробник) основанного на микроконтроллере STM32F103C. Осциллограф имеет минимальный набор внешних компонентов, прост в сборке. Максимальное входное напряжение (только положительной полярности) 6,6 В и может быть увеличено применением внешнего делителя напряжения. Так АЦП STM32F103C 12 бит, это позволило сделать программный умножитель входного сигнала, без существенный потери качества осциллограммы.

При измерении напряжения более 3,3 В, включается делитель напряжения (вручную или автоматически). Управление осциллографом осуществляется при помощи 4-х кнопок. На экран выводятся показания амплитуды входного сигнала, множитель сигнала, длительность одного деления сетки и курсор синхронизации.

1 кГц

Кнопками UP и WOWN можно поменять длительность развертки, множитель входного сигнала и уровень синхронизации. Режимы настроек меняются кнопкой SET.

При нажатии на кнопку HOLD включается режим остановки осциллограммы, кнопками UP и WOWN можно перемещать по горизонтали осциллограмму. Нажимая на кнопку SET поочередно активируются курсоры измерения напряжения и длительности.

Тест полосы пропускания

Максимальная длительность развертки 100 Гц

Максимальная длительность развертки 100 Гц

1000 Гц

10.0 кГц

50,0 кГц

100,0 кГц

100,0 кГц (меандр)

200,0 кГц (меандр)

минимальная длительность развертки

400,0 кГц (меандр)

минимальная длительность развертки

500,0 кГц (меандр)

минимальная длительность развертки

100,0 кГц (синус)

минимальная длительность развертки

200,0 кГц (синус)

минимальная длительность развертки

#include "SPI.h"
#include <EEPROM.h>
#include <Adafruit_GFX_AS.h>   // https://rcl-radio.ru/wp-content/uploads/2020/06/Adafruit_GFX.zip
#include <Adafruit_ILI9341_STM.h>
#include <STM32ADC.h>
#include <HardwareTimer.h> 
 STM32ADC myADC(ADC1);
 uint8 pin = PA0;
 volatile static bool dma1_ch1_Active;
 #define maxSamples 1000
 uint16_t buffer[maxSamples]; 
 uint16 dataPoints[maxSamples]; 
 
#define TFT_CS         PB1                 
#define TFT_DC         PB10            
#define TFT_RST        PB11
  Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Mosi - PA7, SCK - PA5
 
byte data[1000],data_old[1000];
int setting,hold_set,i,x,y,i2,u_max,u_min,minn,u_sinh,mn=2,raz,per,razv,sinhro;
int u1,u2,t1,t2,zap,ux=1,uxx=1,fun;
long h0,h1;
long times,times1,hhh,times2,times3,tim;
byte hold,www,w=1,w1=1,w2=1,w3=1,w4=1,link,w5=1,b1=1,b2=1;
String raz_x;
float k1,k2,del=1;
 
int data1[1000];
 
 
void setup() {
 Serial.begin(115200);
 EEPROM.init(0x801F000,0x801F800,0x400);// 1024 byte
 pinMode(PA0, INPUT_ANALOG);
 pinMode(PB12,INPUT_PULLUP);// HOLD
 pinMode(PB13,INPUT_PULLUP);//+
 pinMode(PB14,INPUT_PULLUP);//-
 pinMode(PB15,INPUT_PULLUP);// SET
 tft.begin();tft.setRotation(1);
 tft.fillScreen(ILI9341_BLACK); 
 razv=EEPROM.read(0);
 sinhro=EEPROM.read(1);
 
 
ADC1->regs->CR1 = 0; // Обнулить регистр управления
ADC1->regs->SQR1 = 0; // Обнулить регистр SQR1
ADC1->regs->CR2 |= ADC_CR2_CAL; // Пуск калибровки
while (!(ADC1->regs->CR2 & ADC_CR2_CAL)){}; 
 
}
 
void loop() {
 
if(digitalRead(PB15)==LOW&&hold==0){w=1;w1=1;b1=1;b2=0;setting++;if(setting>2){setting=0;}delay(300);}
if(digitalRead(PB15)==LOW&&hold==1){w=1;w2=1;w4=1;hold_set++;if(hold_set>4){hold_set=0;}delay(300); }
 
//////  TFT  //////////////////////////////////////////
  tft.setCursor(295, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  //////////////////// HOLD ON OFF ///////////////////////////////////////////
 if(digitalRead(PB12)==LOW&&hold==0){hold=1;w2=1;w4=1;link=1;setting=0;delay(300);}  
 if(digitalRead(PB12)==LOW&&hold==1){hold=0;www=1;b2=0;hold_set=0;delay(300);}
 
 if(link==1){link=0;tft.fillRect(170,0,100,30,ILI9341_BLACK);}
 if(hold==0){tft.setCursor(170, 0);tft.print("OSCILLOSCOPE");tft.setCursor(170, 10);tft.print("VERSION 0.1");tft.setCursor(170, 20);tft.print("RCL-RADIO.RU");}
 
razmer();
 if(hold==0){
 if(setting==0){
  if(digitalRead(PB14)==LOW&&hold==0){razv++;if(razv>12){razv=12;}EEPROM.update(0,razv);delay(300);b2=1;w3=1;w=1;w1=1;u1=0;u2=0;t1=0;t2=0;}
  if(digitalRead(PB13)==LOW&&hold==0){razv--;if(razv<0){razv=0;}EEPROM.update(0,razv);delay(300);b2=1;w3=1;w=1;w1=1;w5=1;}
  razmer();
  if(b2<5){b2++;tft.fillRect(80,0,65,8,ILI9341_RED);tft.setCursor(90, 0);tft.print((float)times3/10/mn,1);tft.print(" uS");}
  }
 
 if(setting==1){
  if(digitalRead(PB14)==LOW&&hold==0){uxx++;if(uxx>5){uxx=5;}del=1;ux=uxx;delay(300);w=1;w1=1;u1=0;u2=0;t1=0;t2=0;}
  if(digitalRead(PB13)==LOW&&hold==0){uxx--;ux=uxx;if(uxx<=0){del=2;uxx=0;ux=1;}delay(300);w=1;w1=1;}
  if(w1==1){w1=0; tft.fillRect(85,10,50,8,ILI9341_RED);tft.setCursor(90, 10);tft.print("U x ");if(uxx==0){tft.print(0.5,1);}else{tft.print(uxx);}}
  }
 
 if(setting==2){
  if(digitalRead(PB13)==LOW&&hold==0){sinhro++;if(sinhro>200){sinhro=200;}EEPROM.update(1,sinhro);delay(10);w=1;w1=1;}
  if(digitalRead(PB14)==LOW&&hold==0){sinhro--;if(sinhro<0){sinhro=0;}EEPROM.update(1,sinhro);delay(10);w=1;w1=1;}
    tft.fillRect(0, 230-sinhro+3, 3, 3, ILI9341_BLACK);tft.fillRect(0, 230-sinhro, 3, 3, 0xFFFFDD);tft.fillRect(0, 230-sinhro-3, 3, 3, ILI9341_BLACK);
 if(w1==1){w1=0;tft.fillRect(85,20,50,8,ILI9341_RED);tft.setCursor(90, 20);tft.print("SINH");}
 }
 }
 
  if(hold==0&&w==1){w=0;
  if(setting!=0){tft.fillRect(80,0,65,8,ILI9341_BLACK);tft.setCursor(90, 0);tft.print((float)times3/10/mn,1);tft.print(" uS");}
  if(setting!=1){tft.fillRect(70,10,65,8,ILI9341_BLACK);tft.setCursor(90, 10);tft.print("U x ");if(uxx==0){tft.print(0.5,1);}else{tft.print(uxx);}}
  if(setting!=2){tft.fillRect(70,20,65,8,ILI9341_BLACK);tft.setCursor(90, 20);tft.print("SINH");
  tft.fillRect(0, 230-sinhro+3, 3, 3, ILI9341_BLACK);tft.fillRect(0, 230-sinhro, 3, 3, 0x333333);tft.fillRect(0, 230-sinhro-3, 3, 3, ILI9341_BLACK);
  }}
 
 
if(uxx==0){pinMode(PA2,OUTPUT);digitalWrite(PA2,LOW);}
if(uxx>0){pinMode(PA2,INPUT);analogRead(PA2);}
 
 
//////////////// HOLD SET ////////////////////////////////////////////////////////////////////////////////
 if(hold==1){
  if(w4==1){w4=0;
  tft.fillRect(80,0,65,8,ILI9341_BLUE);tft.setCursor(90, 0);tft.print((float)times3/10/mn,1);;tft.print(" uS");tft.fillRect(70,10,65,8,ILI9341_BLACK);
  tft.fillRect(0, 230-sinhro, 3, 3, 0x000000);tft.setCursor(90, 10);tft.print("U x ");tft.fillRect(70,20,65,8,ILI9341_BLACK);if(uxx==0){tft.print(0.5,1);}else{tft.print(uxx);}}
 
  tft.setCursor(295, 0);
  if(digitalRead(PB14)==LOW&&hold_set==0){i2+=2;if(i2>290){i2=290;}delay(50);
  tft.drawLine(0, u1+30,320, u1+30,  0x000000);
  tft.drawLine(0, 230-u2,320, 230-u2,  0x000000);
  tft.drawLine(t1,   230, t1, 30,  0x000000);
  tft.drawLine(318-t2,   230, 318-t2, 30,  0x000000);
 
  u1=0;u2=0;t1=0;t2=0;}
  if(digitalRead(PB13)==LOW&&hold_set==0){i2-=2;if(i2<0){i2=0;}delay(50);
  tft.drawLine(0, u1+30,320, u1+30, 0x000000);
  tft.drawLine(0, 230-u2,320, 230-u2,  0x000000);
  tft.drawLine(t1,   230, t1, 30,  0x000000);
  tft.drawLine(318-t2,   230, 318-t2, 30,  0x000000);
 
  u1=0;u2=0;t1=0;t2=0;}
  if(hold==1){tft.fillRect(i2,235,4,3,ILI9341_BLACK);tft.fillRect(i2+2,235,30,3,ILI9341_GREEN);tft.fillRect(i2+32,235,4,3,ILI9341_BLACK);}
  if(hold==0){tft.fillRect(295,0,25,8,ILI9341_RED);tft.fillRect(0,235,240,3,ILI9341_BLACK);}else{tft.print("HOLD");}
 
  if(digitalRead(PB14)==LOW&&hold==1&&hold_set==1){if(u1<199-u2){u1++;}w2=1;if(u1>200){u1=200;}delay(30);w=1;w1=1;}
  if(digitalRead(PB13)==LOW&&hold==1&&hold_set==1){if(u1<201-u2){u1--;}w2=1;if(u1<0){u1=0;}delay(30);w=1;w1=1;}
  if(digitalRead(PB13)==LOW&&hold==1&&hold_set==2){if(u2<199-u1){u2++;}w2=1;if(u2>200){u2=200;}delay(30);w=1;w1=1;}
  if(digitalRead(PB14)==LOW&&hold==1&&hold_set==2){if(u2<201-u1){u2--;}w2=1;if(u2<0){u2=0;}delay(30);w=1;w1=1;}
 
  if(digitalRead(PB14)==LOW&&hold==1&&hold_set==3){if(t1<319-t2){t1++;};w2=1;if(t1>320){t1=320;}delay(30);w=1;w1=1;}
  if(digitalRead(PB13)==LOW&&hold==1&&hold_set==3){if(t1<321-t2){t1--;}w2=1;if(t1<0){t1=0;}delay(30);w=1;w1=1;}
  if(digitalRead(PB13)==LOW&&hold==1&&hold_set==4){if(t2<319-t1){t2++;}w2=1;if(t2>320){t2=320;}delay(30);w=1;w1=1;}
  if(digitalRead(PB14)==LOW&&hold==1&&hold_set==4){if(t2<321-t1){t2--;}w2=1;if(t2<0){t2=0;}delay(30);w=1;w1=1;}
 
 if(w2==1){w2=0;
   tft.drawLine(0, u1-1+30,320, u1-1+30,  ILI9341_BLACK);if(hold_set==1){tft.drawLine(0, u1+30,320, u1+30,  0xFFDAB9);}else{tft.drawLine(0, u1+30,320, u1+30,  0x222222);} tft.drawLine(0, u1+1+30,320, u1+1+30,  ILI9341_BLACK);
   tft.drawLine(0, 230-u2-1,320, 230-u2-1,  ILI9341_BLACK);if(hold_set==2){tft.drawLine(0, 230-u2,320, 230-u2,  0xFFDAB9);}else{tft.drawLine(0, 230-u2,320, 230-u2,  0x222222);} tft.drawLine(0, 230-u2+1,320, 230-u2+1,  ILI9341_BLACK);
   tft.drawLine(t1-1, 230, t1-1, 30,  ILI9341_BLACK);if(hold_set==3){tft.drawLine(t1,   230, t1, 30,  0xFFDAB9);}else{tft.drawLine(t1,   230, t1, 30,  0x222222);}tft.drawLine(t1+1, 230, t1+1, 30,  ILI9341_BLACK);
   tft.drawLine(318-t2-1, 230, 318-t2-1, 30,  ILI9341_BLACK);if(hold_set==4){tft.drawLine(318-t2,   230, 318-t2, 30,  0xFFDAB9);}else{{tft.drawLine(318-t2,   230, 318-t2, 30,  0x222222);}}tft.drawLine(318-t2+1, 230, 318-t2+1, 30,  ILI9341_BLACK);
 
   if(hold_set==1){tft.fillRect(150,0,55,8,ILI9341_RED);}else{tft.fillRect(150,0,55,8,ILI9341_BLACK);}
   if(hold_set==2){tft.fillRect(150,10,55,8,ILI9341_RED);}else{tft.fillRect(150,10,55,8,ILI9341_BLACK);}
   if(hold_set==3){tft.fillRect(220,0,60,8,ILI9341_RED);}else{tft.fillRect(220,0,60,8,ILI9341_BLACK);}
   if(hold_set==4){tft.fillRect(220,10,60,8,ILI9341_RED);}else{tft.fillRect(220,10,60,8,ILI9341_BLACK);}
 
 
    tft.fillRect(150,20,55,8,ILI9341_BLACK);
    tft.setCursor(150, 0);tft.print("U1 = ");tft.print((3.3-u1*0.0165)/ux*del,2);
    tft.setCursor(150, 10);tft.print("U2 = ");tft.print((abs(u2*0.0165))/ux*del,2);
    tft.setCursor(150, 20);tft.print("U  = ");tft.print(((3.3-u1*0.0165)-abs(u2*0.0165))/ux*del,2);
 
    tft.fillRect(220,20,65,8,ILI9341_BLACK);
    if(razv<6){zap=1;}else{zap=0;}
    tft.setCursor(220, 0);tft.print("T1 = ");tft.print(t1*(float)times3/1000/mn,zap);
    tft.setCursor(220, 10);tft.print("T2 = ");tft.print(((float)times3/3.125-t2*(float)times3/1000)/mn,zap);
    tft.setCursor(220, 20);tft.print("T  = ");tft.print(((((float)times3/3.125-t2*(float)times3/1000))/mn-((t1*(float)times3/1000))/mn),zap);
    tft.fillRect(280,20,30,8,ILI9341_BLACK);tft.print(" uS");
 }} 
////////// END HOLD SET ///////////////////////////////////////////////////////////////////////////////////
  setka();
 
  if(hold==0){DMA();if(dma1_ch1_Active == 0){for(int x=0; x<maxSamples; x++){data[x]=map(buffer[x],0,4095/ux,0,200);}}u1=0;u2=0;t1=0;t2=0;}
  arr();
 
 if(hold==0){i2=0;for(i=1;i<1000;i++){if(data[i+5]>sinhro&&data[i+3]<sinhro){fun=i;if(fun>680){fun=0;}i=2000;}}
  for(i=0;i<1000-fun;i++){data1[i]=data[fun+i];}i=0;}
 
 while(i<320){ 
 tft.drawLine(i*mn, 230-data_old[i],i*mn+mn-1, 230-data_old[i+1], ILI9341_BLACK);
 tft.drawLine(i*mn, 230-data1[i+i2],i*mn+mn-1, 230-data1[i+1+i2],  ILI9341_RED);i++;}i=0;
 while(i<639){data_old[i]=data1[i+i2];i++;}i=0; 
 if((mn>1&&w1==1&&hold==0&&setting==0)||www==1){www=0;w=1;w1=0;tft.fillScreen(ILI9341_BLACK);}
 if(razv==2&&w5==1){w5=0;w=1;w1=0;tft.fillScreen(ILI9341_BLACK);}
}
 
void DMA(){
 
     switch(per){
       case 0: rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_2); break;
       case 1: rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_4); break;
       case 2: rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); break;
       case 3: rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_8); break;
      }
     switch (raz) {
      case 0: adc_set_sample_rate(ADC1, ADC_SMPR_1_5); break;
      case 1: adc_set_sample_rate(ADC1, ADC_SMPR_7_5); break;
      case 2: adc_set_sample_rate(ADC1, ADC_SMPR_13_5); break;
      case 3: adc_set_sample_rate(ADC1, ADC_SMPR_28_5); break;
      case 4: adc_set_sample_rate(ADC1, ADC_SMPR_41_5); break;
      case 5: adc_set_sample_rate(ADC1, ADC_SMPR_55_5); break;
      case 6: adc_set_sample_rate(ADC1, ADC_SMPR_71_5); break;
      case 7: adc_set_sample_rate(ADC1, ADC_SMPR_239_5); break;
       } 
 
  adc_set_reg_seqlen(ADC1, 1);
  ADC1->regs->SQR3 = PIN_MAP[pin].adc_channel;      
  ADC1->regs->CR2 |= ADC_CR2_CONT;
  ADC1->regs->CR2 |= ADC_CR2_EXTSEL;   
  ADC1->regs->CR2 |= ADC_CR2_SWSTART; 
 
  dma_init(DMA1);  
  dma_attach_interrupt(DMA1, DMA_CH1, DMA1_CH1_Event);
  myADC.setDMA(buffer, maxSamples, (DMA_MINC_MODE | DMA_TRNS_CMPLT), DMA1_CH1_Event);
  dma1_ch1_Active = 1;
 
 
  times3 = micros();
  dma_enable(DMA1, DMA_CH1); 
  while (dma1_ch1_Active == 1);
  dma_disable(DMA1, DMA_CH1); 
  times3 = micros() - times3;
}
 
 
void setka(){ 
 for(y=30;y<240;y=y+50){for(x=10;x<320;x=x+5){tft.drawPixel(x, y, ILI9341_DARKGREY);}}  
 for(x=0;x<320;x=x+64){for(y=40;y<240;y=y+10){tft.drawPixel(x, y, ILI9341_DARKGREY);}}}
 
static void DMA1_CH1_Event(){dma1_ch1_Active = 0;}
 
void arr(){
   ///// U max max
 if(millis()-times>500){u_max=0;u_min=4100;w3=1;
 tft.fillRect(40,0,30,28,ILI9341_BLACK);
  for(int mmm=0;mmm<640;mmm++){u_min=min(u_min,buffer[mmm]);u_max=max(u_max,buffer[mmm]);}
 tft.setCursor(0, 0);tft.print("Vmax = ");tft.print(u_max*3.3/4095*del,2);
 tft.setCursor(0, 10);tft.print("Vmin = ");tft.print(u_min*3.3/4095*del,2);
 u_sinh = u_max-u_min;
 tft.setCursor(0, 20);tft.print("Vpp  = ");tft.print(u_sinh*3.3/4095*del,2);
 times=millis();
 if(u_max*3.3/4095>=3.3){uxx=0;ux=1;del=2;w3=1;tft.fillRect(70,10,65,8,ILI9341_BLACK);tft.setCursor(90, 10);tft.print("U x ");tft.print(0.5,1);}}
  }
 
void razmer(){
     switch(razv){
    case 0: mn=4;      per=0;raz=0;;break;  
    case 1: mn=2;      per=0;raz=0;;break; 
    case 2: mn=1;      per=0;raz=0;break; 
    case 3: mn=1;      per=0;raz=1;break;
    case 4: mn=1;      per=1;raz=1;break; 
    case 5: mn=1;      per=2;raz=1;break; 
    case 6: mn=1;      per=3;raz=1;break; 
    case 7: mn=1;      per=3;raz=2;break; 
    case 8: mn=1;      per=3;raz=3;break; 
    case 9: mn=1;      per=3;raz=4;break; 
    case 10: mn=1;     per=3;raz=5;break;
    case 11: mn=1;     per=3;raz=6;break;
    case 12: mn=1;     per=3;raz=7;break;
    }
  }

Поддержка платы STM32 в Arduino IDE — https://rcl-radio.ru/?p=68376

STM32 + TFT-дисплей SPI 320×240 (ILI9341C)

STM32 Arduino IDE

Комментарии

Добавить комментарий

Войти с помощью: 

Случайные статьи

  • Экономичный LED фонарик

    При изготовлении малогабаритного фонарика главным является его экономичность. При применении светодиода с током потребления 24мВт 4-х щелочных батареек типа АА хватит до одного месяца непрерывной работы. Фонарик основан на таймере 7555 который работает в автоколебательном режиме (не использовать 555). Белый светодиод 400 mcd имеет малый ток потребления и яркое направленное …Подробнее...
  • Электронная регулировка громкости на TDA8199

    Электронная регулировка громкости на TDA8199

    Двух канальный регулятор на микросхеме TDA8199 имеет следующие параметры: Напряжение питания от 10,8 до 13,2В (12В номинальное) Ток потребления 21-28мА К усил=12дБ Rвх=22кОм Коэффициент гармоник от 0,35 до 1% Напряжение регулировки от 0,5 до 4,5В Номинальное входное напряжение 0,125…0,5В(2В максимальное при коэффициенте гармоник 5%)  Подробнее...
  • Двухобъектный цифровой термометр

    Двухобъектный цифровой термометр

    Для измерения температуры воздуха в помещении и вне его необходимо 2  термометра, данное устройство позволяет измерять температуру двумя датчиками и одним цифровым термометром, причем как в ручном режиме так и автоматическом. Основа прибора АЦП двойного интегрирования на КР572ПВ5 и интегральных датчиков К1019ЕМ1. Питание АЦП осуществляется от биполярного источника. Положительное напряжение …Подробнее...
  • Микшер на TA7137

    Микшер на TA7137

    На ИМС TA7137 можно собрать простой  и не дорогой микшер, ИМС TA7137 представляет собой предусилитель низкой частоты. Технические характеристики TA7137: Напряжение питания: номинальное 5 В, максимальное  15 В; Коэффициент усиления  69 дБ; Встроенный узел управления АРУ; Среднеквадратичное напряжение шума, приведенное ко входу 1 мкВ; Коэффициент нелинейных искажений (Vout = 0,2 В)  0,1%; Диапазон …Подробнее...
  • break (Arduino)

    break (Arduino)

    break используется для принудительного выхода из циклов do, for или while, не дожидаясь завершения цикла по условию. Он также используется для выхода из оператора switch. Пример использования: void setup(){ pinMode(A1,INPUT); } int i; void loop(){ for(i=0;i<100;i++){ if(analogRead(A1)>500){ break; } } } Запускаем цикл for, пока переменная i меньше 100 цикл …Подробнее...