Pic programming issue. - Page 1
Forum section: electronics / general

author: RodH
author_rank: Newbie
timestamp: July 11, 2015, 10:24:32 pm
content: I have an assembly program for the pic 16f84a. This program is for model railroaders to start and stop a railroad crossing signal. The program is intended to start when it receives a external pulse from a 555 chip acting as a switch debouncer. The program then causes two LED's to flash alternately and also count the external pulses. When it counts four pulses, it should stop flashing and return to stand bye mode. The program starts, flashes and appears to count pulses, but will not stop. Anyone have an idea?Here is the Assembly code:;======================================================; train crossing light control version 1.0;;======================================================; list p=16f84a; include "p16f84a.incradix hex;======================================================; cpu equates (memory map)tmr0 equ 0x01status equ 0x03porta equ 0x05portb equ 0x06intcon equ 0x0bvar1 equ 0x30var2 equ 0x31;;======================================================; variables; store;;======================================================;config_xt_osc;;;======================================================org 0x00goto start ;skip interrupt vector;start org 0x004bcf intcon,7 ;disable global interruptmovlw b'11110000'tris portb ;setup port b 1=in,0=outmovlw b'00000000' ;clear port bmovwf portb ;clear port bmovlw b'11010111'optionbcf status,2pgm btfsc portb,6 ;test bit 6,port bcall init ;starts lampsgoto pgm ;repeat;==========================================================initmovlw b'00000001'movwf var2 ;start sensor countgoto first;=========================================================firstmovlw b'00000000'movwf var1 ;inital load (0) storebsf portb,0 ;set first lampclrf tmr0 ;clear/start timer0goto circle ;check timer flagbtfsc portb,6call add1 ;check switchgoto second;==========================================================secondbcf portb,0 ;clear lamp 1bsf portb,1 ;set set lamp 2movlw b'00000000'movwf var1 ;clear storebtfsc portb,6call add1 ;check switchgoto third;===========================================================circlebtfsc portb,6 ;check switchcall add1btfss intcon,2 ;check tmr0 flag,skip next on truegoto circlebcf intcon,2 ;clear tmr0 flagclrf tmr0 ;start tmr0incf var1 ;add 1 to var1btfsc portb,6 ;check switchcall add1movlw 5 ;place value in wnopsubwf var1,w ;subtract var1 from wbtfss status,2goto circlebcf status,2goto second ;lamp 1 to lamp 2;===========================================================add1incf var2 ;add one to countreturn;===========================================================thirdbtfss intcon,2 ;check tmr0 flag,skip next on truegoto thirdbcf intcon,2 ;clear timer flagclrf tmr0 ;start timer0btfsc portb,6 ;check switchcall add1incf var1 ;add 1 to var1movlw 5 ;place value in wnopsubwf var1,w ;subtract var1 from wbtfss status,2goto thirdmovlw b'00000001' ;preset port b with green lamp onmovwf portb ;complete presetbtfsc portb,6call add1 ;check switchclrw ;clear wmovlw 4nopsubwf var2,w ;checking switch countbtfss status,2goto first;lights off back to presetgoto start;=======================================================================end

author: MarkF
author_rank: Super Contributor
timestamp: July 12, 2015, 03:51:58 am
content: Any reason you're not doing this in C. It would be so much easier.For example:Code:#include <xc.h>#include <stdint.h>// CONFIGURATION BITS#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)#pragma config WDTE = OFF // Watchdog Timer (WDT disabled)#pragma config PWRTE = ON // Power-up Timer Enable bit (Power-up Timer is enabled)#pragma config CP = OFF // Code Protection bit (Code protection disabled)#define _XTAL_FREQ 20000000L // 20MHz clock#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))uint8_t Xing=0; // switch countuint8_t LEDbits=3; // portB bits 0 and 1 for LEDs (0=LED On, 1=LED Off)uint8_t TRIGenable=1;uint8_t frame=0;void main(){OPTION_REGbits.nRBPU=1; // Port B pull-ups disabledTRISA = 0xff; // Set Port A direction bitsTRISB = 0xf0; // Set Port B direction bitsPORTB = LEDbits;// MAIN LOOPwhile (1) {// Look for external pulseif (PORTBbits.RB6 == 1 && TRIGenable) {Xing++; // increment pulse countTRIGenable = 0;}else if (PORTBbits.RB6 == 0) { // wait for pulse to go awayTRIGenable = 1;}// Process RR Crossing LEDsif (Xing > 0) {// start LED flashing if both are offif (LEDbits == 3) {frame = 0; // restart frame countLEDbits = 1; // turn on one LEDPORTB = LEDbits; // output to portB}// toggle LEDs when frame count wrapselse if (frame == 0) {LEDbits ^= 3; // toggle LEDsPORTB = LEDbits; // output to portB}// stop LED flashing if 4 pulses receivedelse if (Xing >= 4) {Xing = 0;LEDbits = 3; // turn off LEDsPORTB = LEDbits; // output to portB}// increment frame count and wrap when time delay reached// toggle LEDs every secondif (frame++ >= 25) frame = 0;}delay_ms(20); // 50 Hz loop}}

