eddiewwm 发表于 2019-1-11 18:21:47

8F328P-U 示波器

本帖最后由 eddiewwm 于 2019-1-15 10:23 编辑

8F328P-U 示波器
參考:https://create.arduino.cc/projec ... cilloscope&offset=5

更改後的程序:
#define bytesPerPackage 32
#define switch1 4               //sw1 pin
#define switch2 3               //sw2 pin

uint8_t bytesRead;
byte inputBuffer;
byte outputBuffer;
boolean sw1, sw2;

void setup() {
analogReadResolution(8);
pinMode(switch1, INPUT);
digitalWrite(switch1, HIGH);// enable internal pullup
pinMode(switch2, INPUT);
digitalWrite(switch2, HIGH);
ADMUX =B01000000;         // select internal reference (Vcc - 5V) and port 5 (A0)
//ADMUX =B00000000;         // set external aref and port
ADCSRA = B10101101;         // ADC enable, interrupt enable, set default prescaler
ADCSRB = B00000000;         // free running mode
sei();            // enable interrupts
ADCSRA |=B01000000;         // start first conversion
Serial.begin(115200);
}

void loop() {
sw1 = digitalRead(switch1);
sw2 = digitalRead(switch2);
if (bytesRead >= bytesPerPackage) {// Buffer full. Send the package.
    cli();
    bytesRead = 0;
   // for (uint8_t i = 0; i < bytesPerPackage; i += 2) {
   for (uint8_t i = 0; i < bytesPerPackage; i ++) {
      byte adch = inputBuffer;
      if (!sw1) adch |= B00001000;      // switch position in bits 10 & 11 of each byte pair
      if (!sw2) adch |= B00000100;
      outputBuffer = adch;
    }
    sei();
    Serial.write(outputBuffer, bytesPerPackage);
}

if (Serial.available()) {                // incoming byte -> set prescaler
    byte inByte = (byte)Serial.read();
    cli();
    ADCSRA= B10101000|(inByte&B00000111);// last 3 bytes of ADCSRA set the prescaler
    sei();
    ADCSRA |=B01000000;                  // start first conversion
}
}

ISR(ADC_vect) {
if (bytesRead < bytesPerPackage) {
    inputBuffer = ADCL;
    byte temp = ADCH;
    bytesRead++;
}
}
配合使用的 Processing程序:
import processing.serial.*;
import java.awt.event.KeyEvent;

// Settings --------------------------------------------------------------------------
int serialBaudRate=115200;
int bufferSize=10000000;      // number of samples (memory use: 2 bytes per sample)
float samplesPerLine=1;       // increment 1 screen line for each samples
boolean sync=true;            // sync to trig
float trigLevelLPF=.0001;   // trigLevel lowpass filter (exponential moving average)
boolean hold=false;         // pause
int prescaler=5;            // ADC prescaler: 3:8 | 4:16 | 5:32 | 6:64 | 7:128
// -----------------------------------------------------------------------------------

Serial serial;
byte[] buffer= new byte;
int writeIndex, prevWriteIndex, readIndex, trigIndex, trigCounter, loopCounter, windowWidth, windowHeight, offset;
float voltageRange, sps, frequency, trigLevel, timer;
int windowX=30;
int windowY=50;
boolean connected=false;
String serialPort;

void settings() {
size(1000, 600);
}

void setup() {
background(0);
surface.setResizable(true);
frameRate(50);
}

