Continue to Site

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

Status
Not open for further replies.

#### thierryneuch

##### Member level 2
the bug is on (movlw .15) --->movlw D'15'

Code:
;**********************************************************************
;*  ********************Programme pricnipal********************
;**********************************************************************
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
movwf Delay                       ; code to read the ADC comes next

- - - Updated - - -

the bug is on (movlw .15) --->movlw D'15'

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

movwf Delay
; code to read the ADC comes nextdecfsz 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 D'15'

- - - Updated - - -

Code:
;**********************************************************************
;*  ********************Programme pricnipal********************
;**********************************************************************
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
movwf Delay
; code to read the ADC comes next

Last edited by a moderator:

#### thierryneuch

##### Member level 2
I thing that first step about communication for LCD we must the Pin declare and variable initializes
Code:
;**********************************************************************
;*  ********************Variable declare                       ********************
;**********************************************************************
D1            EQU        0X20
D2            EQU        0X21
D3            EQU        0X22
D4            EQU        0X23
D5            EQU        0X24
D6            EQU        0X25

That Right ?

#### betwixt

##### Super Moderator
Staff member
No!
MPLABX allows 'D' or '.' before a number to indicate it is decimal. The bug is trickier than that and there is nothing wrong with the instructions I gave you.
The problem is this:

I already mentioned the ADC only takes 0.00013 seconds to take a reading so if you use the one second delay, read the ADC, store the result and then wait for another second before repeating, the delay will fail. The reason is TMR0 is counting relatively slowly so when you return to the routine it will not have had time for the count to increase, it will still be zero. That will make it drop through to the 'decfsz' line stright away instead of waiting for TMR0 to complete another loop. The fix is easy, we need to add new lines to ensure TMR0 is not zero before using the 'Wait' routine.
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

; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.

;***** VARIABLE DEFINITIONS
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
movwf   OSCCAL         ; update register with factory cal value

start
clrf LCD_data
clrf Counter_data
clrf Counter
clrf Delay

; remaining code goes here

Wait
movwf Delay
movlw 1			;give TMR0 a start value
movwf TMR0
Wait1
movf TMR0,f		;set Z in STATUS if TMR0 = 0
btfss STATUS,Z		;bit test the Z bit, skip if set (= Zero)
goto Wait1			;not zero yet so keep checking

decfsz Delay,f		;subtract 1 from Delay and see if zero
goto Wait1			;not reached zero yet so keep checking
return

I have done several things:
1. loaded TMR0 with a starting value of 1 at the beginning of the routine
2. moved the lines so 'Delay' is set before it is used
3. added another label 'Wait1' and changed the calls to it so the loop runs after Delay and TMR0 have been initialized
4. added a 'return' instruction at the end.

The return instruction makes it a 'universal' delay sub-routine that can be used anywhere in the program with the instruction 'call Wait'. The subroutine will return when about 1 second has elapsed. There is something to be aware of in the PIC10 processors - each subroutine 'call' requires it to store the address it goes back to after the 'return' instruction and these simple processors only have capacity to store TWO addresses. We call it a two deep stack, it limits you to making one 'call' while already in a subroutine. It saves the return address of the first subroutine, then the address of a second subroutine. Any further calls will overwrite the first address and almost certainly crash the program. Be careful with nested subroutines!

Lets write a new routine to read the voltage using the ADC (Analog to Digital Converter). You already know the code to configure ADCON0 and OPTION so you can add those lines to "remaining code goes here" in the program. The ADC is a circuit built in the silicon of the PIC, you route a voltage from one of the pins using ADCON0, tell it to start measuring it and it completes with a numeric version of the voltage. It doesn't tell you what the voltage actually is, it returns an 8-bit number between 0 for 0V and 255 for maximum voltage. In this PIC the maximum voltage is the VDD (positive supply line) voltage. For example, if you use a 5V supply and gradually increase the voltage on GP0, the ADC result would go up from zero to 255.

The ADC module needs to be told when to start a measurment, in some applications you have to synchronize it to some event but here I assume the wind speed voltage is always present so it can be measured at any time. To start the ADC, all you do is make the GO/-DONE bit in ADCON0 equal '1'. It stays at '1' until the ADC has finished measuring the voltage, it's a fast process, when finished it makes GO/-DONE zero again by itself and the value it measured is present in the ADRES (Analog to Digital RESult) register.

So the process is:
1. make sure the input pin is configured for analog use
2. select that pin as the input to the ADC
3. set the GO/-DONE bit in ADCON0

