www.micro-examples.com : PicOscilloMeter

Views
From www.micro-examples.com
(Difference between revisions)
Jump to: navigation, search
(Download project)
(PicOscilloMeter: A direct oscilloscope reading frequency/volt meter)
Line 4: Line 4:
 
A short video clip is sometimes better than a long explanation :
 
A short video clip is sometimes better than a long explanation :
 
{{#ev:youtube|36m5Q_BKYrU&list}}
 
{{#ev:youtube|36m5Q_BKYrU&list}}
 +
 +
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 :
 +
* circuit can display alphanumeric from 0-9 and A-Z characters
 +
* circuit can work as frequency meter from 1 Hz to 1.5 MHz
 +
* circuit can work as voltmeter from 0 to 5V
 +
* a push button toggles frequency/volt meter
  
 
==Circuit Schematic==
 
==Circuit Schematic==

Revision as of 00:19, 17 February 2012

PicOscilloMeter screen capture

Contents

 [hide

PicOscilloMeter: A direct oscilloscope reading frequency/volt meter

A short video clip is sometimes better than a long explanation :


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 :

  • circuit can display alphanumeric from 0-9 and A-Z characters
  • circuit can work as frequency meter from 1 Hz to 1.5 MHz
  • circuit can work as voltmeter from 0 to 5V
  • a push button toggles frequency/volt meter

Circuit Schematic

PicOscilloMeter-schematic.png

C Source code

/*
 *******************************************************************************
 * PICOSCILLOMETER : PIC Oscilloscope Meter
 *******************************************************************************
 *
 * This program show 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
                }
        }

Download project

Download PicOscilloMeter-project.ZIP file for mikroC : File:PicOscilloMeter-project.zip

Includes :

  • mikroC PRO project files for PIC12F683, should work also with most of PIC
  • PicOscilloMeter C source code
  • PicOscilloMeter ready to flash .HEX files

Discussion and comments

Current user rating: 89 (32 votes)
You didn't vote on this yet.

 89%

Thomas
(74 months ago)
Reply
When I compare the Config Word of the precompiled HEX File with the Config Word resulting from recompiling the Project with mikroC V5.6.1, they are completely different.
precompiled HEX-File: Config Word = 0x0014 (Code Protection set..)
recompiled Source Fie: Config Word = 0x0FF2
Which one is correct?

When I connect the Outputs to an Oscilloscope with external Trigger from X and Chan1 from Y, I can see a steady wave containing 4 dedicated Voltage levels, but no readable Text. What is wrong?
BrunoG
(74 months ago)
Reply
Hi Thomas, thank you for your message

configuration word value 0x0014 is correct for PIC12F683, as it is in the binary file

please note that the oscilloscope must not be set in X/Y configuration but in external trigger mode&|60;: GP2 output pin is connected to the trigger input of your oscillo to get correct horizontal synchronization

timebase should be 0.5 ms/div

hope this will help
Thomas
(74 months ago)
Reply
Thank you Bruno,

with my old analogue Oscilloscope I now get readable outputs, much better than using a digital Oszilloscope.

I also changed R3 from 680 Ohm to 330 Ohm to achieve the right R2R Voltage Levels.
diego
(83 months ago)
Reply
val *= 5000&|60;; // convert 12 bits reading to voltage
//incorrect
val *= 5000&|60;; // convert 10 bits reading to voltage
//correct
Roberjones
(1 year ago)
Reply
Very nice of sharing. Recently I had been looking for this type blog . I am very happy by seeing your post and I got several ideas from your story. Looking forward to getting your next story .Thank you.
https://essaypaperreviews.com/
Pouria zamani
(1 year ago)
Reply
thank you very much
Rory
(1 year ago)
Reply
Can you please provide a board image from Eaglecad?
bschatz
(1 year ago)
Reply
Nice project. I have one question, what is in the file built_in.h?
electro
(1 year ago)
Reply
great idea and nice code.
name
(1 year ago)
Reply
good
tgh
(1 year ago)
Reply
zfd
...

Navigation
Others
Donation
You can help :
with Paypal
Share
Personal tools
www.micro-examples.com Electronic circuits with micro-controllers, projects with source code examples