Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

a.c. 50Hz voltage measurement trouble

Status
Not open for further replies.

steph6

Technical User
Apr 9, 2008
1
GB
I have written code in assembly language which can read a voltage and current and display it on my LCD with scaling factors for the application I need. Its fine but I cant figure out how to store numbers and use interrupts in asm. The inputs are from voltage and current transducer circuits including summer amps etc, that I have made so the input range is unipolar 0-5 volts to suit the PIC18F452 microcontroller I am using. The ac inputs need to be sampled 20 times per 50Hz cycle, that being 1000 samples
a second. The samples need to be squared, summed, the mean found and finally the square root is found to get the rms values. I am having great difficulty in doing this.So I need to make the timer read the samples 20 times per second, then store the samples. Thats the basic bit I need, and am stuck with.
Any ideas would be good. the ra0 ACD input on the PIC is fine for the voltage, which is the single part I am working on now. So in summary, I need to store the input at ra0, and at the end of the 20 stored values, just divide the total of the 20 samples by 20. Its really
simplified down but this is as far as I have managed to get on my own.

This is the working code so far, which shows the instantaneous voltage and current in real time.
-------------------------------------------------------

list p=18f452
#include p18f452.inc


;Program Configuration Registers
__CONFIG _CONFIG1H, _OSCS_OFF_1H & _EC_OSC_1H
__CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_ON_2L
__CONFIG _CONFIG2H, _WDT_OFF_2H
__CONFIG _CONFIG3H, _CCP2MX_OFF_3H
__CONFIG _CONFIG4L, _STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_OFF_4L
__CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L
__CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
__CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L
__CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
__CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L
__CONFIG _CONFIG7H, _EBTRB_OFF_7H

#define scroll_dir TRISA,4
#define scroll PORTA,4 ;Push-button RA4 on PCB
#define select_dir TRISB,0
#define select PORTB,0 ;Push-button RB0 on PCB

EXTERN LCDInit, temp_wr, d_write, i_write, LCDLine_1, LCDLine_2
EXTERN UMUL0808L, FXD1608U, AARGB0, AARGB1, BARGB0


ssprw macro ;check for idle SSP module routine
movlw 0x00
andwf SSPCON2,W
sublw 0x00
btfss STATUS,Z
bra $-8

btfsc SSPSTAT,R_W
bra $-2
endm

variables UDATA
ptr_pos RES 1
ptr_count RES 1
temp_1 RES 1
temp_2 RES 1
temp_3 RES 1
cmd_byte RES 1
LSD RES 1
MsD RES 1
MSD RES 1


NumH RES 1
NumL RES 1
TenK RES 1
Thou RES 1
Hund RES 1
Tens RES 1
Ones RES 1

STARTUP CODE
NOP
goto start
NOP
NOP
NOP
PROG1 CODE

stan_table ;table for standard code
; "XXXXXXXXXXXXXXXX"
; ptr:
data " Voltage Output " ;0
data " S3 for reading " ;160
data " GENSET OUTPUT " ;32
data "Waiting........." ;48
data " S3=Select " ;64
data "RA4= --> RBO= ++" ;80
data " RESET to EXIT " ;96
data "Volts = " ;112
data " Current " ;128
data "Current = " ;144



start
call LCDInit

movlw B'10100100' ;initialize USART
movwf TXSTA ;8-bit, Async, High Speed
movlw .25
movwf SPBRG ;9.6kbaud @ 4MHz
movlw B'10010000'
movwf RCSTA

bcf TRISC,2 ;configure CCP1 period
movlw 0x80 ;initialize PWM duty cycle
movwf CCPR1L
bcf CCP1CON,CCP1X
bcf CCP1CON,CCP1Y

movlw 0x05 ;postscale 1:1, prescaler 4, Timer2 ON
movwf T2CON

bsf TRISA,4 ;make switch RA4 an Input
bsf TRISB,0 ;make switch RB0 an Input


;**************** STANDARD CODE MENU SELECTION *******************
;Introduction
movlw .32 ;send "Microchip" to LCD
movwf ptr_pos
call stan_char_1

movlw .48 ;send "PICDEM 2 PLUS" to LCD
movwf ptr_pos
call stan_char_2
call delay_1s ;delay for display
call delay_1s ;delay for display
menu

;------------------ VOLT MEASUREMENT ----------------------------
btfss scroll ;wait for RA4 release
goto $-2
btfss select ;wait for RB0 release
goto $-2

movlw 0x00 ;voltmeter
movwf ptr_pos
call stan_char_1

movlw .48 ;RA4=Next RB0=Now
movwf ptr_pos
call stan_char_2
v_wait
btfss select ;voltmeter measurement ??
bra voltmeter
btfsc scroll ;next mode ??
bra v_wait ;NO
btfss scroll ;YES
bra $-2 ;wait for RA4 release



