Eines de l'usuari

Eines del lloc



He estat buscant i he trobat varis, el conversor analogic(ADC) es de 10 bits(0-1023), el més ràpit seria enviar un byte a 115200, que es la màxima velocitat. El que he trobat utilitza una interrupció de temps cada 5kHz,(0,2ms 0,0002s), i pot canviar-se canviant l'escala del timer de la interrupció. Jo he pensat dividir 1023/4=255, per enviar només un byte, a més hi ha un tema que es trigger, perquè la imatge no es mogui, el provarè, ja he vist que BYTE no està definit, però si posem Serial.write(analogRead(A0)) ja està envia el byte. Per començar pot estar be, així també practique les interrupcions que son molt interessants per a la programació de màquines.

Encara que seria més correcte dividir el int de la lectura que te 2 bytes, en bytes i enviar el mes significatiu, aquesta funció s'utilitza molt en programació de automats, que alguns tenen el primer byte el de més pes i altres del reves i cal canviar el orde dels bytes. L'arduino ja te implementada aquesta possibilitat.

byte byte1 = lowByte(lectura);
byte byte2 = highByte(lectura);

que en C++ general es de la següent manera:

int value = 257;
low = (byte) (value & 0xFF); // borra els bits que estan a l'esquerra dels 8 de la dreta
System.out.println("low: " + low);
high = (byte) ((value >> 8) & 0xFF); // passem el 8 bits de l'esquerra a la dreta i borrem els de la dreta
System.out.println("high: " + high);
int valueInvertit = low|high; // afegit per mi, amb ORs tornem genrar l'int

Arduin-O-Scope v01

I put together a little oscilloscope based on an arduino duemilanove as a first project to learn about how the system works. There's plenty of polishing to be done, but it mostly works and runs at about 5kHz with the default setting.

It uses a counter interrupt as a time base and just uses the top 8 bits of the ADC to give 8-bit resolution. The Arduino reads analog input 0 every time the interrupt fires and sends the value over USB to a program running in Processing. The Processing code scans the incoming data to see when it passes through a trigger level. Once the trigger level is detected it starts saving the incoming data and then plots it to the screen. If too much time goes by it just plots what data it has so you get a 'live' view of what is going on at the input pin. Clicking anywhere on the screen sets the trigger level to the mouse location.

The Arduino code contains one special line, “#define TEST_MODE”. If you leave this line as-is the Arduino ignores the analog input and sends a mathematically generated ramp wave which is nice for debugging the Processing code. Comment this line out and you will get the analog input pin values instead.

The Processing code has a few debugging items too. A white circle in the upper left-hand corner blinks when the frame updates. If this isn't blinking something is hanging in the code. There is another green circle that appears if the frame was started by a trigger event, and a red circle appears if the frame was started without a trigger event. A horizontal purple line shows where the trigger level is.

Welp, it's good enough for now and I'm sick of reading datasheets. Thanks to these forums and the Arduino team for all the great help!


Known Bugs 1) The frames in Processing sometimes do not update smoothly. I think the root of this problem is that the loops that read the serial port are too short and run the CPU to 100% constantly polling for new input. Eventually the CPU wanders off to handle its other tasks and the screen hangs for a minute. There is likely a better way to do this polling.

2) Values of 5V and 0V input can run the scope trace off the screen. This is kind of annoying, but just needs a better scaling method.

To Do 1) It would be nice to have a pre-trigger, just like on a real oscilloscope, that would let you see a bit of the data that came in before the trigger event.

2) I think the sampling rate can still be faster. Maybe running the ADC on self-triggering mode and fixing the choking issue with the Processing code would help. If anyone can point me to a good guide on setting the ADC to free-running mode I'd greatly appreciate it.

3) It would be cool to add the ability for Processing to change the sampling rate from the UI by sending messages to the Arduino.

4) Add a scale to the UI for both voltage and time steps.


#include <avr/io.h>
#include <avr/interrupt.h>

#define BAUD_RATE 115200 
#define INPUT_PIN 0
#define LED_PIN 13

//#define TEST_MODE                            // comment out to read analog pin, uncomment for test ramp wave
volatile int j;

void setup()
 pinMode(LED_PIN, OUTPUT);
 cli();                                     // disable interrupts while messing with their settings
 TCCR1A = 0x00;                             // clear default timer settings, this kills the millis() funciton
 TCCR1B = 0x00;
 TCCR1B |= (1 << WGM12);                    // Configure timer 1 for CTC mode
 TCCR1B |= (0 << CS12);                     // Set timer prescaling by setting 3 bits 
 TCCR1B |= (1 << CS11);                     // 001=1, 010=8, 011=64, 101=1024 
 TCCR1B |= (1 << CS10); 
 TIMSK1 |= (1 << OCIE1A);                   // Enable CTC interrupt
 OCR1A  = 50;                               // Set CTC compare value
 sei();                                     // turn interrupts back on