void draw() {
windowWidth=width-100;
windowHeight=height-100;
if (!connected) {
    background(0, 0, 0);
    text("ARDUINO OSCILLOSCOPE\n\nSelect serial port:", 25, 25);
    for (int i=0; i<Serial.list().length; i++)
      text("F"+(i+1)+" - "+Serial.list(), 25, 80+i*20);
} else {
    background(0, 0, 0);

    // update frequency counters every second
    loopCounter++;
    if (loopCounter>frameRate) {
      loopCounter=0;
      float elapsedSeconds=(millis()-timer)/1000;
      timer=millis();
      sps=(writeIndex-prevWriteIndex)/elapsedSeconds;// sample rate
      if (sps<0)sps+=bufferSize;
      prevWriteIndex=writeIndex;
      frequency=trigCounter/elapsedSeconds;            // signal frequency
      trigCounter=0;
    }
/*
    // read switch position & set voltage range
    boolean switch1=((buffer&(byte)8)==8);                                                
    boolean switch2=((buffer&(byte)4)==4);
    if (!switch1&&!switch2) voltageRange=20;
    if (!switch1&&switch2) voltageRange=10;
    if (switch1&&!switch2) voltageRange=6.64;
    if (switch1&&switch2) voltageRange=5;
*/
voltageRange=5;

    // print voltage scale
    for (int n=0; n<=10; n++)                                                                           
      text(nf(voltageRange/10*n, 2, 2)+"V", windowX+windowWidth+5, windowY+windowHeight-(n*windowHeight/10));

    // print interface and statistics
    text(" ZOOM | SYNC: "+sync+" | HOLD: "+hold+" | TRIG LPF | PRESCALER: "+nf((pow(2, prescaler)), 1, 0)+" | [<--->] OFFSET", 25, 25);
    text("frequency: "+nf(frequency, 5, 2)+"Hz"
      +" | average DCV: "+nf(trigLevel/256*voltageRange, 2, 2)+"V"
      +" | samplerate: "+nf(sps, 5, 2)+"Hz"
      +" | samples per line: "+samplesPerLine
      +" | division: "+samplesPerLine/sps*(float)width*100+"ms", 25, height-20);

    // draw trigLevel (= average voltage) line
    stroke(0, 0, 100);                                                                                 
    int trigLevelHeight=(int)(trigLevel*(float)windowHeight/256);
    line(windowX, windowY+windowHeight-trigLevelHeight, windowX+windowWidth, windowY+windowHeight-trigLevelHeight);

    // draw grid
    stroke(50);                                                                                          
    for (float n=0; n<=windowWidth; n+=(float)windowWidth/10)
      line(n+windowX, windowY, n+windowX, windowHeight+windowY);
    for (float n=0; n<=windowHeight; n+=(float)windowHeight/10)
      line(windowX, n+windowY, windowX+windowWidth, n+windowY);

    // ------------------------------
    // DRAW WAVEFORM
    // ------------------------------
    stroke(255);
    float prevSampleValue=0;
    if (sync) readIndex=trigIndex;                               // sync: start reading from last trig position
    if (!sync) readIndex=writeIndex;                           // no sync: start reading from last sample we received
    readIndex+=offset;
    float lineIncr=(float)1/samplesPerLine;
    if (lineIncr<1) lineIncr=1;
    for (float line=0; line<windowWidth; line+=lineIncr) {                                          // cycle screen lines (from right to left)
      float sampleValue=(float)getValueFromBuffer((int)((float)readIndex-line*samplesPerLine));   // get the value for the screen line
      sampleValue*=(float)windowHeight/256;                                                      // scale to windowHeight
      if (line>0)
      line(windowX+windowWidth-line,
          windowY+windowHeight-prevSampleValue,
          windowX+windowWidth-line-lineIncr,
          windowY+windowHeight-sampleValue);
      prevSampleValue=sampleValue;
    }

    // ------------------------------
    // BUFFER INCOMING BYTES & TRIG
    // ------------------------------
    if (hold) {
      serial.clear();                                                                                    // HOLD: don't receive samples; clear serial buffer
    } else {
      while (serial.available ()>0) {                                                                      // RUN: receive samples
      writeIndex++;
      if (writeIndex>=bufferSize) writeIndex=0;                                                          // handle overflow
      //buffer=(byte)serial.read();                                                 // add 1 sample (2 bytes) to buffer
      buffer=(byte)serial.read();                                                 // add 1 sample (2 bytes) to buffer
   //   buffer=(byte)serial.read();
      trigLevel=trigLevel*(1-trigLevelLPF)+(float)getValueFromBuffer(writeIndex)*trigLevelLPF;         // level for trigger intersection = exponential moving average of voltage
      if (getValueFromBuffer(writeIndex)>=trigLevel&& getValueFromBuffer(writeIndex-1)<trigLevel) {      // rising intersect detected
          trigIndex=writeIndex;                                                                            // set trigIndex (index of buffer that corresponds to last trig)
          trigCounter++;                                                                                 // count trigs (to calculate the frequency)
      }
      }
    }
}
}


