Hello everyone,
I am currently working on a little project here, and it's becoming rather frustrating at the moment. The project is an adjustable power supply with an LCD showing the Voltage.
After preparing the parts for the power supply and the supply for the PIC+Display, i started to work on the measurements. I'm using a PIC16F883 together with a 10 Character LC-Display. I worked my way through the datasheet and started to experiment with the PIC's ADC. I started out small - measuring 0..5 V and displaying it with 10 LED's - and worked my way up from there. I got it to function with the LCD after that.
Currently I set up a Voltage divider, so that I can measure up to 40 V.
This is where it get's problematic. The LCD shows everything just fine, except the ten's digit. I'm measuring 15 Volts from a Laptop power supply and the reading is 05,xxx. I also measured a lead-acid Battery with 11.1xx V and the display is showing 01,1. Same thing with 24 V: 04,xxx. When i hook up a little rechargeable battery with 1.29 V, it reads 01,250 V. (With another ac-adapter (3.3V) I'm getting 03,2xx).
A short review about my code-logic:
First the ADC result is multiplied with 40 (*5*8, because of the scaling)
then the binary number in mV is converted to BCD-code by
-first subtracting 10000 from the result as often as possible (then I count the subtractions and that's my first digit)
-same thing with 1000 for the rest..
-ame thing with 100 for the rest..
-same thing with 10 for the rest..
-and the rest is the last digit
-afterwards, the value 30h is added to each digit and then sent to the LCD
Here's my code: (I'm using MPLAB btw)
Obviously I didn't include all of the code, I tried to narrow it down to the important parts (sorry if some comments are in German)
I can't seem to find my mistake, I've been at this for quite some time now, and I just don't see where I'm going wrong. So any help would be truly appreciated.
Thank you in advance for taking a look at this.
If more code/schematics/information is needed, I will gladly provide it.
Thomas
I am currently working on a little project here, and it's becoming rather frustrating at the moment. The project is an adjustable power supply with an LCD showing the Voltage.
After preparing the parts for the power supply and the supply for the PIC+Display, i started to work on the measurements. I'm using a PIC16F883 together with a 10 Character LC-Display. I worked my way through the datasheet and started to experiment with the PIC's ADC. I started out small - measuring 0..5 V and displaying it with 10 LED's - and worked my way up from there. I got it to function with the LCD after that.
Currently I set up a Voltage divider, so that I can measure up to 40 V.
This is where it get's problematic. The LCD shows everything just fine, except the ten's digit. I'm measuring 15 Volts from a Laptop power supply and the reading is 05,xxx. I also measured a lead-acid Battery with 11.1xx V and the display is showing 01,1. Same thing with 24 V: 04,xxx. When i hook up a little rechargeable battery with 1.29 V, it reads 01,250 V. (With another ac-adapter (3.3V) I'm getting 03,2xx).
A short review about my code-logic:
First the ADC result is multiplied with 40 (*5*8, because of the scaling)
then the binary number in mV is converted to BCD-code by
-first subtracting 10000 from the result as often as possible (then I count the subtractions and that's my first digit)
-same thing with 1000 for the rest..
-ame thing with 100 for the rest..
-same thing with 10 for the rest..
-and the rest is the last digit
-afterwards, the value 30h is added to each digit and then sent to the LCD
Here's my code: (I'm using MPLAB btw)
Rich (BB code):
; Display for Voltage Measurements
;-------------------------------------------
; PORTC: 0----E
; 1----R/W
; 2----R/S
; PORTB: RB0-RB7 ---- D0-D7
; PORTA 1--ADC
;--------------------------------------------
list p=16f883
#include <P16F883.INC>
__CONFIG _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO
__CONFIG _CONFIG2, _WRT_OFF & _BOR21V
org 0x00
loops equ 0x2C
loops2 equ 0x2D
loops3 equ 0x2E
xw0 equ 0x22 ;
xw1 equ 0x23 ;
f0 equ 0x24 ;
f1 equ 0x25 ;
counter equ 0x26 ;
Fehler equ 0x27 ;
SZT equ 0x2C ;
ST equ 0x28 ;
SZ equ 0x29 ;
SH equ 0x2A ;
SE equ 0x2B ;
[...]
; right justify
BANKSEL ADCON1
bsf ADCON1, 7
bcf ADCON1, 5
bcf ADCON1, 4
bcf STATUS, 5
BANKSEL ANSEL
BSF ANSEL, 1 ;Set RA0 to analog
; Select Channel AN1
BANKSEL ADCON0
bcf ADCON0, 5 ; ADCHS3=0
bcf ADCON0, 4 ; ADCHS2=0
bcf ADCON0, 3 ; ADCHS1=0
bsf ADCON0, 2 ; ADCHS0=0
; ADC Frequency, turn on ADC
bsf ADCON0, 7
bcf ADCON0, 6
bsf ADCON0, 0 ; ADC on
; start a conversion
Main
clrf f0
clrf f1
clrf xw0
clrf xw1
BANKSEL ADCON0
bsf ADCON0, 1 ; start
movlw D'10' ; wait a bit
movwf loops
call WAIT
cl
btfsc ADCON0, 1 ; done?
goto cl ; no, go back
BANKSEL ADRESH
movfw ADRESH
bcf STATUS, 5
movwf f1
BANKSEL ADRESL
movfw ADRESL
bcf STATUS, 5
movwf f0
;call x8 ; result x 8
call mV ;
call B2D ;
call output
goto Main
[...]
;*********************************************************************
;16 bit Addition,
Add16 ; 16-bit add: f := f + xw
movf xw0,W ; xw0 nach W
addwf f0,F ; f0 := f0 + xw0
movf xw1,W ; xw1 nach W
btfsc STATUS,C ; fall ein Überlauf auftrat:
incfsz xw1,W ; xw1+1 nach W
addwf f1,F ; f1 := f1 + xw1
return ; fertig
;*****************************************************
; 16 Bit Subtraction,
Sub16 ; 16 bit f:=f-xw
clrf Fehler ; extraflags löschen
movf xw0, w ; f0:=f0-xw0
subwf f0, f
btfsc STATUS,C
goto Sub16a
movlw 0x01 ; borgen von f1
subwf f1, f
btfss STATUS,C
bsf Fehler, C ; Unterlauf
Sub16a
movf xw1,w ; f1:=f1-xw1
subwf f1 ,f
btfss STATUS,C
bsf Fehler, C ; Unterlauf
bcf STATUS, C ; C-Flag invertieren
btfsc Fehler, C
bsf STATUS, C
return
;*****************************************************
; Division durch 2 wird w-mal ausgeführt
; die zu dividierende Zahl steht in xw
Div2
movwf counter ; Anzahl der Divisionen speichern
Div2a ; 16 bit xw:=xw/2
bcf STATUS, C ; carry löschen
rrf xw1, f
rrf xw0, f
decfsz counter, f ; fertig?
goto Div2a ; nein: noch mal
return
;*****************************************************
; Wandlung des ADC-Wert in Millivolt (binär)
; Der ADC-Wert steht in f1,f0
; Ergebnis steht in f1,f0
mV
;Multiply the result with 8 (Voltage Divider)
movfw f0
movwf xw0
movfw f1
movwf xw1
call Add16 ; f := 2xADC
call Add16 ; f := 3xADC
call Add16 ; f := 4xADC
call Add16 ; f := 5xADC
call Add16 ; f := 6xADC
call Add16 ; f := 7xADC
call Add16 ; f := 8xADC
; multiplication with 5
movfw f0
movwf xw0
movfw f1
movwf xw1
call Add16 ; f := 2xADC
call Add16 ; f := 3xADC
call Add16 ; f := 4xADC
call Add16 ; f := 5xADC
; ADC * 5 to xw
movfw f0
movwf xw0
movfw f1
movwf xw1 ; xw := 5xADC
; xw durch 64 dividieren (6 mal durch 2)
; dann ist xw = 5xADC/64
movlw 6
call Div2
call Sub16 ; f := 5xADC - 5xADC/64
; xw auf 5xADC/128 verringern
movlw 1
call Div2
call Sub16 ; f := 5xADC - 5xADC/64 - 5xADC/128
return ; fertig
;*****************************************************
;Converting the Binary to BCD: STZ, St, SH, ST, SZ, SE
B2D
; Test auf Zehntausender 10000d = 0x2710
movlw 27h
movwf xw1
movlw 10h
movwf xw0
call B2Da
movwf SZT
; Test auf tausender 1000d = 0x03E8
movlw 0x03
movwf xw1
movlw 0xE8
movwf xw0
call B2Da
movwf ST
; Test auf hunderter 100d = 0x0064
clrf xw1
movlw 0x64
movwf xw0
call B2Da
movwf SH
; Test auf zehner 10d = 0x000A
clrf xw1
movlw 0x0A
movwf xw0
call B2Da
movwf SZ
movfw f0
movwf SE
return
B2Da
clrf counter
B2Sb
incf counter, f ; wie oft abgezogen?
call Sub16 ; f:=f-xw
btfss STATUS, C ; zu oft abgezogen?
goto B2Sb ; nein: noch einmal
call Add16 ; f:=f+xw
decf counter, w ; weil immer 1 zuviel gezählt wird
return
[...]
I can't seem to find my mistake, I've been at this for quite some time now, and I just don't see where I'm going wrong. So any help would be truly appreciated.
Thank you in advance for taking a look at this.
If more code/schematics/information is needed, I will gladly provide it.
Thomas