;------------------ CURRENT MEASUREMENT ----------------------------
menu_current
btfss scroll ;wait for RA4 release
goto $-2
btfss select ;wait for RB0 release
goto $-2

movlw .128 ;voltmeter
movwf ptr_pos
call stan_char_1

movlw .48 ;RA4=Next RB0=Now
movwf ptr_pos
call stan_char_2
c_wait
btfss select ;voltmeter measurement ??
bra current
btfsc scroll ;next mode ??
bra c_wait ;NO
btfss scroll ;YES
bra $-2 ;wait for RA4 release




;-------------------------------------------------------------------
bra menu ;begining of menu
return

;*******************************************************************




;************* STANDARD USER CODE **********************************



;------------- Voltmeter----------------------------

voltmeter
btfss select ;wait for RB0 release
bra $-2

movlw B'01000001' ;configure A/D converter
movwf ADCON0 ;turn A/D on
movlw b'10001110' ;RA0 = analog input
movwf ADCON1

movlw .112 ;send "Volts = " to the LCD
movwf ptr_pos
call stan_char_1
volts_again
bsf ADCON0,GO ;start conversion
again
btfsc ADCON0,GO
goto again
movf ADRESH,W ;ADRESH --> WREG

movwf AARGB0 ;move ADRESH into AARGB0
movlw 0x64 ;19.5mV/step 0xC3 = 195
movwf BARGB0
call UMUL0808L

movlw 0x64 ;divide result by 200 (0x128)
movwf BARGB0
call FXD1608U

movf AARGB0,W ;prepare for 16-bit binary to BCD
movwf NumH
movf AARGB1,W
movwf NumL
call bin16_bcd ;get volts ready for LCD

call LCDLine_2 ;display A/D result on 2nd line
movf Hund,W ;get hunds
call bin_bcd
movf LSD,W ;send high digit from LSD
movwf temp_wr

movwf temp_wr
call d_write

movf Tens,W ;get tens
call bin_bcd
movf LSD,W ;send low digit x.#x
movwf temp_wr
call d_write

movf Ones,W ;get ones
call bin_bcd
movf LSD,W ;send low digit x.x#
movwf temp_wr
call d_write
movlw A'V' ;send "V" unit
movwf temp_wr
call d_write

movlw 0x20 ;3 spaces
movwf temp_wr
call d_write
movlw 0x20
movwf temp_wr
call d_write
movlw 0x20
movwf temp_wr
call d_write
movlw A'R' ;send "RB0=Exit" to LCD
movwf temp_wr
call d_write
movlw A'E'
movwf temp_wr
call d_write
movlw A'S'
movwf temp_wr
call d_write
movlw A'='
movwf temp_wr
call d_write
movlw A'E'
movwf temp_wr
call d_write
movlw A'x'
movwf temp_wr
call d_write
movlw A'i'
movwf temp_wr
call d_write
movlw A't'
movwf temp_wr
call d_write
movlw 0x20 ;2 spaces
movwf temp_wr
call d_write
movlw 0x20
movwf temp_wr
call d_write

movlw "\r" ;move data into TXREG
movwf TXREG ;carriage return
btfss TXSTA,TRMT ;wait for data TX
bra $-2
btfss select ;exit volt measurement ??
bra menu_current ;YES
bra volts_again ;NO, do conversion again

;------------- Currentmeter--------------------------------------------
current
btfss select ;wait for RB0 release
bra $-2

movlw B'01000001' ;configure A/D converter
movwf ADCON0 ;turn A/D on
movlw b'00001110' ;RA0 = analog input
movwf ADCON1

movlw .144 ;send "Volts = " to the LCD
movwf ptr_pos
call stan_char_1
current_again
bsf ADCON0,GO ;start conversion
again1
btfsc ADCON0,GO
goto again1
movf ADRESH,W ;ADRESH --> WREG

movwf AARGB0 ;move ADRESH into AARGB0
movlw 0xC3 ;19.5mV/step 0xC3 = 195
movwf BARGB0
call UMUL0808L

movlw 0xAA ;divide result by 100 (0x64)
movwf BARGB0
call FXD1608U

movf AARGB0,W ;prepare for 16-bit binary to BCD
movwf NumH
movf AARGB1,W
movwf NumL
call bin16_bcd ;get volts ready for LCD

call LCDLine_2 ;display A/D result on 2nd line
movf Hund,W ;get hunds
call bin_bcd
movf LSD,W ;send high digit from the LSD #.xx
movwf temp_wr
call d_write