// Read value from buffer
int getValueFromBuffer(int index) {                                                                     
while (index<0) index+=bufferSize;                                                                     // handle overflow of circular buffer
//return((buffer&3)<<8 | buffer&0xff);                                                 // convert bytes to int
return(buffer&0xff);                                                 // convert bytes to int
}

// Handle keys
void keyPressed() {
if (key == CODED) {
    if (connected) {
      if (keyCode == KeyEvent.VK_F1) {
      samplesPerLine*=1.1;
      if (samplesPerLine*windowWidth>bufferSize) samplesPerLine=bufferSize/windowWidth;
      }
      if (keyCode == KeyEvent.VK_F2) {
      samplesPerLine/=1.1;
      if (samplesPerLine<1/(float)windowWidth) samplesPerLine=1/(float)windowWidth;
      }
      if (keyCode == KeyEvent.VK_F3) {
      sync=!sync;
      }
      if (keyCode == KeyEvent.VK_F4) {
      hold=!hold;
      }
      if (keyCode == KeyEvent.VK_F5) {
      if (trigLevelLPF<.01) trigLevelLPF*=10;
      }
      if (keyCode == KeyEvent.VK_F6) {
      if (trigLevelLPF>.000001) trigLevelLPF/=10;
      }
      if (keyCode == KeyEvent.VK_F7) {
      if (prescaler>3) prescaler--;
      serial.write((byte)prescaler);
      }
      if (keyCode == KeyEvent.VK_F8) {
      if (prescaler<7) prescaler++;
      serial.write((byte)prescaler);
      }
      if (keyCode == LEFT) {
      offset-=samplesPerLine*20;
      if (offset<-bufferSize) offset=-bufferSize;
      }
      if (keyCode == RIGHT) {
      offset+=samplesPerLine*20;
      if (offset>0) offset=0;
      }
    } else {
      serial = new Serial(this, Serial.list(), serialBaudRate);
      serial.write((byte)prescaler);
      connected=true;
    }
}
}

eddiewwm 发表于 2019-1-16 09:40:23

