Mity Eltu
Member
I am using a single data type variable to take a running average of four numbers. I made this really simple so I could verify that it is doing what it is supposed to do, but I find it doesn't do what I think it should.
Here's the code:
And here is a list of the averages it gives:
0.275000 - correct
0.824999 - incorrect. should be 0.285
1.649999 - incorrect. should be 1.65
2.750000 - correct. weird
3.849999 - incorrect. should be 3.85
the rest are incorrect from here out following the same behavior of x.xx9999.
Is there some setting I need to change or is this just a function of the single precision data type? I don't believe there is a round command in the basic compiler, so is there a simple way to fix this?
Here's the code:
Code:
'18F4520
'LCD Configuration - 4-bit lower
Define LCD_LINES = 2
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTD
Define LCD_DBIT = 4
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_RWREG = PORTD
Define LCD_RWBIT = 1
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
Define CLOCK_FREQUENCY = 8
Define SINGLE_DECIMAL_PLACES = 6
Define SIMULATION_WAITMS_VALUE = 10
'Global Variables
Dim flags As Byte
Dim vals(4) As Single
Dim i As Byte
Dim ii As Byte
Dim avg As Single
Dim num As Single
Dim cnt As Single
main:
OSCCON = 0x72 'Internal 8MHz osc
Gosub setup
Lcdinit 0
Lcdout "Ready"
WaitMs 1000
Lcdcmdout LcdClear
Lcdout "Average = "
loop:
'running average:
'array of 4 numbers, [0-3]
'first four are loaded with index 0-3, summed
'and divided by 4
'then start replacing each number 0-3 where
'index 0 holds the oldest, and hence, the
'smallest number
If flags.0 = 0 Then 'new number coming in NOTE: I made this so it would just run instead of waiting for the timer interrupt
flags.0 = 0
num = cnt * 1.10000
vals(i) = num
avg = 0
For ii = 0 To 3
avg = avg + vals(ii)
Next ii
avg = avg / 4.00000
Lcdcmdout LcdLine2Clear
Lcdout #avg
i = i + 1
If i = 4 Then i = 0
cnt = cnt + 1.00000
Endif
Goto loop
End
setup:
INTCON = 0xd0 'int0 en
INTCON2 = 0xc0 'pull ups disabled, int0 on rising egde
PIE2.1 = 1 'tmr3 int enabled
RCON.7 = 1 'priority ints enabled
IPR2.1 = 1 'tmr3 int hi priority
CCP1CON = 0x00 'cap / comp off
CCP2CON = 0x00
SSPCON1 = 0x21 'spi on, fosc/16, clk idel state low
SSPSTAT = 0x40 'sample in middle, cke=1 - xfer on clk high to low
ADCON0 = 0x00 'A/D off
ADCON1 = 0x0f 'all digital
CMCON = 0x07 'comp off, digital io
CVRCON = 0x00
HLVDCON = 0x00 'Low volt detect off
TRISA = 0x00
TRISB = 0x01
TRISC = 0x00
TRISD = 0x00
TRISE = 0x00
LATA = 0x00
LATB = 0x00
LATC = 0x00
LATD = 0x00
LATE = 0x01 'porte0 set for MAX6675 chip select
'set timer3 for interrupt for logging new number
'for demo use timer0 and 256 prescale
T3CON = 0x30 'tmr3 1:8 (262mS) prescale, off
flags = 0x00
i = 0 'array index
cnt = 1
Return
On High Interrupt
If INTCON.1 = 1 Then 'int0
INTCON.1 = 0
flags.0 = 1 'set val to be added
Endif
'if tmier ovf, set flag1 to get new number
If PIR2.1 = 1 Then 'tmr3
PIR2.1 = 0
flags.0 = 1
Endif
Resume
And here is a list of the averages it gives:
0.275000 - correct
0.824999 - incorrect. should be 0.285
1.649999 - incorrect. should be 1.65
2.750000 - correct. weird
3.849999 - incorrect. should be 3.85
the rest are incorrect from here out following the same behavior of x.xx9999.
Is there some setting I need to change or is this just a function of the single precision data type? I don't believe there is a round command in the basic compiler, so is there a simple way to fix this?