Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Tough assembly program for the PIC16F84

Status
Not open for further replies.
I have a question about the rlf, that is a rotate left shift correct?

It is "Rotate Left f through Carry". It's in the PIC16F84 datasheet.

Wouldn't that be different than a regular left shift which I need to perform?

I don't know where you're coming from but in the PIC16F84 instruction set, RLF is the only "regular left shift" instruction. My advice is to try to understand what RLF exactly does and code accordingly. Don't get hung up on another processor's instruction set.

Anyway, I normally group the code in bunches so that is best undestood within that context. I also separate the groups by the comment character ';'. It is the same character that terminates a line of code in C.

The code group:

Code:
    bcf    status,C 
    rlf    entered_pass_code,f  
    bcf    status,C 
    rlf    entered_pass_code,f 
;

can also be coded as follows with the same result:

Code:
    rlf    entered_pass_code,f  
    rlf    entered_pass_code,f 
    movlw  b'11111100'
    andwf  entered_pass_code,f 
;
 
I'm not sure I'm understanding what you're saying. The interrupt service I have will detect the key pressed and wake the PIC from sleep mode.

Sorry. I may have mistook INTE for T0IE in the same register.

In that case, my other advice is to be careful with switch bounce. Using interrupts to process key presses, you will definitely have to deal with them. The only reason I see for using interrupts to process keypresses is to save on power by putting the PIC to sleep.

You can insert a 20-50msec delay in the interrupt service before clearing INTF. This will cause additional transistions in RB0 caused by switch bounce to be ignored during the delay.
 
I have a couple questions about some of your code.

Why do you check to see if the password is the supervisor in the update_pass_code subroutine? If you look at my original code under 'endless_loop' I first check to see if the 'Enter' key was pressed and if it is I jump to 'compare_pass_code' and if only a number was pressed I goto 'update_pass_code.' Only when a number is pressed as the last key will it update the code and when enter is pressed it will compare and see if its supervisor mode and if it is the next passcode will be added to the passcode list.

Also, why does status,Z determine if supervisor mode is set?

Code:
update_pass_code:
    movf   supervisor_mode,w
    btfsc  status.Z               ; Check if supervisor mode
    goto   change_user_passcode 
 
    bcf    status,C
    rlf    entered_pass_code,f  
    bcf    status,C
    rlf    entered_pass_code,f
;
    movlw  b'00000011'
    andwf  last_key_press,w       ; mask out upper bits
    addwf  entered_pass_code,f    ; add to entered pass code
;
    return
change_user_passcode:
    movf   num_pass_codes,w
    andlw  b'00001111'
    addlw  passcodes
    movwf  fsr
;
    movf   entered_pass_code,w
    movwf  indf
;
    incf   num_pass_codes,f
    clrf   supervisor_mode
;
    return

compare_pass_code:
    movlw  supervisor_code
    xorwf  entered_pass_code,w  ; compare to supervisor code
    movlw  0 
    btfsc  status,Z
    movlw  1
    movwf  supervisor_mode 
;
; additonal code here to compare with user pass codes
;       
    return
 
A couple more questions....sorry for asking so much...

What does the following do? What does the anding of 00000011 with 'last_key_press' accomplish?
Code:
    movlw  b'00000011'
    andwf  last_key_press,w       ; mask out upper bits
    addwf  entered_pass_code,f    ; add to entered pass code
;
    return

And what does this subroutine do? Again, I'm not understanding the 00001111 part. Also, what does 'passcodes' do?

motion said:
Code:
change_user_passcode:
    movf   num_pass_codes,w
    andlw  b'00001111'
    addlw  passcodes
    movwf  fsr
;
    movf   entered_pass_code,w
    movwf  indf
;
    incf   num_pass_codes,f
    clrf   supervisor_mode
;
    return

For the last part, why are you using the xorwf to compare the entered passcode to the supervisor? Can't you just subtract the two (subwf) and see if the result is zero?
Code:
compare_pass_code:
    movlw  supervisor_code
    xorwf  entered_pass_code,w  ; compare to supervisor code
    movlw  0
    btfsc  status,Z
    movlw  1
    movwf  supervisor_mode


Thank you so much!
 
Why do you check to see if the password is the supervisor in the update_pass_code subroutine? If you look at my original code under 'endless_loop' I first check to see if the 'Enter' key was pressed and if it is I jump to 'compare_pass_code' and if only a number was pressed I goto 'update_pass_code.' Only when a number is pressed as the last key will it update the code and when enter is pressed it will compare and see if its supervisor mode and if it is the next passcode will be added to the passcode list.