I propose this code, note the use of the 'bsf' (Bit Set in File) instruction and how I use the names of the register and bit instead of their numbers. There is an equivalent 'bcf' (Bit Clear in File) instruction to make a bit zero.
Code:
; read the voltage on the analog input pin, return result in W
bsf ADCON0,GO_NOT_DONE	;start measuring the voltage
btfsc ADCON0,GO_NOT_DONE ;skip next instruction if GO/-DONE is zero
movf ADRES,W		;copy the result to W
return
See if you can understand it. I made it a subroutine again. If you add it and assemble the code you will have reached the stage where the PIC is initialized, has a delay routine and can measure voltages - all in less than 20 bytes of code!

Brian.

#### thierryneuch

##### Member level 2
SO

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

;***************************************************************************
; *******************microcontroller initialization***************************************
;***************************************************************************

movlw			b'00001001' 	;sets GP1 and GP2 as Outputs
TRIS			GPIO
movlw           0x41

movlw 0xC7
option
;****************************************************************************
;***** VARIABLE DEFINITIONS**************************************************
;****************************************************************************
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
;**********************************************************************
;******************* coding begins*************************************
;**********************************************************************
ORG     0x000             ; coding begins here
movwf   OSCCAL         ; update register with factory cal value

start
clrf LCD_data
clrf Counter_data
clrf Counter
clrf Delay

;***********************************************************************
;                       remaining code goes here
;***********************************************************************
Wait
movwf Delay
movlw 1			;give TMR0 a start value
movwf TMR0
Wait1
movf TMR0,f		;set Z in STATUS if TMR0 = 0
btfss STATUS,Z		;bit test the Z bit, skip if set (= Zero)
goto Wait1			;not zero yet so keep checking

decfsz Delay,f		;subtract 1 from Delay and see if zero
goto Wait1			;not reached zero yet so keep checking
return
;********************************************************************
;********************************************************************

bsf ADCON0,GO_NOT_DONE	;start measuring the voltage
btfsc ADCON0,GO_NOT_DONE ;skip next instruction if GO/-DONE is zero
movf ADRES,W		;copy the result to W
return

- - - Updated - - -

after reading the voltage on the analog input pin, I suppose we must now coding thé filter

#### paulfjujo

hello,

I don't have a PIC10F220 , even no ISIS simultaor,
but i did some test , with mikroC, wich can accept asm code inside C langage
and i wrote this.. for averaging up to 256 measures wich give result in Beaufort range 0 to 9.
you can use this ,because it is quiet standard asm PIC (even i used a 18F2550 at 48MHz!)

to get the Beaufort value and 1seconde timer .. use of 7 bytes of RAM
i tested it under mikroC environment..
maybe some instruction can differe a litle bit .. like Right Rotation trough Carry (RRC)
but easy to adapt with 10F220 data sheet instructions list.

with integer value, and 8 bits only, it is not evident to get a very linear correspondance
with binary and decimal (step 0 to 9)
so some artifices are added to keep 0 value and add the 9th step
without using integer 16 bits and more RAM...

#### betwixt

##### Super Moderator
Staff member
That is an interestng method. You accumulate 256 measurements and count the number of times the overflow flag is set then divide the result by 32 to scale the result to lie between 0 and 9. If it's > 8 you make it -1 then add 1 to the result. I will have to look into that deeper but it might be a good solution.

Thierry, please do not use this code on the PIC10F220, it uses instructions that PIC will not understand but if the method is viable I can convert it so it will run on that processor.

Brian.

#### thierryneuch

##### Member level 2
OK i not use the code

#### thierryneuch

##### Member level 2
:thinker::thinker: the time with me is already scarce with this topic ,I have read everything Possible but I find no solutions

#### thierryneuch

##### Member level 2
Is there a possibility or a simple way to modify or change the Paulfjujo’s code so that its compatible with my microcontroller? I find no solutions:bang:

#### betwixt

##### Super Moderator
Staff member
The 10F220 only has 33 instructions so it isn't difficult to learn! Take a close look at all the instruction details in chapter 9 of the data sheet.

I have been working away unexpectedly so I have not had much time to help you but here is code I have written and simulated, it works so far but I have not added the LCD routine yet.
Code:
;***** VARIABLE DEFINITIONS
cblock    0x10

Delay			;variable for the delay ,to make delays
Counter			;count the number of measurements
Average			;average value of the measurements
Temporary		;use for holding partial results in calculations
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
movwf   OSCCAL            ; update register with factory cal value

start
clrf LCD_data
clrf Counter_data
clrf Counter
clrf Delay

movlw			b'00001001' 	;sets GP1 and GP2 as Outputs
TRIS			GPIO
movlw           0x41
movlw			0xC7
option

