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.

Modified LED Blinker

Status
Not open for further replies.

jonathan

New Member
I am using a PIC16F628 PIC. I am programming it with ASM. I have an LED connected to each availible pin of the PIC - 13 LEDs total. I want to turn on the LEDs one by one with a short delay between each. I know that there is an error in this line of the code: bsf PORTA, TRISAPOS. PORTA holds the location of PORTA just like it sounds and TRISAPOS is the location for a register that holds the next bit to be set in the loop. What is happening is that the program reads 32h (the location of the register) not the value the register holds. The loop decrements this register so the value always changes. This is hard to explain but the source code is posted below. Hopefully it will clear up any questions. If not please ask. The two probelm lines are marked in the comments section.


;*****Set up the Constants****

STATUS equ 03h ;Address of the STATUS register
TRISA equ 85h ;Address of the tristate register for port A
TRISB equ 86h ;Address of the tristate register for port B
PORTA equ 05h ;Address of Port A
PORTB equ 06h
COUNT1 equ 30h ;First counter for our delay loops
COUNT2 equ 31h ;Second counter for our delay loops
COUNT3 equ 34h ;Third Delay Counter
TRISAPOS equ 32h ;port position in TRISA
TRISBPOS equ 33h ;port position in TRISB
TRISANUM equ 04h ;number of ports in TRISA
TRISBNUM equ 07h ;number of ports in TRISB

;****Set up the port****

bsf STATUS,5 ;Switch to Bank 1
movlw 00h ;Set the Port A pins
movwf TRISA ;to output.
movwf TRISB
bcf STATUS,5 ;Switch back to Bank 0

;****Turn the LED on****

Start

movlw 04h ;reset port positions
movwf TRISAPOS

movlw 07h
movwf TRISBPOS


;****************TRISA******************

TRISALOOP
bsf PORTA, TRISAPOS ;turn on the pin's LED ----- PROBLEM HERE ------
call Delay ;delay
decfsz TRISAPOS, 1 ;subtract one from TRISA position
goto TRISALOOP ;restart loop if not zero

TRISBLOOP
bsf PORTB, TRISBPOS ;turn on the pin's LED ----- PROBLEM HERE --------
call Delay ;delay
decfsz TRISBPOS, 1 ;subtract one from TRISB position
goto TRISBLOOP ;restart loop if not zero


;****Start of the delay ****

call Delay

;****Delay finished, now turn the LED off****

movlw 00h ;Turn the LED off by first putting
movwf PORTA ;it into the w register and then on ;the port
movwf PORTB

;****Add another delay****

call Delay

;****Now go back to the start of the program

goto Start ;go back to Start and turn LED ;on again

;****End of the program****


;********Delay*****************
Delay

movlw 0FFh
movwf COUNT1 ;reset counters
movwf COUNT2
movwf COUNT3
Loop

nop
nop
nop
nop

decfsz COUNT1,1
goto Loop ;actual delay
decfsz COUNT2,1 ;subtract one from each variable each pass
goto Loop
decfsz COUNT3, 1
goto Loop

return

end ;Needed by some compilers, ;and also just in case we miss ;the goto instruction.


For the two lines MP LAB gives this error:

Warning[202] G:\LED\LED2.ASM 38 : Argument out of range. Least significant bits used.

This is what leads me to beleive that the register location is being used, not the register value. Is there a way to turn on each LED with a loop? I would like to use a loop if possible to make the code as small as possible and easier to read.

Sorry if this is a simple question. This is only my second PIC project. I am used to programming high level languages like VB, C, C++, HTML, ASP etc. I am taking electrical engineering in the fall and I want to get a head start. Thanks for the help in advance.
 
If you jst want to to turn on the leds in a running fashion you can use the
"rrf" command to rotate right or the "rlf" command to rotate left.
This would only 4 or 5 comnds in the loop.

To end the loop you could just check to see when the carry bit is high.
 
Is it possible to use the value of a register for this? I am used to high level languages so it may not be possible. It just seems to me that there would be a way to use the value of a register. If I moved the value of the register into w would that help any? Then I could use this command in the loop for the one that has the error: bsf TRISAPOS, w. Is that a valid command?

My point is that there has to be a way to get data back out of a register. Why would you put data in a register if you couldn't get it back out? It seems that I am just missing a simple concept of assembler and low level languages in general.

I was planning to turn on the LEDs one by one. All the previosly light LEDs would stay on until the end of the program when they would all be turned off.

Sorry if I seem unwilling to compromise but the ability to use the value of a register in instructions would be very helpful for this project and projects in the future. Thanks for the help.
 
Hi Jonathan, it seams like your a little confused as to what the BSF instruction does, it stands for Bit Set in File.

