Пультоскоп на Arduino 27МГц!!!

Novice User
Offline
Зарегистрирован: 25.09.2017

 D5- для частотомера

C3-аналоговый вход для пультоскопа

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Novice User пишет:

 D5- для частотомера

C3-аналоговый вход для пультоскопа

 

Спасибо за оперативный ответ. 

Замечу, что на сайте http://srukami.inf.ua/pultoscop_v25110.html в схеме либо коде есть неточности

#define power 8 //пин который опрашивает кнопку включения
#define OFF 14//пин который управляет ключем питания
#define  timepowerON 50 //время удержания кнопки выключения
#define levo 13  //кнопка ЛЕВО(можно любой пин)
#define ok 12    //кнопка ОК(можно любой пин)
#define pravo 11 //кнопка ПРАВО(можно любой пин)
#define akb A5 //любой своюодный аналоговый пин для измерения напряжения АКБ 

Конкретно D8(пин который опрашивает кнопку включения) на схеме не показан

void setup(){
pinMode(A4,INPUT);
digitalWrite(OFF,HIGH);//включем питание 

В функции setup() А4 настроен на вход. Возможно речь о А5 (АКБ)

Код взят с сайта

Да и настроек пинов кнопок тоже не заметил

Novice User
Offline
Зарегистрирован: 25.09.2017

а зачем А5 настраивать на вход?

Novice User
Offline
Зарегистрирован: 25.09.2017

MIK22 пишет:

Я пробовал пультоскоп на Massduino UNO LC c тактовой частотой 16 Ьгц.

Получил,можно ваш скетч?

Electronik83
Offline
Зарегистрирован: 06.12.2015

mobistrike пишет:

Electronik83 пишет:

Работоспособна схема при питании ардуины строго +5 вольт. ....

Тут теряется весь смысл измерения напряжения питания arduino .

Я пошел другим путем - взял за основу код от форумчанина DIMAX, за что ему спасибо  - ТУТ . 

Измерение производится внутренней коммутацией, не используя внешние аналоговые входы, причем довольно точно.

Заинтересовало, только так и не смог ничего измерить. В порт выводит inf

..... ((((((

MIK22
Offline
Зарегистрирован: 09.02.2017
Скутч не мой, сборный.
#include <SPI.h>
#include <MsTimer2.h>
#include <FreqMeasure.h>
#include <Adafruit_ST7735.h>
#include <PWM.h> 
#include <avr/wdt.h> 
 
#define TFT_CS  10
#define TFT_DC  7
#define TFT_RST A0
//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);
#define TFT_SCLK 13 // set these to be whatever pins you like!
#define TFT_MOSI 11  // set these to be whatever pins you like!
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
 
#define MEASURE_PERIOD 500  // время периода измерения
#define ADC_U_COEFF 0.000008408 // коэффициент перевода кода АЦП в напряжение
int timeCount;  // счетчик времени
long  sumU1; // переменные для суммирования кодов АЦП
long  avarageU1; // сумма кодов АЦП (среднее значение * 500)
boolean flagReady;  // признак готовности данных измерения
#define TEAL    0x0410
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
#define BUFSIZE 700
#define Reset_AVR() wdt_enable(WDTO_30MS); while(1) {}            // soft reset
#define overclock 16.0
#define KEY_L 2  // кнопка ЛЕВО(можно любой пин)
#define KEY_OK 3 // кнопка ОК(можно любой пин)
#define KEY_R 4  // кнопка ПРАВО(можно любой пин)
#define Out  9   //пин для генератора сигналов (не менять)
#define led  9   //пин для генератора dds (не менять)
//пользовательские настройки!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
byte menu=0;     // пункт меню
byte mainMenu=0; // пункт главного меню
byte subMenu=0;     // пункт меню 
byte SinU=30;   //уровень синхронизации 0 до 255 
byte adcBuf[701]; // буфер проебразований АЦП
byte synU=30;    // уровень синхронизации 0 до 255
byte razv=0;//значение развертки
bool vRef=1;  // флаг опорного напряжения
bool pause=0; //флаг режима паузы
int Vmax=0;// максимальное напряжение 
int PWM = 50;    // стартовое значение ШИМ от 0 до 100 для генератора    
int  pOffset=0;   // смещение графика в режиме паузы (прокрутка)
int grOffset=0; // смещение графика в рабочем режиме
float Vakb=0; //напряженеиЕКБ
float VCC=4.16;
float frequency = 500; //стартовое значение частоты в Гц
int d=0;
byte hag=0;
int mnog=0;
boolean flag=0;
double sum=0;
unsigned long count =0; 
//##############################################
  static float vccRead(byte us =100) {
  ADMUX = (1<<REFS0)|(1<<MUX0); // опорное напряжение - Vcc   
  ADMUX |= 0xC0;  //стабилизированного напряжения 1.0
  delayMicroseconds(us); 
  ADCSRA = 0xC7;
  //ADCSRA |= (1<<ADSC);         // запуск АЦ-преобразования
  while(ADCSRA & (1<<ADSC)); // и ожидание его завершения
  word x = ADC;
  return x ? (1100L * 4095) / x : -1;  }   
 
  /*int Vbg() {  
ADMUX = (1<<REFS0)|(0<<REFS1)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0);
long buffersamp=0;
for (int n=0x0; n<=0xff; n++ ) {
ADCSRA |= (1<<ADSC)|(1<<ADEN);  //Starts a new conversion
while (bit_is_set(ADCSRA,ADSC));
buffersamp += ADC; }
buffersamp >>=4; //16368 full scale 14bit
ADCSRA &= ~(1 << ADEN);  // отключаем АЦП
return buffersamp;
 }*/
//#########################  главное меню  ##########################
void GlavMenu (){
     tft.setRotation(1);
     tft.setTextColor(RED);
     tft.setCursor(35, 13);
     tft.println("Осцилограф");
     tft.setCursor(35, 28);
     tft.println("Генератор PWM");
     tft.setCursor(35, 43);
     tft.println("Снятие АЧХ");  
     tft.setCursor(35, 58);
     tft.println("Терминал"); 
     tft.setCursor(35, 73); 
     tft.println("Частотомер");  
     tft.setCursor(35, 88);  
     tft.println("Вольтметр");      
     tft.setTextColor(BLUE);     
     tft.setCursor(35, 103);
     tft.println("Батарея ="); tft.println(Vakb); tft.print("B");            
}
void setup(){ 
    Vakb= vccRead()/4000,1;    
   //Vakb= (float)(1.0*16368)/Vbg() ;
   //pinMode(analogRead_12bits(A3),INPUT); 
   pinMode(analogRead(A3),INPUT);
   pinMode(8, INPUT);
   pinMode(KEY_OK, INPUT); pinMode(KEY_L, INPUT); pinMode(KEY_R, INPUT);  //  тест!!! Так меньше будет потребление питания и так правильнее!!!!
   tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab    
   tft.setRotation(1);              //  повернуть по горизонту
   tft.fillScreen(BLACK);
   
   tft.drawRect(0,0,160,128,WHITE); // рисуем рамку
   tft.drawRect(3,3,154,122,BLUE); // рисуем рамку
   tft.drawRect(6,6,148,116,RED); // рисуем рамку 
   
 while(digitalRead(KEY_OK) == LOW) {  // зацикливаем, пока не нажали кнопку ОК из главного меню (перебор меню)
   if (digitalRead(KEY_L) == HIGH) { mainMenu--; if (mainMenu==255) mainMenu = 5; delay (100); }
   if (digitalRead(KEY_R) == HIGH) { mainMenu++; if (mainMenu==6  ) mainMenu = 0; delay (100); }
    // Рисуем главное меню  
    if (mainMenu==0) {     
       GlavMenu ();
     tft.setCursor(35, 13);  tft.println("Осцилограф"); }
    if (mainMenu==1) {
       GlavMenu ();
     tft.setCursor(35, 28);  tft.println("Генератор PWM"); }        
    if (mainMenu==2) {
       GlavMenu ();
     tft.setCursor(35, 43);  tft.print("Снятие АЧХ"); } 
    if (mainMenu==3) {
       GlavMenu ();
     tft.setCursor(35, 58);  tft.print("Терминал"); }    
    if (mainMenu==4) {
       GlavMenu ();
     tft.setCursor(35, 73);  tft.print("Частотомер"); }    
    if (mainMenu==5) {
       GlavMenu ();
     tft.setCursor(35, 88);  tft.print("Вольтметр"); } 
 
    if (digitalRead(KEY_L) == HIGH && digitalRead(KEY_R) == HIGH) { delay(1000);
    wdt_enable(WDTO_30MS); while(1) {} ;
    Reset_AVR(); } // soft reset             
  
   if (mainMenu==0) { FreqMeasure.begin(); }
   if (mainMenu==1) { InitTimersSafe(); bool success = SetPinFrequencySafe(led, frequency); }   
   if (mainMenu==2) razv = 0; 
   if (mainMenu==4) { FreqMeasure.begin(); }    
    delay(100); // антидребезг кнопки ОК   
 }
 }
//###############################################################
void Zamer() {
  if (razv%10) { // (razv>0)        // если развертка без задержек всяких
    ADCSRA = 0b11100000 | (8-(razv%10)); // установили делитель (/2 - не работает, так что начинаем с /4)
    for(int i=0; i<BUFSIZE; i++) {  // цикл для чтения  
      //while ((ADCSRA & 0x10)==0);   // ждем готовность АЦП
      //ADCSRA|=0x10;                 // запускаем следующее преобразование
      while(ADCSRA & (1<<ADSC)); // и ожидание его завершения
      ADCSRA |= 1<<ADSC;
      adcBuf[i]=ADCH;               // записываем данные в массив
    }
    delay(0.3*BUFSIZE);             // компенсация задержки по сравнению с разверткой 0...
  } else {                          // развертка с задержками (delay)
    ADCSRA = 0b11100111;            // делитель на /128
    for(int i=0; i<BUFSIZE; i++) {  // цикл для чтения
      //while ((ADCSRA & 0x10)==0);   // ждем готовность АЦП
      //ADCSRA|=0x10;                 // запускаем следующее преобразование
      while(ADCSRA & (1<<ADSC)); // и ожидание его завершения
      ADCSRA |= 1<<ADSC;
      delayMicroseconds(500);       // делаем задержку
      adcBuf[i]=ADCH;               // записываем данные в массив
    }
  }
}
//###################################################################
// обработка прерывания 1 мс
void  timerInterupt() {
  timeCount++;  // +1 счетчик выборок усреднения
  sumU1+= analogRead(A4);  // суммирование кодов АЦП
  // проверка числа выборок усреднения
  if ( timeCount >= MEASURE_PERIOD ) {
    timeCount= 0;
    avarageU1= sumU1; // перегрузка среднего значения     
    sumU1= 0;    
    flagReady= true;  // признак результат измерений готов
    }
}              
//##################################################################
void loop() { 
  //float Vakb= (float)(1.0*16368)/Vbg() ;
  if(mainMenu==0){tft.fillScreen(BLACK);
  while(1){ 
  ADMUX = vRef ? 0b00100011 : 0b11100011; // установка опорного напряжения АЦП        
  //ADMUX = vRef ? 0b11100100 : 0b10100100 : 0b00100100; // установка опорного напряжения АЦП     
  if (!pause) Zamer(); // если нет паузы, то снимаем осциллограмму  
   // обрабатываем кнопки
  if (digitalRead(KEY_L))   switch (subMenu) {
    case 0 : tft.setRotation(0); tft.fillRect(15, 0, 106, 24, BLACK);   tft.fillRect(16, 34, 100 , 160, BLACK); tft.setRotation(1);vRef=!vRef;  break;
    case 1 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); razv--; if(razv==255) razv= 0; break;
    case 2 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); pOffset-=10; if (pOffset<0) pOffset=0; break;
    case 3 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1);synU-=20; if (synU<20) synU=20;        break;
  }
  if (digitalRead(KEY_R))  switch (subMenu) {
    case 0 : tft.setRotation(0); tft.fillRect(15, 0, 106, 24, BLACK); tft.fillRect(16, 34, 100 , 160, BLACK); tft.setRotation(1); vRef=!vRef;  break;
    case 1 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); razv++; if (razv==7) razv=6;           break;
    case 2 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); pOffset+=10; if(pOffset>570) pOffset=570; break;
    case 3 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); synU+=20; if(synU>230) synU=230;       break;
  }       
  if (digitalRead(KEY_OK)) { { subMenu++; if (subMenu==4) {subMenu=0; pause=0; } } // перебор меню
  delay (100);
  tft.setRotation(0); 
  tft.fillRect(118, 0, 128, 160, BLACK); //стирание верх меню
  tft.fillRect( 0, 0, 10, 160, BLACK);//стиране ниж меню    
  tft.fillRect(16, 34, 100, 160, BLACK);//стиране поля графика
  }  
   // === Отрисовка меню осцилла ===      
  tft.setRotation(1); 
  if (subMenu==0) tft.setTextColor(WHITE, RED); else tft.setTextColor(RED);tft.setCursor(4,0); 
  if (vRef) { tft.print("V=5.3");} else tft.print("V=1.1");
  if (subMenu==1) tft.setTextColor(WHITE, RED); else tft.setTextColor(RED);
  tft.setCursor(58, 0); tft.print("РАЗВ=");  tft.print(razv);
  if (subMenu==2) { tft.setTextColor(WHITE, RED); pause=1; } else tft.setTextColor(RED);
  tft.setCursor(120,0); tft.print("ПАУЗА");  
  if (subMenu==3) { pOffset=0; pause=0; 
  tft.fillCircle(155, 112-synU/3.5, 5, WHITE);  tft.fillCircle(155, 112-synU/3.5, 2, BLUE);}
    
 if(FreqMeasure.available()) {     
  sum = sum + FreqMeasure.read();
  count = count + 1;    if (count > 30) {
  float frequency = FreqMeasure.countToFrequency(sum / count);    
  tft.fillRect( 0, 121, 130, 128, BLACK);   
  tft.setTextColor(TEAL); tft.setCursor(0, 121); tft.println("F="); tft.setCursor(13, 121);
  //--------Блок вычисления частоты в ГЦ---------------------
  if (frequency <= 1000){   tft.print(frequency);  tft.println("Hz");       }
  //--------Блок вычисления частоты в КГЦ---------------------      
  else { float freq = frequency / 1000;  tft.print(freq);  tft.println("KHz");  }        
  sum = 0;  count = 0;   
    }
  }   
    tft.setTextColor(TEAL);
     tft.print("v");
    tft.setCursor(135,121);
    tft.print(Vakb);    
    tft.setCursor(69,121);
    tft.print("Vmax=");
    tft.setTextColor(TEAL, BLACK);
    if (vRef) tft.print(Vmax*VCC/255,1);
        else  tft.print(Vmax*1.1/255,1);
    delay(200);
 
if (vRef) {
    tft.setTextColor(TEAL);
    tft.setCursor(18,104);tft.println("0"); 
    tft.setCursor(0, 88); tft.println("1.00"); 
    tft.setCursor(0, 72); tft.println("2.00"); 
    tft.setCursor(0, 56); tft.println("3.00"); 
    tft.setCursor(0, 40); tft.println("4.00"); 
    tft.setCursor(0, 24); tft.println("5.00");        
}
else  {
    tft.setTextColor(TEAL);
    tft.setCursor(18,104);tft.println("0"); 
    tft.setCursor(0, 88); tft.println("0.25"); 
    tft.setCursor(0, 72); tft.println("0.50"); 
    tft.setCursor(0, 56); tft.println("0.75"); 
    tft.setCursor(0, 40); tft.println("1.00"); 
    tft.setCursor(0, 24); tft.println("1.25");        
}
 //ось напряжения##########################################  
 tft.drawFastVLine(32,12,102,BLUE);tft.drawFastVLine(33,12,102,BLUE);   
 for(byte i=110;i>14; i=i-16) {tft.drawLine( 28, i,32 , i, BLUE); } // черточки слева 
 
 //ось времени##########################################
 tft.drawFastHLine(33,112,160,RED);tft.drawFastHLine(33,113,160,RED);
 for(byte i=160;i>34; i=i-16) {tft.drawLine( i, 113, i, 117, RED); } // черточки внизу
 
 // Определение точки синхронизации 
  bool flagSINHRO=0;
  bool flagSINHRnull=0;
  for (int y=1; y<573; y++) {
    if (!flagSINHRO && adcBuf[y]<SinU) flagSINHRnull=1;
    if (!flagSINHRO && flagSINHRnull && adcBuf[y]>SinU) { flagSINHRO=1; grOffset=y;  }  }   
 
  // максимальное значение сигнала
  Vmax=0; 
  for (int y=1; y<255; y++) if (Vmax<adcBuf[y]) Vmax=adcBuf[y];
// отрисовка графика
 
   for(int y=34; y<160; y++) {
   tft.drawLine(y, 110-adcBuf[y+(pause ? pOffset : grOffset)]/3.8, y, 110-adcBuf[y+(pause ? pOffset : grOffset)+1]/3.8,   (BLACK, GREEN));
   //tft.drawLine(y, 110-adcBuf[y+(pause ? pOffset : grOffset)]/3.8, y, 110-adcBuf[y+(pause ? pOffset : grOffset)+1]/3.8,   GREEN); 
   }     
    if(pause) { // если в режиме паузы, то рисуем с прокруткой...  
    tft.drawLine(pOffset/8,117,pOffset/8+6,117, BLUE); //шкала прокрутки
    tft.drawLine(pOffset/8,118,pOffset/8+6,118, BLUE); //шкала прокрутки      
     } else {
    tft.fillCircle(155,112-synU/3.8, 2, YELLOW); // рисуем уровень синхронизации    
    grOffset = 0;                               // сброс синхронизации
  }    
  if (digitalRead(KEY_L) == HIGH && digitalRead(KEY_R) == HIGH) { delay(1000);
  wdt_enable(WDTO_30MS); while(1) {} ;
  Reset_AVR(); } // soft reset 
  }
  }
  //######## Генератор ##############
if(mainMenu==1){ tft.fillScreen(BLACK);
  while(1){     
    tft.setRotation(1); 
  if (flag==0){//флаг выборов режима настройки  Частоты
  if(digitalRead(KEY_L)==HIGH){ frequency=frequency-mnog; if(frequency<0){ frequency=0; }
          bool success = SetPinFrequencySafe(Out, frequency);
          delay(3);//защита от дребезга
          tft.fillRect(6, 22, 160, 38, BLACK);//стирание поля
        }
   if(digitalRead(KEY_R)==HIGH){ frequency=frequency+mnog; 
          bool success = SetPinFrequencySafe(Out, frequency);
          delay(3);//защита от дребезга
          tft.fillRect(6, 22, 160, 38, BLACK);//стирание поля закрашиваем
        }
      }
   if(digitalRead(KEY_OK)==HIGH){//переключение разряда выбора частоты
        delay (30);
        while((digitalRead(KEY_OK)==HIGH)); hag++; if(hag>=6){ hag=0; }
        tft.fillRect(6, 5, 155, 22, BLACK);//стирание поля
        tft.fillRect(28, 109, 129, 127, BLACK);//стирание в низу число шим
      }
      ////////////////////////////////////////////////////////////////////
      tft.setCursor(36, 110); 
      tft.setTextColor(GREEN, BLACK);
      tft.setTextSize(2);
      tft.println("PWM=");
      tft.setCursor(84, 110);  
      tft.print(PWM);         
      tft.setCursor(108, 110);
      tft.println( "%");
      
      for (char x=22; x<126; ) {
    if (PWM!=0)             tft.drawLine(x, 60, x+PWM/6, 60, TEAL); x+=PWM/6;       // верх 
    if (PWM!=0 && PWM!=100) tft.drawLine(x, 60, x, 100, TEAL);                       // спад
    if (PWM!=100)           tft.drawLine(x, 100, x+15-PWM/6, 100, TEAL); x+=15-PWM/6; // низ
    if (PWM!=0 && PWM!=100 && x<120) tft.drawLine( x,100, x, 60, TEAL);              // подъем   
  }        
      //////////////////////////////////////////////////////////////////////
       tft.setTextSize(2);
       tft.setTextColor(WHITE);
       tft.setCursor(36, 30);
      long frequencyX=frequency*(overclock/16.0);
if(frequencyX<1000){tft.print(frequencyX); tft.println("Hz");}
if(frequencyX>=1000){if(frequencyX<10000){tft.print((frequencyX/1000.0),2);tft.println("KHz");}}
if(frequencyX>=10000){if(frequencyX<100000){tft.print((frequencyX/1000.0),1); tft.println("KHz");}}
if(frequencyX>=100000){tft.print((frequencyX/1000.0),0); tft.println("KHz");}  
 
  tft.setCursor(22, 5);
  tft.setTextColor(WHITE, BLUE);
  tft.println("X"); 
  tft.setTextColor(YELLOW);
if (hag==0) { // выбор множителя частоты 
  tft.print(1*(overclock/16.0),0);  tft.println("Hz");   
    mnog=1; flag=0;
  }
  // Выбор множителя частоты
  if (hag==1) { tft.print(  10*(overclock/16.0),0);  mnog=10; tft.println("Hz");  }
  if (hag==2) { tft.print( 100*(overclock/16.0),0);  mnog=100; tft.println("Hz"); }
  if (hag==3) { tft.print(1000*(overclock/16.0),0);  mnog=1000; tft.println("Hz");} 
  if (hag==4) { tft.print(10000*(overclock/16.0),0);  mnog=10000; tft.println("Hz");}
        
  if(hag==5){//выбор  PWM        
  flag=1;        
        tft.println("PWM=");       
        tft.setCursor(84, 5); 
        tft.print(PWM);         
        tft.setCursor(108, 5);        
        tft.println("%");
        
   if(digitalRead(KEY_R)) { tft.fillRect(20, 60, 130, 106, BLACK); tft.fillRect(6, 5, 155, 21, BLACK); 
 { PWM++; if(PWM>100) PWM=0; delay(200); }  }    
   if(digitalRead(KEY_L)) { tft.fillRect(20, 60, 130, 106, BLACK) ; tft.fillRect(6, 5, 155, 21, BLACK);
 { PWM--; if(PWM<0) PWM=100; delay(200); }  }         
      }   
      pwmWrite(Out, PWM*2.55); // задали ШИМ         
      delay(50);  
  if (digitalRead(KEY_L) == HIGH && digitalRead(KEY_R) == HIGH) { delay(1000);
  wdt_enable(WDTO_30MS); while(1) {} ;
  Reset_AVR(); } // soft reset           
  }
  } 
//############# Снятие ФЧХ #################
  if(mainMenu==2) {  tft.fillScreen(BLACK);   
  while(1){   
  ADMUX = vRef ? 0b01100011 : 0b11100011; // установка опорного напряжения АЦП    
  ADCSRA = 0b11100011; //delitel 8
  //ADCSRA|=0x10; // запуск преобразования АЦП
  ADCSRA |= 1<<ADSC;
 if (digitalRead(KEY_L))   switch (subMenu) {
    case 0 : tft.setRotation(0); tft.fillRect(15, 0, 106, 24, BLACK);   tft.fillRect(16, 34, 100 , 160, BLACK); tft.setRotation(1);vRef=!vRef;  break;
    case 1 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); razv--; if(razv==255) razv= 2; break;
    case 2 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); grOffset-=10; if (grOffset<0) grOffset=700; break;
    case 3 : for (int y=0; y<700; y++) adcBuf[y] = 0; grOffset=0; 
    tft.fillScreen(BLACK); tft.setCursor(3, 20); tft.print("Буфер очищен!"); delay(1000);  break; 
           } delay(100); // антидребезг кнопки
 
  if (digitalRead(KEY_R))  switch (subMenu) {
    case 0 : tft.setRotation(0); tft.fillRect(15, 0, 106, 24, BLACK); tft.fillRect(16, 34, 100 , 160, BLACK); tft.setRotation(1); vRef=!vRef;  break;
    case 1 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); razv++; if (razv==3) razv=0;           break;
    case 2 : tft.setRotation(0); tft.fillRect(16, 34, 100, 160, BLACK); tft.setRotation(1); grOffset+=10; if(grOffset>1402) grOffset=0; break;
           delay(100); } // антидребезг кнопки
  if (digitalRead(KEY_OK)) { { subMenu++; if (subMenu==4) {subMenu=0; pause=0; }  // перебор меню  
   adcBuf[(count++)%701] = 255; adcBuf[(count++)%701] = 0; adcBuf[(count++)%701] = 255; if (count>159) grOffset = count - 160; } // отметка паузы на графике
    delay(100);    // антидребезг кнопки    
  tft.setRotation(0); 
  tft.fillRect(118, 0, 128, 160, BLACK); //стирание верх меню
  tft.fillRect( 0, 0, 10, 160, BLACK);//стиране ниж меню    
  tft.fillRect(16, 34, 100, 160, BLACK);//стиране поля графика 
  }    
  // === Отрисовка менюшки ===  
  tft.setRotation(1);
 // tft.setTextColor(RED);  
  if (subMenu==0) tft.setTextColor(WHITE, RED); else tft.setTextColor(RED);tft.setCursor(4,0); 
  if (vRef) { tft.print("V=5.3");} else tft.print("V=1.1");
  if (subMenu==1)  tft.setTextColor(WHITE, RED); else tft.setTextColor(RED);
  tft.setCursor(58, 0); tft.print("РАЗВ=");  tft.print(razv);
  if (subMenu==2) { tft.setTextColor(WHITE, RED); pause=1; } else  tft.setTextColor(RED);
  tft.setCursor(120,0); tft.print("П "); tft.print(" ");  tft.print((grOffset%701)/3, 0);  tft.print("%"); 
  tft.setTextColor( RED);
  if (subMenu==3) {tft.setTextColor( RED); tft.setCursor(120,0); tft.print("C "); } 
 
  // максимальное значение сигнала
  Vmax=0; 
  for (int y=1; y<255; y++) if (Vmax<adcBuf[y]) Vmax=adcBuf[y];
  
  // === Отрисовка сетки ===  
    tft.setTextColor(TEAL);
    tft.print("v");
    tft.setCursor(135,121);
    tft.print(Vakb);     
    tft.setCursor(69,121);
    tft.print("Vmax=");
    tft.setTextColor(TEAL, BLACK);
    if (vRef) tft.print(Vmax*VCC/255,1);
        else  tft.print(Vmax*1.1/255,1);
    
    //ось напряжения##########################################    
   for(byte i=107;i>11; i=i-16) {tft.drawLine( 0, i, 4, i, BLUE); } // черточки слева 
   tft.drawFastVLine(5,12,102,BLUE);tft.drawFastVLine(6,12,102,BLUE);
   //ось времени##########################################
   for(byte i=160;i>7; i=i-16) {tft.drawLine( i, 113, i, 117, RED); } // черточки слева 
   tft.drawFastHLine(7,112,160,RED);tft.drawFastHLine(7,113,160,RED);
 
  // === Отрисовка графика ===    
  for (int y=8; y<160; y++) tft.drawLine(y, 105, y, 105-adcBuf[(y + grOffset)%701]/3.5, GREEN);
  if (pause) { // если пауза - рисуем шкалу прокрутки
    tft.drawLine((grOffset%701)/9,118,(grOffset%701)/9+6,118, BLUE); // шкала прокрутки
    tft.drawLine((grOffset%701)/9,119,(grOffset%701)/9+6,119, BLUE); // шкала прокрутки                
  } else { // если не пауза, то снимаем показания
     while ((ADCSRA & 0x10)==0); // ждем, пока АЦП считает    
     adcBuf[count%701]=ADCH; // сохраняем число из АЦП в массив
     if (count>159) grOffset = count - 160;
     count++;
     if (count>1401) count=701; // зацикливаем счетчик
     //45мс - программа выполняется
     switch (razv) {
       case 0 : delay(55*(overclock/16.0)); break; // секунда на клетку
       case 1 : delay(05*(overclock/16.0)); break; // пол секунды на клетку
       case 2 : break; // без задержки.......
     }
  } 
  if (digitalRead(KEY_L) == HIGH && digitalRead(KEY_R) == HIGH) { delay(1000);
  wdt_enable(WDTO_30MS); while(1) {} ;
  Reset_AVR(); } // soft reset  
  }
   }  
   // === UART приемник === 
  if(mainMenu==3) {  tft.fillScreen(BLACK);   
   while(1){   
   const long speedUart[] = { 1200,2400,4800,9600,19200,38400,57600,115200 };  
  tft.setTextSize(2);
  tft.setTextColor(WHITE, BLUE); 
  tft.setCursor(135, 40); tft.println("+");
  tft.setCursor(25, 40); tft.print("-");
  tft.setTextColor(RED);
  tft.println(" ");      
  tft.print(speedUart[menu]);
  tft.println(" ");
  tft.setCursor(36,15); tft.println("Скорость:");
  tft.setTextColor( GREEN);
  tft.setCursor(18,60); tft.println("ОК - запуск");
  if(digitalRead(KEY_L))  { tft.fillRect( 0, 38, 150, 58, BLACK);
  menu--; if(menu==255) menu=7;   delay(200);  }
  if(digitalRead(KEY_R))  { tft.fillRect( 0, 38, 150, 58, BLACK); 
  menu++; if(menu==8)   menu=0;   delay(200);  }
  if(digitalRead(KEY_OK)) {
    Serial.begin(speedUart[menu]*(16.0/overclock));
    tft.setCursor(25,85);    
    tft.print(">"); 
    delay(200);     
    int x=83;
    while (1) {         
      if (Serial.available()) { // Если в буфере есть данные
        if(++x==84) { // проверяем, не пора ли экран очистить
          x=0;
          tft.fillScreen(BLACK);
        }
        tft.print((char)(Serial.read())); // печать байта в дисплей        
      } 
    }         
  }  
  if (digitalRead(KEY_L) == HIGH && digitalRead(KEY_R) == HIGH) { delay(1000);
  wdt_enable(WDTO_30MS); while(1) {} ;
  Reset_AVR(); } // soft reset   
   }
//############ Частотомер ################
   if(mainMenu==4) {  tft.fillScreen(BLACK);   
   while(1){    
  tft.setTextSize(2); 
  tft.setTextColor(GREEN);
  tft.setCursor(33, 30); tft.println("Частота:"); 
  if(FreqMeasure.available()) {        
  sum = sum + FreqMeasure.read();
  count = count + 1;    if (count > 30) {
  float frequency = FreqMeasure.countToFrequency(sum / count);    
  tft.fillRect( 0, 64, 160, 84, BLACK);     
  tft.setTextColor(RED);  tft.setCursor(24, 65);
  //--------Блок вычисления частоты в ГЦ---------------------
  if (frequency <= 1000){   tft.print(frequency);  tft.println(" Hz");       }
  //--------Блок вычисления частоты в КГЦ---------------------      
  else { float freq = frequency / 1000;  tft.print(freq);  tft.println(" KHz");  }        
  sum = 0;  count = 0;   
    }
  }  
  if (digitalRead(KEY_L) == HIGH && digitalRead(KEY_R) == HIGH) { delay(1000);
  wdt_enable(WDTO_30MS); while(1) {} ;
  Reset_AVR(); } // soft reset     
   }   
   }    
// === Вольтметр === 
  if(mainMenu==5) {  tft.fillScreen(BLACK);   
   while(1){
    tft.setTextSize(2);
tft.setTextColor(GREEN); 
tft.setCursor(10, 25);
tft.print("Вольтметр DC");    
 MsTimer2::set(1, timerInterupt); // прерывания по таймеру, период 1 мс 
  MsTimer2::start();              // разрешение прерывания
 if ( flagReady == true ) {
    flagReady= false;
    // пересчет в напряжение и передача на компьютер
    tft.setTextColor(BLUE);
tft.setCursor(32, 50);
tft.fillRect( 59, 50, 160, 70, BLACK );
tft.print("V= ");
tft.setTextColor(RED);    
    tft.print( (float)avarageU1 * ADC_U_COEFF, 2); 
   }
  if (digitalRead(KEY_L) == HIGH && digitalRead(KEY_R) == HIGH) { delay(1000);
  wdt_enable(WDTO_30MS); while(1) {} ;
  Reset_AVR(); } // soft reset  
   }
   } 
   } 
 
 
      
  