MainLoop
movlw 4
movwf Counter
clrf Total
SumLoop
call Wait			;one second delay
movwf Temporary		;store the result
bcf STATUS,C		;must not shift carry bit into result
rrf	Temporary,f		;divide result by 2
bcf STATUS,C		;must not shift carry bit into result
rrf Temporary,w		;divide by 2 with result in W
decfsz Counter,f	;see if 4 measurements have been averaged
goto SumLoop	;no - so repeat until all 4 taken
;Total = the sum of 4 readings taken at 1 second intervals

call LCDUpdate		;update the display
goto MainLoop

; remaining code goes here

Wait
movwf Delay
movlw 1				;give TMR0 a start value
movwf TMR0
Wait1
movf TMR0,w			;set Z in STATUS if TMR0 = 0
btfss STATUS,Z		;bit test the Z bit, skip if set (= Zero)
goto Wait1			;not zero yet so keep checking
Wait2
movf TMR0,w			;set Z in STATUS if TMR0 = 0
btfsc STATUS,Z		;wait for TMR0 to be NOT zero
goto Wait2
decfsz Delay,f		;subtract 1 from Delay and see if zero
goto Wait1			;not reached zero yet so keep checking
return

bsf ADCON0,GO_NOT_DONE	;start measuring the voltage
btfsc ADCON0,GO_NOT_DONE ;skip next instruction if GO/-DONE is zero
movf ADRES,W		;copy the result to W
return

; show the scaled result on the LCD
LCDUpdate

END                       ; directive 'end of program'

I did not use Paulfjujo's code although with some simple changes it would work. His code adds 256 ADC readings together then divides the result to make it fall in the 0 to 9 range. I decided to divide the individual results first then add them together. The mathematical result is the same but my method may be more adaptable because it does not constrain you to taking 256 measurements every time.

Put my code in MPLABX and see if you can add a 'watch' window to see the contents of the registers. If you run it or single step it you can see exactly what each instruction does and how it changes the values in the registers. See if you can work out the exact time the 'Wait' routine takes, it isn't exactly 1 second but very close, with MPLABX you can add a breakpoint at the start and end of the Wait routine and use the stopwatch to see the exact time taken between them.

Brian.

#### thierryneuch

##### Member level 2
hello
Somebody can tell me please how I can set the LCD-SPI software, since I try to display data on LCD, but I cannot do it, it does not work

#### betwixt

##### Super Moderator
Staff member
Hint: before the LCD will display anything you have to initialize it.

Remember making a pin = 1 in C is the same as using 'bsf' in assembler and making a pin = 0 is the same as 'bcf'.
You have examples already of how to create loops.

Brian.

#### milan.rajik

##### Banned
I am attaching a code. It doesn't compile. There are few errors. They have to be fixed. Maybe betwixt can fix the errors and make it work. I am not an experienced ASM programmer. I have tried to port the 2 Wire LCD C code to ASM code for PIC10F220. I was not successful.

#### Attachments

• 2 Wire LCD ASM PIC10F220.rar
11.3 KB · Views: 19

#### thierryneuch

##### Member level 2
His is what I try to do for the LCD is it correct? and I do not understand the difference between LCD and LCD-SPI, How to code a LCD-SPI?

Code:
; LCD TRIS
Ban1                          ;lcd RW leg is grounded, so we'll only write data to the lcd, and never read.

movlw b'11000000'
movwf tris_lcd    ;all output ports

LCD_int

;use both lines of the display
movlw b'00000010' ;mode 4 bits
movwf port_lcd
call e_pulse
movlw b'00000010' ;mode 4 bits
movwf port_lcd
call e_pulse

;allow display and hide the cursor

movlw b'00001000' ;mode 4 bits
movwf port_lcd
call e_pulse
call busy

;Entry Mode Set

movlw b'00000000'
movwf port_lcd
call e_pulse
movlw b'00000110'
movwf port_lcd
call e_pulse
call busy

;---------------------------------------------------------------------------
;                     50 us
;---------------------------------------------------------------------------

busy ; 50us
movlw 6
movwf temp_busy

attd_boucle
nop
nop
nop
decfsz temp_busy,F
goto attd_boucle
return

#### milan.rajik

##### Banned
In your project you are using only 2 wires to connect to LCD. It is not actually SPI. SPI needs 3 wires. In your project 74HC595 which is a shift register is used. See the asm code I have posted. Most of that code is correct. Only some errors related to asm usage doesn't allow it to compile. Maybe betwixt can fix it or he can give you better code.

Use this tool to create delay codes.

#### thierryneuch

##### Member level 2
His is what I try to do for the LCD is it correct? and I do not understand the difference between LCD and LCD-SPI, How to code a LCD-SPI?

Code:
; LCD TRIS
Ban1                          ;lcd RW leg is grounded, so we'll only write data to the lcd, and never read.

movlw b'11000000'
movwf tris_lcd    ;all output ports

LCD_int