Oops. I think the intended code should be as follows:

Code:
update_passcode:
    bcf    status,C
    rlf    entered_pass_code,f 
    bcf    status,C
    rlf    entered_pass_code,f
;
    movlw  b'00000011'
    andwf  last_key_press,w       ; mask out upper bits
    addwf  entered_pass_code,f    ; add to entered pass code
;
    return

change_user_passcode:
    movf   num_pass_codes,w
    andlw  b'00001111'
    addlw  passcodes
    movwf  fsr
;
    movf   entered_pass_code,w
    movwf  indf
;
    incf   num_pass_codes,f
    clrf   supervisor_mode
;
    return

compare_pass_code:
    movf   supervisor_mode,w
    btfss  status,Z               ; Check if supervisor mode
    goto   change_user_passcode
 
    movlw  supervisor_code
    xorwf  entered_pass_code,w  ; compare to supervisor code
    movlw  0
    btfsc  status,Z
    movlw  1
    movwf  supervisor_mode
;
; additonal code here to copare with user pass codes
;       
    return

Also, why does status,Z determine if supervisor mode is set?

Oops again. Another bug. I am not used to coding this way. I normally use the macro SKPZ in my programs. It should be as follows:

Code:
    movf   supervisor_mode,w
    btfss   status,Z               ; Check if supervisor mode
    goto   change_user_passcode

The status,Z is altered when the preceding instruction "movf supervisor_mode,w" is executed. The instruction btfss status,Z tests the zero flag.

A simpler test is:

Code:
    btfsc  supervisor_mode,0
    goto   change_user_passcode
 
What does the following do? What does the anding of 00000011 with 'last_key_press' accomplish?
Code:

movlw b'00000011'
andwf last_key_press,w ; mask out upper bits
addwf entered_pass_code,f ; add to entered pass code
;
return

I assume the keycode is found in lowest 2 bits in the last_key_press. Since it was read off PORTA in the ISR, the upper bits can take any value and should be masked out and they will not interfere when added to the entered_pass_code.
 
motion said:
What does the following do? What does the anding of 00000011 with 'last_key_press' accomplish?
Code:

movlw b'00000011'
andwf last_key_press,w ; mask out upper bits
addwf entered_pass_code,f ; add to entered pass code
;
return

I assume the keycode is found in lowest 2 bits in the last_key_press. Since it was read off PORTA in the ISR, the upper bits can take any value and should be masked out and they will not interfere when added to the entered_pass_code.

I'm having trouble understanding what the subroutine "change_user_passcode" does. Does it simply store the new passcode into the passcode list?
 
This is my new updated code. I have probably have several bugs and incorrect code so if someone can check me starting at update_pass_code that would be help tremendously. The subroutine "compare_to_list" gave me the most trouble so if someone can let me know how to fix it, that'll be great.



Code:
	list P=16F84
	include	P16F84.INC

; Define the direction bit types
f		equ	1
w		equ	0

; Define the data storage locations
; These locations must NOT be modified!
entered_pass_code	equ 0x20	; the entered passcode - last four keys pressed
num_pass_codes		equ 0x21	; the number of passcodes stored
success				equ 0x40	; grant or deny access
history			 	equ 0x41	; history of passcodes entered
supervisor_mode		equ 0x42	; supervisor code entered -> adding new pass code to list
status_temp			equ 0x4A	; temp storage of STATUS reg during subroutines
w_temp				equ	0x4B	; temp storage of W during subroutines
last_key_press		equ 0x4F	; last key pressed
new_num_passcodes	equ 0x50
counter				equ 0x10
temp_passcode		equ 0x11
new_loc				equ 0x12

			org	0x30
passcodes			res	16	; location of the passcodes

; Define the control code for adding new users
control_code		equ 0x1B

; start defining the program
; interrupts, so start at 0x30
	org	0x00
		goto start
; Interrupt Service Routine
	org 0x04
		movwf w_temp 		; store the value of W
		movf STATUS, w
		movwf status_temp 	; store the STATUS register
		movf PORTA, w 		; get the key pressed
		movwf last_key_press; move the captured key press to reg
		bcf INTCON, INTF	; clear interrupt flag
		movf status_temp, w	; restore the status register's value
		movwf STATUS	
		movf w_temp, w		; restore the W register's value
		retfie

