I actually work on a simple digital voltmeter allowing measurement from 00.0V to +99.9V, trough a 1/20 voltage divider. For this, I use one of the ADC contained in the 12F675 (full scale 0..5V), and transmit measure result via 3 shift registers, each driving one seven seg displays.
All works fine for getting analog input value, and for displaying the two first number of the real analog value.
But I don't find how display the third number. I tried with "mod" operator, searched examples on the web, and tried with "7seg_display.ppp" sample provided with MikroPascal (this last one works for an "0000..9999" integer value but not for a real value). After a full day searching on how to dow, I can't get good result for this last number.
The following schematic show what is done for 36,57 V measurement : the two first number are "3" and "6", that is OK. Now, I try to display the last number, that should be "5" or "6" if rounded (no matter for me).
(click on image for full size)
Can someone help me, please ?
My code is following :
Code: Select all
program Voltmetre_005a;
var
ArrOut : Array[3] of byte; // one byte per 7 seg display
wIn: word;
procedure Init();
begin
INTCON := %00000000;
IOC := 0;
T1CON := %00000001;
OPTION_REG := %10000001;
TRISIO := %00000000;
TRISIO := %00001011;
TRISIO.0 := 1;
TRISIO.1 := 0;
TRISIO.2 := 0;
TRISIO.3 := 1; // always input
TRISIO.4 := 0;
TRISIO.5 := 0;
CMCON := %00000111; // comparators OFF
ANSEL := %00100001; // AN0 only enabled (last 4 bits are enable bits {AN3:AN0}
ANSEL.ANS0 := 1; // set as analog input
ANSEL.ANS1 := 0; // set as digital I/O
ANSEL.ANS2 := 0; // set as digital I/O
ANSEL.ANS3 := 0; // set as digital I/O
ADCON0 := %00000001;
ADCON0.ADFM := 1; // left justified, 1 = right justified
ADCON0.VCFG := 0; // voltage ref is VDD
ADCON0.ADON := 1; // turn on ADC module
ADCON0.ADCS0 := 1; // |
ADCON0.ADCS1 := 0; // | ADCS = 100 = Fosc/4
ADCON0.ADCS2 := 0; // |
end;
procedure Out_UpdateAll;
const
iDelayData = 10; // 10 us
var
iDisp, iOut: byte;
Data: boolean;
begin
{
GP2 = DATA
GP4 = CLOCK
GP5 = STROBE
}
// set Data to low level
ClearBit(GPIO, 2);
// set Clock to low level
ClearBit(GPIO, 4);
// set Strobe to false, to avoid new output values propagate through latches
ClearBit(GPIO, 5);
// send 3 x 7 seg displays data
for iDisp := 0 to 2 do
begin
for iOut := 7 downto 0 do
begin
Data := ArrOut[iDisp].iOut;
if Data then
SetBit(GPIO, 2)
else
ClearBit(GPIO, 2);
Delay_us(iDelayData);
SetBit(GPIO, 4); // clock high
Delay_us(iDelayData);
ClearBit(GPIO, 4); // clock low
Delay_us(iDelayData);
end;
end;
// set Strobe to high, to allow new output values propagate through latches
SetBit(GPIO, 5);
// set Data to low level
ClearBit(GPIO, 2);
Delay_us(iDelayData);
end;
function Mask(iVal: byte): byte;
begin
case iVal of
0 : result := %00111111;
1 : result := %00000110;
2 : result := %01011011;
3 : result := %01001111;
4 : result := %01100110;
5 : result := %01101101;
6 : result := %01111101;
7 : result := %00000111;
8 : result := %01111111;
9 : result := %01101111
else result := %01000000;
end;
end;
procedure ValToDisp(iVal: word);
var
iDigit: byte;
rVolt: real;
begin
// iVal = 0 for Vin = 0V - iVal = 1023 for Vin = +100V
// rVolt := (100 / 1024) * iVal;
rVolt := 0.0976562 * iVal;
// decimal part
iDigit := (rVolt div 10) mod 10; // works
ArrOut[2] := Mask(iDigit);
// unit part
iDigit := (rVolt) mod 10; // works
ArrOut[1] := Mask(iDigit);
// fract part
iDigit := ???; // don't know how to do
ArrOut[0] := Mask(iDigit);
end;
// main program
begin
Init;
while true do
begin
wIn := ADC_Read(0);
ValToDisp(wIn);
Out_UpdateAll;
delay_ms(100);
end;
end.
best regards,
Remy