PDA

View Full Version : Variable changing mid-code in 16F883?



achilles03
- 4th September 2024, 04:32
I've been trying to figure out what's going on with this code, but for the life of me I can not. I've posted the whole code, but I believe the issue is in the loop titled "pulse_test". The variable "address" should increment by 16 every second time it goes through the loop, immediately after an EEPROM write. However it appears to be changing randomly during the program. I've added some debug statements and slowed down timer1 which is polled to space out measurements. After pressing STRT_BUT, some variables are set and it goes into "pulse_test". The output of the debug statements are shown below. As shown, address initially increments to 16 correctly but then is 13344 at the start of the next loop. I was sure there was a typo, but now wondering if it's something in the hardware I have set incorrectly? The loop is supposed to measure A, measure B every 8th loop, measure C, write to EEPROM every other loop, repeat. Any suggestions or thoughts are much appreciated!

"THERMAL START
A0-0-0
B0-0-0
C0-1-0
A0-2-0
C0-3-0
D0-3-16
A0-4-13344
C0-5-13344
A0-6-13344
C0-7-13344
D0-7-13360
A0-8-13360
C0-9-13360
A0-10-13360
C0-11-13360
D0-11-13376
A0-12-13376
C0-13-13376
A0-14-13376
C0-15-13376
D0-15-13392
A0-1-13392
C0-2-13392
A0-3-13392
C0-4-257
A0-5-257
C0-6-257
A0-7-257
C0-8-257"


#CONFIG
__config _CONFIG1, _HS_OSC & _WDT_OFF & _MCLRE_OFF & _LVP_OFF & _CP_OFF
__CONFIG _CONFIG2, _WRT_OFF & _BOR21V
#ENDCONFIG

'INTERRUPT VARS
'wsave var byte $70 system 'needed for interrupt
'wsave var byte $70 SYSTEM
'wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
'wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
ibit var bit
icount var byte
'GENERAL VARS
tempbit var bit
wrbit var bit
tempvar var word
tempvar2 var word
tempbyt var byte
n var byte
current var word
voltage var word
EDATA var word[4]
hbyte var byte
lbyte var byte
TIME1 var word
TIME2 var word
'HX711 specific
HX711A var Word
'MAX6675 specific
MXTemp var word
'ADS1115 specific
adrs_w var byte
adrs_r var byte
config1 var byte
config2 var byte
CNFGREG VAR BYTE
CNVRREG var byte
'EEPROM specific
wconfig var byte
rconfig var byte
address var word

ABRT_BUT var PORTA.1
STRT_BUT VAR PORTA.0
DIAG_BUT VAR PORTE.3
LED var portA.2
Hdta var PORTA.3 'HX711 pins
Hclk var PORTA.4 'HX711 pins
PIN_OUT var PORTC.3 'serial out pin
PIN_IN var PORTC.2 'serial in pin
ADC_CLK var PORTC.1 'ADC clock pin
ADC_DAT var PORTC.0 'ADC data pin
ADC_RDY var PORTA.5 'ADC alert/ready pin
EE_CLK var PORTC.5 'I2C EEPROM clock pin
EE_DAT var PORTC.4 'I2C EEPROM data pin
MXDATA var PORTB.5 'MAX6675 DATA pin (was HX711 pin)
MXCLK var PORTB.7 'MAX6675 CLOCK pin (was HX711 pin)
MXCS var PORTB.6 'MAX6675 Chip Select
MOT_PWM var PORTB.4 'MOTOR PWM OUTPUT

'INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
'INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts

T1CON = %00110000 ' Prescaler = 1:1, Timer off

ANSEL=%00000000 'all analogue ports to digital
ANSELH=%00000000 'all analogue ports to digital
ADCON0.0=0 'disable ADC
CM1CON0=%00000000 'disable COMPARATOR 1
CM2CON0=%00000000 'disable COMPARATOR 2
SSPCON=%00000000 'disable SERIAL PORT
RCSTA=%00000000 'disable SERIAL PORT
PCON=%00000000 'disable BOR and ULPW

TRISA=%00101011 '(0=output, 1=input)
TRISB=%00100001 '(0=output, 1=input)
TRISC=%00000000 '(0=output, 1=input)
TRISE=%00001000 '(0=output, 1=input)

OPTION_REG=%11000101

define OSC 20

low MOT_PWM
low Hclk
HIGH MXCS
HIGH EE_CLK