It takes the address of a fileregister, like PORTA, and also a "bit-index" value 0 to 7. This bit is then set to a 1, leaving the rest of the register un-touched.

To get the value of a register into w, you would use the MOVF PORTA, W

MOVF been Move File, PORTA been the file register to move, and W been the desitination.

RRF and RLF both work in a similar way, they take the ADDRESS of a file, and the operation is perfomed on the contents of that file.

If you need Indirection (Pointers) look up the INDF register in the datasheet for mid-end devices
 
In the first part of your reply is exactly what I was trying to do. Here is an example.

The value of register TRISAPOS would start out at 04h. So in the line bsf PORTA, TRISAPOS I want to use the value stored in TRISAPOS (4 for the first pass). So it would be replacing bsf TRISAPOS, 4 by using the 04h in the register of TRISAPOS. This would set bit 4 of PORTA.

In the second pass of the loop TRISAPOS would have been decremented and would now contain 03h. So the instruction bsf PORTA, TRISAPOS would now set bit 3 of PORTA.

Here is an example.

------------------------------------------------------------

;First Pass - TRISAPOS = 04h
bsf PORTA, TRISAPOS ;4 would be entered in the place of TRISAPOS because 4 is the value held in TRISAPOS

;Second Pass - TRISAPOS = 03h (decremnted once)
bsf PORTA, TRISAPOS ;3 would be entered in the place of TRISAPOS because 3 is the value held in TRISAPOS

;Third Pass - TRISAPOS = 02h (decremented twice)
bsf PORTA, TRISAPOS ;2 would be entered in the place of TRISAPOS because 2 is the value held in TRISAPOS

;Fourth Pass - TRISAPOS = 01h (decremented three times)
bsf PORTA, TRISAPOS ;1 would be entered in the place of TRISAPOS because 1 is the value held in TRISAPOS

------------------------------------------------------------

The best way I can explain what I am trying to do is that I want to use the value in register TRISAPOS, not the location (32h). Every pass of the loop TRISAPOS would be decremented so it would set bits 4,3,2,1, and then 0. The value of TRISAPOS would change with every pass of the loop so I don't have to enter a constant bit to set. This would save me from copying the same lines over and only changing one character in each line. This is a principal of high level programming so I am not sure how it would be done in assembler.

I'm not sure what you mean about RRF and RLF. I understand they rotate the bits but what exactly does that mean? Can you give me an example in binary? Would it do something like this:

Initial Value b'1000000'
End Value b'0000001'

A pointer may be the solution. Would I find the datasheet on Microchip's web site? Thanks for the help.
 
Yeah, microchips site has the datasheets. They are also usually available on the sites of vendors who sell microcontrollers.

BTW - Are you powerman from the [H] forum?
 
I'm getting closer but not quite there lol. I got two LEDs to blink - ones that shouldn't have blinked. They were RA0 and RB0. The code should have omitted them because of the decfsz instruction skipping the next line when the value is 0. Any ideas why the pins that should be on are off and the ones that should be off are on? I double checked the wiring and LEDs.

Here's my new code:

INCLUDE "p16f628.inc"

;*****Set up the Constants****

STATUS equ 03h ;Address of the STATUS register
TRISA equ 85h ;Address of the tristate register for port A
TRISB equ 86h ;Address of the tristate register for port B
PORTA equ 05h ;Address of Port A
PORTB equ 06h
COUNT1 equ 30h ;First counter for our delay loops
COUNT2 equ 31h ;Second counter for our delay loops
COUNT3 equ 34h ;Third Delay Counter
TRISAPOS equ 32h ;port position in TRISA
TRISBPOS equ 33h ;port position in TRISB
TRISANUM equ 04h ;number of ports in TRISA
TRISBNUM equ 07h ;number of ports in TRISB

;****Set up the port****

bsf STATUS,5 ;Switch to Bank 1
movlw 00h ;Set the Port A pins
movwf TRISA ;to output.
movwf TRISB
bcf STATUS,5 ;Switch back to Bank 0

;****Start of Main Loop****

Start

movlw 4 ;reset port positions
movwf TRISAPOS
movlw 0x32
movwf FSR


;****************Turn on LEDs one by One******************

TRISALOOP

bsf PORTA, INDF ;turn on the pin's LED
call Delay ;delay
decfsz INDF, 1 ;subtract one from TRISA position
goto TRISALOOP ;restart loop if not zero

movlw 7 ;reset port positions
movwf TRISBPOS
movlw 0x33
movwf FSR

TRISBLOOP
bsf PORTB, INDF ;turn on the pin's LED
call Delay ;delay
decfsz INDF, 1 ;subtract one from TRISB position
goto TRISBLOOP ;restart loop if not zero


