Need help with blink for PIC (Internal oscilaltor) - Page 1
Forum section: electronics / general

author: Beninot
author_rank: Newbie
timestamp: February 21, 2016, 05:28:05 am
content: Hi guys, after playing with transistor logic gates, arduino and many others, I'm now to the point where I need to learn PIC assembly programming, I read a lot about it and understand the basics of this langage, but I can't get the f****ing led to blink, I can set it to a positive or negative output, but not interact with it... I spent many hours reading the datasheets, I found some explanations, but now I'm stuck.My chip is a pic16f630and there comes the codeCode:__config 01fdhSTATUS equ 03hTRISC equ 87hPORTC equ 07hCOUNT1 equ 08hCOUNT2 equ 09hCOUNT3 equ 11hbsf STATUS,5 ;Switch to Bank 1movlw 00hmovwf TRISCbcf STATUS,5 ;Switch back to Bank 0Start movlw 0xffmovwf PORTCDelaymovwf 0x00movwf PORTCDelaygoto StartDelaybanksel COUNT1movlw 0xFFmovwf COUNT1movwf COUNT2movlw 0x05movwf COUNT3decfsz COUNT1,fgoto $-1decfsz COUNT2,fgoto $-3decfsz COUNT3,fgoto $-5returnendfor the circuitry, it's pretty straight forward, vcc, gnd, reset to + and a led on a portC pin

author: rich
author_rank: Frequent Contributor
timestamp: February 21, 2016, 07:11:28 am
content: Quote from: Beninot on February 21, 2016, 05:28:05 ammovlw 0x00 is probably what you intended?

author: picandmix
author_rank: Frequent Contributor
timestamp: February 21, 2016, 10:53:47 am
content: Good first try - this bit of code should put you on the right road.Code:list p=16f630 ; list directive to define processor#include <p16F630.inc> ; processor specific variable definitions; so no need to specify system variableserrorlevel -302 ; suppress message 302 from list file__CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT; config parameters in visible state, not just a hex number; set up the chip to use its internal 4mhz oscillatorcblock0x20; specify user variables from hex 0x20 Bank 0COUNT1COUNT2COUNT3endcbanksel TRISCclrf TRISC; set TrisC to 0 /Outputsbanksel 0; return to bank 0clrf PORTC; turn off all of PortC outputsStart movlw 0xff; start of main loopmovwf PORTCcall Delay1secmovwf 0x00movwf PORTCcall Delay1secgoto Start; end of main loop; subroutine Delay; avoid the $- , use labels instead; there is a handy delay calculator here; http://www.golovchenko.org/cgi-bin/delayDelay1secbanksel COUNT1movlw 0xFFmovwf COUNT1movwf COUNT2movlw 0x05movwf COUNT3dly1 decfsz COUNT1,fgoto dly1decfsz COUNT2,fgoto dly1decfsz COUNT3,fgoto dly1returnend; end of code

author: dannyf
author_rank: Super Contributor
timestamp: February 21, 2016, 12:56:47 pm
content: Code in C, as it is so much simpler.

author: KL27x
author_rank: Super Contributor
timestamp: February 23, 2016, 02:06:01 am
content: If your config and user register addresses are correct (and no one is going to bother decoding your configuration the way you wrote it) surely Rich found the only obvious problem in your code. FYI, "movwf 0x00" is going to attempt to transfer contents of W register into address 0x00, which is not a user register.But you may want to look at the OPTION register.And double check that all your peripherals are off.Make sure WDT is disabled.And you should probably put an ORG 0x0000 before your code starts. 0x0000 is the reset address.Also, FYI, 0x0004 is the interrupt address, so if you're going to use interrupts you will have to move things around. E.g.org 0x0000goto LABEL_MAINCODEorg 0x0004[interrupt routine, retfie. Or you could CALL or GOTO your interrupt from here and write it somewhere else.]*LABEL_MAINCODE[your main code]Picnmix has a lot of good code suggestionsIf you use the MPLAB header ".inc" file for the 16F630, as he has shown, you will not have to define all your registers. I'm not sure why he changed the start location of your user registers to 0x20. Maybe that's a hint you should double check your datasheet.Here are just a couple of observations:One little thing is the decfsz is going to skip on 0x00, and when it loops back, count1 and count 2 will start at 0x00. So it's odd that you are purposely starting them at 0xFF rather than just clearing them to 0x00. (Unless you just happened to tune your delay to be exactly 257 cycles short on purpose.) So just FYI, using a delay loop like this, 0x01 will be the minimum value and 0x00 will be the maximum. 0xFF is just one of the 254 values in the middle that happens to be one card shy of a full deck.This delay will be pretty long at 4Mhz. If you don't want to wait several seconds to see if your code is working, change count3 to .1. Or remove it altogether.*BTW, that family of PIC doesn't have context saving, so if you are going to use an interrupt, you have to save your STATUS bankbits and contents of W register... you really ought to use the MPLAB template source code for this device, which will be in the MPLAB folder, somewhere.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: February 23, 2016, 06:03:29 pm
content: Quote from: dannyf on February 21, 2016, 12:56:47 pmWe choose to code in assembly language in this decade and do the other things, not because they are easy, but because they arehard.

author: Beninot
author_rank: Newbie
timestamp: February 25, 2016, 07:36:29 pm
content: Quote from: KL27x on February 23, 2016, 02:06:01 amThank you ! Thank you ! Thank you!You were awesomely and deeply right about everything, I followed your advice and found my problem in the datasheet! I'm such a fool, I used a gray register of the memory map, meaning it was unimplemented! changed 0x08 and 0x09 to 0x20 and 0x21 and everything works fine!Now, I'm just asking myself, what happens with count1 after it comes to 0 by decfsz? What's his new value?

author: picandmix
author_rank: Frequent Contributor
timestamp: February 25, 2016, 08:33:53 pm
content: You want to the Mplab IDE (v8.92 shown) SIMulator. ( not sure if its still in MPlabX ? - do not use it )Set the Breakpoints on your code and use the Run and Step functions while viewing the state of the registers in the Watch Window.

author: KL27x
author_rank: Super Contributor
timestamp: February 27, 2016, 10:24:54 am
content: QuoteWhen it becomes zero, decfsz skips the next instruction, so instead of going back to the beginning, it continues to the instruction after that one and goes on to decfsz count2. If count2 isn't zero, yet, the next instruction of goto $-3 will set the pc counter to jump back to the beginning of your delay routine, and count1 decrements from 0x00, rolling over to 0xFF.... which isn't zero, so the next instruction isn't skipped, and things carry on. Count1 is going to start out at 0x00, giving 256 cycles per value of count2, except the first, where you started it at 0xFF, giving it a head start of 1.Hence 0x00 is the max value that will give 256 cycles before skipping. In fact, if you should so prefer to think of it that way, you could initialize count1/2 to .256 or 0x100. The assembler will insert 0x00 into that register, dropping the most significant bit, leaving the "least significant" 8 bits, which are all zeroes.There's nothing wrong with the way you wrote it. (And if you wanted the delay to be 0.000001% shorter, that's how you would do it.) It just suggests that you don't completely understand how your delay loop works. And the more you understand, the less mistakes you are going to make and the more confident you will be in writing code.