Novice User
Offline
Зарегистрирован: 25.09.2017

Спасибо!

Electronik83
Offline
Зарегистрирован: 06.12.2015

Много знакомых строчек))) Рекомендую спрятать в спойлер.

В транзистор тестере не такой ли экран стоит? 

И вообще, хорошим тоном считается указывать под какой экран заточен скейтч. 

Хоть пару строк описания....

Electronik83
Offline
Зарегистрирован: 06.12.2015

Достал после переезда коробку с ардуинами. Буду заниматься этим проектом дальше. В планах:

1. Создать мини faq (раньше давно был);

2. Перенос версии 18 на omaled ssd (забыл как называется);

3. Исправление ошибки с отображением частоты (спектрум тыкал - там как то с частотами не то);

4. Перезагрузка с кнопок.

5. Очень хочу добавить сохранение настроек всех значений пользователя в еепром! Но вышел затык с контрастом....

6. Непонятка с питанием от лития и измерения напряжений- надо разобраться.

7. Просмотрел много скейтчев - в одном из них увидел вольтметр - на кой черт он нужен?!?!

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Electronik83 пишет:

И вообще, хорошим тоном считается указывать под какой экран заточен скейтч. 

Skaytch ?   Слово Sketch  по-русски и по-английски произносится как скетч.