;****Start of the delay ****

call Delay

;****Delay finished, now turn the LED off****

movlw 00h ;Turn the LED off by first putting
movwf PORTA ;it into the w register and then on ;the port
movwf PORTB

;****Add another delay****

call Delay

;****Now go back to the start of the program

goto Start ;go back to Start and turn LED ;on again

;****End of the program****


;********Delay*****************
Delay

movlw 0FFh
movwf COUNT1 ;reset counters
movwf COUNT2

Loop

decfsz COUNT1,1
goto Loop ;actual delay
decfsz COUNT2,1 ;subtract one from each variable each pass
goto Loop


return

end ;Needed by some compilers, ;and also just in case we miss ;the goto instruction.


Also what gave away I was also from the [H]? Could it have been the identical source code? :D Thanks for the help.
 
Just to let you know, you don't need to explicitly define most of your constants if you include p16f628.inc, it defines most everything you need. Open the files and you'll see all of the equ statements.

I'm not sure why you're using the FSR and INDF registers, those are used for indirect addressing, which is a concept I'm not entirely familiar with. Perhaps TheAnimus can explain, because I certainly don't understand what they're used for. INDF returns 0 when read IIRC, so when you're using bsf PORTA, INDF, you're always setting the 0 bit, which would be RA0 and RB0.

And have you tried writing this out in 'literal code', ie no calls, no variables. Just write it from start to finish specifying all of the values used where, insert the delays manually and write each cycle manually (just cut n paste as needed for as many cycles as you want). Make sure it works there. Then start moving things back into loops, calls, and variables, and see when it stops working. I'm not really sure what's wrong with your code, but this technique has served me well in C++.

And I did recognize your code from the [H], not to mention the timing was correct.
 
Does anyone have any suggestions? I am kind of stuck right now. Would I have better luck using C instead of assembler? Would the PIC 16F628 take a program written in C? The reason I ask is because I am sure the loop that I am trying to do with assembler can be done in C. Atleast it can be done for PC programs. Thanks for the help.
 
Yes program written in C can work with PIC provided it is a dedicated PIC C compiler like C2C Compiler, PICC compiler, HITECH Compiler etc. Search google to find links to these compilers websites. Most of them offer free demo which can produce code for 16F84 or say upto 1kb.
 
1111

Here:

It's a CLEARVIEW assmebler of scrolling LEDS on port B, if anybody in here has the time to change it to microchip assembler then please do, other wise gimme a day and Ill do it for you





device pic16f84,xt_osc,protect_off,pwrt_off,wdt_off

org 0ch ; Start of RAM

ax ds 1
bh ds 1
cx ds 1

org 0 ; Start of code space (ROM)

START
clr RA
clr RB
mov !rb,#00000000b ; rb - output
mov !ra,#10000b ; r0->r3 = output / r4 = input
Begin

Main
mov cx, #0h
Lt1
cje cx, #8, Main
mov w, cx
call getpattern
mov rb, w
call led_delay
inc cx

jmp Lt1

end

led_delay
mov bh, #0ffh ; depanding on the crystal, the delay will
wait00 djnz bh, wait00 ; change
ret

getpattern jmp pc+w
retw 00000001b, 00000010b, 00000100b, 00001000b
retw 00010000b, 00100000b, 01000000b, 10000000b
 
@johnatan

The instruction BSF will take one register on which to set the bit and the bit number. The register in this case is PORTA or PORTB and the bit number is always fixed, it can't be taken from a register. So your instruction

bsf PORTA, TRISAPOS will be translated to

bsf 5, 32h which will be assembled as

bsf 5, 2 (set bit 2 of register 5) and generate a warning (because of 32 conversion to 2).

I haven't tried it myself, but you could use instead of:

bsf PORTA, TRISAPOS ;turn on the pin's LED ----- PROBLEM HERE ------

something like:

movlw TRISAPOS, W
call GETPATTERN_A
movwf PORTA

where GETPATTERNA is a subroutine:

GETPATTERNA:
addwf PCL, F ; Make a GOTO depening on W value
retlw B'00010000' ; Returned if W=0
retlw B'00001000' ; Returned if W=1
retlw B'00000100' ; Returned if W=2
retlw B'00000010' ; Returned if W=3
retlw B'00000001' ; Returned if W=4

And similar for PORTB, with a call to GETPATTERNB, which will have 8 patterns (8 retlw instructions).

You could do it also with rotate instructions, but this will allow for any patterns (even more than 5, respective 8 for the two ports). I hope the code is clear enough and that it solves your problem.

Best regards!
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top