Nouvelles:

Le Forum est maintenant chiffré (préambule https). Bien sûr, des liens externes insérés dans les sujets vont demeurer inchangés. Mais la composition des pages du Forum est désormais sécurisée. Si des problèmes d'affichage surviennent, veillez à vider votre cache pour ce site.

Menu principal

EB_#333 Oscilloscope Arduino

Démarré par cyberfun, Décembre 03, 2019, 10:24:05 PM

« précédent - suivant »

cyberfun

Salut, Avec du vieux on fait du neuf, cela tombais a pic, j'avais un ancien moniteur de camera CRT...

Maintenant reste plus qu'a produire un code sources du code source optimisé....

Au passage j'ai trouvé ceci : http://radiopench.blog96.fc2.com/blog-entry-893.html avec un écran Oled. Une piste pour l'optimisation...

En attendant voila ma bidouille...
Un ancien écran CRT moniteur de camera de surveillance dont j'ai retiré le Switch de camera car a l’arrière on avait un connecteur pour brancher 4 cameras.
Donc il me restait un connecteur pour alimenter l’Arduino au travers d'un pont de diode filtrage et régulateur 5v. Ce moniteur possède donc un transformateur avec plusieurs enroulement.
















Bonne bidouille...

Électro-Bidouilleur

Vous êtes bien parti en effet. Vous vous engagez de la sorte à  me soumettre votre code source!

Au passage, ce serait préférable que vous réduisiez les photos. Très difficile de les consulter...

Curiosus

#2
Bonjour cyberfun, et tout le forum,

Pour améliorer le code il faudrait changer de langage de programmation,  et passer par ce qui est le plus rapide en langage de programmation
qui est le langage ASM.

Très bonne idée de la part de Électro-Bidouilleur pour ce challenge, ben moi je connais pas le langage Arduino, mais je pourrais m’amuser
à  le réécrire avec  un microcontrôleur Pic18F26K22 en ASM.

C'est vrai les images sont un peu grande,  merci pour les liens que tu donnes, qui sont très riche.

A+

Électro-Bidouilleur

Il est possible d'améliorer les caractéristiques de l'oscilloscope Arduino sans passer à  de l'assembleur. Mais pour la performance, c'est plus difficile en effet.

cyberfun

#4
Salut amis Bidouilleurs,


Désolé pour la taille des images j'avais pas fait attention au pixel.... J'ai corrigé cela.
De l'ASM pour un Arduino bof bof je suis pas pro en ASM... Mais je sais qu'avec l'Arduino il est possible de contrôler directement les bit et réduire ainsi le code source au plus strict.
De plus il est possible de mettre une veille pendant une acquisition ce qui évite les bruits parasites et accélère l’acquisition sur le A0 car on peut directement mentionné le canal du MUX du convertisseur analogique.

J'ai un soucis de synchro d'affichage quand il échantillonne a quelques Hz au dessus des 300Hz sa passe bien... mais bon le moniteur est pas nouveau et toujours analogique lui aussi....
Enfin sa fait deux jour que je potasse le code source.... j'ai quelques éclaircies dans ma tête sur le code en même temps la page web que je cite dans la publication précédente apporte aussi un complément. et ajoute même une fonction HOLD à  la mesure... Mais bon le sujet n'est pas pour ici maintenant. dans l'organisation du code source du lien c'est a mon avis déjà  plus précis sur les temporisation etc.... mais bon je potasse..... J’espère sortir une bonne mouture de code source....

Edit 6/12/2020 10:05

une autre piste :
ceci pour controler plus en détail l'ADC de l’Arduino. Peut-être gagner en vitesse d’acquisition....
ADC tuto : http://www.robotplatform.com/knowledge/ADC/adc_tutorial_4.html
ou mieux encore : https://www.gammon.com.au/adc

Électro-Bidouilleur