另一個初學型示波器範例:
Arduino - Oscilloscope (poor Man's Oscilloscope)
https://www.instructables.com/id/Arduino-Oscilloscope-poor-mans-Oscilloscope/

// 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 = true;

void setup() {
analogReadResolution(10);
Serial.begin(9600);
//Serial.begin(115200);

// Generate a signal to examine (testing)
if (SIG_OUT) {
    pinMode(DIGITAL_OUT, OUTPUT);

    // 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
ISR(TIMER1_COMPA_vect) {
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 );
}


配合使用的Processing程序:
/*
* 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 ([email protected])
* ------------------------------------------------
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* 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= 0;   // 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(), 9600);    // Com port specified here
values = new int;
times = new long;
timeBars = width/3;
timeBars = 2*width/3;
pause = false;
smooth();
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 = values;
values = value;
}

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

// Draw waveform
void drawLines() {
int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
stroke(255,255,0);
for (int i=0; i<width; i++) {
    x1 = round(width - ((width-i) * zoom) + centerH);
    y1 = getY(values);
    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 - width - centerH)/zoom);
    int idx1 = round(width + (timeBars - 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 == 0 || times == 0)
      text("Time: N/A", 30, height-12);
    else{
      float timeDiff = truncate((times - times)/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, 0, timeBars, height);
    stroke(100, 100, 255);
    line(timeBars, 0, timeBars, height);
}
else if (timeMode == 2) {
    line(timeBars, 0, timeBars, height);
    stroke(100, 255, 100);
    line(timeBars, 0, timeBars, 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;
    break;
case MGL_DOWN:                                             // Decrease minor grid lines
    if (gridLines > 0)
      gridLines -= 1;
    break;
case BAR_LEFT:                                             // Move the time bar left (also mouse click)
    if (timeMode == 1 && timeBars > 0)
      timeBars -= 1;
    else if (timeMode == 2 && timeBars > 0)
      timeBars -= 1;
    break;
case BAR_RIGHT:                                          // Move the time bar right (also mouse click)
    if (timeMode == 1 && timeBars < width-1)
      timeBars += 1;
    else if (timeMode == 2 && timeBars < width-1)
      timeBars += 1;
    break;
}
}

// 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;
    break;
case Z_OUT:                                                // Zoom horizontal
    zoom /= 2.0f;
    if (zoom < 1.0f)
      zoom *= 2.0f;
    break;
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;
    break;
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 = 0;                                       // Clear data on resume
      times = 0;
      }
    }
    pause = !pause;
}
}

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

// Primary drawing function
void draw()
{
background(0);
drawGrid();
// Get current voltage, time of reading
val = getValue();
valTime = System.nanoTime();

// If not paused
if (!pause && val != -1) {
    // Push value/time onto array
    pushValue(val);
    pushTime(valTime);
   
    // Print current voltage reading
    textFont(f, 16);
    fill(204, 102, 0);
    voltage = truncate(5.0*val / 1023, 1);
    text("Voltage: " + voltage + "V", 1170, 30);
}
drawLines();
drawVertLines();
}

eddiewwm 发表于 2019-1-16 14:36:41

把以上範例改以VUSB代替串口:

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

#include <HIDSerial.h>

HIDSerial serial;

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

void setup() {
analogReadResolution(8); //use 1-byte A/D
serial.begin(); //HID

//Serial.begin(9600);
//Serial.begin(115200);

// Generate a signal to examine (testing)
if (SIG_OUT) {
    pinMode(DIGITAL_OUT, OUTPUT);

    // 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
ISR(TIMER1_COMPA_vect) {
digitalWrite(DIGITAL_OUT, digitalRead(DIGITAL_OUT) ^ 1);   // Toggle
}

//byte val = 0;
void loop() {
byte val = analogRead(ANALOG_IN);
/*
    Serial.write( 0xff );
    Serial.write( (val >> 8) & 0xff );
    Serial.write( val & 0xff );
*/
if (val==0) val=1; //use 1-byte only and reserve 0 for special use
serial.write( val );
serial.poll();
}


配合使用的Processing程序:
/*
* 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 ([email protected])
* ------------------------------------------------
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* 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
// * ----------------------------------------------

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;

/*****************************************************
Host software for HID-class USB serial communication.
It allows connecting to a HID serial device (16c0:05df),
sending (up to 32 bytes per packet) and receiving
strings from the device. The code uses a slightly modified
version of the g4p library for user interface, and the
HIDAPI library for handling HID requests.

The code was initially written by Chaniel Chadowitz
and modified by Ray Wang (Rayshobby LLC). The code is published
under Creative Commons Attribution-ShareAlike 3.0 license.
*************************************************************/
import g4p_controls.*;
import com.codeminders.hidapi.HIDDeviceInfo;
import com.codeminders.hidapi.HIDManager;
import com.codeminders.hidapi.HIDDevice;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.awt.Font;

GButton connectButton;

boolean paused;
String serialText = new String();

int VENDOR_ID = 0x16c0;
int PRODUCT_ID = 0x05df;
HIDDevice device = null;
Boolean device_initialized = false;
byte value1 = 0;
int value = 0;

// Setup
void setup() {
size(1280, 480);
G4P.setGlobalColorScheme(5);

connectButton = new GButton(this, 10, 15, 100, 20, "Connect");
connectButton.setTextBold();

device_initialized = false;
values = new int;
times = new long;
timeBars = width/3;
timeBars = 2*width/3;
pause = false;
smooth();
f = createFont("Arial", 16, true);
}


// 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 = values;
values = value;
}

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

