![]() | ![]() | ![]() |
| | |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
| | Thread Tools | Display Modes |
| | (permalink) |
| 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. |
| | |
| | (permalink) |
| Experienced Member | 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.
__________________ Dude, no way!!!! |
| | |
| | (permalink) |
| New Member | 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. |
| | |
| | (permalink) |
| Experienced Member | 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 |
| | |
| | (permalink) |
| New Member | 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. |
| | |
| | (permalink) |
| Experienced Member | 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? |
| | |
| | (permalink) |
| New Member | 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? |
| | |
| | (permalink) |
| Experienced Member | 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. |
| | |
| | (permalink) |
| New Member | 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. |
| | |
| | (permalink) |
| Super Moderator | 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.
__________________ "There is no way to peace, peace is the way!" |
| | |
| | (permalink) |
| New Member | hey, have you resolved your problem with pics and leds efects? take care. |
| | |
| | (permalink) |
| New Member | 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 |
| | |
| | (permalink) |
| New Member | @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! |
| | |