Electronik83
Offline
Зарегистрирован: 06.12.2015

Мне это слово сразу не понравилось. Приму к сведенью))))

MIK22
Offline
Зарегистрирован: 09.02.2017

Дисплей ST7735S.

Входные пины А3 Д8. Д8 определен библиотекой FreqMeasure. Она занимает меньше места.

Функция ZAMER для massduino и wemos NANO у меня заработала только в таков виде, хотя это одно и тоже

      //while ((ADCSRA & 0x10)==0);   // ждем готовность АЦП
      //ADCSRA|=0x10;                 // запускаем следующее преобразование
      while(ADCSRA & (1<<ADSC)); 
      ADCSRA |= 1<<ADSC;
 Для wemos NANO не нашел аппаратный SPI поэтому дисплей подключен по програмному. Для massduino все нормально работает.
Вольтметр до 30 вольт. коэффициунт расчитан для аходного делителя.
Была еще прозвонка но сделать ее на тех же входных пинах не получилось, а делать дополнительный вход не хотелось.
alex_c
Offline
Зарегистрирован: 22.06.2018

парни добрый день кто подскажет как можно сделать может кто делал развертку (сек/дел) больше чем у оригинала?

мне просто надо что бы было 1-2 сек на деление

Electronik83
Offline
Зарегистрирован: 06.12.2015

