claudiolenz
Published © LGPL

Interleaving Oscilloscope - get a nice 20kHz wave with UNO

Based on a referenced project I implemented interleaved sampling for repetitive waves triggered at same point, achieving 3µs resolution.

IntermediateWork in progress7,776
Interleaving Oscilloscope - get a nice 20kHz wave with UNO

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
I used a robust Brazilian Arduino: BlackBoard, from RoboCore.
×1
Analog Devices AD9833 - DDS
Optional: Nice DDS waveform Direct Digital Synthesis; or optionally: the audio output from you cellular phone or computer
×1

Software apps and online services

Processing
The Processing Foundation Processing
Necessary for the GUI

Story

Read more

Schematics

Basic Connections for Oscilloscope measuring RC circuits

Code

Arduino Sketch

Arduino
// Interleaved Oscilloscope for Arduino UNO - easily achieve 20kHz wavefunctions 
// Arduino Sketch by Claudio Lenz Cesar(CLC) - Instituto de Fisica - UFRJ (25/July/2020)
// Based on the osciloscope Sketch by  Veldekiaan at https://create.arduino.cc/projecthub/Veldekiaan/sampling-scope-frequency-counter-2e4196
// Need to Install "Processing" and the new Processing Sketch (added a Save Ch button and comands '<','>' to increase PWM freq.) or use his Processing Sketch (.pde) in the link above 
// and change the first 3 TimebaseSets (lines ~229) to  
/*  
  new TimebaseSet(1, 0.0001, 475, 0.000003), // 0 com Interleaving x5
  new TimebaseSet(2, 0.0001, 140, 0.000015), 
  new TimebaseSet(5, 0.0001, 350, 0.000015), 
 */
// and lines 5 and 7 to:
/*
 boolean scope = true; // start with Scope instead of Counter

 static final String SerialPort ="/dev/cu.usbserial-RCBB_4OK6T4";            // Change this to match your Arduino port
 */
// The original Veldekiaan's project triggered (Interrupt) in a PWM port square signal (I changed the port: needed that for the DDS AD9833 control) 
// Here I keep the PWM pin5 but disconnected the trigger input Pin2 (can still use it)
// I added a trigger Interrupt based on the AnalogComparator (pins6[+] and 7[-]) (lines 215...)
// FOr this realization, the AC+ = internal reference = 1.1V and the sinewave generated by the AD9833 (at about 3V) is also input in AC-=pin7[-]
// I increased the clock for the ADC, using Prescaler=04. The conversion then takes about 13,5 cycles = 13,5*(4/16) s= 3,4s
// Using an interleaving factor of x5 (in the 100s scale only), I set the readings after each trigger to be happen at 15s time interval (timer interrupt)
// Then, after getting many points in a single AC trigger (single wave), I restart again, but now getting the ADC readings after a time delay of 3s, then again at 6s, and so on
// Connections: For the AD9833:13=CLK,11=DATA, 10=FSYNC
// D5=saida PWM, ligada num led+300ohm p/ GND (piscando to rapido que s vemos intensidade mdia) e tambm na A5 para ler no osciloscpio
// D4=sada do trigger, ligada num LED+300ohm p/ GND = deve ficar piscando
// pino7 = entrada AIN1 para comparador: ligada na sada do AD9833 ou Onda de Entrada = A0 (entrada analgica) e um cap entre Aref & GND
// pino6 ser no utilizavel pois vou ligar o AIN0  tenso interna de referncia de 1.1V como nvel de trigger
// If you do not use a function generator, connect the PWM output (D5) to the AIN- = pin7 input for trigger.
//

/* Comandos para o AD9833 inseridos aqui: linhas ~36, ~555 -> no Setup
// Pins for SPI communication with the AD9833 IC
#include <SPI.h>
#include <MD_AD9833.h>
#define DATA  11     ///< SPI Data pin number
#define CLK   13     ///< SPI Clock pin number
#define FSYNC 10     ///< SPI Load pin number (FSYNC in AD9833 usage)
#define CS_DIGIPOT 9 // MCP41010 chip select - digital potentiometer. Not used in this implementation (use default)
MD_AD9833 AD(FSYNC); // Hardware SPI = AD9833
unsigned long fnu; // Frequncia da Onda Senoidal do AD9833 (linha 557)
*/