; Success or Failure Subroutine
grant_deny
		movwf w_temp 		; store the value of W
		movf STATUS, w
		movwf status_temp 	; store the STATUS register
		btfss success, 0
		goto update_history
open_door
		movlw 0x8			; send open door signal -> RA3
		movwf PORTA
		movlw 0x0
		movwf PORTA
update_history
		bcf STATUS, 0		; clear the carry bit to allow for shift thru carry
		rlf history, f
		movf success, w
		addwf history, f
		clrf entered_pass_code	; clear last attempt's pass code
		clrf success			; clear success flag
		movf status_temp, w		; restore the STATUS register
		movwf STATUS
		movf w_temp, w			; restore the W register
		return

; Sleep subroutine
sleep_now
		sleep
		; nop needed after sleep command for correct interrupt handling
		nop	
		return

; start main program
	org 0x30
start
		; Set-up Interrupt on RB0
		bsf INTCON, GIE			; enable global interrupts
		bsf INTCON, INTE		; enable RB0 interrupts
		; Set-up Inputs
		bsf STATUS, RP0		; select bank 1
		movlw 0x07			; configure first 3 bits as inputs
		; The following instruction generates a MESSAGE[302] warning from MPLAB - this is expected.
		movwf TRISA 		; load configuration into RA port
		bcf STATUS, RP0		; select bank 0
		clrf history		; zero out history of successes
		clrf PORTA			; clear the output on PORTA
		clrf num_pass_codes	; start out with an empty authorized pass codes list
		clrf supervisor_mode

; This is the main program loop that calls your subroutines.
endless_loop
		call sleep_now
		btfsc last_key_press, 2	; test for Enter press
		goto enter_pressed
		call update_pass_code	; update the entered pass code if Enter not pressed
		goto endless_loop
enter_pressed
		call compare_pass_code
		goto endless_loop

; Place your subroutines (compare_code & update_code) here:


update_pass_code:
	movf   entered_pass_code,w	  ; move entered passcode into w
	movwf  temp_passcode		  ; move entered passcode into new location so it won't be modified
    bcf    STATUS,C
    rlf    temp_passcode,f 
    bcf    STATUS,C		
    rlf    temp_passcode,f
;
    movf   entered_pass_code,w 	  ; move the original entered_pass_code into w
    addwf  temp_passcode,w    	  ; add to new temp_passcode, gets you the new format
	call   compare_pass_code
return

compare_pass_code:
	movf   supervisor_mode,f
	btfss  STATUS,Z				  ;check to see if supervisor_mode is 0 or 1
	goto   not_super
	goto   super

not_super
	movf   entered_pass_code,w
	sublw  0x1B,f					; subtract entered_pass_code from supervisor's code(0x1B		
	btfss  STATUS,Z					; check to see if they are equal(0 as answer)
	call   supermode
    call   compare_to_list

super								;store the new passcode in list
    movf   passcodes,w
    movwf  FSR
;
    movf   entered_pass_code,w
    movwf  INDF
;
    incf   num_pass_codes,f
    clrf   supervisor_mode
;
    return
	

supermode:
	movwf  supervisor_mode  
	movlw  0x01				;insert 1 into supervisor_mode, since the enter_pass_code matched
	return

no_match
	incf	  counter,f
	incf	  new_num_passcodes,w
	subwf	  num_pass_codes,f
	btfss	  STATUS,Z
	call 	  compare_to_list
	call      grant_deny
	
compare_to_list

 	movlw     passcodes				; set passcodes to the value in 0x30
    addwf     counter,w				; place passcodes into counter
    movwf     FSR			  
    movf      INDF,w				; get the passcode to place in temp register
    movwf     new_loc				; move into new location
	subwf	  entered_pass_code,f	; compare the entered code to the list
	btfss     STATUS,Z				; check to see if answer equals 0
	call 	  grant_deny	
	goto	  no_match
return
 