Дак в моей версии там есть.....

alex_c
Offline
Зарегистрирован: 22.06.2018

а где ознакомится можно?

Electronik83
Offline
Зарегистрирован: 06.12.2015

https://yadi.sk/d/OWt4M28A3ULLcf

Последняя нормальная версия... для 5110

alex_c
Offline
Зарегистрирован: 22.06.2018

спасибо я посматрел но на 0 тоже самое ( а это много

Electronik83
Offline
Зарегистрирован: 06.12.2015

alex_c пишет:

спасибо я посматрел но на 0 тоже самое ( а это много

Там отдельный режим сделан - снятие АЧХ. Он медленный.

alex_c
Offline
Зарегистрирован: 22.06.2018

да спасибо нашел)

Electronik83
Offline
Зарегистрирован: 06.12.2015

Чет у меня походу SSD1306 накрылся..... блин я в печали... хотел переписать под него и не работатет экранчик....

Andry Smart
Offline
Зарегистрирован: 06.09.2016

вот блин а я так ждал.... и что теперь делать? как по мне этот экран рожден для пультоскопа.

weisswp
Offline
Зарегистрирован: 26.05.2018

эх.. и я ждал (

slider
Offline
Зарегистрирован: 17.06.2014

Electronik83 пишет:

Чет у меня походу SSD1306 накрылся..... блин я в печали... хотел переписать под него и не работатет экранчик....

подикась напрямую к ардуине зацепляли , без делителей ?

MIK22, вроде massduino может работать на 32МГц ? по идее , после заливки скетча с настройками надо перепаять кварц, должно заработать.

Electronik83
Offline
Зарегистрирован: 06.12.2015

Дак дисплей этот очень долго так работал. Тем более на плате у самого дисплея распаяны делители. Я переписал прогу под него, запустил и все. Кирдык ему. Могу поделиться скетчем убицом таких дисплеев)))) Или может он мехаеически пострадал. В общем не до конца понятно что случилось)