/* Veldekiaan's scope:
   6-channel oscilloscope

  Operation mode:
    '#': frequency counter
    '*': oscilloscope
    '!': reset
    
   Trigger modes:
    'E': rising edge
    'F': falling edge

   Sweep mode:
    'C': continuous
    'D': single sweep

   Time base:
   100, 200, 500 us
   1, 2, 5 ms
   10, 20, 50 ms
   100, 200, 500 ms
   1, 2, 5 s
   10, 20, 50 s
   100, 200 s

   Timebase is identified by characters 'a'-'t'

   Channel:
   Channels are selected by '0'-'5'

   Counter time base
   'G': 1 period, clock divider 1024
   'H': 1 period, clock divider 256
   'I': 1 period, clock divider 64
   'J': 10 periods, clock divider 1024
   ...
   'U': 10000 periods, clock divider 64
*/

#define ScopeMode '*'
#define CounterMode '#'

#define InitialMode '*'

// Trigger input pin (only 2 or 3)
#define TriggerPin 2  // digital trigger still available: but use it or AnalogComparator trigger

#define MaxSamples 1000 

// Pin to connect an LED showing counter measuring intervals
// original: #define CounterPin 13 // => save for programing  AD9833 
#define CounterPin 4
// Pin to generate a PWM signal (5 or 6 only)
#define PwmPin 5 //  com o AnalogComp o pino 6 passa a ser o AIN0 e agora a saida PWM ser no pino5
#define PwmFreq65k 0x1  // 62.5 kHz = 16MHz/(1=prescaler * 256) 
#define PwmFreq7k 0x2   // 7.8125 kHz = 16MHz/(8=prescaler * 256)
#define PwmFreq976 0x3  // 976.56 Hz = 16MHz/(64=prescaler * 256)
#define PwmFreq244 0x4  // 244.14 Hz = 16MHz/(256=prescaler * 256)
#define PwmFreq061 0x5  // 61.035 Hz = 16MHz/(1024=prescaler * 256)

// Timer and interrupt settings para trigger Externo no Pino 2
#define INTBIT B00000001
#define TRIGCLR B00000001
#define TRIGRISE B00000011
#define TIMERCTCA B00000000
#define TIMERCTCB B10001000
#define TIMERCNTA B00000000
#define TIMERCNTB B00000000
#define TIMERNOCLK B11111000
#define TIMERPS0001 B00000001 // clock do timer = clock do Arduino = 16 MHz
#define TIMERPS0256 B00000100
#define TIMERPS1024 B00000101
#define ADCINIT B10000111 // ADEN=1,enable ADC: isso j resolve o Anal.Comp., ADC=0 No Comea Conversao, ADATE=0 (sem AutoTrigger), ADIF=0, ADIE=0, ADSprescaler=111=128
// o programa no mexe em ADCSRB, portantos bit ADTS2,1,0 so 000 = free runing (to rpido quanto possvel)
#define ADCSELECT B01100000 // original: 5V
// #define ADCSELECT B11100000 // CLC: mudar para 1.1V de referncia (aumenta resoluo p/ ondas de pico <1.1V)
#define ADCSTART B01000000
#define ADCPSCLR B11111000
#define ADCPS002 B00000001 // CLC 
#define ADCPS004 B00000010 // CLC 
#define ADCPS008 B00000011 // CLC
#define ADCPS016 B00000100 // 76.9 kSps ? Tem que mexer tambm em CNT do trigger do contador
#define ADCPS032 B00000101
#define ADCPS064 B00000110
#define ADCPS128 B00000111
#define ADCREADY B00010000
#define CLEARADIF B10101111 // Does not do anything ?- na operao ADCSRA &= CLEARADIF, limpa os bits 6(ADC StartConversion) e 4(ADIntFlag) e mantm os outros do ADCSRA

boolean scope = true;

//The interrupt setting depends on the choice of the trigger pin: 2 (INT0) ou 3(INT1)
byte intBit = (INTBIT << (TriggerPin == 2 ? 0 : 1));

// Current mode variables
boolean continuousSweep = true; 
byte currentChannel = 0;
char currentBase;

// Sample variables
volatile byte sample[MaxSamples];
byte timerPrescaler;
int samples;
volatile int index=0;
volatile int writeIndex;

