PDA

View Full Version : This should be simple?



jderson
- 29th September 2008, 19:37
I am reading data from a sensor using SHIFTIN. While reading the data, the word-sized variable overflows. So I have to count the overflows. The problem is how to count these overflows without getting multiple counts while the YVALTOT is running. It seems to me that interrupts are the answer, but I can't figure out how. The code below is my latest attempt, but it gives multiple overflow counts when I only want one. Any help will be appreciated.

@ DEVICE pic16F689, intrc_osc_noclkout, wdt_off, mclr_off, protect_off
CM1CON0 = 0
CM2CON0 = 0
ADCON0 = 0
ANSEL = 0
ANSELH = 0
OSCCON = %01100001 '4 mhz. internal

TRISA = %101100

'RA5 = Switch high input
'RA4 = Output to Speaker
'RA3 = Input from MISO
'RA2 = Input from RB7
'RA1 = Output to SCLK
'RA0 = Output to MOSI

TRISB = %0000

'RB7 = Output to RA2 (EXT INT)
'RB6 = SCL output
'RB5 = Output to NCS
'RB4 = SDA output

TRISC = %00000000

'RC7 = Output to green led
'RC6 = Output to red led
'RC5 = Output to LCD ENABLE
'RC4 = Output to LCD RS
'RC3 = Output to LCD DB3
'RC2 = Output to LCD DB2
'RC1 = Output to LCD DB1
'RC0 = Output to LCD DB0

OPTION_REG = %11000000

Define LCD_DREG PORTC 'Set LCD data port
DEFINE LCD_DBIT 0 'Set LCD starting data bit
DEFINE LCD_RSREG PORTC 'Set LCD register select port
DEFINE LCD_RSBIT 4 'Set LCD register select bit
DEFINE LCD_EREG PORTC 'Set LCD enable port
DEFINE LCD_EBIT 5 'Set LCD enable bit
DEFINE LCD_BITS 4 'Set LCD bus size
DEFINE LCD_LINES 2 'Set LCD number of lines
DEFINE LCD_COMMANDUS 1500 'Set command delay time in us
DEFINE LCD_DATAUS 200 'Set data delay time in us

NCS VAR PORTB.5
SPEAKER VAR PORTA.4
MOSI VAR PORTA.0
MISO VAR PORTA.3
DATAIN VAR BYTE
MOTBYTE var BYTE
MOTBIT var BIT
MOTBIT = MOTBYTE.BIT7
YVAL VAR BYTE
XVAL VAR BYTE
YVALTOT VAR WORD
OVERFLOW VAR WORD

MOTBIT = 0
LOW PORTC.6
LOW PORTC.7
DATAIN = 0
PAUSE 1000

NCS = 0
NCS = 1
NCS = 0
SHIFTOUT MOSI,PORTA.1,5,[$3a\8] 'Reset sensor
PAUSE 10
SHIFTOUT MOSI,PORTA.1,5,[$5a\8]
ncs = 1
yval = 0
yvaltot = 0
OVERFLOW = 0
PORTB.7 = 0

Main:

ncs = 0
shiftout mosi,PORTA.1,5,[$02\8]
PAUSE 10
SHiftin miso,PORTA.1,6,[MOTBYTE\8]
Pause 10
ncs = 1
If MOTByTE = $e0 then YCOUNT
LCDOUT $fe,1,dec YVALTOT 'Display starting values
lcdout $fe,$c0,dec overflow
goto Main

YCOUNT:

ncs = 0
SHIFTOUT MOSI,PORTA.1,5,[$03\8] 'input values
SHIFTIN MISO,PORTA.1,6,[YVAL\8]
SHIFTOUT MOSI,PORTA.1,5,[$04\8]
SHIFTIN MISO,PORTA.1,6,[XVAL\8]
ncs = 1
yvaltot = yvaltot + yval 'count Y values
if yvaltot > 65000 then OPLUS 'keep track of y overflows
goto Main

OPLUS:

overflow = overflow + 1 'count overflows
goto OTest

OTest:

if yvaltot < 65000 THEN MAIN
goto Main

skimask
- 29th September 2008, 19:57
You're adding in the overflow in OPLUS, but you aren't dropping the yvaltot value, so the next time around, it still sees the same 'almost overflowing' yvaltot, and still increments the overflow.
If I was you...and this is just one way of doing things...make yvaltot hold a value from 0-9999, then another word variable, say yvaltot_high hold the next 4 digits to the left of that...
Yes, I'm going to colonize your program, just for me :D
Changes in bold...


