Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PIC10F220 RC filter first order by numerical simulation in the microcontroller

Status
Not open for further replies.

betwixt

Super Moderator
Staff member
Joined
Jul 4, 2009
Messages
15,729
Helped
5,068
Reputation
10,161
Reaction score
4,924
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
133,205
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
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
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
Joined
Jul 4, 2009
Messages
15,729
Helped
5,068
Reputation
10,161
Reaction score
4,924
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
133,205
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.
 

thierryneuch

Member level 2
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
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.





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
Joined
Jul 4, 2009
Messages
15,729
Helped
5,068
Reputation
10,161
Reaction score
4,924
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
133,205
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
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
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      
    ;ADCON0		    0x41
    movlw           0x41
    movwf           ADCON0
 

milan.rajik

Banned
Joined
Apr 1, 2013
Messages
2,524
Helped
540
Reputation
1,078
Reaction score
524
Trophy points
1,393
Activity points
0
@Brian

Tell him to make the timer isr and timer initialization code.
 
Last edited:

thierryneuch

Member level 2
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
I do not know exactly all the variable that will be used
 

milan.rajik

Banned
Joined
Apr 1, 2013
Messages
2,524
Helped
540
Reputation
1,078
Reaction score
524
Trophy points
1,393
Activity points
0
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
Joined
Jul 4, 2009
Messages
15,729
Helped
5,068
Reputation
10,161
Reaction score
4,924
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
133,205
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
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
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
 

ads-ee

Super Moderator
Staff member
Joined
Sep 10, 2013
Messages
7,935
Helped
1,822
Reputation
3,654
Reaction score
1,806
Trophy points
1,393
Location
USA
Activity points
60,130
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
Joined
Jun 9, 2008
Messages
1,459
Helped
296
Reputation
592
Reaction score
279
Trophy points
1,363
Location
France 01800
Activity points
10,409
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
Joined
Jul 4, 2009
Messages
15,729
Helped
5,068
Reputation
10,161
Reaction score
4,924
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
133,205
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'
 

thierryneuch

Member level 2
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
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'



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
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
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
Joined
Jul 4, 2009
Messages
15,729
Helped
5,068
Reputation
10,161
Reaction score
4,924
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
133,205
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
Joined
Jun 7, 2015
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
313
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
Joined
Apr 1, 2013
Messages
2,524
Helped
540
Reputation
1,078
Reaction score
524
Trophy points
1,393
Activity points
0
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/

**broken link removed**
 
Last edited:

betwixt

Super Moderator
Staff member
Joined
Jul 4, 2009
Messages
15,729
Helped
5,068
Reputation
10,161
Reaction score
4,924
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
133,205
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.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Top