// Interleaving variables (for the 100s scale: CLC)
volatile boolean FlagItlvd = false; // Flag whether to use of not interleaving: only made TRUE at 100s/Div
volatile int itlvdCnt=0; // CLC = interleaved count=0,1,..,4. Vou usar na amostragem mais rpida: 5 leituras com timedelays
volatile int itlvdCntMax=5; // CLC = 5 interleaved points
volatile int tdelay=3; // CLC = interleaving delay in microseconds 
volatile int indexWrt; // CLC

// Frequencey counter current ode variables
int periodCount;
volatile int periods = 0;
volatile unsigned long count;
volatile byte counterDiv = 5;

// PWM output value  ("-" and "+" changes this duty cycle)
unsigned int pwm = 128;

/* Initialize the Analog-Digital Converter */
void initAdc()
{
  ADCSRA = ADCINIT;
  ADMUX  = ADCSELECT;
}

/* Read a sample from the ADC */
void readAdc()
{
  unsigned int result = 0;
  ADCSRA |= ADCSTART; // Start conversion
  while ((ADCSRA & ADCREADY) == 0);
  sample[index*(FlagItlvd ? itlvdCntMax : 1)+itlvdCnt+1] = ADCH;                       // 8-bit sample size for speed
  index++;
//  ADCSRA &= CLEARADIF; no faz nada
}


/* Trigger Interrupt Service Routine . Pino 2  INT0 e pino 3  INT1 */
#if (TriggerPin == 2)
ISR(INT0_vect)
#else
ISR(INT1_vect)
#endif
{
  if (scope)
  {
    EIMSK &= ~intBit; // Disable trigger interrupt first; (zera o INT1 ou INT0)
    EIFR |= intBit;// Clear pending interrupts (escreve 1 em EIFR(INTFR1 ou INTF0) e assim limpa)

    readAdc();                                    // Read first sample immediately
    TCNT1 = 0;                                    // Reset timer
    TCCR1B |= timerPrescaler;                     // Start timer now
  }
  else
  {
    int c = TCNT1;
    
    TCNT1 = 0;
    TCCR1B = counterDiv;                          // Start counter
    count += c;                                   // Add current timer to total count
    periods++;                                    // Another period counted
    if (periods > periodCount)                    // If all periods counted for a measurment...
    {
      TCCR1B = 0;                                 // ... Stop counter
      writeCount(count);                          // Report value to PC
      counterReset();                             // Reset counter for next measurement
    }
  }
}
/* Trigger with the Analog Comparator - CLC */
ISR(ANALOG_COMP_vect) {
 // ACSR  |=  (1<<ACI);    // clear Analog Comparator interrupt
  if (scope)
  {
//    EIMSK &= ~intBit; // Disable trigger interrupt first; (zera o INT1 ou INT0)
//    EIFR |= intBit; // Clear pending interrupts (escreve 1 em EIFR(INTFR1 ou INTF0) e assim limpa)
  bitClear(ACSR,ACIE); // DISABLE ADC interrupt first  = CLC
  bitSet(ACSR,ACI); // Clear Pending Interrupt = CLC
  digitalWrite(CounterPin, !digitalRead(CounterPin));   // toggle state of Pin 4
  delayMicroseconds(tdelay*itlvdCnt); // CLC= delay for interleaving
  readAdc();                                    // Read first sample immediately
  TCNT1 = 0;                                    // Reset timer
  TCCR1B |= timerPrescaler;                     // Start timer now
  }
}

/* Handle the end of a sweep */
void stopSweep()
{
  TCCR1B &= TIMERNOCLK;                           // Set clock select to 0 (no clock)
  index++;
  writeData();                                    // Write sampled data to serial connection
  if (continuousSweep)
  {
    scopeReset();                                 // Restart automatically in continuous sweep mode
  }
}

/* Reset the scope for a new sweep */
void scopeReset()
{
  TCCR1B &= TIMERNOCLK;                           // Stop the timer by setting clock select to 0 (no clock)

  Serial.print((char) 0xFF);                      // Mark end of sweep to console
  index = 0;                                      // Reset sweep data
  itlvdCnt=0; 
  writeIndex = 0;
  
  // CLC: faz a 1a converso que demora mais. No guarda os dados
  ADCSRA |= ADCSTART; // Start conversion
  while ((ADCSRA & ADCREADY) == 0); // espera terminar
  
  EIFR |= intBit;                                 // Reset trigger interrupt flag
  EIMSK |= intBit;                                // Enable interrupts on trigger input

  bitSet(ACSR,ACI); // Clear Pending Interrupt = CLC
  bitSet(ACSR,ACIE); // ENABLE ADC again = CLC
  // Wait for trigger signal interrupt
}