// Draw waveform
void drawLines() {
int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
stroke(255, 255, 0);
for (int i=0; i<width; i++) {
    x1 = round(width - ((width-i) * zoom) + centerH);
    y1 = getY(values*4);
    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 - width - centerH)/zoom);
    int idx1 = round(width + (timeBars - 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 == 0 || times == 0)
      text("Time: N/A", 30, height-12);
    else {
      float timeDiff = truncate((times - times)/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, 0, timeBars, height);
    stroke(100, 100, 255);
    line(timeBars, 0, timeBars, height);
} else if (timeMode == 2) {
    line(timeBars, 0, timeBars, height);
    stroke(100, 255, 100);
    line(timeBars, 0, timeBars, 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;
    break;
case MGL_DOWN:                                             // Decrease minor grid lines
    if (gridLines > 0)
      gridLines -= 1;
    break;
case BAR_LEFT:                                             // Move the time bar left (also mouse click)
    if (timeMode == 1 && timeBars > 0)
      timeBars -= 1;
    else if (timeMode == 2 && timeBars > 0)
      timeBars -= 1;
    break;
case BAR_RIGHT:                                          // Move the time bar right (also mouse click)
    if (timeMode == 1 && timeBars < width-1)
      timeBars += 1;
    else if (timeMode == 2 && timeBars < width-1)
      timeBars += 1;
    break;
}
}

// 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;
    break;
case Z_OUT:                                                // Zoom horizontal
    zoom /= 2.0f;
    if (zoom < 1.0f)
      zoom *= 2.0f;
    break;
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;
    break;
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 = 0;                                       // Clear data on resume
      times = 0;
      }
    }
    pause = !pause;
}
}

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


// Primary drawing function
void draw() {
background(0);

if ( device != null && !paused ) {
    deviceRead();
}

drawGrid();
// Get current voltage, time of reading
val = value;

//valTime = System.nanoTime();

// If not paused
if (!pause && val != -1) {
    // Push value/time onto array
    pushValue(val);
    pushTime(valTime);

    // Print current voltage reading
    textFont(f, 16);
    fill(204, 102, 0);
    voltage = truncate(3.3*val / 256, 2);
    text("Voltage: " + voltage + "V", 1170, 30);
}
drawLines();
drawVertLines();
}

public void deviceInitialize() {
if (!device_initialized) {
    device_initialized = true;
    com.codeminders.hidapi.ClassPathLibraryLoader
      .loadNativeHIDLibrary();
}
}

public void deviceFindFirst() {
deviceInitialize();
HIDDeviceInfo[] infos = deviceFindAllDescriptors();

if (infos.length > 0) {
    try {
      device = infos.open();
    }
    catch (Exception e) {
      device = null;
    }
}
}

public HIDDeviceInfo[] deviceFindAllDescriptors() {
deviceInitialize();

List<HIDDeviceInfo> devlist = new ArrayList<HIDDeviceInfo>();

try {
    HIDManager hidManager = HIDManager.getInstance();

    HIDDeviceInfo[] infos = hidManager.listDevices();

    for (HIDDeviceInfo info : infos) {
      if (info.getVendor_id() == VENDOR_ID
      && info.getProduct_id() == PRODUCT_ID) {
      devlist.add(info);
      }
    }
}
catch (Exception e) {
}

return devlist.toArray(new HIDDeviceInfo);
}