for n = 0 to 9
high LED
pause 100
low LED
pause 100
next n

'setup EEPROM
wconfig=%10100000
rconfig=%10100001

'setup ADC configuration
adrs_w=$48
adrs_w=adrs_w<<1 ' Add read/write bit at end (0=write)
adrs_r=adrs_w+1 ' Add read/write bit at end (1=read)
CNFGREG=$01 ' Address of the configuration register
CNVRREG=$00 ' Address of the conversion register

waitforstart:
if STRT_BUT=0 then waitforstart

config1=%11010001 ' A+ = A1, A- = GND
config2=%11100011
I2CWRITE ADC_DAT,ADC_CLK,adrs_w,CNFGREG,[config1,config2] 'set config register
ibit=0
address=0
icount=0
pause 2
TMR1H=0
TMR1L=0

tempbyt=0

serout2 PIN_OUT,32,["THERMAL START",13,10] '19200bps
high LED

@ bsf T1CON, TMR1ON ' Start timer
'@ INT_ENABLE TMR1_INT ; enable TMR1 interrupts
pulse_test:
TIME2.highbyte=tempbyt
I2CWRITE ADC_DAT,ADC_CLK,adrs_w,[CNVRREG] 'point to conversion register
I2CREAD ADC_DAT,ADC_CLK,adrs_r,[hbyte,lbyte] 'read voltage from ACS712 (current sensor) via ADC
current.highbyte=hbyte
current.lowbyte=lbyte
EDATA[icount]=current
'switch ADC to channel A2 (batt voltage)
config1=%11100001 'A+ = A2, A- = GND
I2CWRITE ADC_DAT,ADC_CLK,adrs_w,CNFGREG,[config1,config2] 'write config register channel
serout2 PIN_OUT,32,["A",dec ibit,"-",dec icount,"-",dec address,13,10]
if icount=0 then
LOW MXCS
shiftin MXDATA,MXCLK,0,[MXTemp\16] 'read the data to MXTemp
HIGH MXCS
serout2 PIN_OUT,32,["B",dec ibit,"-",dec icount,"-",dec address,13,10]
endif

hold1:
tempbyt=TMR1H
if tempbyt<>128 then hold1
TIME2.LOWbyte=tempbyt
icount=icount+1
I2CWRITE ADC_DAT,ADC_CLK,adrs_w,[CNVRREG] 'point to conversion register
I2CREAD ADC_DAT,ADC_CLK,adrs_r,[hbyte,lbyte] 'read batt voltage through 1/2 voltage divider via ADC
voltage.highbyte=hbyte
voltage.lowbyte=lbyte
EDATA[icount]=voltage
'switch ADC to channel A1 (current)
config1=%11010001 ' A+ = A1, A- = GND
I2CWRITE ADC_DAT,ADC_CLK,adrs_w,CNFGREG,[config1,config2] 'write config register channel
tempbyt=icount & %00000011
serout2 PIN_OUT,32,["C",dec ibit,"-",dec icount,"-",dec address,13,10]
if tempbyt=3 THEN
I2CWRITE EE_DAT,EE_CLK,wconfig,address,[EDATA[0],EDATA[1],MXTemp,TIME1,EDATA[2],EDATA[3],MXTemp,TIME2]
address=address+16
serout2 PIN_OUT,32,["D",dec ibit,"-",dec icount,"-",dec address,13,10]
toggle LED
endIF
icount.bit4=0 'rollover from 15 to 0
if address=1600 then goto readout
TIME1=TIME2
hold2:
tempbyt=TMR1H
if tempbyt<>128 then hold2
icount=icount+1
goto pulse_test

readout:
'@ INT_DISABLE TMR1_INT ; enable TMR1 interrupts
low MOT_PWM
serout2 PIN_OUT,32,["READOUT",13,10]
low LED
for tempvar=0 to 105
address=tempvar<<3
I2CREAD EE_DAT,EE_CLK,rconfig,address,[current,voltage,MXTemp,TIME1]
serout2 PIN_OUT,32,[dec tempvar," ",dec current," ",dec voltage," ",MXTemp," ",TIME1.highbyte," ",TIME1.lowbyte,13,10]
next tempvar
goto waitforstart

END

richard
- 4th September 2024, 05:49
for tempvar=0 to 105
address=tempvar<<3