/* Reset the frequency counter to start another measurement */
void counterReset()
{
  digitalWrite(CounterPin, HIGH - digitalRead(CounterPin)); // Toggle indicator LED
  periods = 0;                                    // Reset counted periods
  count = 0UL;                                    // Reset total timer counts
  TCNT1 = 0;                                      // Reset timer
  EIFR != intBit;
}

/* Interrupt Service Routine for timer OCR compare match : next sampling reading after the usual time delay */
ISR(TIMER1_COMPA_vect)
{
  readAdc();                             // Read next ADC sample and store it
  if (index >= samples)                  // algo tem que ocorrer se pegou toda a sample dessa vez
      if ((!FlagItlvd) || (itlvdCnt+1 >= itlvdCntMax))   {stopSweep();} // se no tem interleaving: pegou toda a amostra: STOP
        else { // seno ... vai pro prximo indice de interleaving
          itlvdCnt++;
          TCCR1B &= TIMERNOCLK;           // tem que parar o clock interrupt: select to 0 (no clock)
          index=0; // reseta o indice para interleaved e, reabilita e espera novo triger do ADC: 
          bitSet(ACSR,ACI); // Clear Pending Interrupt = CLC
          bitSet(ACSR,ACIE); // ENABLE AComp interrupt again = CLC         
         // Serial.print("\n Ix,It="); Serial.print(index); Serial.print(itlvdCnt); // debug
     }
 }

/* Set the sample time for the selected time base.
 * The selection is done with a single character 'a'-'t'.
*/
void setSampleTime(char c)
{
  unsigned int cnt;

  currentBase = c;                                // Store the time base as current

  ADCSRA &= ADCPSCLR;                             // Clear prescaler
  // Set ADC prescaler
  switch (c)
  {
    case 'a':
    case 'b':
    case 'c':
    case 'd':
      ADCSRA |= ADCPS004; //CLC teste = melhor
    // ADCSRA |= ADCPS008; //CLC teste
    // ADCSRA |= ADCPS016; // Original
      break;
    case 'e':
      ADCSRA |= ADCPS032;
      break;
    case 'f':
      ADCSRA |= ADCPS064;
      break;
    default:
      ADCSRA |= ADCPS128;
      break;
  }

  // Set #samples
  switch (c)
  {
    case 'a':
      samples = 95; FlagItlvd=true; // Interleaving somente na escala de 100s/div
// original      samples = 48;
      break;
    case 'b':
      samples = 140; FlagItlvd=false; // 200s/div scale
//      samples = 91;
      break;
    case 'c':
//      samples = (50 << (c - 'a'));
      samples = 350; FlagItlvd=false; // 500s/div scale
      break;
    case 'd':
    case 'e':
      samples = 400; FlagItlvd=false;
      break;
    default:
      samples = (c >= 'o' ? 1000 : 500);  FlagItlvd=false;
      break;
  }

  // Set timer prescaler
  timerPrescaler = (c <= 'j' ? TIMERPS0001 : (c <= 'r' ? TIMERPS0256 : TIMERPS1024));

  // Set counter max value
  switch (c)
  {
    case 'a':
        cnt = 240;  //240=15*16 para 15s de converso (o interleaved entra de 3 em 3 s, itlvdcnt=0,1,2,3,4). 100s/div
       break; 
    case 'b':
    case 'c':
//      cnt = 400; // No TIMERPS001 isso daria 400/(16MHz)=25 s; enquanto a converso deve durar 13,5 ciclos de clock do ADC, o que no Prescaler ADCPS008 daria 7s
//      cnt = 336; // ORIGINAL (CLC)
        cnt = 240; //240=15*16 para 15s de converso . 200s/div and 500s/div
       break;
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
      cnt = 400 << (c - 'd'); // No TIMERPS001 isso daria 400/(16MHz)=25 s em c='d'e vai dobrando; 1ms/div=25s, 2ms/div=50s, 5ms/div=100s, 10ms/div=200s, 20ms/div=400s
      break;
    case 'i':
      cnt = 16000; // 1ms
      break;
    case 'j':
      cnt = 32000; // 2ms
      break;
    case 'k':
      cnt = 250; // agora TIMERPS0256 => 250/(16M/256) = 4ms
      break;
    case 'l':
    case 'm':
    case 'n':
      cnt = 625 << (c - 'l');// 10ms, 20ms, 40ms
      break;
    case 'o':
    case 'p':
    case 'q':
      cnt = 3125 << (c - 'o'); //50ms, 0.1s, 0.2s
      break;
    case 's':
      cnt = 15625; // s(prescaler=1024):1s
      break;
    case 'r':
    case 't':
      cnt = 31250;// r:0.5s, t(prescaler=1024): 2s
      break;
  }
  OCR1A = cnt;
}