public void deviceRead() {
try {
    device.disableBlocking();
    byte[] data = new byte;
    int read = device.read(data);
    if (read > 0) {
      for (int i=0; i<read; i++) {
      if (data!=0) {
          value1 = data;
          //convert signed byte to unsigned byte
          if (value1 >=0)
          {
            value = value1;
          } else {
            value = int (value1 + 255);
          }
      }
      }
    }
}
catch(IOException ioe) {
    //ioe.printStackTrace();
    System.out.println("deviceRead error");
}
}

public void handleButtonEvents(GButton button, GEvent event) {
if ( event == GEvent.CLICKED ) {
    if ( button.equals(connectButton) ) {
      if (device!=null) {
      try {
          device.close();
      }
      catch (IOException ioe) {
          ioe.printStackTrace();
      }
      device = null;
      connectButton.setText("Connect");
      connectButton.setTextBold();
      value = 0;
      } else {
      deviceFindFirst();
      connectButton.setText("Disconnect");
      connectButton.setTextBold();
      }
    }
}
}

eddiewwm 发表于 2019-1-16 14:38:46

以上的範例的實用性不大,但可作程序操練之用!:);P

弘毅 发表于 2019-1-16 15:31:25

:lol有高清无码大图嘛

eddiewwm 发表于 2019-1-17 11:48:00

效果確實差得不能見人!:lol

在網上看同一些用聲卡的示波器程序,這兩款看來很好:
虚拟示波器 0.94(利用声卡虚拟示波器)绿色版
http://www.7edown.com/xiazai/1562.html


Soundcard Oscilloscope
https://www.zeitnitz.eu/scope_en

eddiewwm 发表于 2019-1-18 13:03:49

按書本《玩轉Arduino電子制作 - 吳漢清 編著》P.227範例更改後的程序:

#include "U8glib.h"

// setup u8g object, please remove comment from one of the following constructor calls
// IMPORTANT NOTE: The following list is incomplete. The complete list of supported
// devices with all constructor calls is here: https://github.com/olikraus/u8glib/wiki/device
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_NO_ACK|U8G_I2C_OPT_FAST); // Fast I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK);// Display which does not send AC

int Input = A0;
int Key_add = 8;
int Key_sub = 9;
int Key_hold = 10;
int x, y;
int i, i1, i2, V_min, V_max, V_mid, t, t0, t1, sta, Key = 1, hold = 0;
long Freq;
float Vpp;
int Y;
int Buffer;

void sample() {
for (i = 0; i < 192; i++) {
    Buffer = ADCH;
    switch (Key) {
      case 1: delayMicroseconds(3); //__asm__("nop\n\t");//0.02 ms/div
      break;
      case 2: delayMicroseconds(10);//0.05 ms/div
      break;
      case 3: delayMicroseconds(21);//0.1 ms/div
      //__asm__("nop\n\t");
      break;
      case 4: delayMicroseconds(43);//0.2 ms/div
      break;
      case 5: delayMicroseconds(110);//0.5 ms/div
      break;
      case 6: delayMicroseconds(222);//1 ms/div
      break;
      case 7: delayMicroseconds(444);//2 ms/div
      break;
      case 8: delayMicroseconds(1130);//5 ms/div
      break;
      case 9: delayMicroseconds(2220);//10 ms/div
      break;
      default: break;
    }
}
for (i = 0; i < 192; i++) {
    Serial.write(Buffer);
}
}

void Measure() {
V_max = Buffer;
V_min = Buffer;
for (i = 0; i < 192; i++) {
    if (Buffer > V_max)   V_max = Buffer;
    if (Buffer < V_min)   V_min = Buffer;
}
V_mid = (V_max + V_min) / 2;
Vpp = (V_max - V_min) * 5.0 / 255;
for (i = 0; i < 197; i++) {
    if (Buffer < V_mid && Buffer >= V_mid) {
      i1 = i;
      break;
    }
}
for (i = i1 + 1; i < 98 + i1; i++) {
    if (Buffer < V_mid && Buffer >= V_mid) {
      i2 = i;
      break;
    }
}
t = i2 - i1;
if (t > 0) Freq = 8000 / t;
elseFreq = 0;
}