void loop() {
 // nothing to do, its all in the interrupt handler!

ISR(TIMER1_COMPA_vect)                            // when timer counts down it fires this interrupt
 #ifdef TEST_MODE
   Serial.print((j%64)*4 , BYTE);                // test mode, generate a ramp wave
   Serial.print( analogRead(INPUT_PIN), BYTE);   // real mode, sample analog pin


import processing.serial.*;

Serial inPort;                           // the port to read from
int BAUD_RATE = 115200;                  // set baud rate here, needs to be the same value as in the arduino code
int BUFFER_SIZE=200;                     // data buffer size
int GRIDS=10;                            // number of grids to draw
int inVal;                               // y-data read in from the arduino
int lastVal;                             // old value of y-data
int[] yVals = new int[BUFFER_SIZE];      // y-data buffer, scaled to the screen size
int[] xVals = new int[BUFFER_SIZE];      // x-data buffer, scaled to the screen size
int trigger;                             // trigger, when the incoming data passes this value a frame starts
int timeOut;                             // if no trigger is detected by timeOut samples, plot what is at input port
int i;                                   // counter
boolean blinker;                         // blinks a light on each frame update so you know when program is running     
boolean noTrigger;                       // true until trigger is detected
boolean noTimeOut;                       // true until timeout runs out if no trigger is found first

void setup() 
 inPort = new Serial(this, Serial.list()[0], BAUD_RATE);    
 size(600, 400);                                            

void draw()
 // dump any old data sent while program wasn't running or was busy
 // wait for trigger event or timeout 
 while(noTrigger & noTimeOut){
    if (inPort.available()>1){                                    // wait for a byte to appear on serial port
        inVal=(inPort.read());                                    // read the byte
        if((inVal>trigger)&(lastVal<=trigger)) noTrigger=false;   // check for trigger event
        if (i>timeOut) noTimeOut=false;                           // check for timeout event
 // collect a frame of data
 while(i<BUFFER_SIZE){                                            // read a buffer full of date                  
   if (inPort.available()>1){
         inVal=( inPort.read());
         yVals[i]=height-((height)*inVal)/254;                    // scale data to screen height
         xVals[i]=(width*i)/BUFFER_SIZE;                          // scale x-value to screen width
 // draw grid lines
 // draw trigger level
 // draw scope trace
 for (i=1;i<BUFFER_SIZE;i++){
 // draw a dot that changes state each screen update
 // if this isnt blinking, something is wrong
 if (blinker) ellipse(10,10,5,5);
 // draw a green dot if trigger event fired frame
 if (!noTrigger){
 // draw a red dot if timeout event fired frame
 if (!noTimeOut){
 // this delay seems to be needed to let the system handle random events

// move the trigger level to wherever the user clicks the mouse
void mousePressed() {

Divisor de tensió

Amb un senill divisor de tensió podem veure entrades de qualsevol tensió, inclús negatives, perquè recordem el ADC del aorduino mesura de 0-5V.

Mes informació: divisor-tensio-entrada-osciloscopi.zip

Encara mes senzill

Aquesta seria la mínima expresió per visualitzar l'entrada analògia pel processing

Arduino versio 1

int analogPin = 0;
float xPos = 0;
void setup(){
void loop(){
delay(20); //change the delay time here


import processing.serial.*;
Serial port

void setup(){
  port = new Serial(this, Serial.list[0], 9600);

void draw(){

void serialEvent (Serial port) {

  String inString = port.readStringUntil('\n');

  if (inString != null) {
    inString = trim(inString);

    float inByte = float(inString); 
    inByte = map(inByte, 0, 1023, 0, height);

    line(xPos, height - inByte, xPos, height);

    if (xPos >= width) {
      xPos = 0;
    else {
la funcio map canvia d'escala, el valor inByte que està en 0-1024, el passa a un valor equrvalent entre 0,hight

Comprovació del funcionament

He comprovat el funcionament i es correcte, tant del o-scope com del senzill, encara que el processing del senzill no m'ha funcionat, amb només l'arduino puc veure'l amb el serial plotter que porten les noves versions del arduino.

Es molt mes rapit el o-scope, he visualitzat comunicació serie a 9600bps, amb altre arduino a 115200bps, amb el o-scope a penes es veia aluna trama, amb el senzill i el serial-plotter es veien com passaven les trames.

Això ha donat que pensar si vull veure comunicació, que no una ona(repetitiva-triger), el que necessite es un analitzador lògic, un petita cerca i veig que hi ha moltíssims.

Arduino - Improved Poor Man's Oscilloscope

Crec que he trobat un osciloscopi que desa el tot el que captura i després es pot veure tot el que hem capturat, polsant pausa una vegada, i una segona vegada commença de nou l'adquisisció:



// Oscilloscope
// Input defined by ANALOG_IN
// SIG_OUT true puts a 2kHz wave on DIGITAL_OUT for testing.

#define ANALOG_IN 0
#define DIGITAL_OUT 13
bool SIG_OUT = false;

void setup() {
  // Generate a signal to examine (testing)
    // initialize timer1 
    noInterrupts();           // disable all interrupts
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    OCR1A = 31250;            // compare match register 16MHz/256/2Hz
    TCCR1B |= (1 << WGM12);   // CTC mode
    TCCR1B |= (1 << CS12);    // 256 prescaler 
    TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
    interrupts();             // enable all interrupts

// Interrupt based
  digitalWrite(DIGITAL_OUT, digitalRead(DIGITAL_OUT) ^ 1);   // Toggle

void loop() {
  int val = analogRead(ANALOG_IN);
  Serial.write( 0xff );
  Serial.write( (val >> 8) & 0xff );
  Serial.write( val & 0xff );


* Oscilloscope
 * Gives a visual rendering of analog pin in realtime.
 * ---------------- IMPROVEMENTS ------------------
 * Updates by John Porter, 2/7/2014
 * Added ability to move waveform left or right.
 * Added gridlines (bounds and minor).
 * Added ability to pause/resume.
 * Added ability to measure time.
 * General usability improvements.
 * --------------- ORIGINAL PROJECT ---------------
 * This project is part of Accrochages
 * See http://accrochages.drone.ws
 * (c) 2008 Sofian Audry (info@sofianaudry.com)
 * ------------------------------------------------
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.

// * ------------------ HOT KEYS ------------------
final char T_UP       = 'w'; // Translate waveform up
final char T_DOWN     = 's'; //                    down
final char T_LEFT     = 'a'; //                    left
final char T_RIGHT    = 'd'; //                    right
final char Z_IN       = 'c'; // Horizontal zoom in
final char Z_OUT      = 'z'; //                 out
final char S_IN       = 'e'; // Vertical scale in
final char S_OUT      = 'q'; //                out
final char MGL_UP     = 'r'; // Minor grid lines increase
final char MGL_DOWN   = 'f'; //                  decrease
final char TOG_PAUSE  = 'p'; // Toggle pause (unpause resets waveform)
final char RESET_AXIS = ' '; // Reset axis settings
final char MEAS_TIME  = 'x'; // Adds and/or highlights vertical bars (time measurement)
final char BAR_LEFT   = ','; // Move highlighted vertical bar left (can also mouse click)
final char BAR_RIGHT  = '.'; //                               right
// * ----------------------------------------------

// * --------------- STARTING STATE ---------------
float zoom    = 1.0;
float scale   = 0.5;
int centerV   = 0;
int centerH   = 0;
int gridLines = 0;
int com_port  = 1;   // Index number in Serial.list
// * ----------------------------------------------

// Global vars
import processing.serial.*;
Serial port;                    // Create object from Serial class
int val;                        // Data received from the serial port
long valTime;                   // Time data was received
int[] values;
long[] times;
float voltage;
float measTime = 0;
int   timeMode = 0;
int[] timeBars = {0, 0};
PFont f;
boolean pause;

// Setup
void setup() {
  size(1280, 480);
  port = new Serial(this, Serial.list()[com_port], 9600);    // Com port specified here
  values = new int[width];
  times = new long[width];
  timeBars[0] = width/3;
  timeBars[1] = 2*width/3;
  pause = false;
  f = createFont("Arial", 16, true);

// Read value from serial stream
int getValue() {
  int value = -1;
  while (port.available () >= 3) {
    if (port.read() == 0xff) {
      value = (port.read() << 8) | (port.read());
  return value;

// Get a y-value for the datapoint, varies based on axis settings
int getY(int val) {
  return (int)(height/2 -(val-512+centerV)*scale / 1023.0f * (height - 1));

// Push the values in the data array
void pushValue(int value) {
  for (int i=0; i<width-1; i++)
    values[i] = values[i+1];
  values[width-1] = value;

// Push the timestamps in the time array
void pushTime(long time) {
  for (int i=0; i<width-1; i++)
    times[i] = times[i+1];
  times[width-1] = time;

// Draw waveform
void drawLines() {
  int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
  for (int i=0; i<width; i++) {
    x1 = round(width - ((width-i) * zoom) + centerH);
    y1 = getY(values[i]);
    if(i > 1)
      line(x0, y0, x1, y1);
    x0 = x1;
    y0 = y1;

// Draw gridlines (bounds, minor)
void drawGrid() {
  // Get scaled values for bounds
  int pFive = getY(1023);
  int zero  = getY(0);

  // Draw voltage bounds
  stroke(255, 0, 0);
  line(0, pFive-1, width, pFive-1);
  line(0, zero+1, width, zero+1);

  // Add voltage bound text
  textFont(f, 10);
  fill(255, 0, 0);
  text("+5V", 5, pFive+12);
  text(" 0V", 5, zero-4);

  // Draw minor grid lines
  int gridVal = 0;
  stroke(75, 75, 75);
  for (int i = 0; i < gridLines; i++) {
    gridVal = getY(round((i+1.0)*(1023.0 / (gridLines+1.0))));
    line(0, gridVal, width, gridVal);

  // Add minor grid line text
  if (gridLines > 0) {
    textFont(f, 16);
    fill(204, 102, 0);
    float scaleVal = truncate(5.0f / (gridLines+1), 3);
    text("Grid: " + scaleVal + "V", 1170, height-12);
  // Print difference between vertical 'time' bars
  if (timeMode > 0) {
    textFont(f, 16);
    fill(204, 102, 0);
    int idx0 = round(width + (timeBars[0] - width - centerH)/zoom);
    int idx1 = round(width + (timeBars[1] - width - centerH)/zoom);
    // Ensure time bars are over a recorded portion of the waveform
    if(idx1 < 0 || idx0 < 0 || idx1 > (width-1) || idx0 > (width-1) || times[idx1] == 0 || times[idx0] == 0)
      text("Time: N/A", 30, height-12);
      float timeDiff = truncate((times[idx1] - times[idx0])/2000000.0,2);
      text("Time: " + timeDiff + "ms", 30, height-12);

// Draw vertical 'time bars' (seperate from above for better layering)
void drawVertLines(){
  stroke(75, 75, 75);
  if (timeMode == 1) {
    line(timeBars[1], 0, timeBars[1], height);
    stroke(100, 100, 255);
    line(timeBars[0], 0, timeBars[0], height);
  else if (timeMode == 2) {
    line(timeBars[0], 0, timeBars[0], height);
    stroke(100, 255, 100);
    line(timeBars[1], 0, timeBars[1], height);

// Truncate a floating point number
float truncate(float x, int digits) {
  float temp = pow(10.0, digits);
  return round( x * temp ) / temp;

// When a key is pressed down or held...
void keyPressed() {
  switch (key) {
  case T_UP: centerV += 10/scale; break;                     // Move waveform up
  case T_DOWN: centerV -= 10/scale; break;                   // Move waveform down
  case T_RIGHT: centerH += 10/scale; break;                  // Move waveform right
  case T_LEFT: centerH -= 10/scale; break;                   // Move waveform left
  case MGL_UP:                                               // Increase minor grid lines
    if (gridLines < 49)
      gridLines += 1;
  case MGL_DOWN:                                             // Decrease minor grid lines
    if (gridLines > 0)
      gridLines -= 1;
  case BAR_LEFT:                                             // Move the time bar left (also mouse click)
    if (timeMode == 1 && timeBars[0] > 0)
      timeBars[0] -= 1;
    else if (timeMode == 2 && timeBars[1] > 0)
      timeBars[1] -= 1; 
  case BAR_RIGHT:                                            // Move the time bar right (also mouse click)
    if (timeMode == 1 && timeBars[0] < width-1)
      timeBars[0] += 1;
    else if (timeMode == 2 && timeBars[1] < width-1)
      timeBars[1] += 1; 

// When a key is released...
void keyReleased() {
  println(key+": "+(int)key);
  switch (key) {
  case Z_IN:                                                 // Zoom horizontal
    zoom *= 2.0f;
    if ( (int) (width / zoom) <= 1 )
      zoom /= 2.0f;
  case Z_OUT:                                                // Zoom horizontal
    zoom /= 2.0f;
    if (zoom < 1.0f)
      zoom *= 2.0f;
  case S_IN: scale*=2; break;                                // Scale vertical
  case S_OUT: scale /= 2; break;                             // Scale vertical
  case RESET_AXIS:                                           // Reset all scaling
    centerV = 0; centerH = 0;
    scale = 0.5; zoom  = 1; gridLines = 0;
  case MEAS_TIME: timeMode = (timeMode + 1) % 3; break;      // Change the vertical bars (off, left bar, right bar)
  case TOG_PAUSE:                                            // Toggle waveform pausing
    if (pause) {
      centerH = 0;
      for (int i=0; i<width; i++){
        values[i] = 0;                                       // Clear data on resume
        times[i] = 0;
    pause = !pause;

// Use mouse clicks to quickly move vertical bars (if highlighted)
void mousePressed() {
  if(timeMode == 1)
    timeBars[0] = mouseX;
  else if(timeMode == 2)
    timeBars[1] = mouseX;

// Primary drawing function
void draw()
  // Get current voltage, time of reading
  val = getValue();
  valTime = System.nanoTime();
  // If not paused
  if (!pause && val != -1) {
    // Push value/time onto array
    // Print current voltage reading
    textFont(f, 16);
    fill(204, 102, 0);
    voltage = truncate(5.0*val / 1023, 1);
    text("Voltage: " + voltage + "V", 1170, 30);

Despres dels comentaris un parell de coses.

1. Soroll:

You need to add a 1M Ohm pull-down resistor (from GND of course) to A0 to remove majority of the noise. Works though!!

2. Velocitat: What kind of bandwidth is this capable of measuring ?

Rising edge lasts about 8ms, so the program is able to check signal once for 8ms. So I think that max freq is only about 125Hz.Thats what I got after setting 100Hz square signal. I would really love to make it run faster ;) Greetings

I saw that rising edge in case of putting 3,3V by hand lasts about 8ms, what means the frequency isn't very good if our oscilloscope checks the values every 8ms. I tried to increase baud rate, but I think this problem coud be connected with operations needed to expose the signal for Processing. I'll try to increase the frequency and I will let you know. Greetings, thanks for the project :)

Aquí una resposta per millorar el rendiment:

What a great project. I was looking for a simple oscope to test a circuit for another arduino project. I am just learning and I found that playing around with this project helped me to learn a lot. With the help of my brother who is an electrical engineer, we were able to make some efficiency changes to the code.

The first idea was to attempt to send the sync byte only once in order to increase the overall efficiency. That only worked partially. Due to an oddity in the way the serial port starts up, we were only able to achieve sync about 20% of the time. We would have to start processing first and then repeatedly reset the Arduino. So my brother got an idea. The implementation is quite a ways over my head but I will attempt to explain the basics and post the code changes.

In the original code, the arduino sends a sync byte, and two data bytes to encompass the 10bit analog stream. This amounts to three bytes sent for every 10 bits of needed data which could be encompassed inside two bytes. So what my brother did was use the upper few bits of the upper byte to place a sync flag and then read that back in each cycle of data transmission. So instead of using a full byte to achieve a data sync, only two are used. The improvement is about 30%. I was able to see signals of around 6Hz clearly on the oscope.

I hope this works. I'll be interested in hearing what others get for results.


So here is the code for the Arduino side and then Processing below that.

Arduino Code - Replace the loop() with this…

void loop() {

int loval;

int hival;

int val = analogRead(ANALOG_IN);

hival = ( (val >> 8) | ( val & 0x80) >> 3) | 0x80;

loval = (val & 0x7f);

Serial.write( hival & 0xff );

Serial.write( loval & 0xff );


Processing Code - Replace all of getValue() with this…

// Read value from serial stream

int getValue() {

int value = -1;

int loval;

int hival;

while (port.available () >= 2)


hival = port.read();

if((hival & 0x80) == 0x80) { // found hival flag, now read loval

loval = port.read();

if((loval & 0x80) == 0) { // loval flag = 0, as expected

value = ((hival & 0x03) << 8) | ((hival & 0x10) << 3) | loval;




// error - low byte flag <> 0 as expected

value = -1;





// error - high byte flag missing

value = -1;



return value;


Oscilloscopi digital sembla professional

Aquest, sense paraules, 5V, 3Khz, trigger = captura quan hi un canvi, es queda quiet??? Si es queda quiet quan acab la mesura del ample de pantalla seria perfecte.


Com no també a instructables i github




public/automatismes/arduino/processing/oscil_loscopi.txt · Darrera modificació: 2017/07/14 13:26 per crevert