alexey561
Offline
Зарегистрирован: 23.06.2018

Здравствуйте, сделал осциллограф с усилителем и смещением нуля, возникла проблема как измерить напряжение входного сигнала? Может у кого нибудь есть идеи? https://youtu.be/si_QmqxYATE

alexey561
Offline
Зарегистрирован: 23.06.2018

Буду благодарен за любую информацию

weisswp
Offline
Зарегистрирован: 26.05.2018

сомневаюсь, что можно программно убить дисплей, поэтому готов рискнуть одним из своих)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Дисплеи умирают от того, что не рассчитаны на работу с 5-вольтовыми МК. Недавно писал как узнать совместимый с 5в дисплей.

VicSan
Offline
Зарегистрирован: 27.04.2017

я сразу себе делители поставил.

MIK22
Offline
Зарегистрирован: 09.02.2017

dimax

Разрещите обратиться к Вам в личку.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

MIK22, тут лички нет :)

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Наткнулся тут на старинький скетч От Electronik83  ver 17032017, попробовал в работе - довольно шустрый.  От себя заменил терминал на меню контрастности и вкл. откл. подсветки с сохранением в EEPROM. Работает, но уже немного с задержкой из меню переходит в подменю))). Скетч для 5110 (делитель 100к10к), если кому не лень, то работа над ошибками приветствуется. 

Ну ещё полезно тем кто любит рисовать  Image2Bitmap

//Страница проэкта  http://srukami.inf.ua/pultoscop_v25110.html
// ---------------------------------------------------------------
// От Electronik83 (mailto: gsmkillersevsk@mail.ru): ver 17032017
// 1. В режиме генератора PWM в процентах в целых числах (без дробей), нарисовал график сигнала PWM
// 2. В генераторе пофиксил/оптимизировал вывод частоты (1000 герц не показывало)
// 3. Автоматическое определение схемы подключения кнопок (при включении лучше ничего не нажимать:) :
//      a). Как у автора - кнопки к питанию и резюки на массу
//      b). Как я хочу - кнопки к земле и без всяких резюков
// 4. Отправил вэйвы для DDS генератора во флэш - оперативы больше стало свободной
// 5. Реализовал перезапуск при зажатии кнопок "+" и "-" (из осцилла не работает (не знаю, как исправить!))
// 6. Убрал развертки 7 и 8 (программное растягивание) 
// 7. На DDS - генераторе видно форму выводимого сигнала, оптимизировал, сделал свои формы -  ваще клевый стал... 
// 8. Переделал меню генератора - вроде удобней стало.
// 9. В терминале можно выбирать стандартные скорости
// 10. Координально переделал некоторые куски кода, например - вывод меню....
// 11. От smokok, заменил терминал на меню контрастности и вкл. откл. подсветки с сохранением в EEPROM
// 12. Сломал перезагрузку менюхи кнопками + и -, но прошива очень шустрая однако!!!
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <FreqCount.h> 
#include <PWM.h>
#include <EEPROM.h>
// ---- UserSpace ---- //
// Подключение дисплея 
// (clk(scl, sck), din(sda, mosi), dc, ce (cs), rst)  
#define Ekran     8  //Экран/////////////////////////////////Подсвет
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 4, 3, 2); // пины к которым подключен дисплей        
//  #define contrast 52  // контрастность дисплея////////////////////////////////////////
#define key_down 11  // кнопка минус (можно любой пин)
#define key_ok   12  // кнопка ОК (можно любой пин)
#define key_up   13  // кнопка плюс (можно любой пин)
#define akb A5       // любой свободный аналоговый пин для измерения напряжения АКБ 
#define overclock 16 // частота на которой работает Ардуино
float VCC=5.10;  // напряжение питания, меряем мультиметром
// ---- UserSpace_End ---- //
//        A3    !!   // пин подключиния входа осцилла (для отображения формы сигнала)
//        D5    !!   // пин подключиния входа осцилла (для аппаратного измерения частоты через таймер (в FreqCount.h))
#define led  9       // пин для генератора сигналов (не менять)
#define dds  10      // пин для генератора dds (не менять)

// ---- Глобальные переменные ---- //
byte contrast;
byte Set=0;       ///////////////////////Экран/////////////////////////////////
bool BL;          /////////////////////////Экран///////////////////////////////
bool flag_key;       // нужно для разных подключений кнопок
byte mode=0;         // режим работы прибора
byte menu=0;         // подменю
const char* const modeStr[] PROGMEM= { " Осциллоскоп ", "PWM-генератор", "DDS-генератор", "* * Экран * *"};

// ---- Переменые для осциллоскопа ---- //
#define BUFSIZE 700
byte adcBuf[BUFSIZE]; // буфер проебразований АЦП
byte syncLevel=30;    // уровень синхронизации 0 до 255
byte razv=6;          // развертка
bool pause=0;         // флаг режима паузы
bool opornoe=0;       // флаг опорного напряжения
int  pauseOffset=0;   // смещение графика в режиме паузы (прокрутка)
long count=0;         // для подсчета частоты сигнала
//         bool magnify=0; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// ---- Переменные для генератора ---- //
unsigned long stepFreq=0;
int PWM = 50;    // стартовое значение ШИМ от 0 до 100 для генератора        
unsigned long freq = 500; // стартовое значение частоты в Гц для генератора