movf Tens,W ;get tens
call bin_bcd
movf LSD,W ;send low digit x.#x
movwf temp_wr
call d_write
movlw A'.' ;send decimal point "."
movwf temp_wr
call d_write

movf Ones,W ;get ones
call bin_bcd
movf LSD,W ;send low digit x.x#
movwf temp_wr
call d_write
movlw A'A' ;send "A" unit
movwf temp_wr
call d_write

movlw 0x20 ;3 spaces
movwf temp_wr
call d_write
movlw 0x20
movwf temp_wr
call d_write
movlw 0x20
movwf temp_wr
call d_write
movlw A'R' ;send "RB0=Exit" to LCD
movwf temp_wr
call d_write
movlw A'E'
movwf temp_wr
call d_write
movlw A'S'
movwf temp_wr
call d_write
movlw A'='
movwf temp_wr
call d_write
movlw A'E'
movwf temp_wr
call d_write
movlw A'x'
movwf temp_wr
call d_write
movlw A'i'
movwf temp_wr
call d_write
movlw A't'
movwf temp_wr
call d_write
movlw 0x20 ;2 spaces
movwf temp_wr
call d_write
movlw 0x20
movwf temp_wr
call d_write

movlw "\r" ;move data into TXREG
movwf TXREG ;carriage return
btfss TXSTA,TRMT ;wait for data TX
bra $-2


bra current_again ;NO, do conversion again




;------------------------
;adjust Duty Cycle
inc_dc
btfss scroll ;wait for button release
bra $-2

inc_ccpr1l
btfsc select ;increment CCPR1L ???
goto ccpr1l_out ;NO
call delay_100ms ;YES
call delay_100ms
incf CCPR1L,F ;increment CCPR1L
ccpr1l_out
movlw 0x8C ;move cursor into position
movwf temp_wr
call i_write

col1
btfss scroll ;exit?
bra pwm_out
btfsc select ;wait for RB0 press
bra col1

movf CCPR1L,W ;send PR2 register to conversion
call bin_bcd

movf MSD,W ;send high digit
movwf temp_wr
call d_write
movf MsD,W ;send middle digit
movwf temp_wr
call d_write
movf LSD,W ;send low digit
movwf temp_wr
call d_write
bra inc_ccpr1l

pwm_out
movlw 0
movwf CCP1CON ;turn buzzer off




;*******************************************************************


;************************** ROUTINES ******************************


;----Standard code, Place characters on line-1--------------

stan_char_1
call LCDLine_1 ;move cursor to line 1
movlw .16 ;1-full line of LCD
movwf ptr_count
movlw UPPER stan_table
movwf TBLPTRU
movlw HIGH stan_table
movwf TBLPTRH
movlw LOW stan_table
movwf TBLPTRL
movf ptr_pos,W
addwf TBLPTRL,F
clrf WREG
addwfc TBLPTRH,F
addwfc TBLPTRU,F

stan_next_char_1
tblrd *+
movff TABLAT,temp_wr
call d_write ;send character to LCD

decfsz ptr_count,F ;move pointer to next char
bra stan_next_char_1

movlw "\n" ;move data into TXREG
movwf TXREG ;next line
btfss TXSTA,TRMT ;wait for data TX
goto $-2
movlw "\r" ;move data into TXREG
movwf TXREG ;carriage return
btfss TXSTA,TRMT ;wait for data TX
goto $-2

return

;----Standard code, Place characters on line-2--------------------------
stan_char_2
call LCDLine_2 ;move cursor to line 2
movlw .16 ;1-full line of LCD
movwf ptr_count
movlw UPPER stan_table
movwf TBLPTRU
movlw HIGH stan_table
movwf TBLPTRH
movlw LOW stan_table
movwf TBLPTRL
movf ptr_pos,W
addwf TBLPTRL,F
clrf WREG
addwfc TBLPTRH,F
addwfc TBLPTRU,F

stan_next_char_2
tblrd *+
movff TABLAT,temp_wr
call d_write ;send character to LCD

decfsz ptr_count,F ;move pointer to next char
bra stan_next_char_2

movlw "\n" ;move data into TXREG
movwf TXREG ;next line
btfss TXSTA,TRMT ;wait for data TX
goto $-2
movlw "\r" ;move data into TXREG
movwf TXREG ;carriage return
btfss TXSTA,TRMT ;wait for data TX
goto $-2

return
;----------------------------------------------------------------------


;------------------ 100ms Delay --------------------------------
delay_100ms
movlw 0xFF
movwf temp_1
movlw 0x83
movwf temp_2

d100l1
decfsz temp_1,F
bra d100l1
decfsz temp_2,F
bra d100l1
return

