#include #include #include "Adafruit_ILI9340.h" #define _cs 10 #define _dc 9 #define _rst 8 Adafruit_ILI9340 tft = Adafruit_ILI9340(_cs, _dc, _rst); /********************************************/ #define SCREENWIDTH 320 #define SCREENHEIGHT 240 #define CHARWIDTH 5 // set this to the width of the characters your screen uses #define CHARHEIGHT 7 // set this to the height of the characters your screen uses #define AXISWIDTH (2 + 1) // axis will show two-pixel wide graph ticks, then an empty column #define VISIBLEVALUEPIXELS (SCREENWIDTH - AXISWIDTH) // the number of samples visible on screen #define NUMVALUES (2 * VISIBLEVALUEPIXELS) // the total number of samples (take twice as many as visible, to help find trigger point) // If you don't care about triggering, NUMVALUES can be set to VISIBLEVALUEPIXELS #define TRIGGER_ENABLE_PIN 2 // set this pin high to enable trigger #define SCREEN_UPDATE_ENABLE_PIN 3 // set this pin high to freeze screen byte values[NUMVALUES]; // stores read analog values mapped to 0-127 byte values2[NUMVALUES]; // stores read analog values mapped to 0-127 byte* frontBuffer = values; byte* backBuffer = values2; int pos = 0; // the next position in the value array to read int count = 0; // the total number of times through the loop unsigned long readStartTime = 0; // time when the current sampling started int sampleRate = 1; // A value of 1 will sample every time through the loop, 5 will sample every fifth time etc. int lastStart = 0; // for vsprintf char buffer[32]; /********************************************/ // Draws a printf style string at the current cursor position void displayText(int x, int y, const char* format, ...) { // Erase previous text (contents of 'buffer' remains from last time) tft.setTextColor(ILI9340_BLACK); tft.setCursor(x, y); tft.println(buffer); va_list args; va_start(args, format); vsprintf(buffer, format, args); va_end(args); tft.setTextColor(ILI9340_YELLOW); tft.setCursor(x, y); tft.println(buffer); } // Draws the graph ticks for the vertical axis void drawAxis() { // graph ticks byte div = SCREENHEIGHT / 5; for (int x = 0; x < 2; x++) { tft.drawPixel(x, 0 * div, ILI9340_WHITE); tft.drawPixel(x, 1 * div, ILI9340_WHITE); tft.drawPixel(x, 2 * div, ILI9340_WHITE); tft.drawPixel(x, 3 * div, ILI9340_WHITE); tft.drawPixel(x, 4 * div, ILI9340_WHITE); tft.drawPixel(x, 5 * div, ILI9340_WHITE); } } // Draws the sampled values void drawValues() { int start = 0; float mag = SCREENHEIGHT / 128.0; // sample values are stored as 0-127 values, but we want to scale them to fill the whole screen vertically // If the trigger pin is high, look for the first occurrence of a non-zero sample that follows a // zero sample and start from there instead of the first element of the values array. if ( digitalRead(TRIGGER_ENABLE_PIN) ) { // Find the first occurence of zero for (int i = 0; i < NUMVALUES; i++) { if ( backBuffer[i] == 0 ) { // Now find the next value that is not zero for (; i < NUMVALUES; i++) { if ( backBuffer[i] != 0 ) { start = i; break; } } break; } } // If the trigger point is not within half of our values, we will // not have enough sample points to show the wave correctly if ( start >= VISIBLEVALUEPIXELS ) { for (int i = 0; i < VISIBLEVALUEPIXELS; i++) { tft.drawPixel(i + AXISWIDTH, SCREENHEIGHT - 1 - (frontBuffer[i + lastStart] * mag), ILI9340_WHITE); } return; } } // Erase the old line by drawing a black pixel, and draw the new line with a green pixel for (int i = 0; i < VISIBLEVALUEPIXELS; i++) { tft.drawPixel(i + AXISWIDTH, SCREENHEIGHT - 1 - (frontBuffer[i + lastStart] * mag), ILI9340_BLACK); tft.drawPixel(i + AXISWIDTH, SCREENHEIGHT - 1 - (backBuffer[i + start] * mag), ILI9340_GREEN); } // Swap buffers for next time byte* tmp = backBuffer; backBuffer = frontBuffer; frontBuffer = tmp; lastStart = start; } // Shows the time taken to sample the values shown on screen void drawFrameTime(unsigned long us) { displayText(SCREENWIDTH/2 - 4*CHARWIDTH, SCREENHEIGHT - 1.5*CHARHEIGHT, "%ld us", us); } /********************************************/ void setup() { // Set up the display tft.begin(); tft.setRotation(1); tft.setTextSize(1); tft.fillScreen(ILI9340_BLACK); drawAxis(); buffer[0] = 0; // prevent crash in first call of displayText pinMode(TRIGGER_ENABLE_PIN, INPUT); pinMode(SCREEN_UPDATE_ENABLE_PIN, INPUT); } /********************************************/ // http://extremeelectronics.co.in/avr-tutorials/using-the-analog-to-digital-converter/ void sampleValues() { // set the analog reference (high two bits of ADMUX) and select the // channel (low 4 bits). this also sets ADLAR (left-adjust result) // to 0 (the default). ADMUX = (DEFAULT << 6) | (0 & 0x07); ADCSRA &= ~(ADPS0 | ADPS1 | ADPS2); boolean digi = false; if ( digi ) { for (int i = 0; i < NUMVALUES; i++) { // http://www.arduino.cc/en/Reference/PortManipulation // PORTC maps to Arduino analog pins 0 to 5 backBuffer[i] = PINC; delayMicroseconds(5); } for (int i = 0; i < NUMVALUES; i++) { backBuffer[i] = backBuffer[i] > 0 ? 64 : 0; // 64 will be in the vertical middle } } else { for (int i = 0; i < NUMVALUES; i++) { // Start conversion _SFR_BYTE(ADCSRA) |= _BV(ADSC); // ADSC is cleared when the conversion finishes while (bit_is_set(ADCSRA, ADSC)); // We have to read ADCL first; doing so locks both ADCL // and ADCH until ADCH is read. reading ADCL second would // cause the results of each conversion to be discarded, // as ADCL and ADCH would be locked when it completed. uint8_t low = ADCL; uint8_t high = ADCH; // Combine the two bytes (normally high|low would give a value in 0-1023 backBuffer[i] = (high << 5) | (low >> 3); //0-127 range delayMicroseconds(60); } } } /********************************************/ void loop() { if ( !digitalRead(SCREEN_UPDATE_ENABLE_PIN) ) { readStartTime = micros(); sampleValues(); unsigned long totalSampleTime = (micros() - readStartTime) / 2; // Divide by 2 because we are taking twice as many samples as are shown on the screen // Display the data on screen drawValues(); drawFrameTime(totalSampleTime); } }