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.

asmpic

New Member
I have a programming assignment that I believe to be pretty hard. I have to make a PIC microcontroller program for a Keypad Entry Access Control System. The access control system consists of a five-button keypad (1,2,3,4 and enter), an electronically controlled door lock, and a PIC microcontroller. The control logic for the system will be inside the microcontroller. So the code below is what I have as of now, but I'm having trouble coming up with two last subroutines(update_passcode and compare_pass_code).

Update_passcode is supposed to update the code stored in location 0x20 using a specific method. The updating process simply left shifts the entered pass code by 2 bits and adds this number to the 2-bits representing the last key pressed. When the Enter key is pressed, the program does not update the entered pass code, but instead compares the entered pass code first to the supervisor’s code (0x1B). If the entered code is not the supervisor’s code then the entered pass code is compared to each entry in its list of authorized pass codes, which begins at location 0x30. I can't assume that there will be at least one authorized pass code as the authorized pass code list will be empty upon power-up.

The inputs for the update_passcode will be:
"last_key_pressed" stored at location 0x4F (The interrupt handling routine places the number pressed at the location 0x4F).

It will output:
"entered_pass_code" stored at location 0x20 - The updated pass code (in the format described above) should be placed at location 0x20.


The second subroutine I'm having trouble with is compare_pass_code. This is supposed to compare the entered pass code, stored at location 0x20, first to the supervisor’s pass code (0x1B) and then, assuming the supervisor’s code was not entered and that num_pass_codes > 0, to each of the authorized pass codes beginning at location 0x30. If the entered pass code is the supervisor’s code, then the supervisor_mode flag output is set to 0x01. This subroutine will use this flag to recognize that the next entered pass code should be added to the authorized pass code list instead of being compared to the entries in the list.
The inputs will be:
"entered_pass_code" at locations 0x20 - The entered pass code is stored at location 0x20.
"num_pass_codes" stored at location 0x21 - The number of authorized pass codes is stored at location 0x21.
"auth_pass_codes" stored at location 0x30 - Authorized pass codes are stored beginning at location 0x30.
"supervisor_mode" stored at location 0x42 - Your compare_pass_code subroutine may use the value of location 0x42 to determine if the entered pass code should be added to the authorized pass code list.

Outputs:
"success" stored at location 0x40 - A one (0x01) should be stored at location 0x40 if the entered pass code is found in the list of authorized pass codes. Otherwise the location 0x40 should be cleared.
"supervisor_mode" stored at location 0x42 - A one (0x01) should be stored in location 0x42 if the entered pass code equals the supervisors pass code (0x1B).



Again, I think this program is extremely hard so I understand if you guys don't understand how to do this. Let me know if you need any more information. I appreciate all the help anyone gives me.

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

			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

update_passcode




compare_pass_code

	end
 
Questions usually end with a question mark .....?
i have read it twice and still do not see a question..?
but it is late , and maybe i am just missing it..
 
asmpic said:
wow, no one can help?

Just 8 hrs after you first posted, you start whining this! It's Sunday morning where I am at now. I sure would like to help but I think I would pass on this one bro.
 
motion said:
asmpic said:
wow, no one can help?

Just 8 hrs after you first posted, you start whining this! It's Sunday morning where I am at now. I sure would like to help but I think I would pass on this one bro.

Sorry about that, but usually when a new topic is posted, people on this board reply pretty quickly. So, I didn't know if my topic was just confusing or what.
 
williB said:
Questions usually end with a question mark .....?
i have read it twice and still do not see a question..?
but it is late , and maybe i am just missing it..

I don't have an exact question, I just need help coming up with two subroutines, update_passcode and compare_pass_code. And sorry about it being so long, I didnt know any other way of explaining it clearly.
 
somone on here recomended to somone else to create modules for large projects..
i think that breaking this down into smaller parts might help..ie a new program with just the parts that you are working on at the moment..
 
One thing I noticed, I think your interrupt service routine trashes the status flags. Take a look at the section on context saving during interrupts. It's in the freely available datasheet. You need to use a SWAPF instruction, as this allows you to restore W at the end of the ISR without affecting the Z flag.
 
I have several issues with your code so I don't think it will work as smoothly as predicted. Anyway as I understand it, here is some code to start the discussion:

Code:
update_passcode:
    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 copare with user pass codes
;       
    return
 
There are a couple of things you will have to do but nothing that is too hard. I won't give you complete code but I'll give you enough to get you going in the right direction.

When scanning in button presses, you will have to make sure your program halts until you release the button you are pressing. If you do not, you will your pass code with entirely one button. To read in the code you want the flow to look like this:

Check button press using btfss or btfsc

if pressed call a 5ms delay for debouncing purposes
if not pressed, goto next button check

after 5ms delay btfss or btfsc the same pin and read the value
if still pressed, button is valid - shift the value into a variable
if not pressed, return to scanning routine

