How to display text on an oscilloscope ?
Contents |
A short video clip is sometimes better than a long explanation :
<youtube>36m5Q_BKYrU</youtube>
This project shares the basic of the PicOClock project, to use a simple 8 bit 8 pin microcontroller to print a message on an oscilloscope screen.
The enhancement are :
/* ******************************************************************************* * PICOSCILLOMETER : PIC Oscilloscope Meter ******************************************************************************* * * This program shows how to do a direct reading on an oscillocope * to build a frequency meter and a voltmeter * with a PIC and only 4 resistors. * * Circuit schematic : * * ------------+ * GP2 +----------------> to oscilloscope X trigger input * | * PIC | ____ * GP1 +----|____|-----+---------> to oscilloscope Y input * | 680 | * | +-+ * | | | 680 * | +-+ * | ____ | * GP0 +----|____|-----+ * | 680 | * ------------+ +-+ * | | 680 * +-+ * | * ----- * --- GND * - * * Oscilloscope setup : * set timebase to 0.5 ms, V/div = 2 V * select external trigger. * * source code for mikro C PRO compiler V5.30 * feel free to use this code at your own risks * * target : PIC12F683 * internal 8 MHz clock, no watchdog. * * Author : Bruno Gavand, february 2012 * see more details on http://www.micro-examples.com/ * ******************************************************************************* */ #include "built_in.h" /* * 2 bits R2R DAC gives 4 output levels : */ #define HIGH GPIO = 0b11 // uper line #define MID GPIO = 0b10 // middle line #define LOW GPIO = 0b01 // lower line #define ZERO GPIO = 0b00 // lowest line #define MAX_DIGIT 15 // number of digits to be displayed #define SLOTS (MAX_DIGIT * 3) // number of time slots, 3 per digit /* * to display text, we need to invent 12 segment digits * SEGMENT NAME : A H ----- ----- | | | F| |B |I | G | L | ----- ----- | | | E| |C |J | | | ----- ----- D K SEGMENT ENCODING : */ #define sA 0x001 #define sB 0x002 #define sC 0x004 #define sD 0x008 #define sE 0x010 #define sF 0x020 #define sG 0x040 #define sH 0x080 #define sI 0x100 #define sJ 0x200 #define sK 0x400 #define sL 0x800 /* * DIGIT ENCODING : */ const unsigned int twelveSeg[] = { sH + sI + sJ + sK + sC + sB, // 0 sI + sJ, // 1 sH + sI + sL + sC + sK, // 2 sH + sI + sL + sJ + sK, // 3 sB + sL + sI + sJ, // 4 sH + sB + sL + sJ + sK, // 5 sH + sB + sC + sK + sJ + sL, // 6 sH + sI + sJ, // 7 sH + sI + sJ + sK + sC + sB + sL, // 8 sL + sB + sH + sI + sJ + sK, // 9 0, // blank 10 sE + sF + sA + sH + sI + sJ + sG + sL, // a 11 sF + sA + sB + sG + sL + sJ + sK + sD + sE, // b sH + sA + sF + sE + sD + sK, // c sI + sL + sG + sE + sD + sK + sJ, // d sH + sA + sF + sG + sE + sD + sK, // e sA + sH + sF + sG + sE, // f sA + sF + sE + sD + sK + sJ + sL, // g sF + sE + sG + sL + sI + sJ, // h sB + sC, // i sI + sJ + sK + sD, // j sE + sF + sG + sL + sI + sC, // k sF + sE + sD + sK, // l sE + sF + sA + sB + sC + sH + sI + sJ, // m sC + sB + sH + sI + sJ, // n sA + sH + sI + sJ + sK + sD + sE + sF, // o sE + sF + sA + sH + sI + sL + sG, // p sJ + sI + sH + sA + sF + sG + sL, // q sE + sF + sA + sH + sI + sL + sG + sC, // r sA + sF + sG + sL + sJ + sK + sD + sH, // s sA + sH + sB + sC, // t sB + sC + sK + sJ + sI, // u sF + sE + sD + sC + sB + sH, // v sF + sE + sD + sC + sB + sK + sJ + sI, // w sA + sH + + sB + sC + sD + sK, // x sF + sG + sL + sI + sJ + sK + sD, // y sA + sB + sC + sK, // z } ; unsigned char display[MAX_DIGIT] ; // text to be displayed /* * time slot flags : * bit 0 is upper horizontal line (segments A or H) * bit 1 is middle horizontal line (segments G or L) * bit 2 is lower horizontal line (segments D or K) * (if no line flag is set, spot is redirected to lowest line) * bit 6 is lower vertical bar (segments E, C or J) * bit 7 is upper vertical bar (segments F, B or I) */ unsigned char line[SLOTS] ; unsigned char dIdx = 0 ; // time slot counter unsigned char fIdx = 0 ; // frame counter #define TICKS_PER_SEC ((Clock_KHz() * 1000) / 4 / 256) // number of ticks per second unsigned int scaler ; // ticks per second counter unsigned char t1roll ; // timer 1 rollover counter unsigned long t1ctr = 0 ; // timer 1 ticks per second counter unsigned char freqVolt = 0 ; // frequency or volt meter function // welcome message const char welcomeMsg[] = " welcome " ; const char freqMsg[] = " freq meter " ; const char voltMsg[] = " volt meter " ; /* * ISR */ void interrupt(void) { if(INTCON.T0IF) // if timer 0 overflow { if(line[dIdx].F6 && line[dIdx].F7) // if full vertical bar { LOW, HIGH, LOW, HIGH ; LOW, HIGH, LOW, HIGH ; LOW, HIGH, LOW, HIGH ; LOW, HIGH, LOW, HIGH ; LOW, HIGH, LOW, HIGH ; LOW, HIGH, LOW, HIGH ; LOW, HIGH, LOW, HIGH ; LOW, HIGH, LOW, HIGH ; } else if(line[dIdx].F6) // if lower vertical bar { MID, LOW, MID, LOW ; MID, LOW, MID, LOW ; MID, LOW, MID, LOW ; MID, LOW, MID, LOW ; MID, LOW, MID, LOW ; MID, LOW, MID, LOW ; MID, LOW, MID, LOW ; MID, LOW, MID, LOW ; } else if(line[dIdx].F7) // if upper vertical bar { MID, HIGH, MID, HIGH ; MID, HIGH, MID, HIGH ; MID, HIGH, MID, HIGH ; MID, HIGH, MID, HIGH ; MID, HIGH, MID, HIGH ; MID, HIGH, MID, HIGH ; MID, HIGH, MID, HIGH ; MID, HIGH, MID, HIGH ; } switch(fIdx) // depending on frame index { case 0: // upper horizontal line if(line[dIdx] & 1) { HIGH ; } else { ZERO ; } break ; case 1: // middle horizontal line if(line[dIdx] & 2) { MID ; } else { ZERO ; } break ; case 2: // lower horizontal line if(line[dIdx] & 4) { LOW ; } else { ZERO ; } break ; } dIdx++ ; // next slot if(dIdx == SLOTS) // last slot ? { GPIO.F2 = 1 ; // new frame, triggers the X scope entry dIdx = 0 ; // clear slot fIdx++ ; // next frame if(fIdx == 3) // last frame ? { fIdx = 0 ; // clear frame } } scaler++ ; if(scaler == TICKS_PER_SEC) // check for one second { // get TIMER 1 ticks count T1CON.TMR1ON = 0 ; // stop timer Lo(t1ctr) = TMR1L ; // read timer Hi(t1ctr) = TMR1H ; Higher(t1ctr) = t1roll ; // read timer rollovers TMR1L = 0 ; // reset timer TMR1H = 0 ; t1roll = 0 ; // reset rollover T1CON.TMR1ON = 1 ; // start timer scaler = 0 ; // reset counter } INTCON.T0IF = 0 ; // clear timer 0 overflow } if(PIR1.TMR1IF) // if timer 1 overflow { t1roll++ ; // inc rollover counter PIR1.TMR1IF = 0 ; // clear timer 1 overflow } GPIO.F2 = 0 ; // end trigger } /* * returns 12 segment encoding for character cc */ unsigned char mkdigit(const char cc) { unsigned char c ; c = tolower(cc) ; if((c >= '0') && (c <= '9')) { return(c - '0') ; } if((c >= 'a') && (c <= 'z')) { return(c - 'a' + 11) ; } return(10) ; // space if not printable with our encoding table } /* * build time slots from display string */ mkTimeSlots() { unsigned int i ; unsigned char *p ; /* * prepare time slot flags */ p = line ; for(i = 0 ; i < MAX_DIGIT ; i++) // for each digit { unsigned int s ; unsigned char sl, sh ; s = twelveSeg[display[i]] ; // get 7 segment encoding sl = Lo(s) ; sh = Hi(s) ; (*p).F7 = sl.F5 ; // f segment (*p).F6 = sl.F4 ; // e segment (*p).F0 = sl.F0 ; // a segment (*p).F1 = sl.F6 ; // g segment (*p).F2 = sl.F3 ; // d segment p++ ; // next slot, center part of the digit (*p).F6 = sl.F2 ; // b segment (*p).F7 = sl.F1 ; // c segment (*p).F0 = sl.F7 ; // h segment (*p).F1 = sh.F3 ; // l segment (*p).F2 = sh.F2 ; // k segment p++ ; // next slot, right part of the digit *p = 0 ; (*p).F6 = sh.F1 ; // i segment (*p).F7 = sh.F0 ; // j segment p++ ; } } /* * message scrolling */ void displayMsg(const unsigned char *msg) { unsigned char i ; i = 0 ; while(*msg) { display[i++] = mkdigit(*msg++) ; } mkTimeSlots() ; Delay_ms(1000) ; } /* * main entry */ void main() { unsigned char i ; unsigned long val ; OSCCON |= 0b01110000 ; // select 8 Mhz internal oscillator OSCTUNE = 0 ; // default oscillator calibration CMCON0 = 7 ; // no comparator TRISIO = 0b111000 ; // pin direction ANSEL = 0b010000 ; // configure GPIO 4 for DAC /* * clear buffers */ for(i = 0 ; i < sizeof(line) ; i++) { line[i] = 0 ; } for(i = 0 ; i < sizeof(display) ; i++) { display[i] = 0 ; } // TIMER 1 : T1GINV(1) TMR1GE(2) T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON T1CON = 0b00000011 ; // external clock // OPTION_REG : GPPU INTEDG T0CS T0SE PSA PS2 PS1 PS0 OPTION_REG = 0b11011000 ; // enables timer 1 rollover interrupt PIE1.TMR1IE = 1 ; PIR1.TMR1IF = 0 ; // INTCON : GIE PEIE T0IE INTE GPIE T0IF INTF GPIF INTCON = 0b11100000 ; // start interrupts displayMsg(welcomeMsg) ; for(;;) // main loop { /* * toggle frequency/volt meter */ if(GPIO.F3 == 0) { freqVolt ^= 1 ; if(freqVolt) { displayMsg(freqMsg) ; } else { displayMsg(voltMsg) ; } while(GPIO.F3 == 0) ; Delay_ms(200) ; } memset(display, 10, MAX_DIGIT) ; // clear display buffer if(freqVolt) { // frequency meter val = t1ctr ; if(t1ctr >= 1000000L) // automatic range { val /= 1000L ; // display in KHz if frequency > 1 MHz display[10] = mkdigit('k') ; display[11] = mkdigit('h') ; display[12] = mkdigit('z') ; } else { display[10] = mkdigit('h') ; // display in Hz display[11] = mkdigit('z') ; } display[2] = (val / 100000) % 10 ; // convert decimal to digits display[3] = (val / 10000) % 10 ; display[4] = (val / 1000) % 10 ; display[5] = 10 ; // thousands separator display[6] = (val / 100) % 10 ; display[7] = (val / 10) % 10 ; display[8] = (val / 1) % 10 ; /* * clear leading 0s */ if(display[2] == 0) { display[2] = 10 ; if(display[3] == 0) { display[3] = 10 ; if(display[4] == 0) { display[4] = 10 ; if(display[6] == 0) { display[6] = 10 ; if(display[7] == 0) { display[7] = 10 ; } } } } } } else { /* * volt meter */ val = Adc_Read(3) ; // read ADC channel 3 val *= 5000 ; // convert 12 bits reading to voltage val /= 1024 ; if(val < 1000) // automatic range { /* * display mV */ display[6] = (val / 100) % 10 ; display[7] = (val / 10) % 10 ; display[8] = (val / 1) % 10 ; /* * clear leading 0s */ if(display[6] == 0) { display[6] = 10 ; if(display[7] == 0) { display[7] = 10 ; } } display[9] = mkdigit(' ') ; display[10] = mkdigit('m') ; display[11] = mkdigit('v') ; } else { /* * display V */ display[4] = (val / 1000) % 10 ; display[5] = mkdigit('v') ; display[6] = (val / 100) % 10 ; display[7] = (val / 10) % 10 ; display[8] = (val / 1) % 10 ; } } mkTimeSlots() ; // prepare time slot Delay_ms(100) ; // short delay for display to be comfortable } }
Don't expect to get a high-precision frequency meter, since the PIC is clocked from the internal oscillator !
Download PicOscilloMeter-project.ZIP file for mikroC : File:PicOscilloMeter-project.zip
Includes :
Current user rating: 89/100 (32 votes)
powered by commenterra | Recent comments |