(→Circuit Schematic) |
(→Download project) |
||
| Line 548: | Line 548: | ||
* [[mikroC PRO]] project files for [[PIC12F683]], should work also with most of PIC | * [[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== | ==Discussion and comments== | ||
Contents |
A short video clip is sometimes better than a long explanation :
/*
*******************************************************************************
* 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 PicOscilloMeter-project.ZIP file for mikroC : File:PicOscilloMeter-project.zip
Includes :
Current user rating: 89/100 (32 votes)
| powered by commenterra | Recent comments |