;---------------- 1s Delay -----------------------------------
delay_1s
movlw 0xFF
movwf temp_1
movwf temp_2
movlw 0x05
movwf temp_3
d1l1
decfsz temp_1,F
bra d1l1
decfsz temp_2,F
bra d1l1
decfsz temp_3,F
bra d1l1
return




;---------------- Binary (8-bit) to BCD -----------------------
; 255 = highest possible result
bin_bcd
clrf MSD
clrf MsD
movwf LSD ;move value to LSD
ghundreth
movlw .100 ;subtract 100 from LSD
subwf LSD,W
btfss STATUS,C ;is value greater then 100
bra gtenth ;NO goto tenths
movwf LSD ;YES, move subtraction result into LSD
incf MSD,F ;increment hundreths
bra ghundreth
gtenth
movlw .10 ;take care of tenths
subwf LSD,W
btfss STATUS,C
bra over ;finished conversion
movwf LSD
incf MsD,F ;increment tenths position
bra gtenth
over ;0 - 9, high nibble = 3 for LCD
movf MSD,W ;get BCD values ready for LCD display
xorlw 0x30 ;convert to LCD digit
movwf MSD
movf MsD,W
xorlw 0x30 ;convert to LCD digit
movwf MsD
movf LSD,W
xorlw 0x30 ;convert to LCD digit
movwf LSD
retlw 0

;---------------- Binary (16-bit) to BCD -----------------------
; xxx = highest possible result
bin16_bcd
; Takes number in NumH:NumL
; Returns decimal in
; TenK:Thou:Hund:Tens:Ones
swapf NumH,W
andlw 0x0F
addlw 0xF0
movwf Thou
addwf Thou,F
addlw 0xE2
movwf Hund
addlw 0x32
movwf Ones

movf NumH,W
andlw 0x0F
addwf Hund,F
addwf Hund,F
addwf Ones,F
addlw 0xE9
movwf Tens
addwf Tens,F
addwf Tens,F

swapf NumL,W
andlw 0x0F
addwf Tens,F
addwf Ones,F

rlcf Tens,F
rlcf Ones,F
comf Ones,F
rlcf Ones,F

movf NumL,W
andlw 0x0F
addwf Ones,F
rlcf Thou,F

movlw 0x07
movwf TenK

movlw 0x0A ; Ten
Lb1:
decf Tens,F
addwf Ones,F
btfss STATUS,C
bra Lb1
Lb2:
decf Hund,F
addwf Tens,F
btfss STATUS,C
bra Lb2
Lb3:
decf Thou,F
addwf Hund,F
btfss STATUS,C
bra Lb3
Lb4:
decf TenK,F
addwf Thou,F
btfss STATUS,C
bra Lb4

retlw 0


;---------------------------- EEPROM WRITE -------------------------------
write_eeprom
bsf SSPCON2,SEN ;start bit
btfsc SSPCON2,SEN
goto $-2
movlw B'10100000' ;send control byte (write)
movwf SSPBUF
ssprw
btfsc SSPCON2,ACKSTAT
goto $-2

movlw 0x00 ;send slave address HIGH byte
movwf SSPBUF
ssprw
btfsc SSPCON2,ACKSTAT
goto $-2

movlw 0x05 ;send slave address LOW byte(0x0005)
movwf SSPBUF
ssprw
btfsc SSPCON2,ACKSTAT
goto $-2

movf temperature,w ;send slave DATA = temperature
movwf SSPBUF
ssprw
btfsc SSPCON2,ACKSTAT
goto $-2

bsf SSPCON2,PEN ;stop bit
btfsc SSPCON2,PEN
goto $-2

bcf PIR1,TMR1IF ;clear TIMER1 overflow flag
clrf TMR1L ;clear registers for next overflow
clrf TMR1H

return

;*********************************************************************
end
 
Hello there.
First, i think that you should have asked for help in the microchip forums. The reason is that not many people write code in assembly, and furthermore even less write code that will operate a PIC micro.

* Note that i did not read your code.

So, consider the above and the next: (i am in microchip forums too)
> The 18F family has the mcc18 compiler which is C [free]. You can move your existing code as "inline assembly". With that move, you keep your working code, and you have some easy things... like easy to find the square root.

- Timer and 20samples: You can use a timer, say tmr2, write the correct pre and post/scales, maybe use autoreload. Enable the TMR2IF interrupt, so when it overflows, you will be redirected to the low or high interrupt vector. There you set the GO bit of the A/D module , ...etc
Then you store the result in e.g. the PIC's RAM. See the free space in the datasheet. You can save it in an eeprom if you want, but the RAM would be great. This would be if you used assembly for that part. Now in C, you can define a table (array)... When you write a number of values, you sum them (for loop, because you know how many samples you got), find the square root.


Hope this little info helps
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top