that looked wrong at first if address started a 1600 but it doesn't.
perhaps address gets corrupted every time readout is run,
spaghetti code like that is hard to unravel

HenrikOlsson
- 4th September 2024, 10:35
I'm not saying this is related to your problem but here:


hold1:
tempbyt=TMR1H
if tempbyt<>128 then hold1

This will "hold" until TMR1H is 128 and then countinue.
But for how long is TMR1H 128? Are you sure it's not (still) 128 the next time you check?

I would rewrite this.
* For pacing the loop, poll the TMR1 interrupt flag.
* Create a short subroutine for each "task". MeasureA, MeasureB, MeasureC, WriteEEPROM and so on.
* Have a LoopCount variable that counts from 0 to whatever.
* Use a Select Case block to execute whatever tasks are needed at each increment of the loop.

Crude example:

TMR1IF VAR PIR1.0
LoopCount VAR BYTE

TMR1IF = 0
T1CON = %00110001 ' Prescaler = 1:8, Timer ON

Main:
IF TMR1IF=0 THEN Main ' Wait for TMR1 roll over

TMR1IF=0 ' Reset interrupt flag.

Select Case LoopCount
Case 0
GOSUB MeasureA
GOSUB MeasureB

Case 1
GOSUB MeasureA
GOSUB MeasureC

Case 2
GOSUB MeasureA
GOSUB MeasureB
GOSUB MeasureC

Case 3
GOSUB MeasureB
GOSUB MeasureC
GOSUB WriteEEPROM
END SELECT

LoopCount = LoopCount + 1
IF LoopCount = 4 THEN LoopCount = 0

Goto Main


MeasureA:
' Do stuff
RETURN

MeasureB:
' Do Stuff
RETURN

MeasureC:
' Do Stuff
RETURN

WriteEEPROM:
' Do Stuff
RETURN

richard
- 4th September 2024, 12:53
i had a slightly different take but am amazed at the similarity




#CONFIG
__config _CONFIG1, _HS_OSC & _WDT_OFF & _MCLRE_OFF & _LVP_OFF & _CP_OFF
__CONFIG _CONFIG2, _WRT_OFF & _BOR21V
#ENDCONFIG


DEFINE INTHAND ticker






ANSEL=0 'all analogue ports to digital
ANSELH=0 'all analogue ports to digital




TRISA=%00101011 '(0=output, 1=input)
TRISB=%00100001 '(0=output, 1=input)
TRISC=%00000000 '(0=output, 1=input)
TRISE=%00001000 '(0=output, 1=input)


OPTION_REG=%11000101
PIN_OUT var PORTC.3 'serial out pin
LED var portA.2
wsave var byte $70 SYSTEM
ssave var byte SYSTEM
psave var byte SYSTEM
taskflag var byte
taskswitch var byte
ro_counter var byte
ibit var byte
address var word
icount var word


define OSC 20


intcon =$c0
pir1.0=0
pie1.0=1


serout2 PIN_OUT,32,["THERMAL START",13,10] '19200bps
T1CON=$31




main:
if taskflag then
taskflag = 0
taskswitch = taskswitch + 1
if taskswitch == 4 then taskswitch = 0
select case taskswitch
CASE 0
gosub task0
serout2 PIN_OUT,32,["A",dec ibit,"-",dec icount,"-",dec address,13,10]
serout2 PIN_OUT,32,["B",dec ibit,"-",dec icount,"-",dec address,13,10]
case 1
gosub task1
icount=icount+1
serout2 PIN_OUT,32,["C",dec ibit,"-",dec icount,"-",dec address,13,10]
address=address+16
serout2 PIN_OUT,32,["D",dec ibit,"-",dec icount,"-",dec address,13,10]
case 2
gosub task2
ro_counter =ro_counter +1
if ro_counter == 16 then
serout2 PIN_OUT,32,["READOUT",13,10]
ro_counter =0
endif
case 3
gosub task3

end select
endif
goto main


task0:
'do voltage stuff
return


task1:
'do current stuff
return


task2:
'do other stuff
return


task3:
LED = ! led
return




END


asm
ticker ;tmr1 isr
banksel _taskflag
bsf _taskflag,0
banksel PIR1
bcf PIR1,0
movf psave,W ; restore PCLATH
movwf PCLATH
swapf ssave,W ; restore STATUS
movwf STATUS
swapf wsave,F ; restore W (swap avoids changing STATUS)
swapf wsave,W
RETFIE
endasm