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

Assembly blinking leds using PIC16f877a

Status
Not open for further replies.

Cantafford

Member
Hey,

I'm starting to learn assembly language for PICs. I wrote this following code that's supposed to blink the LED's of PORTA of a PIC16f877a. However the LEDS will stay off and won't blink at all. Please help me identify the issue in the following code if possible. Thank you.

Code:
; Program that adds a number to the working register

; you need to define where in memory program starts
; use the org directive to force program start at reset vector

;Register file map
ADCON1 equ 9fh ; in bank1
STATUS equ 03h ;  in bank0
TRISA equ 85h  ; in bank1
PORTA equ 05h
RP0 equ 05h
RP1 equ 06h

COUNT1 equ 20h; first counter for our delay loops(General Purpose register)
COUNT2 equ 21h;

   org 00h ; set origin

; Program starts here
   clrw ;clear working register

   BCF STATUS, RP0 ; makes RP0 and RP1 0 to selectbank0(we equ'd 03h to STATUS maro)
   BCF STATUS, RP1
   CLRF PORTA ; Initialize PORTA by clearing output data latches

   BSF STATUS, RP0 ;RP0=1, RP1=0 to select bank1
   MOVLW 0x06
   MOVFW ADCON1 ; make PORTA digital :D
   
   MOVLW 0x00   ; make PORTA output(you know this ****)
   MOVFW TRISA

   BCF STATUS, RP0 ; transfer to bank 0
   BCF STATUS, RP1

START MOVLW 0xFF ; turn all leds on move to Wreg
      MOVWF PORTA ; put the value on the actual port

      ;delay
      MOVLW 0xff
      MOVWF COUNT1
      MOVWF COUNT2

LOOP1 DECFSZ COUNT1, 1
      GOTO LOOP1
      DECFSZ COUNT2, 1
      GOTO LOOP1

      MOVLW 0x00 ; turn all leds on move to Wreg
      MOVWF PORTA ; put the value on the actual port
      GOTO START
end
 

House0Fwax

Member
Where you have 'DECFSZ COUNT1, 1' and 'DECFSZ COUNT2, 1' replace the end '1' with 'F'. That way you are decrementing the file, and putting the result back into the file. ie DECFSZ COUNT1, F
 
Steps that you should have taken to debug this:

1. Is everything connected properly?
2. Write a simpler program to only turn the LEDs on. Does that work?
3. Try PORT B. Does that work?
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
If the LED's are connected to the port via the cathode... They will stay off..

You have a delay for off but not for on.... You need two delays as as soon as the port is 0 then you immediately make it 1 again..
 

Jon Wilder

Active Member
Code:
MAIN:
      clrf     PORTA
blinkLoop:
      comf     PORTA,F
      call     Delay
      goto     blinkLoop

Delay:
      movlw    0xFF
      movwf    COUNT1
      movwf    COUNT2
      decfsz   COUNT1,F
      goto     $-1
      decfsz   COUNT2,F
      goto     $-3
      return
 

Cantafford

Member
If the LED's are connected to the port via the cathode... They will stay off..

You have a delay for off but not for on.... You need two delays as as soon as the port is 0 then you immediately make it 1 again..
I know that about the LEDs. I have connected them like this:


About the delay. I have added one after I turn off the LEDS. Like this:
Code:
;Register file map
ADCON1 equ 9fh ; in bank1
STATUS equ 03h ;  in bank0
TRISA equ 85h  ; in bank1
PORTA equ 05h
RP0 equ 05h
RP1 equ 06h

COUNT1 equ 20h; first counter for our delay loops(General Purpose register)
COUNT2 equ 21h
COUNT3 equ 22h
COUNT4 equ 23h
   org 00h ; set origin

; Program starts here
   clrw ;clear working register

   BCF STATUS, RP0 ; makes RP0 and RP1 0 to selectbank0(we equ'd 03h to STATUS maro)
   BCF STATUS, RP1
   CLRF PORTA ; Initialize PORTA by clearing output data latches

   BSF STATUS, RP0 ;RP0=1, RP1=0 to select bank1
   MOVLW 0x06
   MOVFW ADCON1 ; make PORTA digital :D
   
   MOVLW 0x00   ; make PORTA output(you know this ****)
   MOVFW TRISA

   BCF STATUS, RP0 ; transfer to bank 0
   BCF STATUS, RP1

START MOVLW 0xFF ; turn all leds on move to Wreg
      MOVWF PORTA ; put the value on the actual port

      ;delay
      MOVLW 0xFF
      MOVWF COUNT1
      MOVWF COUNT2

LOOP1 DECFSZ COUNT1, 1
      GOTO LOOP1
      DECFSZ COUNT2, 1
      GOTO LOOP1

      MOVLW 0x00 ; turn all leds on move to Wreg
      MOVWF PORTA ; put the value on the actual port

LOOP2 DECFSZ COUNT3, 1
      GOTO LOOP2
      DECFSZ COUNT4, 1
      GOTO LOOP2
end
The LED still stays off forever. :(

Code:
MAIN:
      clrf     PORTA
blinkLoop:
      comf     PORTA,F
      call     Delay
      goto     blinkLoop

Delay:
      movlw    0xFF
      movwf    COUNT1
      movwf    COUNT2
      decfsz   COUNT1,F
      goto     $-1
      decfsz   COUNT2,F
      goto     $-3
      return
Thanks very much man but I would like to know my mistake in the code I wrote. I will try your solution as well. I'm guessing it works :).

F is 1. Don't confuse the kid.
I'm not a kid I'm 23 years old.
 

Jon Wilder

Active Member
Thanks very much man but I would like to know my mistake in the code I wrote. I will try your solution as well. I'm guessing it works :).
Ian explained that. My way is just a much more efficient way of doing it. Less instructions. ;)
I'm not a kid I'm 23 years old.
Compared to most of us (even age-wise), you're a kid. Kid is also used as slang for a novice or amateur. Not a bad thing.
 

Cantafford

Member
Ian explained that. My way is just a much more efficient way of doing it. Less instructions. ;)


Compared to most of us (even age-wise), you're a kid. Kid is also used as slang for a novice or amateur. Not a bad thing.
Haha yeah man I know I did not take it as an insult at all.
 

Cantafford

Member
Your LED is the wrong way round, And so are the two movwf commands
Code:
  MOVLW 0x06
   MOVFW ADCON1 ; make PORTA digital :D
  
   MOVLW 0x00   ; make PORTA output(you know this ****)
   MOVFW TRISA
Ok you were right I misspelled that. It works now.
What do you mean by the led beiing the wrong way round tough?
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Ignore that.. my eyes are getting the worst of me these days... I have four pairs of glasses nowadays... electronics, reading, computer work and normal!!!

If I forget any pair I can just make out the screen!!
 

Cantafford

Member
Guys quick question if you don't mind I didn't wanna make a new thread for this because it's pretty much the same thing.
I have this piece of code which I got from a tutorial:

Code:
BANKSEL PORTB
    decf PORTB
    call _delay_1s
    clrf PORTB
    call _delay_1s
This basically blinks 5 LEDs on PORTB(all at once). So the 5 leds will be 1 second on and 1 second off.
I don't understand that decf PORTB thing. That is supposed to decrement my PORTB register by 1. At the beginning of the program I'm clearing PORTB. So how comes that decrementing the PORTB by 1 lights up all the 5 leds?
I have an ideea as why but I'm not sure if I'm right. I'm guessing that by substracting one from a null register(PORTB=0x00) makes the register PORTB = 0xFF. Is that correct?
 

Jon Wilder

Active Member
Yes. As PORTB is an 8 bit register, decrimenting PORTB at the time it is null causes it to roll over to 255 (0xFF).

Should've been decf PORTB,F as decf is a 2 operand instruction that needs to know where to store the result (whether in W or back in the source register File).
 

atferrari

Well-Known Member
I don't understand that decf PORTB thing. That is supposed to decrement my PORTB register by 1. At the beginning of the program I'm clearing PORTB. So how comes that decrementing the PORTB by 1 lights up all the 5 l
I have an ideea as why but I'm not sure if I'm right. I'm guessing that by substracting one from a null register(PORTB=0x00) makes the register PORTB = 0xFF. Is that correct?
Hola Cantafford

Now that you are learning the basics, get used to MPSIM. Simulate as much as you can and watch the registers appearing in the code being tested. What you ask above is easily seen in MPSIM.

Trust me; you can learn a lot simulating. Of course it is good for debugging well before implementing anything in a board.

One last suggestion: "Divide and conquer" was the first piece of advice I ever got, what means, add code one function at a time, test it and if OK then add the next. If something is wrong you know the last addition is most probably where to look at first. Start small and grow from there.

I like your persistence.
 
One last suggestion: "Divide and conquer" was the first piece of advice I ever got, what means, add code one function at a time, test it and if OK then add the next. If something is wrong you know the last addition is most probably where to look at first. Start small and grow from there.
Yes!
 

Jon Wilder

Active Member
Absolutely. Code is written and tested in stages. Never do they write the entire program in one shot. That's just asking for failure.

Start with building your output functions. Once those are working, then work on your input functions. Once those are working, then you can link your inputs to your outputs. Before you know it, you've got fully working code.
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top