@ DEVICE pic16F689, intrc_osc_noclkout, wdt_off, mclr_off, protect_off
CM1CON0 = 0 : CM2CON0 = 0 : ADCON0 = 0 : ANSEL = 0 : ANSELH = 0 : OSCCON = $61
TRISA = %101100 : TRISB = %0000 : TRISC = 0 : OPTION_REG = $c0
Define LCD_DREG PORTC 'Set LCD data port
DEFINE LCD_DBIT 0 'Set LCD starting data bit
DEFINE LCD_RSREG PORTC 'Set LCD register select port
DEFINE LCD_RSBIT 4 'Set LCD register select bit
DEFINE LCD_EREG PORTC 'Set LCD enable port
DEFINE LCD_EBIT 5 'Set LCD enable bit
DEFINE LCD_BITS 4 'Set LCD bus size
DEFINE LCD_LINES 2 'Set LCD number of lines
DEFINE LCD_COMMANDUS 1500 'Set command delay time in us
DEFINE LCD_DATAUS 200 'Set data delay time in us
NCS VAR PORTB.5 : SPEAKER VAR PORTA.4 : MOSI VAR PORTA.0 : MISO VAR PORTA.3
DATAIN VAR BYTE : MOTBYTE var BYTE : MOTBIT var BIT : MOTBIT = MOTBYTE.BIT7
YVAL VAR BYTE : XVAL VAR BYTE : YVALTOT VAR WORD : YVALTOTHI VAR WORD
MOTBIT = 0 : LOW PORTC.6 : LOW PORTC.7 : DATAIN = 0 : PAUSE 1000 : NCS = 0
NCS = 1 : NCS = 0 : SHIFTOUT MOSI,PORTA.1,5,[$3a\8] 'Reset sensor
PAUSE 10 : SHIFTOUT MOSI,PORTA.1,5,[$5a\8] : ncs = 1 : yval = 0 : yvaltot = 0
yvaltothi = 0 : PORTB.7 = 0
Main:
ncs = 0 : shiftout mosi,PORTA.1,5,[$02\8] : PAUSE 10
SHiftin miso,PORTA.1,6,[MOTBYTE\8] : Pause 10 : ncs = 1
If MOTByTE = $e0 then YCOUNT
LCDOUT $fe,1,dec4 yvaltothi, dec4 yvaltot
goto Main
YCOUNT:
ncs = 0 : SHIFTOUT MOSI,PORTA.1,5,[$03\8] 'input values
SHIFTIN MISO,PORTA.1,6,[YVAL\8] : SHIFTOUT MOSI,PORTA.1,5,[$04\8]
SHIFTIN MISO,PORTA.1,6,[XVAL\8] : ncs = 1
yvaltot = yvaltot + yval 'count Y values
if yvaltot > 10000 then OPLUS 'keep track of y overflows
goto Main

OPLUS:
yvaltot = yvaltot - 10000 : yvaltothi = yvaltothi + 1
goto main

END

jderson
- 29th September 2008, 20:17
IT WORKS! Now I'll spend the rest of the afternoon figuring out HOW it works! Thank you!
Dave

skimask
- 29th September 2008, 20:52
IT WORKS! Now I'll spend the rest of the afternoon figuring out HOW it works! Thank you!
Dave

All the program is doing is pretending that two smaller variables are one bigger variable.
If you think about it, you can extrapolate the concept out to as far as you've got memory for.
A byte will hold 0-255, good enough for 0-99, not quite a 1000
A word will hold 0-65535, good enough for a '3-digit group'.
So a word holds a 3-digit group, just like a calculator does...
You keep adding into the least significant 3-digit group, checking after each add if that '3-digit group' overflowed by going over 999. Going over 999 isn't overflowed for a word variable, but it's overflowed for a '3-digit group'. Therefore, since the variable has held the whole value, we can subtract out the maximum of that '3-digit group', in this case 1000, and add 1 (or 2 if you overflowed to 2000, or 3 if you overflowed to 3000, and so on) to the next higher '3-digit group', which in this case, would also be the next higher word variable.

Example:


ones var word
thousands var word
millions var word
billions var word
trillions var word
quadrillions var word
quintillions var word
sextillions var word

lcdout $fe , 1
'if you had a 40 character LCD, this would probably show up like it should
main:
lcdout dec3 sextillioins,dec3 quintillions,dec3 quadrillions,dec3 trillions,dec3 billions,_
dec3 millions,dec3 thousands,dec3 ones

ones = ones + 1

if ones > 1000 then
ones = ones - 1000 : thousands = thousands + 1
end
if thousands > 1000 then
thousands = thousands - 1000 : millions = millions + 1
endif
if millions > 1000 then
millions = million - 1000 : billions = billions + 1
endif
if billions > 1000 then
billions = billions - 1000 : trillions = trillions + 1
endif
if trillions > 1000 then
trillions = trillions - 1000 : quadrillions = quadrillions + 1
endif
if quadrillions > 1000 then
quadrillions = quadrillions - 1000 : quintilliions = quintillions + 1
endif
if quintillions > 1000 then
quintillions = quintillions - 1000 : sextillions = sextillions + 1
endif
if sextillions > 1000 then you've counted a helluva lot of numbers

goto main
end

I wouldn't sit around waiting for the highest digit to roll over though... Might be there for awhile...

jderson
- 29th September 2008, 21:20
Most EXCELLENT! I have learned so much from you helpful people, thank you