void ShowMode(char m, char y) {
   display.setCursor(3, y);
   switch (m) {
      case 0: display.print(modeStr[0]); break;
      case 1: display.print(modeStr[1]); break;
      case 2: display.print(modeStr[2]); break;
      case 3: display.print(modeStr[3]); break;
    }
}
void ShowModeInv(char y) {
  display.setTextColor(WHITE, BLACK);
  display.setCursor(0, y); display.println(" "); display.setCursor(77, y); display.println(" ");  // для красоты только
  ShowMode(mode, y);
  display.setTextColor(BLACK);
}

// ==== Инициализация всего :) ==== //
void setup() {
  delay(300); // ждем, пока питание устаканится (меньше глюков чтоб потом ловить)
  
////////////////////////////Экран//////////////////////////////
//  Примечание. Экран становится темным,  решение проблемы.///////////////////////////////////////
//  EEPROM.write(0, 50);  //  Записать закрытую строку,  Обновить  и начать использовать.
  contrast = EEPROM.read(0);
  BL       = EEPROM.read(1);
  pinMode(Ekran, OUTPUT);
  digitalWrite(Ekran, BL);
  byte key_test=0;
  digitalWrite(key_up, HIGH); digitalWrite(key_down, HIGH); digitalWrite(key_ok, HIGH); 
  if (digitalRead(key_up))   key_test++; 
  if (digitalRead(key_down)) key_test++; 
  if (digitalRead(key_ok))   key_test++; 
  if (key_test>1) { 
    flag_key=0;   
  }
  else {
    digitalWrite(key_up, LOW); digitalWrite(key_down, LOW); digitalWrite(key_ok, LOW); 
    flag_key=1;
  }   
  display.begin();
  display.setContrast(contrast);  
  while(flag_key-digitalRead(key_ok))  {
    display.clearDisplay();
//////////////////////////////////////////////////////

 // автодетект кнопок
  byte key_test=0;
  //pinMode(key_up, INPUT); pinMode(key_down, INPUT); pinMode(key_ok, INPUT); 
  // подтянули кнопки к питанию
  digitalWrite(key_up, HIGH); digitalWrite(key_down, HIGH); digitalWrite(key_ok, HIGH); 
  // автодетект подключения кнопок при включении..
  if (digitalRead(key_up))   key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
  if (digitalRead(key_down)) key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
  if (digitalRead(key_ok))   key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
  if (key_test>1) { // определили подключение кнопок на массу
    flag_key=0;   
  }
  else { // определили подключение кнопок на питание + резюки на массу
    digitalWrite(key_up, LOW); digitalWrite(key_down, LOW); digitalWrite(key_ok, LOW); // убрали подтяжку 
    flag_key=1;
  }
  // если автодетект работает неверно (менюха скачет постоянно), то нужно расскомментировать одну из следующих строчек:
  // flag_key = 0; // кнопки просто подключены к земле, резюков нету.
  // flag_key = 1; // кнопки подключены к питанию и резюки на землю
  
  while(flag_key-digitalRead(key_ok))  { // выводим меню, пока не выбран режим работы прибора  
    display.clearDisplay();              // чистим дисплей
    // выводим главное меню
    for (char i=0; i<4; i++) {
      if (i==mode) ShowModeInv(i*10); else ShowMode(i, i*10);      
    }
    delay(50);
    display.setCursor(12,40); display.print("Бат=");  // выводим напряжение батареи
    display.print(analogRead(akb)*VCC/1024);
    display.print("v");
    // перемещаемся по меню  
    if (flag_key-!digitalRead(key_up)  ) { mode++; if (mode>3)       mode=0; delay(100); }
    if (flag_key-!digitalRead(key_down)) { mode--; if (mode == 0xFF) mode=3; delay(100); }
    display.display(); // выводим все на экран
  }
  // выбран режим работы...
  if (mode==0) FreqCount.begin(1000);
  if (mode==1) { InitTimersSafe(); SetPinFrequencySafe(led, freq);   }
  if (mode==2) { InitTimersSafe(); SetPinFrequencySafe(led, 200000); }
  delay(200);
}
  } 
// безконечный цикл - по сути прыгаем в подпрограммы
void loop() {
  if (mode==0) Oscill();       // "выпадаем" в осцилл
  if (mode==1) Generator();    // "выпадаем" в генератор 
  if (mode==2) DdsGenerator(); // "выпадаем" в DDS генератор
  if (mode==3) Menu_ekrana();  // "выпадаем" в Menu Экрана
}
// читаем с АЦП данные и помещаем их в буфер...   
void ReadAdc() {
  if (razv) { // (razv>0)           // если развертка без задержек всяких
    ADCSRA = 0b11100000 | (8-razv); // установили делитель (/2 - не работает, так что начинаем с /4)
    for(int i=0; i<BUFSIZE; i++) {  // цикл для чтения  
      while ((ADCSRA & 0x10)==0);   // ждем готовность АЦП
      ADCSRA|=0x10;                 // запускаем следующее преобразование
      adcBuf[i]=ADCH;               // записываем данные в массив
    }
  } else {                          // развертка с задержками (delay)
    ADCSRA = 0b11100111;            // делитель на /128
    for(int i=0; i<BUFSIZE; i++) {  // цикл для чтения
      while ((ADCSRA & 0x10)==0);   // ждем готовность АЦП
      ADCSRA|=0x10;                 // запускаем следующее преобразование
//      delayMicroseconds(500);       // делаем задержку /////////////спасибо, ArduinoFart///////////////////////
      adcBuf[i]=ADCH;               // записываем данные в массив
    }
  }
}