Pour votre problème de synchro de l'affichage, variez la valeur des deux résistances en sortie, particulièrement celle sur l'impulsion de synchronisation. Tentez ne conserver une amplitude totale de 1 Volt lorsque connecté sur votre écran (la charge causée par l'écran importe ici). Vous pouvez aussi pousser un peu plus fort que 1 Volt sans risque.

cyberfun

Bonjour Bidouilleurs et bidouilleuses...
En avant pour une nouvelle année 2020, Bonne et heureuse année avec tout ce qui va avec...

Piloter un ADC en mode directe sa avance pas mal de choses et l'on obtient une vitesse plus rapide car le code est optimisé ! J'avais deja eu l'idée de le programmer de la sorte... Après visu sur le forum arduino.cc du sujet quelqu'un avait déjà  codé l'histoire....
Exemple en dessous pour ceux qui ont vu le post forum du sujet en question sur arduino.cc

140khz en moyenne qui augmente par rapport au 8khz au code standard super la performance mais dessiner une grille ou une syncro... j'y suis pas encore arrivé je fais cela a mes moments perdu de la semaine... Il faut analysé l'echantillonnage stocké et... ben je pedale dans la semoule...

Enfin l'idée est excéllente, quelqu'un d'autre a trouvé quelques choses de plus précis ?


#include <TVout.h>
#include <font4x6.h>

//input pins
const int scalePin = 2;
const int samplePin = 3;
// analog input pin is fixed to 0

// define the graph area
const int graphOffsetX = 18;
const int graphOffsetY = 94;
const int graphWidth = 100;
const int graphHeight = 86;

const int upperGraphLimit = graphOffsetY + 1;
const int lowerGraphLimit = graphOffsetY - graphHeight;

int scaleFactor = 1024/graphHeight+1;
int offset = 0;
int sampleSize = -4;
// if sampleSize <= 0, it denotes the sampling speed.

int minValue, maxValue, avgValue;
long startTime = 0, sampleTime = 0;

//used if sampleSize <=3 to draw faster
int data[graphWidth];
uint8_t dispY[graphWidth];

TVout TV;

void setup(){                                         
  pinMode(scalePin, INPUT_PULLUP);     
  pinMode(samplePin, INPUT_PULLUP);     

  //init TV
  TV.begin(_NTSC,120,96);
  TV.select_font(font4x6);
 
  clearGraph();
  drawScale();
}

void initADC(int speed){
  // speed == 1: normal analogread.
  // speed in [-4,0]: faster (-4 is the fastest)

  ADCSRA = 0x87; //default
  if ( speed >= 1 ) ADCSRA = 0x87;    // turn on adc, freq  = 1/128,  125 kHz.
  if ( speed == 0 ) ADCSRA = 0x86;    // turn on adc, freq  = 1/64,   250 kHz.
  if ( speed == -1 ) ADCSRA = 0x85;   // turn on adc, freq  = 1/32,   500 kHz.
  if ( speed == -2 ) ADCSRA = 0x84;   // turn on adc, freq  = 1/16 ,    1 MHz.
  if ( speed == -3 ) ADCSRA = 0x83;   // turn on adc, freq  = 1/8,      2 MHz.
  if ( speed == -4 ) ADCSRA = 0x82;   // turn on adc, freq  = 1/4,      4 MHz. 

  ADMUX = 0x40;
  ADCSRA |= (1<<ADSC);
  while(!(ADCSRA & 0x10));
}

void resetADC(){
  ADCSRA = 0x00;
}

void readFast(int speed){
  // fills array with data on analog-pin 0.
  // speed >= 1: sample "speed" times and take the adverage.
  // speed in [-4,0]: read faster (-4 is the fastest)
 
  int * data_ptr = data; // pointer to array
 
  volatile char i = graphWidth; // iterator in array, init with array size
  volatile int val = 0, sum;
 
  initADC(speed);
 
  startTime = micros(); // set startTime here, to get a more accurate rate
  if(speed > 1){
    ADCSRA |= (1<<ADSC); // start reading the first value
    do{
      sum = 0;
      for(int j=0; j<speed; j++){
        while(!(ADCSRA & 0x10)); // wait for output
        val = ADCL;  // read out low data bits
        val += (ADCH << 8); // read out high data bits
        ADCSRA |= (1<<ADSC); // already start reading the next value for more speed
        sum += val;
      }
      *data_ptr++ = sum / speed;
    }while(--i);
  }else{
    ADCSRA |= (1<<ADSC); // start reading the first value
    do{
      while(!(ADCSRA & 0x10));
      val = ADCL;
      val += (ADCH << 8);
      ADCSRA |= (1<<ADSC); // already start reading the next value for more speed
      *data_ptr++ = val;
    }while(--i);
  }
  resetADC();
}

void waitFor(int speed, int threshold){
  volatile int val = 0;

  initADC(speed);

  boolean wasLow = false;
  ADCSRA |= (1<<ADSC); // start reading first value
  for(int w=0 ; w<400 ; w++){
    while(!(ADCSRA & 0x10));
    val = ADCL;
    val += (ADCH << 8);
    ADCSRA |= (1<<ADSC); // already start reading next value for more speed
    if(val < threshold){
      wasLow = true;
    }else if((val > threshold) && wasLow){
      break;
    }
  }
  resetADC();
}

void drawPixel(int x, int y, char c){
  if((y > lowerGraphLimit) && (y < upperGraphLimit)){
    TV.set_pixel(x,y,c);
  }
}

int val2y(int val){
  return graphOffsetY - val/scaleFactor - offset;
}

void drawScale(){
  //delete old scale
  TV.draw_rect(0,lowerGraphLimit, graphOffsetX-2,graphHeight+1,0,0);
 
  for(int i = 0; i<=20;i++){
    int y = val2y(1024 * i / 20);
    drawPixel(graphOffsetX-2,y,1);
    if((i % 2 != 0) && (scaleFactor < 8) && (y > lowerGraphLimit + 3) && (y < upperGraphLimit - 3)){
      TV.print(graphOffsetX - 18,y-3,i/4.0,2);
    }
    if(i % 2 == 0){
      drawPixel(graphOffsetX-3,y,1); 
      if((i % 4 != 0) && (scaleFactor <=8) && (y > lowerGraphLimit + 3) && (y < upperGraphLimit - 3)){
        TV.print(graphOffsetX - 15,y-3,i/4.0,1);
      }
    }
    if(i % 4 == 0){
      drawPixel(graphOffsetX-4,y,1);
      drawPixel(graphOffsetX-5,y,1);
      if((y > lowerGraphLimit + 3) && (y < upperGraphLimit - 3)){
        TV.print(graphOffsetX - 9,y-3,i/4);
      }
    }
  }
}

void clearGraph(){
  TV.draw_rect(graphOffsetX - 1,graphOffsetY - graphHeight, graphWidth+1,graphHeight+1,1,0);
}

void drawData(int i, int val){
  // we use dispY[i] to store the displayed pixel. so we only need to
  // erase that pixel, and not the whole column.
  int y = val2y(val);
  int x = i + graphOffsetX;
  drawPixel(x,dispY[i],0);
  drawPixel(x,y,1);
  dispY[i] = y;
}

void drawData(int i, int v1, int v2){
  int u = val2y(v1);
  int v = val2y(v2);
  int x = i + graphOffsetX;
  TV.draw_column(x, graphOffsetY, graphOffsetY - graphHeight + 1, 0);
  u = min(max(u,lowerGraphLimit),upperGraphLimit);
  v = min(max(v,lowerGraphLimit),upperGraphLimit);
  TV.draw_column(x, u, v, 1);
}

void changeScaleFactor(){
  int i = 1;
  while(i < scaleFactor)
    i = i*2;
  scaleFactor = i / 2;
  if(scaleFactor == 0){
    scaleFactor = 1024/graphHeight+1;
  }
  offset = graphHeight/2 - avgValue/scaleFactor;
 
  // we need: 0/scaleFactor + offset >= 0 and 1024/scaleFactor + offset <= graphHeight
  offset = max(graphHeight - 1024/scaleFactor,offset);
  offset = min(0,offset);

  drawScale();
  clearGraph();
}

void changeSampleSize(){
  if(sampleSize<5)
    sampleSize = sampleSize + 1;
  else
    //sampleSize = sampleSize * 2;
    sampleSize = sampleSize * 8 / 5;
  if(sampleSize > 300){
    sampleSize = -4;
  }
  sampleTime = 0;
  clearGraph();
}

boolean scaleButtonPressed = false, sampleButtonPressed = false;
boolean checkButtons(){
  if(digitalRead(scalePin) == HIGH){
    scaleButtonPressed = true;
  }else{
    if(scaleButtonPressed){
      changeScaleFactor();
      scaleButtonPressed = false;
      return true;
    }
  }
  if(digitalRead(samplePin) == HIGH){
    sampleButtonPressed = true;
  }else{
    if(sampleButtonPressed){
      changeSampleSize();
      sampleButtonPressed = false;
      return true;
    }
  }
  return false;
}

float val2volts(int val){
  return val * 5 / 1024.0;
}

void printVolts(){
  TV.print(2,2,val2volts(avgValue),2);
  TV.print("V (");
  TV.print(val2volts(minValue),2);
  TV.print("V-");
  TV.print(val2volts(maxValue),2);
  TV.print("V)");
}

void printSampleRate(){
  long x = graphWidth;
  x = x*1000000/sampleTime;
  if(x > 9999){
    TV.print(85,2, x/1000);
    TV.print("kHz  ");
  }else{
    TV.print(85,2, x);
    TV.print("Hz ");
  }
  //TV.print(sampleSize);
  //TV.print("  ");
}

void loop() {
  checkButtons();
 
  waitFor(sampleSize,avgValue);

  minValue = 1024; maxValue = 0;
  long sum = 0;
  int i = 0; 
  startTime = micros();
  while(i < graphWidth){
    if(sampleSize <= 3){
      //for small sampleSize, sample first and then draw
      readFast(sampleSize);
      if (sampleTime > 0)
        sampleTime = (19 * sampleTime + micros() - startTime) / 20;
      else
        sampleTime = micros() - startTime;
      i=0;
      while(i < graphWidth){
        int val = data[i];
        minValue = min(minValue, val);
        maxValue = max(maxValue, val);
        if(sampleSize > 0)
          sum = sum + sampleSize*val;
        else
          sum = sum + val;
        drawData(i,val);
        i++;
      }
    }else{
      //for large samleSize, do sample and draw at the same time.
      int minV = 1024, maxV = 0;
      volatile int val = 0;

      initADC(1);
     
      ADCSRA |= (1<<ADSC); // start reading first value
      for(int j = 0; j< sampleSize; j++){

        while(!(ADCSRA & 0x10));
        val = ADCL;
        val += (ADCH << 8);
        ADCSRA |= (1<<ADSC); // already start reading next value for more speed

        minV = min(minV,val);
        maxV = max(maxV,val);
        sum = sum + val;
      }

      resetADC();

      drawData(i,minV,maxV);
      minValue = min(minValue,minV);
      maxValue = max(maxValue,maxV);
      i++;

      if(checkButtons()){
        //button has been pressed. reset values.
        i = 0;
        startTime  = micros();
        minValue = 1024; maxValue = 0;
        sum = 0;
      }
      if(i==graphWidth){
        if (sampleTime > 0)
          sampleTime = (9 * sampleTime + micros() - startTime) / 10;
        else
          sampleTime = micros() - startTime;
      }
    }
  }

  if(sampleSize > 0)
    avgValue =  sum / (graphWidth*sampleSize);
  else
    avgValue =  sum / graphWidth;
 
  printVolts();
  printSampleRate();
}

Électro-Bidouilleur

Merci de votre contribution. Vous tirez clairement tout le jus de l'Arduino!

Curiosus

#8
Bonsoir cyberfun, Électro-Bidouilleur, et tout le forum,

Il y a une question que je me pose,  et qui m’empêche de dormir ..... comment peut t'on mesurer un signal alternatif avec une référence de Vref- 0 volts et Vref+ 5volts ?

Y aura t'il quelqu'un pour me l'expliquer ....

Merci  ;)

