Created
June 21, 2017 20:03
-
-
Save edgar-bonet/dbe7ce3be4fa8a8d04b93e70d5f7e552 to your computer and use it in GitHub Desktop.
Dual channel Arduino/AVR oscilloscope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* dual-scope.c: Dual channel Arduino/AVR oscilloscope. | |
* | |
* This program alternatively samples analog inputs 0 and 1, with an | |
* overall sampling rate of about 9615 samp/s (one sample every 104 us), | |
* i.e. 4808 samp/s per channel. The samples are output as 8-bit binary | |
* through the serial port at 115200/8N1. A fixed 16-byte ASCII prologue | |
* is sent at program startup, before the actual binary data, for | |
* synchronization purposes. The first byte sent after the prologue is a | |
* sample from channel 0. | |
* | |
* Program internals: The analog-to-digital converter is set to "free | |
* running mode". The ADC ISR transfers the samples through the serial | |
* port and switches the ADC multiplexer in order to sample both | |
* channels. | |
* | |
* Target platform: This program is intended for an Arduino Uno, but it | |
* does not use the Arduino libraries. It can be compiled either as a | |
* .ino "sketch" or as a plain C file. It is likely to work on most | |
* ATmega microcontrollers having an ADC and clocked at 16 MHz. | |
* | |
* Copyright (c) 2017 Edgar Bonet Orozco. | |
* Released under the terms of the MIT license: | |
* https://opensource.org/licenses/MIT | |
*/ | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <avr/sleep.h> | |
#include <util/delay.h> | |
#define BAUD 115200 // serial port baud rate | |
#define BAUD_TOL 3 // increase the baud rate tolerance to 3% | |
#include <util/setbaud.h> // compute USE_2X and UBRR_VALUE | |
#define PROLOGUE "== STARTING ==\r\n" | |
// ADC interrupt service routine. | |
ISR(ADC_vect) | |
{ | |
// Output the 8-bit ADC reading through the serial port. | |
UDR0 = ADCH; | |
// Switch between ADC channels 0 and 1. | |
ADMUX ^= _BV(MUX0); | |
} | |
int main(void) | |
{ | |
// Configure the serial port. | |
UCSR0A = USE_2X << U2X0; // double speed if needed | |
UCSR0B = _BV(TXEN0); // enable only the transmitter | |
UCSR0C = _BV(UCSZ00) // character size = 8 bits | |
| _BV(UCSZ01); // ...ditto | |
UBRR0 = UBRR_VALUE; // set baud rate | |
// Send the prologue. | |
for (const char *p = PROLOGUE; *p; p++) { | |
UDR0 = *p; // output | |
loop_until_bit_is_set(UCSR0A, UDRE0); // flush | |
} | |
// Configure the ADC in "free running mode". | |
DIDR0 = _BV(ADC0D) // disable the digital inputs ADC0... | |
| _BV(ADC1D); // ...and ADC1 | |
ADMUX = _BV(REFS0) // voltage reference = AVCC | |
| _BV(ADLAR) // left adjust result | |
| 0; // initial input channel = ADC0 | |
ADCSRB = 0; // auto trigger source = self | |
ADCSRA = _BV(ADEN) // enable ADC | |
| _BV(ADSC) // start first conversion | |
| _BV(ADATE) // enable auto trigger | |
| _BV(ADIF) // clear interrupt flag | |
| _BV(ADIE) // enable interrupt | |
| 7; // prescaler = 128 | |
_delay_us(9); // let the conversion start | |
ADMUX |= _BV(MUX0); // first channel switch | |
// Sleep while waiting for interrupts. | |
sei(); | |
sleep_enable(); | |
for (;;) | |
sleep_cpu(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment