You also said "If you take 24 consecutive samples and divide by 6, you'll practically get an average of six 11 bit samples multiplied by two (or 4 averaged 10 bit results added together, which increases the resolution by 1 bit)." First, the 24x O/S satisfies the minimum O/S requirement of 4^2 for 2 extra bits. The /6 removes the superfluous bits. Secondly, "the average of six 11 bit samples multiplied by two" done in the manner of 24x O/S then /6 also satifies the minimum O/S requirement of 4x per extra bit. i.e. the 6x oversampling of the 11-bit value allows for the 12-bits of information. The "multiplied by two" allows the extra bit to be moved out of the fractional part of the number before it is truncated to an integer.I said: "average of six 12 bit samples (using 10 bit ADC) you'll need to take 96 samples, add them, and then divide by 24".
;Tutorial 11_1
;Reading an analogue input, and displaying it on the LCD
;Nigel Goodwin 2004... (Mods) Ian Rogers 2013..
; Device 16F876
LIST p=16F876, W=2, X=ON, R=DEC ;tell assembler what chip we are using
include "P16F876.inc" ;include the defaults for the chip
ERRORLEVEL 0, -302 ;suppress bank selection messages
__CONFIG 0x393A ;sets the configuration settings (oscillator type etc.)
cblock 0x20 ;start of general purpose registers
count
count1
counta
countb
LoX
Bit_Cntr
Timer_H
Flags
Flags2
a1 ; mulpiliers
a2
b1
b2
res1 ; long result
res2
res3
res4
tmp1
tmp2
tmp3
TenK
Thou
Hund
Tens
Ones
templcd
templcd2
Acc1L ;16 bit maths register 1
Acc1H
Point ;position of decimal point
endc
LCD_PORT Equ PORTB
LCD_TRIS Equ TRISB
LCD_RS Equ 0x04 ;LCD handshake lines
LCD_RW Equ 0x06
LCD_E Equ 0x07
LEADZ Equ 0x00 ;set to display leading zeros
;start of program
ORG 0x0000
NOP
BCF PCLATH, 3
BCF PCLATH, 4
GOTO Initialise
ORG 0x0004
RETURN
ORG 0x0005
Initialise clrf count
clrf PORTA
clrf PORTB
clrf PORTC
clrf Flags
BANKSEL ADCON1 ;disable A2D
movlw 0x06
movwf ADCON1
BANKSEL PORTA
;variables for decimal numbers display
bsf Flags, LEADZ ;Don't show leading zeros
movlw 0x03 ;set decimal point position to Three
movwf Point
SetPorts bsf STATUS, RP0 ;select bank 1
movlw 0x00 ;make all LCD pins outputs
movwf LCD_TRIS
bcf STATUS, RP0 ;select bank 0
call LCD_Init ;setup LCD module
call LCD_CurOff ;turn cursor off
call Init_ADC ;initialise analogue input
movlw 0x13
movwf b2
movlw 0x88
movwf b1
Main
call LCD_Line1 ;set to first line
call String1 ;display title string
call LCD_Line2
call Read_ADC ;read analogue input
call MULTI ; ADC * 5000 / 1024
call LCD_Decimal ;and display on LCD (in decimal)
movlw ' '
call LCD_Char ;display a space
movf a2, W
;call LCD_HEX ;and display in hexadecimal
movf a1, W
;call LCD_HEX
call Delay100 ;delay to give 10 readings per second
goto Main ;loop for ever
Init_ADC
; Set ADCON0
movlw b'10000001'
movwf ADCON0
; Set ADCON1
BANKSEL ADCON1
movlw b'10000101'
movwf ADCON1
BANKSEL ADCON0
return
Read_ADC
bsf ADCON0, GO_DONE ;initiate conversion
btfsc ADCON0, GO_DONE
goto $-1 ;wait for ADC to finish
movf ADRESH,W
andlw 0x03
movwf a2
BANKSEL ADRESL
movf ADRESL,W
BANKSEL ADRESH
movwf a1 ;
return
;TABLES
HEX_Table addwf PCL , f
retlw 0x30
retlw 0x31
retlw 0x32
retlw 0x33
retlw 0x34
retlw 0x35
retlw 0x36
retlw 0x37
retlw 0x38
retlw 0x39
retlw 0x41
retlw 0x42
retlw 0x43
retlw 0x44
retlw 0x45
retlw 0x46
Xtext addwf PCL, f
retlw 'T'
retlw 'u'
retlw 't'
retlw 'o'
retlw 'r'
retlw 'i'
retlw 'a'
retlw 'l'
retlw ' '
retlw '1'
retlw '1'
retlw '.'
retlw '1'
retlw 0x00
;end of tables
String1 clrf count ;set counter register to zero
Mess1 movf count, w ;put counter value in W
call Xtext ;get a character from the text table
xorlw 0x00 ;is it a zero?
btfsc STATUS, Z
retlw 0x00 ;return when finished
call LCD_Char
incf count, f
goto Mess1
;math
MULTI clrf res4
clrf res3
clrf res2
movlw 0x80
movwf res1
nextbit
rrf a2,f
rrf a1,f
btfss STATUS,C
goto nobit_l
movf b1,w
addwf res2,f
movf b2, w
btfsc STATUS,C
incfsz b2, w
addwf res3, f
btfsc STATUS,C
incf res4, f
bcf STATUS,C
nobit_l
btfss a1, 7
goto nobit_h
movf b1,w
addwf res3,f
movf b2, w
btfsc STATUS,C
incfsz b2, w
addwf res4, f
nobit_h
rrf res4,f
rrf res3,f
rrf res2,f
rrf res1,f
btfss STATUS,C
goto nextbit
DIVSI movf res2,w ; ditch res0 (8)
movwf res1
movf res3,w ;
movwf res2
movf res4,w
movwf res3
rrf res3,f ; shift right twice (9 & 10)
rrf res2,f
rrf res1,f
bcf STATUS,C
rrf res3,f
rrf res2,f
rrf res1,f
movf res1,w
movwf a1
movf res2,w
movwf a2
return
; end math
;LCD routines
;Initialise LCD
LCD_Init
clrf PORTB
call Delay255
movlw 0x3 ;Set 4 bit mode
movwf LCD_PORT
call Pulse_e
call Delay5
call Pulse_e
call Delay5
call Pulse_e
call Delay5
movlw 0x2 ;Set 4 bit mode
movwf LCD_PORT
call Pulse_e
call Delay20
movlw 0x28 ;Set display shift
call LCD_Cmd
movlw 0x06 ;Set display character mode
call LCD_Cmd
movlw 0x0c ;Set display on/off and cursor command
call LCD_Cmd ;Set cursor off
call LCD_Clr ;clear display
retlw 0x00
; command set routine
LCD_Cmd movwf templcd
swapf templcd, w ;send upper nibble
andlw 0x0f ;clear upper 4 bits of W
movwf LCD_PORT
bcf LCD_PORT, LCD_RS ;RS line to 1
call Pulse_e ;Pulse the E line high
movf templcd, w ;send lower nibble
andlw 0x0f ;clear upper 4 bits of W
movwf LCD_PORT
bcf LCD_PORT, LCD_RS ;RS line to 1
call Pulse_e ;Pulse the E line high
call LCD_Busy
retlw 0x00
LCD_CharD addlw 0x30 ;add 0x30 to convert to ASCII
LCD_Char movwf templcd
swapf templcd, w ;send upper nibble
andlw 0x0f ;clear upper 4 bits of W
movwf LCD_PORT
bsf LCD_PORT, LCD_RS ;RS line to 1
call Pulse_e ;Pulse the E line high
movf templcd, w ;send lower nibble
andlw 0x0f ;clear upper 4 bits of W
movwf LCD_PORT
bsf LCD_PORT, LCD_RS ;RS line to 1
call Pulse_e ;Pulse the E line high
call LCD_Busy
retlw 0x00
LCD_Line1 movlw 0x80 ;move to 1st row, first column
call LCD_Cmd
retlw 0x00
LCD_Line2 movlw 0xc0 ;move to 2nd row, first column
call LCD_Cmd
retlw 0x00
LCD_Line1W addlw 0x80 ;move to 1st row, column W
call LCD_Cmd
retlw 0x00
LCD_Line2W addlw 0xc0 ;move to 2nd row, column W
call LCD_Cmd
retlw 0x00
LCD_CurOn movlw 0x0d ;Set display on/off and cursor command
call LCD_Cmd
retlw 0x00
LCD_CurOff movlw 0x0c ;Set display on/off and cursor command
call LCD_Cmd
retlw 0x00
LCD_Clr movlw 0x01 ;Clear display
call LCD_Cmd
retlw 0x00
LCD_HEX movwf tmp1
swapf tmp1, w
andlw 0x0f
call HEX_Table
call LCD_Char
movf tmp1, w
andlw 0x0f
call HEX_Table
call LCD_Char
retlw 0x00
Pulse_e bsf LCD_PORT, LCD_E
nop
bcf LCD_PORT, LCD_E
retlw 0x00
LCD_Busy
bsf STATUS, RP0 ;set bank 1
movlw 0x0f ;set Port for input
movwf LCD_TRIS
bcf STATUS, RP0 ;set bank 0
bcf LCD_PORT, LCD_RS ;set LCD for command mode
bsf LCD_PORT, LCD_RW ;setup to read busy flag
bsf LCD_PORT, LCD_E
swapf LCD_PORT, w ;read upper nibble (busy flag)
bcf LCD_PORT, LCD_E
movwf templcd2
bsf LCD_PORT, LCD_E ;dummy read of lower nibble
bcf LCD_PORT, LCD_E
btfsc templcd2, 7 ;check busy flag, high = busy
goto LCD_Busy ;if busy check again
bcf LCD_PORT, LCD_RW
bsf STATUS, RP0 ;set bank 1
movlw 0x00 ;set Port for output
movwf LCD_TRIS
bcf STATUS, RP0 ;set bank 0
return
LCD_Decimal
call Convert
btfsc Flags, LEADZ
goto LCD_TENK
movf TenK, w
btfss STATUS, Z
goto LCD_TENK
movf Thou, w
btfss STATUS, Z
goto LCD_THOU
movf Hund, w
btfss STATUS, Z
goto LCD_HUND
movf Tens, w
btfss STATUS, Z
goto LCD_TENS
goto LCD_ONES
LCD_TENK
movlw 0x05 ;test if decimal point 5
subwf Point, w
btfss STATUS , Z
goto NO_DP5
movlw '.'
call LCD_Char ;display decimal point
NO_DP5 movf TenK, w
call LCD_CharD
movlw 0x04 ;test if decimal point 4
subwf Point, w
btfss STATUS , Z
goto LCD_THOU
movlw '.'
call LCD_Char ;display decimal point
LCD_THOU
movf Thou, w
call LCD_CharD
movlw 0x03 ;test if decimal point 3
subwf Point, w
btfss STATUS , Z
goto LCD_HUND
movlw '.'
call LCD_Char ;display decimal point
LCD_HUND
movf Hund, w
call LCD_CharD
movlw 0x02 ;test if decimal point 2
subwf Point, w
btfss STATUS , Z
goto LCD_TENS
movlw '.'
call LCD_Char ;display decimal point
LCD_TENS
movf Tens, w
call LCD_CharD
movlw 0x01 ;test if decimal point 1
subwf Point, w
btfss STATUS , Z
goto LCD_ONES
movlw '.'
call LCD_Char ;display decimal point
LCD_ONES
movf Ones, w
call LCD_CharD
return
;end of LCD routines
;Delay routines
Delay255 movlw 0xff ;delay 255 mS
goto d0
Delay100 movlw d'100' ;delay 100mS
goto d0
Delay50 movlw d'50' ;delay 50mS
goto d0
Delay20 movlw d'20' ;delay 20mS
goto d0
Delay5 movlw 0x05 ;delay 5.000 ms (20 MHz clock)
d0 movwf count1
d1 movlw 0xE7
movwf counta
movlw 0x04
movwf countb
Delay_0 decfsz counta, f
goto $+2
decfsz countb, f
goto Delay_0
decfsz count1 ,f
goto d1
retlw 0x00
;end of Delay routines
;This routine downloaded from http://www.piclist.com
Convert: ; Takes number in a2:a1
; Returns decimal in
; TenK:Thou:Hund:Tens:Ones
swapf a2, w
iorlw B'11110000'
movwf Thou
addwf Thou,f
addlw 0XE2
movwf Hund
addlw 0X32
movwf Ones
movf a2,w
andlw 0X0F
addwf Hund,f
addwf Hund,f
addwf Ones,f
addlw 0XE9
movwf Tens
addwf Tens,f
addwf Tens,f
swapf a1,w
andlw 0X0F
addwf Tens,f
addwf Ones,f
rlf Tens,f
rlf Ones,f
comf Ones,f
rlf Ones,f
movf a1,w
andlw 0X0F
addwf Ones,f
rlf Thou,f
movlw 0X07
movwf TenK
; At this point, the original number is
; equal to
; TenK*10000+Thou*1000+Hund*100+Tens*10+Ones
; if those entities are regarded as two's
; complement binary. To be precise, all of
; them are negative except TenK. Now the number
; needs to be normalized, but this can all be
; done with simple byte arithmetic.
movlw 0X0A ; Ten
Lb1:
addwf Ones,f
decf Tens,f
btfss 3,0
goto Lb1
Lb2:
addwf Tens,f
decf Hund,f
btfss 3,0
goto Lb2
Lb3:
addwf Hund,f
decf Thou,f
btfss 3,0
goto Lb3
Lb4:
addwf Thou,f
decf TenK,f
btfss 3,0
goto Lb4
retlw 0x00
end
numL equ 0X20
numH equ 0x21
tenk equ 0x22
thou equ 0x23
hund equ 0x24
tens equ 0x25
ones equ 0x26
del equ 0x27
ll movlw b'00000011'
movwf numL
movlw b'00000011' ;771
movwf numH
swapf numH,w
iorlw b'11110000'
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 tens,f
rlf tens,f
rlf ones,f
comf ones,f
rlf ones,f
movf numL,w
andlw 0x0f
addwf ones,f
rlf thou,f
movlw 0x07
movwf tenk
movlw 0x0a
lb1
addwf ones,f
decf tens,f
btfss 3,0
goto lb1
lb2
addwf tens,f
decf hund,f
btfss 3,0
goto lb2
lb3
addwf hund,f
decf thou,f
btfss 3,0
goto lb3
lb4
addwf thou,f
decf tenk,f
btfss 3,0
goto lb4
clrw
decfsz del,f
goto $-1
clrw
goto ll
end
the author doesn't seem to know the difference between dividing and dividing.
The result may look like a 12 bit result, but the LSB should be considered as noise.
First we check the lsb of the multiplier (5)
We see that it is a 1. ( An add condition ).. So we put the multiplicand (4) into a register
.You don't seem to know the difference between oversampling and averaging
MULTI clrf res4 ;
clrf res3 ;
clrf res2 ; Ready the Reult
movlw 0x80 ; Set finish flag ( there will be 24 bits )
movwf res1
nextbit
rrf a2,f ; Shift Multiplier >> once
rrf a1,f ;
btfss STATUS,C ; Was the LSBit a one?
goto nobit_l ; No it wasn't!! Go to no bit
movf b1,w ; Yes it was!!
addwf res2,f ; Add Multiplicand B to Result
movf b2, w ;
btfsc STATUS,C ; Standard Interger add
incfsz b2, w ;
addwf res3, f ; Routine
btfsc STATUS,C ;
incf res4, f ;
bcf STATUS,C ;
nobit_l
btfss a1, 7 ; Test if the b2 carried
goto nobit_h ; Nope!!
movf b1,w
addwf res3,f ; Add Multiplicand to Result
movf b2, w ;
btfsc STATUS,C ;
incfsz b2, w ;
addwf res4, f ;
nobit_h
rrf res4,f ; Rotate
rrf res3,f ; Result
rrf res2,f ;
rrf res1,f ;
btfss STATUS,C ; wait for Finish flag
goto nextbit ; continue with next bit
; 4x4 bit multiply
; by Ray Gardiner
; X*Y ; result left in W
; X and Y are 4 bits
;
;
CLRW ; Clear Result
CLRC ; Clear Carry for RLF later ;
BTFSC Y,0 ; ?*1
ADDWF X,W ; W = ?X
RLF X,F ; X = 2X
;
BTFSC Y,1 ; ?*2
ADDWF X,W ; W = ?X + ?2X
RLF X,F ; W = 4X
BTFSC Y,2 ; ?*4
ADDWF X,W ; W = ?X + ?2X + ?4X
RLF X,F ; W = 8X
BTFSC Y,3 ; ?*8
ADDWF X,W ; ?X + ?2X + ?4X + ?8X
;;;;;;;;;;;;;;;;;;;;;;;;;
13 cycles result in W 13 bytes of code space
MPU's mainly cannot multiply ( at least not 16 or 32 bit ) In binary the shift (rlf... rotate right though carry) and add commands can multiply large numbers ie.. 16. 24 and 32 bits quite easily.
4x4 bit multiply
; by Ray Gardiner
; X*Y ; result left in W
; X and Y are 4 bits
;
;
CLRW ; Clear Result
CLRC ; Clear Carry for RLF later ;
BTFSC Y,0 ; ?*1
ADDWF X,W ; W = ?X
RLF X,F ; X = 2X
;
BTFSC Y,1 ; ?*2
ADDWF X,W ; W = ?X + ?2X
RLF X,F ; W = 4X
BTFSC Y,2 ; ?*4
ADDWF X,W ; W = ?X + ?2X + ?4X
RLF X,F ; W = 8X
BTFSC Y,3 ; ?*8
ADDWF X,W ; ?X + ?2X + ?4X + ?8X
;;;;;;;;;;;;;;;;;;;;;;;;;
13 cycles result in W 13 bytes of code space
MPU's mainly cannot multiply ( at least not 16 or 32 bit ) In binary the shift (rlf... rotate right though carry) and add commands can multiply large numbers ie.. 16. 24 and 32 bits quite easily.
Dear Rogers,
You mean, it does not have any hardware for multiplication
Exactly, most CPU's don't.
You're a bit off there and you've obviously misread the meaning of my posts? Adding four 10 bit samples gives you 11 bits of information taking up at most 12 bits of space. Divide by two for the 11 bits. Divide by 4 for 10 bits. The latter is the sample average (biased downwards).You don't seem to know the difference between oversampling and averaging. With your logic I could just add four 10 bit samples and expect the result to be 12 bit.. it just does not work that way.
Your logic is wrong. There is a difference between performing the integer math 6 * 10bit / 6 * 4 (what you've described at the start of the quote) and 24 * 10bit / 6 (what you've described after). If your math is not integer, i.e. real, then both give the same result.If I add six 10 bit samples and divide by 6, I'll get a 10 bit result. If I repeat this four times and add the averaged results, I have added four 10 bit results together.. therefore increasing the resolution by 1 bit. At the end I have a sum of 24 results divided by 6. And the effective resolution has increased by 1 bit. The result may look like a 12 bit result, but the LSB should be considered as noise.
Dear Nigel thanks for the reply,
Most MCU mean, like 16f877a really don't have
But I heard some MCU have But it is not real multiplication, it is doing internally rotate and add ( I am not sure )
Please advice
thanks in advance
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?