A+

MicTSF

Bonjour Curiosus,
Pour réaliser une mesure de tension alternative sur une entrée non symétrique par rapport au zéro volts (la masse) il suffit de rajouter une tension continue à  la tension alternative de façon à  ce qu'elle soit comprise entre le zéro volts et le maximum mesurable. Par exemple sur un arduino nano lorsque la plage de mesure est de 5 volts il suffit de rajouter 2,5 volts continus pour pouvoir mesurer une tension comprise entre 0 et 5 volts crête à  crête (environ 1,77 V eff).
Ce décalage peut se faire à  l'aide d'un ampli opérationnel si on veut une bande passante commençant aux très basses fréquence ou avec un décalage par un pont de résistances et en appliquant la tension alternative par l'intermédiaire d'un condensateur ce qui va toutefois limiter la bande passante aux basses fréquences.
Michel

Curiosus

#10
Bonsoir MicTSF, et tout le forum,

Merci pour ta réponse,

Personnellement, je travaille uniquement avec des microcontrôleurs Pic, mais ça reste le même principe sur Arduino.

Ben ouais, il fallait y pensée, si j'ai bien compris tu fais une addition

Exemple pour une tension de référence Vref- 0 volts et Vref+ 5 volts

Si j'ai une alternance de -2 volts et que je rajoute +2 volts c'est égal à  zéro, mais comme il faut que je puisse l'analyser je vais rajouter 4,5 volts

Ce qui serra égal à  4,5 volts - -2 = 2,5 volts

Tous ce qui aura une valeur en dessous de 2,5 volts serra négatif, et tout ce qui aura une valeur de plus de 2,5 volts sera positif

Notre zéro aura comme valeur 2,5 volts.

J'ai vu sur certain oscilloscope numérique qu'il mette des régulateurs négatives, et positif, c'est peut être plus pratique de faire -2,5 volts et +2,5 volts pour une tension de référence.


A+