I'm sorry, but your program is riddled with problems. You really need to scrap it all and start afresh.
What form does the keypad take? Judging from your "code" it has a strobe connected to RB0, and two databits connected to RA0 and RA1. Am I right?
If so, what are the other RA pins connected to? You will probably need to ANDLW 0x03 at some point to isolate bits 0 and 1, otherwise, when you attempt to ADD the keycode into the stored code, it won't work as you expect.
You've still not fixed your interrupt routine, which trashes the STATUS register. Also, you seem to have copied the faulty context saving into your grant_deny or whatever it's called. This is complete rubbish.
Do you actually have the hardware to test this on, or are you just programming into a black hole?
If you have the hardware, and a means to program the PIC, then I suggest you start from scratch with something extremely simple, such as operating the door release when the ENTER key is pressed. Then you progress to entering 1234 or something similar.
If you have SOMETHING that works, then it'll be far easier to progress. You're not going to get anywhere carrying on in your present manner.
I'm sorry if this sounds harsh, but your professor is obviously a moron, so it's not entirely your fault.
I've made my living writing code that WORKS for the last 30 years, your professor has obviously not. Who are you going to trust?
 
JohnBrown said:
I'm sorry, but your program is riddled with problems. You really need to scrap it all and start afresh.
What form does the keypad take? Judging from your "code" it has a strobe connected to RB0, and two databits connected to RA0 and RA1. Am I right?
If so, what are the other RA pins connected to? You will probably need to ANDLW 0x03 at some point to isolate bits 0 and 1, otherwise, when you attempt to ADD the keycode into the stored code, it won't work as you expect.
You've still not fixed your interrupt routine, which trashes the STATUS register. Also, you seem to have copied the faulty context saving into your grant_deny or whatever it's called. This is complete rubbish.
Do you actually have the hardware to test this on, or are you just programming into a black hole?
If you have the hardware, and a means to program the PIC, then I suggest you start from scratch with something extremely simple, such as operating the door release when the ENTER key is pressed. Then you progress to entering 1234 or something similar.
If you have SOMETHING that works, then it'll be far easier to progress. You're not going to get anywhere carrying on in your present manner.
I'm sorry if this sounds harsh, but your professor is obviously a moron, so it's not entirely your fault.
I've made my living writing code that WORKS for the last 30 years, your professor has obviously not. Who are you going to trust?


lol. The course I'm taking is just an intro course so alot of the code he provides us has obvious bugs to keep things simple and not to take into account every detail. He's only testing us on certain functions actually functioning. The code I had to write starts at the subroutine "update_pass_code" and ends with "compare_to_list" So those are the only sections I really need help with. They all can't be totally wrong (I hope)
 
OK, if you can't be bothered to answer my questions, then I wash my hands of the whole thing. You're on your own as far as I'm concerned.
 
JohnBrown said:
What form does the keypad take? Judging from your "code" it has a strobe connected to RB0, and two databits connected to RA0 and RA1. Am I right?
If so, what are the other RA pins connected to? You will probably need to ANDLW 0x03 at some point to isolate bits 0 and 1, otherwise, when you attempt to ADD the keycode into the stored code, it won't work as you expect.
I dont know the answer to this question, my professor has mentioned nothing of this. All I know is that RB0 indicates the value on the INT pin on the PIC – when a rising edge (transition from 0 to 1) occurs on this pin, an interrupt is signaled to the PIC. The input values for pins RA2,
RA1, and RA0. RA2 is high when the Enter key is pressed. RA1 and RA0 encode the four number keys into 2-bits. It is assumed that only a single key is pressed at a time. I dont know if that's the answer you're looking for but that's all I know about that.

JohnBrown said:
Do you actually have the hardware to test this on, or are you just programming into a black hole?
I'm using MPLAB and I don't have the actual PIC (PIC16F84) but a simulator of it.

JohnBrown said:
You've still not fixed your interrupt routine, which trashes the STATUS register. Also, you seem to have copied the faulty context saving into your grant_deny or whatever it's called.
Again, I cannot edit the interrupt routine nor the grant_deny. Those were all given by my professor. The only thing I'm allowed to touch are subroutines starting at "update_pass_code" which is what I have added to his code.
 
I know exactly what needs to be done but I just can't program it in assembly. I'll show you guys the pseudo code for the compare_pass_code subroutine. I think my main problem is using FSR and INDF, I just don't seem to understand how to use those.

Code:
compare_pass_code

if supervisor_mode==1
     store passcode in list
     clear supervisor mode

else
      if entered_pass_code==0x1B (supervisors passcode)
            set supervisor_mode=1
       
       else
            compare entered_pass_code to list of authorized passcodes
            if match found
                add to list
                set success=1
                call grant_deny
            
           else
             no match found is found, set success=0
             call grand_deny
 
Can someone please give me some advice or help me out with converting the pseudo code I have to assembly language so I can finally get this program finished?
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top