//////////////////////////////// РЕЖИМ ОСЦИЛЛОСКОПА//////////////////////////////
void Oscill() {  
  if(opornoe) ADMUX = 0b01100011; // выбор внешнего опорного
         else ADMUX = 0b11100011; // выбор внутреннего опорного 1,1В
  delay(100);
  if(!pause) ReadAdc(); // если паузы нет, то считываем сигнал в буфер
  // определение точки синхронизации
  bool flagSync=0;    // флаг, когда сигнал ниже уровня синхронизации
  int syncOffset=0;   // смещение для вывода с синхронизацией
  // считаем максимальное и минимальное значение сигнала (для вывода на экран)
  byte Vmax=0, Vmin=255; // тут будем хранить максимальное и минимальное напряжение 
  for(int y=0; y<BUFSIZE; y++) { if(Vmin>adcBuf[y]) Vmin=adcBuf[y]; if(Vmax<adcBuf[y]) Vmax=adcBuf[y]; }
  //syncLevel = (Vmax-Vmin) / 2 + Vmin;
  // считаем смещение графика по уровню синхронизации
  for(int y=0; y<BUFSIZE-80; y++) {
    if(adcBuf[y]<syncLevel) flagSync=1;
    if(flagSync && adcBuf[y]>syncLevel) { syncOffset = y; break; } 
  }
  // отрисовка графика 
  display.clearDisplay(); // чистим дисплей
  byte x=3; // задаем смещение графика немного вправо
  if(pause) { // если в режиме паузы, то рисуем с прокруткой...
    display.drawLine(pauseOffset/8,8,pauseOffset/8+6,8, BLACK); //шкала прокрутки
    display.drawLine(pauseOffset/8,9,pauseOffset/8+6,9, BLACK); //шкала прокрутки
    for(int y=pauseOffset; y<pauseOffset+80; y++) { // рисуем форму сигнала
      display.drawLine(++x, 47-adcBuf[y]/7, x+1, 47-adcBuf[y+1]/7, BLACK);       //линия сигнала/////////
      //display.drawLine(x+1, 47-adcBuf[y]/7+1, x+2, 47-adcBuf[y+1]/7+1, BLACK); //тоньше линия сигнала/////////
    }
  } else {  // если паузы нет, то рисуем немного по другому))..
    display.fillCircle(80,47-syncLevel/7, 2, BLACK); //рисуем уровень синхронизации    
    for(int y=syncOffset; y<syncOffset+80; y++) {  // рисуем форму сигнала
      display.drawLine(++x, 47-adcBuf[y]/7, x+1, 47-adcBuf[y+1]/7, BLACK);        //линия сигнала/////////
      //display.drawLine(x+1, 47-adcBuf[y]/7+2, x+1, 47-adcBuf[y+1]/7+1, BLACK);  //тоньше линия сигнала/////////
    }
  }
  // отрисовка сетки
  for(byte i=47;i>5;i-=7) { display.drawPixel(0, i, BLACK); display.drawPixel(1, i, BLACK); display.drawPixel(2, i, BLACK); }
  for(byte i=47;i>5;i-=3) { display.drawPixel(21,i, BLACK); display.drawPixel(42,i, BLACK); display.drawPixel(63,i, BLACK); }
  for(byte i=3;i<84;i+=3) { display.drawPixel(i,33, BLACK); display.drawPixel(i,19, BLACK); }
 
  // отрисовка menu
  display.setCursor(0,0);
  if (menu==0) { 
    display.setTextColor(WHITE, BLACK); 
    if(flag_key-!digitalRead(key_down) || flag_key-!digitalRead(key_up)) { opornoe=!opornoe; }
    } else display.setTextColor(BLACK);
    
  if(opornoe) display.print(VCC,1); else display.print("1.1");
  
  if (menu==1) {
    display.setTextColor(WHITE, BLACK);
    if(flag_key-!digitalRead(key_down)) { razv--; if(razv==255) razv=6; }
    if(flag_key-!digitalRead(key_up)  ) { razv++; if(razv==7)   razv=0; }
  } else display.setTextColor(BLACK);
  
  display.print(" "); display.print(razv);
  
  if (menu==2) { 
    display.setTextColor(WHITE, BLACK);
    pause=1;
    if(flag_key-!digitalRead(key_down)) { pauseOffset-=27; if(pauseOffset<0)   pauseOffset=0;   }
    if(flag_key-!digitalRead(key_up)  ) { pauseOffset+=27; if(pauseOffset>619) pauseOffset=619; }    
  } else display.setTextColor(BLACK);

  display.print("~");
  display.setTextColor(BLACK);
  
  if(menu==3) {
    pauseOffset=0;
    pause=0;
    if(flag_key-!digitalRead(key_down)) { syncLevel-=20; if(syncLevel<20)  syncLevel=20;  }
    if(flag_key-!digitalRead(key_up)  ) { syncLevel+=20; if(syncLevel>230) syncLevel=230; }   
    display.fillCircle(80,47-syncLevel/7, 5, BLACK);
    display.fillCircle(80,47-syncLevel/7, 2, WHITE); 
  }
  if (flag_key-!digitalRead(key_ok)) { menu++; if(menu==4) { menu=0; pause=0; }}//перебор меню

  // забираем частоту сигнала, полученную аппаратно (через таймер)
  if (FreqCount.available()) count = FreqCount.read(); // забираем по готовности счетчика
    
  // считаем программно частоту сигнала
  byte Freq1=0;
  long Freq=0;
  bool flagFreq1=0, flagFreq2=0, flagFreq3=0;
  for(int y=1; y<255; y++) {
    if(!flagFreq1 && adcBuf[y]<syncLevel) flagFreq2=1; // тут можно че то оптимизировать, тока не могу понять, что [El83]   
    if(!flagFreq1 && flagFreq2 && adcBuf[y]>syncLevel) { flagFreq1=1; Freq1=y; }    
    if( flagFreq1 && adcBuf[y]<syncLevel) flagFreq3=1;    
    if( flagFreq3 && adcBuf[y]>syncLevel) {      
      switch (razv) { // тут позже оптимизирую!                           ////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
        case 6: Freq=1000000/((y-Freq1-1)*3.27);  break; // делитель 4
        case 5: Freq=1000000/((y-Freq1)*3.27)/2;  break; // делитель 8
        case 4: Freq=1000000/((y-Freq1)*3.27)/4;  break; // делитель 16
        case 3: Freq=1000000/((y-Freq1)*3.27)/8;  break; // делитель 32
        case 2: Freq=1000000/((y-Freq1)*3.27)/16; break; // делитель 64
        case 1: Freq=1000000/((y-Freq1)*3.27)/32; break; // делитель 128
        case 0: Freq=1000000/((y-Freq1)*500);     break; // делитель 128
      }  
      flagFreq1=0; flagFreq3=0;
    }
  }
  // отрисовка частоты сигнала
  if (opornoe && ((Vmax*VCC/255)>2.5)) count=count*(overclock/16.0); 
                                  else count=Freq *(overclock/16.0);
  if (count<1000) { display.print(" "); display.print(count); display.print("Hz"); }
             else { display.print(count/1000.0, 1); display.print("KHz"); }
  // отрисовка максимального напряжения сигнала
  display.setCursor(0,40); 
  if (opornoe) display.print(Vmax*VCC/255*11.15,1); else display.print(Vmax*1.1/255*11.15,1);
  display.print("v");
  //delay(200);  
  display.display(); // вываливаем все на экран
}

//////////////////////////////// РЕЖИМ ГЕНЕРАТОРА//////////////////////////////
void Generator() {
  // обработка кнопок и отрисовка одновременно
  display.clearDisplay();
  ShowModeInv(0);  
  if(flag_key-!digitalRead(key_ok)) { if(menu++==7) menu=0; delay(200); } // переходим по разрядам / меняем ШИМ
  if (menu==7) { // меняем ШИМ
    if(flag_key-!digitalRead(key_down)) { PWM--; if(PWM<0)   PWM=100; delay(200); }
    if(flag_key-!digitalRead(key_up))   { PWM++; if(PWM>100) PWM=0;   delay(200); }
    pwmWrite(led, PWM*2.55); // задали ШИМ
    display.setTextColor(WHITE, BLACK); // если меняем шим, то рисуем его инверсным
    display.drawLine(15, 39, 68+(PWM==100?6:0)+(PWM<10?-6:0), 39, BLACK); // сверху полоска для большей инверсности
  } else { // меняем частоту
    if(flag_key-!digitalRead(key_down)) {
      if (freq>stepFreq)  freq-=stepFreq;              // не даем выйти за допустимый диаппазон
      SetPinFrequencySafe(led, freq/(overclock/16.0)); // задали частоту
      delay(200); // задержка для кнопок 
    }
    if(flag_key-!digitalRead(key_up))   {
      if ((freq+stepFreq)<10000000) freq+=stepFreq;    // не даем выйти за допустимый диаппазон
      SetPinFrequencySafe(led, freq/(overclock/16.0)); // задали частоту
      delay(200); // задержка для кнопок 
    }  
    display.setTextColor(BLACK); // если ШИМ не меняем, то выбираем обычный текст
    #define XFREQ 12 // ======== // и, выделяем декаду частоты полосочками
    stepFreq=pow(10, (byte)menu); if (menu>1) stepFreq++; // устраняем глючность pow, почему 10 в степени 2 = 99?
    byte menu_t = menu; if (menu>2) menu_t++; if (menu==6) menu_t++; // делаем табуляцию частоты
    menu_t = 54 - menu_t * 6; // считаем положение полосочек
    display.drawLine(menu_t, XFREQ-2, menu_t+4, XFREQ-2, BLACK); // рисуем полоски
    display.drawLine(menu_t, XFREQ-3, menu_t+4, XFREQ-3, BLACK);
    display.drawLine(menu_t, XFREQ+8, menu_t+4, XFREQ+8, BLACK);          
    display.drawLine(menu_t, XFREQ+9, menu_t+4, XFREQ+9, BLACK);
  }
  // рисуем уровень ШИМ (инверсия текста задана ранее)
  display.setCursor(15, 40); // ставим курсор))
  display.print(" PWM=");  display.print(PWM);  display.print("% "); // выводим уровень ШИМ
  display.setTextColor(BLACK); // убираем инверсию при выводе частоты
  // рисуем частоту с табуляцией  
  display.setCursor(6, XFREQ);
  for (unsigned long freq_t = 1000000; freq_t>0; freq_t/=10) {
  if (freq>=freq_t) {
    display.print((freq/freq_t)%10); if (freq_t==1000000 || freq_t==1000) display.print("'"); }  else { 
    display.print("_");              if (freq_t==1000000 || freq_t==1000) display.print(" "); }
  }
  display.print(" Hz");  
  // отрисовка графика PWM
  for (char x=17; x<67; ) {
    if (PWM!=0)             display.drawLine(x, 25, x+PWM/4, 25, BLACK); x+=PWM/4;       // верх 
    if (PWM!=0 && PWM!=100) display.drawLine(x, 25, x, 36, BLACK);                       // спад
    if (PWM!=100)           display.drawLine(x, 36, x+25-PWM/4, 36, BLACK); x+=25-PWM/4; // низ
    if (PWM!=0 && PWM!=100 && x<43) display.drawLine( x, 36, x, 25, BLACK);              // подъем
  }
  display.display(); // вываливаем буфер на дисплей
}

