- Joined
- Jul 4, 2009
- Messages
- 16,236
- Helped
- 5,140
- Reputation
- 10,309
- Reaction score
- 5,122
- Trophy points
- 1,393
- Location
- Aberdyfi, West Wales, UK
- Activity points
- 137,409
Well done!
The next step is to decide which pins do which function and set the PIC configuration. GP3 can only be used as an input so we can ignore it for now, only GP0 and GP1 can be used as an analog input and you only need one so I suggest you use GP0. That leaves GP1 and GP2 to talk to the shift register driving the LCD.
I have another job I must finish so your 'homework' is to work out the values to write to the various registers to make GP0 an analog input and the other pins digital outputs. Post the values you choose and I will confirm them and show you how to put the values in the registers tomorrow.
Brian.
so
;*******************************************************************************************************
;* Initialisation du microcontrôleur
;*******************************************************************************************************
movwf OSCCAL ; update register with factory cal value
movlw B'01000000'
Microchip cleverly test and pre-program the clock adjustment value in the last location in the PIC memory during manufacture. The reset vector (the address the PIC starts from) is also pre-set to the last address. The program counter (PCL) always counts up by 1 as it picks up an instuction and when it reaches the last memory address it loops back to address zero. This means the first thing the PIC does is read it's own adjustment value into W and arrives at address zero with it ready to use. You don't have to use it, the reason for having it is to 'fine tune' the internal clock frequency to make it more accurate but if speed isn't important and you are very short of memory you can ignore it. The template file uses the instruction "movwf OSCCAL" to save the value in W (the oscillator adjustment value) to the OSCCAL register where it applies the adjustment value.
Table 4-1 in the data sheet shows all the PIC registers. There are only 11 in the whole PIC and they are all 8-bits wide. Not all bits are used in each register.
Registers 0 to 8 can be used at any time in your program and you can use the 'name' instead of it's number to make the program easier to read. In fact you can call all the bits by their names as well. The TRISGPIO and OPTION registers have their own special instruction to program them.
To configure GP0 as an analog input and GP1, GP2, as outputs (GP3 is always an input) you need to put values in TRISGPIO and ADCON0 registers.
Only the lower 4 bits in TRISGPIO are used, each bit corresponds to one of the port pins. Bit 0 controls GP0, bit 1 controls GP1.... bit 3 controls GP3. Putting a '1' in a bit position makes the corresponding pin an input to the PIC (so it can read a signal from outside), a '0' makes the pin an output so it can drive something outside. In your application, GP0 is an input (from the wind speed), GP1 and GP2 are outputs to the LCD so the value has to be 1001 in binary. GP0 is the least significant bit. The instruction to configure the pin data direction is therefore TRISGPIO b'1001'. Most programmers use hexadecimal rather than binary so the equivalent instruction would be 'TRISGPIO 0x09'
Next you have to make GP0 the analog input. Look at "Register 7-1" on page 30.
You have to write 0 or 1 into the bits of the ADCON0 register to configure the Analog to Digital converter. The bits you need to set are:
0 in ANS1 because GP1 is being used as a digital output to the LCD
1 in ANS0 because GP0 is the analog input
the next two bits do nothing so let's just set them to zero
CHS<1:0> selects which of the analog inputs is to have the measurement taken from it, in this case GP0 so the value is 00
GO/-DONE is the trigger bit to start the measurement process, leave it at 0 for now, we will use it later.
ADON turns the entire analog measurement module on or off (to save power). For now leave it turned on so ADON = 1.
So the value to write to ADCON0 is b'01000001' or 0x41.
Unlike TRISGPIO which has it's own special instruction, to write to ADCON0 you do it in two steps, the first is to put the value in the W register, then to copy the W register contents into ADCON0. So the code is:
movlw 0x41
movwf ADCON0
'movlw' means 'MOVe Literal to W', it takes the value in the instruction and puts it in W
'movwf' means 'MOVe W to File', it copies the contents of W into the named file (file = register).
Rules of writing in MPLABX:
The first (leftmost) column is reserved for labels
Anything after the first column is for instructions
Anything after ';' is a comment.
Brian.
[COLOR="#0000FF"]list [/COLOR] p=10F220 ; list directive to define processor
[COLOR="#0000FF"]#include[/COLOR] <p10F220.inc> ; processor specific variable definitions
[COLOR="#FF0000"] __CONFIG _MCLRE_ON & _CP_OFF & _WDT_OFF & _MCPU_OFF & _IOFSCS_4MHZ[/COLOR]
;*************************************************************************************************
; Variable
;*************************************************************************************************
[COLOR="#0000FF"]#define[/COLOR] [COLOR="#FF0000"]input_gpio [/COLOR] GPIO,0 ;from the wind speed
[COLOR="#0000FF"]#define[/COLOR] [COLOR="#FF0000"]output_gpi1[/COLOR] GPIO,1 ;to the LCD
[COLOR="#0000FF"]#define [/COLOR] [COLOR="#FF0000"]output_gpi2 [/COLOR] GPIO,2 ;to the LCD
[COLOR="#0000FF"]#define [/COLOR] [COLOR="#FF0000"] output_gpi3[/COLOR] GPIO,3 ;to the LCD
[COLOR="#0000FF"]ORG [/COLOR] 0x000 ; coding begins here
;************************************************************************
[COLOR="#0000FF"]movlw [/COLOR] b'00001001'
[COLOR="#FF0000"]TRISGPIO [/COLOR] b'1001'
[COLOR="#0000FF"] movlw[/COLOR] 0x41
[COLOR="#0000FF"] movwf [/COLOR] ADCON0
;Variables
cblock 0x09
OldPinState ;used to detect rising edge on tacho input
PulseCount
CycleCount
endc
list p=10F220 ; list directive to define processor
#include <p10F220.inc> ; processor specific variable definitions
__CONFIG _MCLRE_ON & _CP_OFF & _WDT_OFF & _MCPU_OFF & _IOFSCS_4MHZ
;*********************************************************************************
; Variable
;********************************************************************************
cblock 0x09
Signal_IN ;filter input variable
Delay ;variable for the delay
Max_level ;Maximum threshold for output signal
Min_level ;Minimal threshold for output signlal
time
TMP_0
endc
;***********************************************************************************************
ORG 0x000 ; coding begins here
;*******************************************************************************************************
;* initialization microcontroller
;*******************************************************************************************************
movwf OSCCAL ; update register with factory cal value
;************************************************************************
movlw b'00001001' ;sets GP1 and GP2 as Outputs
TRIS GPIO
;ADCON0 0x41
movlw 0x41
movwf ADCON0
The PIC10F series do not have interrupts!Tell him to make the timer isr and timer initialization code.
list p=10F220 ; list directive to define processor
#include <p10F220.inc> ; processor specific variable definitions
__CONFIG _MCLRE_ON & _CP_OFF & _WDT_OFF & _MCPU_OFF & _IOFSCS_4MHZ
;*********************************************************************************
; Variable
;********************************************************************************
cblock 0x09
Delay ;variable for the delay ,to make delays
Counter ;variable to count how many measurements
LCD_data ;hold the data to be sent to the LCD
Counter_data ; hold the counter for the bits as they are sent to the LCD
endc
;***********************************************************************************************
ORG 0x000 ; coding begins here
;*******************************************************************************************************
;* initialization microcontroller
;*******************************************************************************************************
movwf OSCCAL ; update register with factory cal value
;************************************************************************
movlw b'00001001' ;sets GP1 and GP2 as Outputs
TRIS GPIO
;ADCON0 0x41
movlw 0x41
movwf ADCON0
That makes it difficult to store 10 readings and calculate the average with only 6 bytes left for the calculation. It might be possible to do it but for now I suggest calculating the running average by simply adding the new reading to the old one and dividing the result by 2.
The describe method has an exponential effect as the oldest data out of 10 samples contributes only 1/1024th of it's value to the average output.
(((((a+b)/2)+c)/2)+d)/2 etc.
;**********************************************************************
; *
; Filename: speedo.asm *
; Date: December 5, 2010 *
; File Version: 1.00 *
; *
; Author: Brian Kelly *
; Company: *
; *
; *
;**********************************************************************
; *
; Notes: *
; Converts pulse rate representing KPH to MPH. *
; Conversion factor is 1 MPH = 1.60934 KPH *
; 1 KPH = 0.62137 MPH *
; Two modes: with GP1 = 0, converts to MPH, 1 = keep in KPH *
; Two preciions: with GP3 = 0 uses 3/8 division (~2% error) *
; with GP3 = 1 uses 64/103 disvision (~0.05% error) *
; *
;**********************************************************************
list p=10F202 ;list directive to define processor
#include <p10F202.inc> ;processor specific variable definitions
__CONFIG _MCLRE_OFF & _CP_ON & _WDT_OFF
;aliases for GPIO bit numbers
#define Output 0
#define Mode 1
#define TachoIn 2
#define Precision 3
;Variables
cblock 0x10
OldPinState ;used to detect rising edge on tacho input
PulseCount
CycleCount
endc
;**********************************************************************
ORG 0x000 ;code begins here with osc cal in W
initialise
movwf OSCCAL ;update register with factory cal value
movlw 0x0E
tris GPIO ;GPIO.0 is o/p, other pins are inputs
clrf OldPinState ;prepare for use
clrf PulseCount
clrf CycleCount
;if Mode = 1 just copy tacho input to the output (no conversion)
loop
btfss GPIO,Mode ;skip if converting to MPH
goto convert
readTacho
btfss GPIO,TachoIn ;copy the Tacho input directly to Output
goto OutLo
OutHi
bsf GPIO,Output ;Output = 1
goto loop
OutLo
bcf GPIO,Output ;Output = 0
goto loop
;Mode was 0 so convert to MPH. Start by counting rising edges on Tacho input
convert
movf GPIO,w ;read present pin states
andlw 0x04 ;isolate the tacho input signal
xorwf OldPinState,w ;compare with last check
btfsc STATUS,Z ;Z is clear if the input changed
goto loop
movf GPIO,w ;update OldPinState
andlw 0x04
movwf OldPinState
btfss OldPinState,TachoIn ;only update the count if input is now high
goto loop
incf PulseCount,f ;add the new pulse to the count
incf CycleCount,f
;see which division ratio was selected. If Mode = 0 use 3/8, if = 1 use 64/103
btfsc GPIO,Precision ;skip if 3/8 mode
goto HiRes
;LoRes mode, supress pulses 0,3 and 5 in each 8 pulse sequence
;Start by counting pulses modulo 8
movlw 0x08 ;roll PulseCount to zero after 8 pulses
subwf PulseCount,w
btfsc STATUS,Z ;skip if the count wasn't 8
clrf PulseCount ;clear the count
;with only 3 values to check, it's quicker to just compare them
movf PulseCount,w
btfsc STATUS,Z ;skip if not zero
goto loop ;wait for next Tacho pulse
movlw 3
subwf PulseCount,w
btfsc STATUS,Z ;skip if not 3
goto loop ;wait for next Tacho pulse
movlw 5
subwf PulseCount,w
btfsc STATUS,Z ;skip if not 5
goto loop ;wait for next Tacho pulse
goto sendpulse ;send remaining pulses to the output
;HiRes mode, supress every third pulse and 6 others in every 103 pulse sequence
HiRes
movlw .103 ;roll PulseCount to zero after 103 pulses
subwf PulseCount,w
btfsc STATUS,Z ;skip if the count wasn't 103
clrf PulseCount ;clear the count
movlw .3
subwf CycleCount,w ;roll CycleCount to zero after 3 pulses
btfsc STATUS,Z
clrf CycleCount
movlw .24
subwf PulseCount,w ;always drop pulse 24
btfsc STATUS,Z
goto loop
movlw .38
subwf PulseCount,w ;always drop pulse 38
btfsc STATUS,Z
goto loop
movlw .52
subwf PulseCount,w ;always drop pulse 52
btfsc STATUS,Z
goto loop
movlw .64
subwf PulseCount,w ;always drop pulse 64
btfsc STATUS,Z
goto loop
movlw .88
subwf PulseCount,w ;always drop pulse 88
btfsc STATUS,Z
goto loop
movlw .94
subwf PulseCount,w ;always drop pulse 94
btfsc STATUS,Z
goto loop
movlw .102
subwf PulseCount,w ;always drop pulse 102
btfsc STATUS,Z;
goto loop
movf CycleCount,f ;check if Cyclecount is zero
btfsc STATUS,Z ;skip if it isn't
goto loop
goto sendpulse
;send a pulse. make output high, wait for tacho input = 0 then make it low again.
sendpulse
bsf GPIO,Output ;make the output high
waitlow
btfsc GPIO,TachoIn ;copy tacho pulse to the output pin
goto waitlow
bcf GPIO,Output ;make the output low again
goto loop
dt "(C)Brian Kelly 2010."
END ;directive 'end of program'
The complication of average in a small memory situation is understood, this is why I queried if it was acceptable. There is an alternative, the range of output values (the average) is only 0 to 9 so the ADC values can be scaled before summing them. For example, using only the 6 most significant bits and summing four consecutive samples will ensure the total stays within 8-bits. I have not ruled out the possibility of storing more results, maybe as many as 10 as the LCD only needs updating when an average has been calculated. It may still be possible to average a 16-bit total if the RAM is released for the LCD routine afterwards.
My problem at the moment is lack of time, I have deadlines to meet and the current project is the exact opposite of this one. I'm manipulating 2Mb of data using a 16-bit PIC with 64K of internal ROM and it controls 51 IO lines! It's one of those programs full of strange constructs and 'difficult to get your head around' algorithms. I switch to Edaboard to get a rest from the headaches!
Thierry, here is a program I wrote for an EDAboard user a few years ago. I'm not sure if the original thread is still here to see. It uses a PIC10F202 which has even less memory than the 10F220. It converts a tachometer input measuing KPH to MPH by pulse swallowing but the basic construction of the program should help you see how it's done. The code you have written so far is good.
Code:;********************************************************************** ; * ; Filename: speedo.asm * ; Date: December 5, 2010 * ; File Version: 1.00 * ; * ; Author: Brian Kelly * ; Company: * ; * ; * ;********************************************************************** ; * ; Notes: * ; Converts pulse rate representing KPH to MPH. * ; Conversion factor is 1 MPH = 1.60934 KPH * ; 1 KPH = 0.62137 MPH * ; Two modes: with GP1 = 0, converts to MPH, 1 = keep in KPH * ; Two preciions: with GP3 = 0 uses 3/8 division (~2% error) * ; with GP3 = 1 uses 64/103 disvision (~0.05% error) * ; * ;********************************************************************** list p=10F202 ;list directive to define processor #include <p10F202.inc> ;processor specific variable definitions __CONFIG _MCLRE_OFF & _CP_ON & _WDT_OFF ;aliases for GPIO bit numbers #define Output 0 #define Mode 1 #define TachoIn 2 #define Precision 3 ;Variables cblock 0x10 OldPinState ;used to detect rising edge on tacho input PulseCount CycleCount endc ;********************************************************************** ORG 0x000 ;code begins here with osc cal in W initialise movwf OSCCAL ;update register with factory cal value movlw 0x0E tris GPIO ;GPIO.0 is o/p, other pins are inputs clrf OldPinState ;prepare for use clrf PulseCount clrf CycleCount ;if Mode = 1 just copy tacho input to the output (no conversion) loop btfss GPIO,Mode ;skip if converting to MPH goto convert readTacho btfss GPIO,TachoIn ;copy the Tacho input directly to Output goto OutLo OutHi bsf GPIO,Output ;Output = 1 goto loop OutLo bcf GPIO,Output ;Output = 0 goto loop ;Mode was 0 so convert to MPH. Start by counting rising edges on Tacho input convert movf GPIO,w ;read present pin states andlw 0x04 ;isolate the tacho input signal xorwf OldPinState,w ;compare with last check btfsc STATUS,Z ;Z is clear if the input changed goto loop movf GPIO,w ;update OldPinState andlw 0x04 movwf OldPinState btfss OldPinState,TachoIn ;only update the count if input is now high goto loop incf PulseCount,f ;add the new pulse to the count incf CycleCount,f ;see which division ratio was selected. If Mode = 0 use 3/8, if = 1 use 64/103 btfsc GPIO,Precision ;skip if 3/8 mode goto HiRes ;LoRes mode, supress pulses 0,3 and 5 in each 8 pulse sequence ;Start by counting pulses modulo 8 movlw 0x08 ;roll PulseCount to zero after 8 pulses subwf PulseCount,w btfsc STATUS,Z ;skip if the count wasn't 8 clrf PulseCount ;clear the count ;with only 3 values to check, it's quicker to just compare them movf PulseCount,w btfsc STATUS,Z ;skip if not zero goto loop ;wait for next Tacho pulse movlw 3 subwf PulseCount,w btfsc STATUS,Z ;skip if not 3 goto loop ;wait for next Tacho pulse movlw 5 subwf PulseCount,w btfsc STATUS,Z ;skip if not 5 goto loop ;wait for next Tacho pulse goto sendpulse ;send remaining pulses to the output ;HiRes mode, supress every third pulse and 6 others in every 103 pulse sequence HiRes movlw .103 ;roll PulseCount to zero after 103 pulses subwf PulseCount,w btfsc STATUS,Z ;skip if the count wasn't 103 clrf PulseCount ;clear the count movlw .3 subwf CycleCount,w ;roll CycleCount to zero after 3 pulses btfsc STATUS,Z clrf CycleCount movlw .24 subwf PulseCount,w ;always drop pulse 24 btfsc STATUS,Z goto loop movlw .38 subwf PulseCount,w ;always drop pulse 38 btfsc STATUS,Z goto loop movlw .52 subwf PulseCount,w ;always drop pulse 52 btfsc STATUS,Z goto loop movlw .64 subwf PulseCount,w ;always drop pulse 64 btfsc STATUS,Z goto loop movlw .88 subwf PulseCount,w ;always drop pulse 88 btfsc STATUS,Z goto loop movlw .94 subwf PulseCount,w ;always drop pulse 94 btfsc STATUS,Z goto loop movlw .102 subwf PulseCount,w ;always drop pulse 102 btfsc STATUS,Z; goto loop movf CycleCount,f ;check if Cyclecount is zero btfsc STATUS,Z ;skip if it isn't goto loop goto sendpulse ;send a pulse. make output high, wait for tacho input = 0 then make it low again. sendpulse bsf GPIO,Output ;make the output high waitlow btfsc GPIO,TachoIn ;copy tacho pulse to the output pin goto waitlow bcf GPIO,Output ;make the output low again goto loop dt "(C)Brian Kelly 2010." END ;directive 'end of program'
I kinda looked I found an exponential moving average method is it good?
Ma = (α X sample)+((1 - α) x Ma(t-1))
α =2/(sample+1)
Ma = exponential moving average
α = Smoothing coefficient
Sample = Value read by the ADC Microcontroller
Ma(t-1) =exponential moving average previous
I'm sure it is but you only have 16 bytes of memory to use for the whole program and all the memory is 8-bits wide so it can only hold values between 0 and 255. To do the multiplication alone would probably need more than 16 bytes so it simply can't be done in such small memory. I'm off to a meeting but will be back later to explain how to create the time delays between samples.
Brian.
BCF LED ; the LED is turned off
;**********************************************************************
;*************initialize filter*********************************
;**********************************************************************
movlw 0x00
movwf LCD_data
movlw 0x00
movwf Counter_data
;**********************************************************************
;*************Initialisation counter****************************
;**********************************************************************
movlw 0x00
movwf Counter
movlw 0x00
movwf Delay
;**********************************************************************
;* ******************* Main program********************
;**********************************************************************
movlw 0x00
movwf LCD_data
movwf Counter_data
;**********************************************************************
;*************Initialisation counter****************************
;**********************************************************************
movwf Counter
movwf Delay
clrf LCD_Data
clrf Counter_data
clrf Counter
clrf Delay
movlw 0x55 ;put value 0x55 in W
movwf register1
movwf register2
movwf register3
movlw 0xC7
option
Wait
movf TMR0,f ;set Z in STATUS if TMR0 = 0
btfss STATUS,Z ;bit test the Z bit, skip if set (= Zero)
goto Wait ;not zero yet so keep checking
decfsz Delay,f ;subtract 1 from Delay and see if zero
goto Wait ;not reached zero yet so keep checking
;'Delay' has reached zero so ~1 second has elapsed
movlw .15 ;reload 'Delay' again
movwf Delay
; code to read the ADC comes next
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?