author: android
author_rank: Regular Contributor
timestamp: July 12, 2015, 07:40:10 am
content: I'm not sure if this helps, but the code in red will never be executed...Quote

author: rolycat
author_rank: Super Contributor
timestamp: July 12, 2015, 08:10:50 am
content: Other questions might include:Why use a 555 timer to debounce your switch when it is connected to a microcontroller?Why use a prehistoric chip like the 16F84A, rather than, say, the 16F1847, which is pin-compatible, doesn't require an external oscillator, has vastly more capability and costs three times less?

author: picandmix
author_rank: Frequent Contributor
timestamp: July 12, 2015, 09:29:32 am
content: There are a few set up errors with your code, the attached file has corrected them , though I have not gone though the actual logic of your main loop.Could do that later if you are still stuck.As said you can use the Pic to sense a switch, as long as its a voltage below 5v.Use the btfss/c PORTB,1 instructions to read in the signal, and then use a small software delay of say 50 ms to debounce the input , then use the btfss/c again to ensure it is on.Examples here -http://www.winpicprog.co.uk/pic_tutorial2.htmThis site has a handy delay calculator.http://www.golovchenko.org/cgi-bin/delayAs Rolycat mentions you can use more modern chips, but you will also need a modern programmer whereas you may well be using a simple 'el cheapo' programmer that will do what you need on the 84A for now.

author: 22swg
author_rank: Frequent Contributor
timestamp: July 12, 2015, 09:39:17 am
content: I ran your code in MPLAB first thing that cropped up was that Watch dog timer had not been disabled . this timer will reset the pic continually, your file should have a config line, something like this...Code:LIST P=16F84a#INCLUDE <P16F84a.INC>__CONFIGH'3FF0' ; CP OFF (B13-B4): PWRT ENABLED: WD DISABLED__BADRAM H'07', H'50'-H'7F', H'87' ; XT= LP or whatever ! ;add this and see where you get .

author: picandmix
author_rank: Frequent Contributor
timestamp: July 12, 2015, 04:33:44 pm
content: Missed one of the Bank1 registers, so you need to amend the code as follows to ensure the Option Register is used properly.Also what frequency crystal or similar are you using ? your code contained XT_OSC so that indicates a crystal up to 4 MhzIs the code your own or from a web page, if so can you give a link ?Code:startbcf intcon,7 ;disable global interruptmovlw b'11110000'banksel TRISBmovwf TRISB ;setup port b 1=in,0=outmovlw b'11010111'movwf OPTION_REGbanksel 0movlw b'00000000' ;clear port bmovwf portb ;clear port bWith the above code corrections to the start up section your code , the whole program runs in a simulator.When the switch is closed it will start flashing at about 1hz ( with a 4mhz oscillator, (not shown in the simulator diagram) ) but even with lots of on/offs from the switch nothing seems to stop the flashing.Think a bit of work and you will be able to fix it ....?

author: Dinsdale
author_rank: Regular Contributor
timestamp: July 13, 2015, 04:44:08 pm
content: You also have a call to "init" for which there is never a return. It does not hurt anything since that enters a loop that is never exited, but you have used up one stack level.

author: RodH
author_rank: Newbie
timestamp: July 14, 2015, 06:37:31 pm
content: Thank you all for your comments.. However, the program runs in my emulator without problems. Where it does not run is in the circuit board I created to support it. In the circuit, it responds to the first pulse, the lights flash as desired; but it does not respond to any other pulses in order to stop it. That is the problem and why I asked for help. I had hoped someone would see a software issue that I have overlooked.

author: Andy Watson
author_rank: Super Contributor
timestamp: July 14, 2015, 06:55:33 pm
content: Quote from: RodH on July 14, 2015, 06:37:31 pmWhich strongly suggests either a problem with the hardware, or a mis-understanding of the real-world interface of the PIC. Can you give some more details of the hardware?