//////////////////////////////// DDS генератор//////////////////////////////
void DdsGenerator() {
  static const byte ddsWave[][32] PROGMEM = {
    2,10,21,37,57,79,103,127,152,176,198,218,234,245,253,255,253,245,233,218,198,176,152,128,103,79,57,37,21,10,2,0,    // El83_sinNew    
    16,32,48,64,80,96,112,128,143,159,175,191,207,223,239,255,239,223,207,191,175,159,143,128,112,96,80,64,48,32,16,0,  // El83_treugNew    
    8,16,25,33,41,49,58,66,74,82,90,99,107,115,123,132,140,148,156,165,173,181,189,197,206,214,222,230,239,247,255,0,   // El83_pilaNew
    255,247,239,230,222,214,206,197,189,181,173,165,156,148,140,132,123,115,107,99,90,82,74,66,58,49,41,33,25,16,8,0 }; // El83_pilaObrNew
  const char* const ddsStr[] PROGMEM = { "    Синус", " Треугольник", "    Пила", "Обратная пила"};
  byte ddsCount=0;
  // Рисуем DDS-генератор
  display.clearDisplay();  
  ShowModeInv(0);  
    for (byte i=0; i<84;) display.drawLine(i, 37-pgm_read_byte(&ddsWave[menu][i%32])/9, i, 37-pgm_read_byte(&ddsWave[menu][(i++)%32])/9, BLACK);
  display.setCursor(3, 40);  display.print(ddsStr[menu]);  display.display(); // отрисовали все
  // выводим выбранный сигнал, пока не нажали кнопку
  while(flag_key-digitalRead(key_up) && flag_key-digitalRead(key_down) && flag_key-digitalRead(key_ok)) {
    pwmWrite(dds, pgm_read_byte(&ddsWave[menu][(ddsCount++)&0x1F]));
  }
  if (++menu==4) menu = 0; // нажали кнопку - переключаем режим
  delay(200); // чтоб кнопки нормально нажимались
}

//////////////////////////////Экран/////////////////////////////////
void Menu_ekrana() {
  Set=0;delay(300);
  while (flag_key-digitalRead(key_ok)){
    display.clearDisplay();
    if (Set == 0) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
    display.setCursor(0 , 0); display.println("Контраст:"); display.setTextColor(BLACK);
    display.setCursor(60 , 0); display.println(contrast);
    display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
    if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл");} else
                 { display.setCursor(60 , 10); display.println("Отк");} display.display();
    if (flag_key-!digitalRead(key_up))   contrast++;
    if (flag_key-!digitalRead(key_down)) contrast--;
    if (contrast<30) contrast=30;
    if (contrast>70) contrast=70;
    display.setContrast(contrast); 
    delay(150);
  }
  Set=1; delay(300);
  while (flag_key-digitalRead(key_ok)){
    display.clearDisplay();
    display.setCursor(0 , 0); display.println("Контраст:");
    display.setCursor(60 , 0); display.println(contrast);
    if (Set == 1) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
    display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
    if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл"); digitalWrite(Ekran, BL); } else
                 { display.setCursor(60 , 10); display.println("Отк"); digitalWrite(Ekran, BL);  }
    if (flag_key-!digitalRead(key_up))   BL=1;
    if (flag_key-!digitalRead(key_down)) BL=0;
    display.display();
    delay(150);
  }
  display.display();
  display.clearDisplay();
  EEPROM.write(0, contrast);
  EEPROM.write(1, BL);
  setup();
}

 

Novice User
Offline
Зарегистрирован: 25.09.2017

удалил

Andry Smart
Offline
Зарегистрирован: 06.09.2016

а точно делитель 100/10k? а то что то показания у меня не правильные по напряжению.                      

Andry Smart
Offline
Зарегистрирован: 06.09.2016

ложная тревога. поставил делитель 20/2k и теперь все ок. по ошибке не тот резистор попал. 

 

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Andry Smart пишет:

по ошибке не тот резистор попал. 

 

Хорошо что хоть не транзистор))))). Быает.

Ребята, как вернуть развёртку 7 - 8 в тот скетч что выше? И почему через делитель не ту частоту показывает?

Electronik83
Offline
Зарегистрирован: 06.12.2015

Развертку 7...8 я вырезал. Это по сути 6-ая развертка с растягиванием формы сигнала. Зачем это нужно то?

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Electronik83 пишет:
Зачем это нужно то?
Значит уже не нужно))). Ну прошивочка класс, шустрая хоть и старая. Хорошо что её нашёл, спасибо. Вот только когда добавил сохранение настроек экрана в епром, то посыпались ошибки при сборке на код перезапуск кнопками, пришлось вырезать не разобравшись. И из главного меню включение какого нибудь режима нужно кнопку давить около секунды. Может что в код дописать нужно? Цыфры менял, результат не увидел. Посмотри пожалуйста.
<Может кто к такому экрану подключал LCR-T4(T3)NoStripGrid ? Было бы удобно два в одном и от двух атмег

rusoturisto
rusoturisto аватар
Offline
Зарегистрирован: 20.03.2018

rusoturisto
rusoturisto аватар
Offline
Зарегистрирован: 20.03.2018

   Добрый вечер. Начал с фото (т.к. первый раз и не был уверен, что получится), но после фото комментарий не вписывается; пишу отдельно.    В таком корпусе собрал пультоскоп. Питание от внешнего БП (9 вольт), щуп из двухкубового шприца. Почему-то от вспышки на дисплее пропадает изображение: приходится выключить и включить питание чтобы изображение появилось. А это макет-демоверсия.

rusoturisto
rusoturisto аватар
Offline
Зарегистрирован: 20.03.2018

   Корпус от выпрямителя для волос. Дисплей по центру приложить не получилось (ножки не дают), но я думаю идея понятна. А ещё нашёл я как-то нерабочий блок розжига ксеноновых ламп фирмы michi. В металлическом корпусе плата залита рыхлым компаундом; его я удалил отвёрткой. Плату можно вставить свою и сделать пультоскоп.  А у ардуино DUE - один мегасемпл в секунду. Если хочется больше - нужен внешний АЦП. Например как в схеме Импульс-5110 на сайте РАДИОСКОТ.

kostyamat
Offline
Зарегистрирован: 16.11.2017

Вообще-то, масштабирование убивает напрочь разрешение адц. Лучше на Aref через RC подавать ШИМ с PWM вывода самой ардуино. На много лучше получится.

black-stripe
Offline
Зарегистрирован: 03.07.2018

Подскажите, пожалуйста, куда подключать обозначенный на схеме pultoscop v2 пин "А6 - АКБ"?
Замеры производить щупами на пине А5 и пине А6?
FCC- понятно, питание сталилизированное.

Спасибо.

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Ребята, помогите пожалуйста реализовать код в скетч для подачи звукового сигнала предупреждения при превышении 5 Вольт на щуп. 

Electronik83
Offline
Зарегистрирован: 06.12.2015

Я бы помог, но на отдыхе сейчас)))

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Electronik83 пишет:

Я бы помог, но на отдыхе сейчас)))

Отдыхай на здоровье, набирайся сил.

Подождём))).  Тема хорошая, особенно для переменного делителя.

Запустил экранчик от Нокия 6210 (96х60) на Adafruit_PCD8544.h. Распиновка подошла от 3310 (8 пин). Немного полазил по библиотеке, но ни как не удаётся убрать мусор в низу экрана и в режиме осцила происходит бутлуп экрана. Жалко что библиотека не подходит. 

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

smokok пишет:

Electronik83 пишет:

Я бы помог, но на отдыхе сейчас)))

Отдыхай на здоровье, набирайся сил.

Подождём))).  Тема хорошая, особенно для переменного делителя.

Запустил экранчик от Нокия 6210 (96х60) на Adafruit_PCD8544.h. Распиновка подошла от 3310 (8 пин). Немного полазил по библиотеке, но ни как не удаётся убрать мусор в низу экрана и в режиме осцила происходит бутлуп экрана. Жалко что библиотека не подходит. 

Возможно дисплей китайский ?

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Возможно дисплей китайский ?

 Сомневаюсь что это чистый китай, так как выдрал его из старого тела MADE BY NOKIA. Просто нужно правильно отредактировать драйвер под этот котроллер. Распиновку брал тут http://radiomaster.com.ua/uploads/posts/2009-09/thumbs/1253098427_nokia.gif

Про мусор читал тут https://radiokot.ru/articles/29/  и возможно вы найдёте решение для своего экрана 3310. 

Мусор почти весь убрал, остался только немного с права, постоянно движется типо не четко дублируя вольтаж батареи, осталось победить  экран, (победил))) и естественно пересовать сетку и график под разрешение 96х60. 

Electronik83
Offline
Зарегистрирован: 06.12.2015

Потому что это экран 3410. Я под него хотел сделать изначально прибор, есть парочка с телефонов. Я вроде вопрос задавал тут.

Electronik83
Offline
Зарегистрирован: 06.12.2015

Del....