;use both lines of the display
movlw b'00000010' ;mode 4 bits
movwf port_lcd
call e_pulse
movlw b'00000010' ;mode 4 bits
movwf port_lcd
call e_pulse

;allow display and hide the cursor

movlw b'00001000' ;mode 4 bits
movwf port_lcd
call e_pulse
call busy

;Entry Mode Set

movlw b'00000000'
movwf port_lcd
call e_pulse
movlw b'00000110'
movwf port_lcd
call e_pulse
call busy

;---------------------------------------------------------------------------
;                     50 us
;---------------------------------------------------------------------------

busy ; 50us
movlw 6
movwf temp_busy

attd_boucle
nop
nop
nop
decfsz temp_busy,F
goto attd_boucle
return

betwixt is that correct?

#### milan.rajik

##### Banned
The code you have posted is for parallel interface of LCD. In your project you can't use parallel interface. You are using serial interface with 74HC595. The LCD in 2 wire serial interface works in 4 bit mode. You have to send data to LCD serially and also the control signals.

#### thierryneuch

##### Member level 2
paulfjujo made this code but it is in C and Since yesterday I try to transform its assembly language but I Boque serious !! It's like magic I don't understand

#### Attachments

• SerialLcdTest.zip
7 KB · Views: 12

#### FvM

##### Super Moderator
Staff member
His is what I try to do for the LCD is it correct? and I do not understand the difference between LCD and LCD-SPI, How to code a LCD-SPI?

In your project you are using only 2 wires to connect to LCD.

I reviewed the thread and don't see any schematic posted by thierryneuch himself. All interface circuits have been suggested by others. How do you know which circuit he's presently using?

Before the thread is descending into chaos, the matter of debate should be clarified.

#### betwixt

##### Super Moderator
Staff member
Unforunately the code in post #73 is for PIC18F series processors which are significantly different to the PIC10 being used. The code will not translate easily.
Thierry, you need to understand the principles of driving an LCD before going further. I will again try to explain:

The LCD module typically has 16 pins which connect to an internal processor, generically called HD44780.

There are two pins for the backlight LED which we can ignore.
There are 8 data pins, these are the pins used to carry information for configuation and what characters to display.
There are three control pins:
'E' is the Enable pin, it turns the LCD on to receive data/commands when low and tells it to action the data/commands when taken high.
R/-W is the Read/Write pin, when low, the HD44780 accepts data/commands, when high the internal status of the HD44780 can be read back.
RS is the register select pin, when low it directs information on the data pins to the configuration registers, when high the information is to be displayed.
The other pins are for the supply voltage and contrast setting voltage.

'Data' is the numeric code for the character to print, 'Commands' are for things like telling it how many lines to display, positioning the cursor, making it flash and so on.

They can be used in two different ways called '8-bit mode' and '4-bit mode'. From the viewers perspective, there is no difference but electrically, the lower 4 bits of the data bus are ignored and the 8-bit data the LCD needs is sent as two halves on the upper data pins. So instead of bits 7-0 being sent in one step, bits 7-4 are sent first then bits 3-0 are sent second. This is done to save connections to the LCD, it's a little slower but normally not noticed.

The problem in your application is you need to send all those LCD bits but there are only two pins on the PIC to do it. There is a way to send any amount of bits using only two wires, it is called 'serial', meaning 'one after another'. You need another device in the circuit to read the bits as they arrive one-by-one and convert them back to parallel (all present at once). The method is to use one pin as the 'clock' and the other to carry the 'Data'. You make the data pin high if the bit is '1' and low if it is '0' so the pin holds the state of the first bit in the number you are sending. Then you change the state of the clock pin, then you change the clock back again. The serial to parallel converter sees the change in clock state and moves the data bit into a 'shift register'. This process is repeated 8 times, once for each of the data bits. The shift register then holds all the 8 bits it has collected and they can be read out in parallel on 8 pins. There is a complication though! How does the shift register know which bit is which? Although it has received 8 clock pulses and shifted 8 bits in to itself, it may have started on bit 5 of one lot of data and finished on bit 4 of the next, there is nothing to tell it where each block of bits starts from. This is what the third signal on an SPI bus does, when low it alerts the SPI device that a transfer is about to start and when it goes high again, it tells the device that all the bits have been sent and it is safe to use them.

Your PIC does not have enough pins to produce that third signal so you can not use SPI. 'Clock' and 'Data' are already using the only pins you have. So a slightly different trick is used, it is not SPI but similar. You can ignore the LCD signal called R/-W because you are never going to read the HD44780 status, just trust it is correct, that reduces the number of signals to the LCD to six, D7, D6, D5, D4, RS and E. The spare bits can be used to reset the shift register, they become 'markers' to show where the data starts and stops.

Brian.

Status
Not open for further replies.