author: picandmix
author_rank: Frequent Contributor
timestamp: July 14, 2015, 07:57:31 pm
content: Quote from: RodH on July 14, 2015, 06:37:31 pmBecause there were so many corrections needed to the set up part of the code, assumed that was the main cause of your problems and with the code I sent you would be able to resolve that last problem within your main loop.Will take a further look at your code and see if I can spot the problem.Am I correct with the schematic I showed above ? and that it uses a 4mhz crystal ?

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: July 14, 2015, 10:05:11 pm
content: Quote from: RodH on July 14, 2015, 06:37:31 pmPerhaps you didn't simulate it thoroughly enough. I tried simulating your code in MPLAB 8 and found a problem here:-Code:circlebtfsc portb,6 ;check switchcall add1btfss intcon,2 ;check tmr0 flag,skip next on truegoto circleIf the switch is held closed then it will continuously add 1 to var2. This loop is only a few instructions so it counts very quickly (about 9us per count). When the switch is opened again at some later time, var2 will be a random number between 0 and 255.This is a problem because later you stop the flashing sequenceonlyif var2 = 4...Code:movlw 4nopsubwf var2,w ;checking switch countbtfss status,2 ;<-- skpz = skip if zero (ie. if var2 = 4)goto first;lights off back to presetgoto start...but since the value of var2 is random, there is only one chance in 256 of the sequence stopping!Is the 'call add1' in 'circle' some kind of debounce timer? If so then perhaps you should only call add1 onlyaftertimer 0 overflows, stop counting (in add1) if/when it gets to 255, and use skpc instead of skpz when testing the switch count so that it will skip on a count which is equal toor higherthan the debounce value you are comparing it to.When using mechanical switches you have to assume that the switch could be on or off for long periods of time, or even flicking between on and off. When simulating a switch I set breakpoints at places in the code where the switch's action should trigger a response (eg. starting the flashing light sequence, turning the lights off and restarting). I then toggle the I/0 port to simulate turning the switch on and let the programrununtil it hits a breakpoint, thencontinuerunning from the breakpoint (without toggling the switch off) to see where it will end up next. This should show up any 'holes' in the program that let it fall through to places you don't want it to reach while the switch is held down.A few notes on style:-1. Use the official register names and bits defined in the device's include file, eg. 'bcf INTCON,TMR0IF'2. Use built in macros such as 'skpz', rather than the obtuse 'btfss status,2'3. Assign symbolic names to raw numbers wherever practicable, eg. '#define SWITCH 6', 'btfsc PORTB, SWITCH'.This will make your code easier to follow and more maintainable. It is much easier and less error prone to change one define, rather than having to hunt through all your code looking for a particular number just to change a port pin!

author: picandmix
author_rank: Frequent Contributor
timestamp: July 14, 2015, 10:35:02 pm
content: I should have given your code a better look earlier as afraid your code will not work in its present form, despite it appearing to run in a simulator, which is more by chance.You are using Timer0 as your delay source but that can only divide the main frequency by 256 so even if using a watch crystal at 32khz that means its maximum delay can only be - Fosc/4 / prescaler = 32k/4 / 256 = 1/32 of a second.You have two options , continue with Timer0 as the source to a larger software delay loop or use a pure sofware loop like the ones I pointed to in the link earlier.Thats why you need to state what frequency oscillator /crystal you are using, as until thats given no timings can be established.Can give you some help if you cannot see a way forwards by yourself as your code does need rewriting, but its not that complex to achive what you want to do.Edit - just to get you on the right track here is your code but with the start and flasher code rewritten using a 1 second software delay based on a 4mhz crystal ( value can be easily changed).See what you think ... Have some thoughts on how I would complete it, but think you might like to try it yourself first .. ?

author: picandmix
author_rank: Frequent Contributor
timestamp: July 15, 2015, 04:05:55 pm
content: Below is a .hex file for the complete routine you might be able to simulate or run on your hardware.Its based on a 4mhz crystal or r/c. - frequency can be easily changed.What it can also do, is act as a debouncer for your switch as it can handle any length of ON pulse * without affecting the flashing leds timings.* currently based on a minimum ON pulse of 100ms, though that can be reduced if needed.Have not included the source code yet, as perhaps you want to try and complete the coding yourself , as mentioned yesterday.

author: jnz
author_rank: Frequent Contributor
timestamp: July 17, 2015, 03:34:46 am
content: I find it fascinating that beginners will try and use ASM and deal with the issues over just learning basic C elementsIt's the weird sharp curve where noobs and experts are likely to use assembly.

author: RodH
author_rank: Newbie
timestamp: July 17, 2015, 07:21:19 pm
content: As a matter of fact, jnz I learned to use assembly language on the pic microcontrollers in a college course while earning my BS in engineering.. Your comment looks like one of those made by trolls on Facebook.

author: picandmix
author_rank: Frequent Contributor
timestamp: July 17, 2015, 10:00:46 pm
content: Quote from: jnz on July 17, 2015, 03:34:46 amI must be really weird then, I started programming NatSemi micro chips in Machine Code .......

author: picandmix
author_rank: Frequent Contributor
timestamp: July 17, 2015, 10:02:08 pm
content: Quote from: RodH on July 17, 2015, 07:21:19 pmAny progress with your project ?My code below if you need it.