/* Set trigger mode to falling or rising edge no TriggerPin */
void setTriggerMode(char c)
{
  if (c == 'F')
  {
    EICRA &= ~(TRIGCLR << (TriggerPin == 2 ? 0 : 2));
    bitSet(ACSR,ACIS0); // CLC : Analog Comparator
  }
  else
  {
    EICRA |= TRIGRISE << (TriggerPin == 2 ? 0 : 2);
    bitClear(ACSR,ACIS0); // CLC : Analog Comparator
  }
}

/* Sweep mode (continuous or single) */
void setSweepMode(char c)
{
  continuousSweep = (c == 'C');                   // 'C' is continuous, 'S' is single
}

/* Set the channel '1'-'6' */
void setChannel(char c)
{
  currentChannel = (c - '1');                     // Internally, channels are 0-5
  ADMUX &= B11110000;
  ADMUX |= (currentChannel & 0x7);                // Switch the ADC multiplexer to the channel pin
}

/* Start oscilloscope mode */
void setScope()
{
  scope = true;
  digitalWrite(CounterPin, LOW);                  // Switch off counter indicator
  TCCR1A = TIMERCTCA;                             // Use Timer1 in 'match OCR' mode for sampling
  TCCR1B = TIMERCTCB;                             // No clock, so no interrupts yet
  TIMSK1 |= (1 << OCIE1A);                        // Enable timer1 compare interrupts
  execute(currentBase);                           // Set the time base to the last used
  scopeReset();                                   // Restart scope
}

/* Start frequency counter mode */
void setCounter()
{
  scope = false;
  periodCount = 1;
  digitalWrite(CounterPin, HIGH);                 // Switch on counter indicator
  TCCR1A = TIMERCNTA;                             // Use Timer1 in normal mode for counting
  TCCR1B = 0;                                     // Hold timer
  TIMSK1 &= ~(1 << OCIE1A);                       // Disable timer1 compare interrupts
  EIFR |= intBit;
  EIMSK |= intBit;                                // Enable external interrupt
  counterReset();                                 // Restart frequency counter
}

/* Set the number of periods to count for determining frequency */
void setPeriods(char c)
{
  int s = c - 'G';
  int p = s / 3;                                  // Period count 1, 10, 100, 1000 or 10000
  counterDiv = 5 - (s % 3);                       // Clock divider 64, 256 or 1024 for accuracy
  periodCount = 1;
  for (int per = 0; per < p; per++)
  {
    periodCount *= 10;
  }
}

/* Handle command characters sent from the console */
void execute(char c)
{
  switch (c)
  {
    case '!':
      break;
    case 'E':
    case 'F':
      setTriggerMode(c);
      break;
    case 'C':
    case 'D':
      setSweepMode(c);
      break;
    case '#':
      setCounter();
      break;
    case '*':
      setScope();
      break;
    case '-':
      if (pwm > 0)
      {
        pwm--;
      }
analogWrite(PwmPin, pwm);
      break;
    case '+':
      if (pwm < 255)
      {
        pwm++;
      }
 analogWrite(PwmPin, pwm);
      break;
     case '<':
       if ((TCCR0B & 0x07) > 0x02)
       {TCCR0B = (TCCR0B & 0xF8) | ((TCCR0B & 0x07)-0x1);}
       break;
      case '>':
       if ((TCCR0B & 0x07) < 0x05)
       {TCCR0B = (TCCR0B & 0xF8) | ((TCCR0B & 0x07)+0x1);}
       break;
    default:
      if (c >= '1' && c <= '6')
      {
        setChannel(c);
      }
      else if (islower(c))
      {
        setSampleTime(c);
      }
      else
      {
        setPeriods(c);
      }
      break;
  }
  if (scope)
  {
    scopeReset();
  }
  else
  {
    counterReset();
  }
}