void Transform() {
for (sta = 0; sta < 96; sta++) {
    if (Buffer < 128 && Buffer > 128)   break;
}
for (i = 0; i < 96; i++) {
    Y = 63 - (Buffer >> 2);
}
}

void draw() {
for (x = 0; x < 95; x++)   u8g.drawLine(x, Y, x, Y);
u8g.drawFrame(0, 0, 97, 64);
u8g.drawLine(48, 0, 48, 63);
u8g.drawLine(0, 32, 96, 32);
for (x = 0; x < 96; x += 8)   u8g.drawLine(x, 31, x, 33);
for (y = 0; y < 64; y += 8)   u8g.drawLine(47, y, 49, y);
for (x = 8; x < 96; x += 8) {
    for (y = 8; y < 64; y += 8)   u8g.drawPixel(x, y);
}
u8g.drawStr(98, 7, "MS/div");
u8g.drawStr(98, 23, "V/div");
u8g.drawStr(98, 30, "0.625");
u8g.drawStr(98, 40, "Vpp");
u8g.setPrintPos(98, 47);
u8g.print(Vpp);
u8g.drawStr(118, 47, "V");
u8g.drawStr(98, 55, "F(Hz)");
switch (Key) {
    case 1:
      u8g.drawStr(98, 14, "0.02");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq * 50);
      break;
    case 2:
      u8g.drawStr(98, 14, "0.05");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq * 20);
      break;
    case 3:
      u8g.drawStr(98, 14, "0.1");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq * 10);
      break;
    case 4:
      u8g.drawStr(98, 14, "0.2");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq * 5);
      break;
    case 5:
      u8g.drawStr(98, 14, "0.5");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq * 2);
      break;
    case 6:
      u8g.drawStr(98, 14, "1");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq);
      break;
    case 7:
      u8g.drawStr(98, 14, "2");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq / 2);
      break;
    case 8:
      u8g.drawStr(98, 14, "5");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq / 5);
      break;
    case 9:
      u8g.drawStr(98, 14, "10");
      u8g.setPrintPos(98, 62);
      u8g.print(Freq / 10);
      break;
    default: break;
}
}

void Key_scan() {
if (digitalRead(Key_add) == LOW) {
    while (digitalRead(Key_add) == LOW);
    Key ++;
    if (Key == 10)Key = 9;
    delay(10);
}

if (digitalRead(Key_sub) == LOW) {
    while (digitalRead(Key_sub) == LOW);
    Key --;
    if (Key == 0)Key = 1;
    delay(10);
}

if (digitalRead(Key_hold) == LOW) {
    while (digitalRead(Key_hold) == LOW);
    hold == ~ hold;
    delay(10);
}
}

void setup() {
//for 32MHz clock only
sysClock(INT_OSC); //use internal 32MHz RC clock
CLKPR = 0x80;
CLKPR = 0x00;   //Divider=1, =>32MHz/1 = 32MHz
//
pinMode(Key_add, INPUT_PULLUP);
pinMode(Key_sub, INPUT_PULLUP);
pinMode(Key_hold, INPUT_PULLUP);
ADMUX = 0x60; // use Vcc reference, 8-bit left align
//ADMUX = 0xa0; // use 2.048V reference, 8-bit left align
//ADMUX = 0xe0; // use 1.024V reference, 8-bit left align
Serial.begin(115200);

ADCSRA = 0xe2;
u8g.setFont(u8g_font_5x7);
}

void loop() {
sample();
Measure();
Transform();
Key_scan();
if (hold == 0) {
    u8g.firstPage();
    do {
      draw();
    }
    while ( u8g.nextPage());
}
}

页: [1]
查看完整版本: 8F328P-U 示波器