Continue to Site

# PIC10F220 RC filter first order by numerical simulation in the microcontroller

Status
Not open for further replies.

#### betwixt

##### Super Moderator
Staff member
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.

#### thierryneuch

##### Member level 2
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'

- - - Updated - - -

so
;*******************************************************************************************************
;* Initialisation du microcontrôleur
;*******************************************************************************************************
movwf OSCCAL ; update register with factory cal value

movlw B'01000000'

movwf OSCCAL ; update register with factory cal value

movlw B'01000000'
tris GPIO

#### betwixt

##### Super Moderator
Staff member

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

'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.

#### thierryneuch

##### Member level 2

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

'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.

Code:
	[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

is it correct like this or I made mistakes or forget something

Last edited by a moderator:

#### betwixt

##### Super Moderator
Staff member
Almost correct, you don't need the "TRISGPIO b'1001'" line, use "tris GPIO" instead, it will use the value in W which you loaded in the previous line. You also removed the OSCCAL line, I suggest you put it back in although it won't stop the program running.

The #define lines are not really necessary but you can use them if you wish. All the #define does is create an alias (alternate text) to make the program easier to read. For example if you typed ' bcf output_gpi1' the assembler would read it as 'bcf GPIO,1' . Sometimes, especially in large programs it is easier to give a descriptive name to a pin than keep remembering it's number, for example the line 'bcf alarm_bell' would tell you what it did but 'bcf GPIO,2' would not. There are other tricks you can do with defines but you need not worry about them yet. Incidentally, GPIO3 can not be used as an output.

One point, when you post code on Edaboard, paste it from MPLAB then highlight it and click the '#' icon above the message window. It tells the forum not to change the text formatting so it appears exactly as in MPLABX. You should see the word CODE inside brackets before and after the part you pasted. Without it, the forum aligns all text to the left side so we can't see if you indented it properly.

The next thing to do is decide which variables you will need. All variables are 8-bits wide and there is a limit of 16 of them on that PIC. 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. See if you can work out what variables you will need and give them descriptive names. To add them to the program use the assembler directive 'cblock' followed by the start address of variable storage. In that PIC the variables are stored in 'General Purpose Registers' which start immediately above the ones used by the PIC's own hardware. So start the block with 'cblock 0x09'. It ends with 'endc' and you list the variables one per line between them.

This is an example from a program I wrote:
Code:
;Variables
cblock    0x09
OldPinState                            ;used to detect rising edge on tacho input
PulseCount
CycleCount
endc

It assigns storage for variable 'OldPinState' at address 0x09, PulseCount at 0x0A and CycleCount at 0x0B. 'cblock' builds a storage area so you do not have to tell it the address for each variable individually. Note I used the # to post the code!

Brian.

#### thierryneuch

##### Member level 2
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
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
movlw           0x41
movwf           ADCON0

#### milan.rajik

##### Banned
@Brian

Tell him to make the timer isr and timer initialization code.

Last edited:

#### thierryneuch

##### Member level 2
I do not know exactly all the variable that will be used

#### milan.rajik

##### Banned
If you see my code then you will have an idea of how many variables you will be needing. Use one variable as flags variables and each bit of the variable can be used as a flag.

#### betwixt

##### Super Moderator
Staff member
Tell him to make the timer isr and timer initialization code.
The PIC10F series do not have interrupts!

You will at least need these:
a variable to hold the previous measurement (so you can add the new one to it to find their average)
a variable to count how many measurements have been taken so you know when to update the LCD
a variable to hold the data to be sent to the LCD
a variable to hold the counter for the bits as they are sent to the LCD (they will be sent serial so you need to know how many bits have been sent)
at least one variable to make delays. I will explain how to use the timer and prescaler later.

It's late at night here and I still have other work to finish so I will add more tomorrow.

Brian.

#### thierryneuch

##### Member level 2
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
movlw           0x41
movwf           ADCON0

##### Super Moderator
Staff member
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.

Brian, I just had to interject that what you are describing isn't a moving average. The description didn't make sense to me so I tried computing both a moving average (see this) and the describe method in excell. 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.

#### paulfjujo

##### Advanced Member level 4
hello,

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.

Can you post an example (in asm) of this algorithm use
and quantify what could be the exact amount of bytes used to do that ?
because somme add of 2 bytes, will need an integer size for storing intermediate results.
and the goal is to do this application with 16 bytes RAM only.
it's a big challenge..

#### betwixt

##### Super Moderator
Staff member
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
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'

#### thierryneuch

##### Member level 2
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
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'

waouh I tried to read many times, but I do not understand

but what's next I have to do?
we already initialized to the microcontroller, declare variable, what do we do after his ?

I understand better with gradually proceed

#### thierryneuch

##### Member level 2
Code:
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

#### betwixt

##### Super Moderator
Staff member
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.

#### thierryneuch

##### Member level 2
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.

I started the variable to initialize it is good??

Code:
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********************
;**********************************************************************

#### milan.rajik

##### Banned
Code can be replaced by

Code:
movlw      0x00
movwf      LCD_data

movwf     Counter_data

;**********************************************************************
;*************Initialisation counter****************************
;**********************************************************************

movwf      Counter

movwf      Delay

You can also use

Code:
clrf LCD_Data
clrf Counter_data
clrf Counter
clrf Delay

https://www.mikroe.com/chapters/view/10/chapter-9-instruction-set/

Last edited:

#### betwixt

##### Super Moderator
Staff member
Sorry for the delay returning you message, I have many other duties here!

In general, when you want to set the value of a variable to zero you can use the 'clrf' instruction "CLeaR File" followed by the name of the variable. It can be done by setting W to zero (there is a special instruction 'clrw' for doing that) and copying it to the register instead. There is an important difference in the two methods which is not critical in your code yet but is worthwhile noting: the bits (announcement flags) in the STATUS register are set differently with the two methods. In particular the Z (zero) bit is set when the clrf instruction is used but is not changed from it's previous state by the 'movwf' instruction. In fact, the 'movwf' instruction never changes anything in the status register and that is very important as you will see later.

If you want to set several registers to any value other than zero, your method of loading the value in to W with 'movlw' is correct but W is copied by 'movwf' and the value is not lost so you could use for example:
Code:
movlw 0x55 ;put value 0x55 in W
movwf register1
movwf register2
movwf register3
which would put 0x55 in register1, register2 and register3 and it would still be in W too.

Back to your program. You will be taking several readings to derive the average but you need to space them apart in time. To take a measurement in the PIC10F220 takes only 0.000013 seconds! Taking all the readings one after another would be pointless so you need some method of inserting a delay between them. The PIC has a timer built in for this purpose called TMR0 (TiMeR 0), bigger PICs also have TMR1, TMR2 and so on but there is only TMR0 in the 10F220. Take a look in the data sheet at 'Figure 6-1' which shows how it can be configured. It is possible to use TMR0 to count external signals but for your application we want it to count internal clock cycles so it can be used to create a fixed delay. Follow the diagram and you will see how it's done, all the bits are in the OPTION register:

T0SE lets you count either rising edges or falling edges of an external signal but we are not using that so just set it to 0
T0CS decides whether it counts internal or external signals, we want internal so set it to 0
PS2,PS1,PS0 are PreScaler bits, it's a divider to allow a smaller number of signal pulses reach the counter, we want it to be as slow as possible so use 111
PSA decides whether the signal is used directly or from the prescaler. Set it to 0 so it counts the prescaler output.

So the OPTION register should be set to 11000111 = 0xC7. Load it with:
Code:
movlw 0xC7
option

At this point the timer should be happily counting away to itself!
TMR0 counts upwards until it reaches 11111111 = 0xFF = 255 then rolls over to zero and start counting up again. Unfortunately, in the 10F series PICs thereis no way of telling it's value without reading it. Bigger PICs have a special 'zero' notification method for the timers which makes programming easier. For your program we will create the delay by counting the 'roll over to zero' several times in software. On it's own, the roll over happens once every 256 counts and the counts are taken from the 1MHz inctruction clock divided by the prescaler which we set to 256 with the PSx bits earlier. So TMR0 counts 1,000,000/256 times a second = 3,906 and rolls over 3906/256 times a second = 15. That's still too fast, there is no point in measuring the wind speed 15 times a second! Measuring once per second would be much better so between each measurment you need to count 15 TMR0 roll-overs. This is why I suggested the 'Delay' variable should be assigned, you will use it like another prescaler to slow the time down but in software instead of hardware. Remember that TMR0 counts all the time by itself. This is where I introduce the 'Label' and conditional jump instructions. You could start by setting 'Delay' to zero and counting up to 15 but that would mean doing the math to see if the value had reached 15, there is an easier way in PIC language if you count DOWN instead of up.
The special instruction is 'decfsz' (DECrement File and Skip if Zero), it subrtacts one from the number in the file you name, then one of two things happen, if the result is NOT zero it carries on to the next instruction, if it IS zero if jumps over the next instruction and carries on from there. It lets you put a jump instruction immediately after it which would divert the program flow but 'skip' it if the result is zero. It's a clever way of putting a decision in a program because it uses few instructions than a normal 'if...' construct was used. Decfsz has another clever feature, you follow the register being decremented with a comma then either 'f' or 'w', this puts the new value of the file back in the file itself (,f) or in the W register (,w) so if necessary it can save another instruction as well.

This is the code to try:
Code:
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
I have deliberately left a serious bug in that code - see if you can see what it is. (Clue: it isn't the instructions, it's the way they are used)

Brian.

Status
Not open for further replies.