/* Send all available samples to the console */
void writeData()
{ if (FlagItlvd) {indexWrt=samples*itlvdCntMax+1;} else {indexWrt=index;}
  for (writeIndex=1; writeIndex < indexWrt; writeIndex++) 
  {
  Serial.print((char) sample[writeIndex]);  // Original= vai o binrio
// Serial.print("\n"); Serial.print(sample[writeIndex]);  // aqui vai o nmero em decimal
  }
  Serial.print((char) (0xFF));                    // Send all ones to mark end of transmission
}

/* Writes the count value for the defined number of periods in 4 bytes, LSB first */
void writeCount(unsigned long cnt)
{
  unsigned long c = cnt;
  
  for (int d = 0; d < 4; d++)
  {
    Serial.print((char) (c & 0xFF));
    c >>= 8;
  }
  Serial.print((char) (0xFF));                    // Send all ones to mark end of transmission
}

/* Standard set-up */
void setup()
{
  // original: Serial.begin(115200);                           // Fast serial connection
  Serial.begin(115200); 

/* AD9833:Begin
  AD.begin();
  fnu = 2000UL; // 10000UL = 10kHz
  AD.setFrequency(MD_AD9833::CHAN_0, fnu);  
// AD9833:End
*/
  pinMode(TriggerPin, INPUT_PULLUP);              // The trigger input
  pinMode(CounterPin, OUTPUT);                    // The frequency counter indicator LED
  pinMode(PwmPin, OUTPUT);                        // A PWM source for testing

  TIMSK0 = 0;                                     // Disbable other timer interrupts
  TIMSK2 = 0;

 /* mudei d0 2o pro 1o abaixo */
 // TCCR0B = (TCCR0B & 0xF8) | PwmFreq7k;
//  TCCR0B = (TCCR0B & 0xF8) | PwmFreq976;           // Set pin 5/6 PWM frequency
  TCCR0B = (TCCR0B & 0xF8) | PwmFreq061;  // para as contantes de tempo R+C longas!!!
  
  // External interrupt for trigger signal (in TrigPin =2)
  EIMSK &= ~intBit;                               // Disable trigger interrupt first; (zera o INT1 ou INT0)
  EIFR |= intBit;                                 // Clear pending interrupts (escreve 1 em EIFR(INTFR1 ou INTF0) e assim limpa)
  EICRA = TRIGRISE << (TriggerPin == 2 ? 0 : 2);  // Start with rising edge

  initAdc();                                      // Set up the analog inputs and the ADC

  // AnalogComparator: Begin (CLC)
  //  ; AIN0=Bandgap=1.1V
  pinMode(7, INPUT); 
  DIDR1 = B00000011; // disable digital input to AIN1/0
/* ACSR =
   (0 << ACD) |    // Analog Comparator: Enabled
   (1 << ACBG) |   // ou no:Analog Comparator Bandgap Select: bandgap 1.1V in AIN0 (positive input)
   (0 << ACO) |    // Analog Comparator Output: OFF
   (1 << ACI) |    // Analog Comparator Interrupt Flag: Clear Pending Interrupt
   (1 << ACIE) |   // Analog Comparator Interrupt: Enabled 
   (0 << ACIC) |   // Analog Comparator Input Capture: Disabled
   (1 << ACIS1) | (0 << ACIS0);   // Analog Comparator Interrupt Mode: Comparator Interrupt on Rising Output Edge
*/
ACSR = B01011010; // enable AC, AIN0=1.1V, ACO=off, ClearPendindInt, ACintEnable,ACInputCapt=Disabled, falling edge do comparador=rising edge do meu sinal
// AnalogComparator: End (CLC)

  // Set the default controls
  execute('E');                                   // Rising edge trigger
  execute('C');                                   //  mudei para Single sweep - Continuous sweep
  execute('1');                                   // Channel A0
  /* mudei de 'h' pra 'd'*/
  execute('h');                                   // 
  execute('G');                                   // Counter time base at 1x/1024

  execute(InitialMode);                           // Start in selected initial mode

  analogWrite(PwmPin, pwm);                       // Switch on PWM signal
}

/* Standard loop */
void loop()
{
  if (Serial.available())                         // If a command was sent from the console, ...
  {
    execute(Serial.read());                       // ...handle it here
  }
}

Processing Sketch (GUI)

Processing
No preview (download only).

Credits

claudiolenz

claudiolenz

0 projects • 1 follower

Comments