(after shifting in variable)
btfss or btfsc the same button
if still pressed, keep checking until not pressed
if not pressed, return to your keypad scan routine


In terms of comparing your inputted combination to the stored one, the way to check it will depend on whether your combo is stored as a single byte or a byte for each digit. Either way, subtract the inputted value from the stored value and check the Zero flag. If the flag is set, the values are the same. If the flag is cleared, the values are different and you can branch accordingly in your program

Hope that helps somewhat.

-Bill
 
motion said:
I have several issues with your code so I don't think it will work as smoothly as predicted. Anyway as I understand it, here is some code to start the discussion:

Code:
update_passcode:
    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 copare with user pass codes
;       
    return


Thanks for the code! I understand how you compared the entered code with the supervisor code but how exactly would you compare the entered code with all the different user passcodes? Would you setup another FSR and INDF type thing? ...I'm sorry if I'm asking so much, I know this must be a joke of a problem but I'm totally new as far as assembly programming goes, it's been two weeks since I've started learning this.
 
I mentioned before that you Interrupt Service Routine (ISR) is trashing the status bits. You do not seem to have taken any notice. Here is an extract from the datasheet for the 16F87X, it applies equally to the 16F84.


EXAMPLE 12-1: SAVING STATUS, W, AND PCLATH REGISTERS IN RAM
MOVWF W_TEMP ;Copy W to TEMP register
SWAPF STATUS,W ;Swap status to be saved into W
CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3
MOVWF PCLATH_TEMP ;Save PCLATH into W
CLRF PCLATH ;Page zero, regardless of current page
:
:(ISR) ;(Insert user code here)
:
MOVF PCLATH_TEMP, W ;Restore PCLATH
MOVWF PCLATH ;Move W into PCLATH
SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W
;(sets bank to original state)
MOVWF STATUS ;Move W into STATUS register
SWAPF W_TEMP,F ;Swap W_TEMP
SWAPF W_TEMP,W ;Swap W_TEMP into W

It may be that your main loop is currently so trivial that trashing the status flags isn't a problem. One day it will be, and it will drive you crazy trying to debug your program. Ignore this advice at your peril.
 
JohnBrown said:
I mentioned before that you Interrupt Service Routine (ISR) is trashing the status bits. You do not seem to have taken any notice. Here is an extract from the datasheet for the 16F87X, it applies equally to the 16F84.


EXAMPLE 12-1: SAVING STATUS, W, AND PCLATH REGISTERS IN RAM
MOVWF W_TEMP ;Copy W to TEMP register
SWAPF STATUS,W ;Swap status to be saved into W
CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3
MOVWF PCLATH_TEMP ;Save PCLATH into W
CLRF PCLATH ;Page zero, regardless of current page
:
:(ISR) ;(Insert user code here)
:
MOVF PCLATH_TEMP, W ;Restore PCLATH
MOVWF PCLATH ;Move W into PCLATH
SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W
;(sets bank to original state)
MOVWF STATUS ;Move W into STATUS register
SWAPF W_TEMP,F ;Swap W_TEMP
SWAPF W_TEMP,W ;Swap W_TEMP into W

It may be that your main loop is currently so trivial that trashing the status flags isn't a problem. One day it will be, and it will drive you crazy trying to debug your program. Ignore this advice at your peril.

I understand what you are saying and the only reason I haven't really said anything about it is because my professor told us to do the ISR that particular way. I dont know why, but I suppose like you said it might not be much of a problem for now.
 
Would you setup another FSR and INDF type thing? ...

Yes. I leave this to you to finish.

Also, I must stress that there are other problems with the program. For example, the routine "update_passcode" must only be called when a key has actually been pressed. Right now, it seems that when the timer overflows, an interrupt is generated and update_passcode is called. This will cause false data to be shifted into entered_pass_code.
 
Also, I must stress that there are other problems with the program. For example, the routine "update_passcode" must only be called when a key has actually been pressed. Right now, it seems that when the timer overflows, an interrupt is generated and update_passcode is called. This will cause false data to be shifted into entered_pass_code.

On the other hand, putting the PIC to sleep would shut off the clocks and so the timers will also stop. The PIC would be unable to wake from sleep. :(
 
motion said:
I have several issues with your code so I don't think it will work as smoothly as predicted. Anyway as I understand it, here is some code to start the discussion:

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


I have a question about the rlf, that is a rotate left shift correct? Wouldn't that be different than a regular left shift which I need to perform?
 
motion said:
Also, I must stress that there are other problems with the program. For example, the routine "update_passcode" must only be called when a key has actually been pressed. Right now, it seems that when the timer overflows, an interrupt is generated and update_passcode is called. This will cause false data to be shifted into entered_pass_code.

On the other hand, putting the PIC to sleep would shut off the clocks and so the timers will also stop. The PIC would be unable to wake from sleep. :(

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. Also, the Watch Dog Timer (WDT) that will cause an interrupt will be disabled within MPLAB.
 
Status
Not open for further replies.

Latest threads

Back
Top