![]() | ![]() | ![]() |
| | |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
| | LinkBack | Thread Tools | Display Modes |
| | (permalink) |
| Hi Guys, I have posted a couple of times in the past and had great responses so I hope I can get some more help this time. This is my first attempt at programming a PIC and it is quite an ambitious project. My parts/programmer (Epic) have finally arrived and I loaded the code with great expectations but unfortunately Mr. Murphy stepped in and decided to mess things up! When I wrote the code I put it through the demo version of 'PIC Simulator IDE' and after a couple of tweaks it ran perfectly, EVERYTHING worked as it should. However, when I load the code into my PIC 16F818 I can only get two out of the three subroutines to work. PB1SUB and PB2SUB work fine but PB3SUB executes the first two lines and then hangs for as long as you have the button depressed and then it returns to the main routine. This in itself is odd as the first line should turn off the pushbutton so the length of time it is held should be irrelevant. Interestingly if I 'rem' out all the lines that refer to the random function and add a line of delay code between 'High RLED' and 'Low RLED' I can get the red LED to come on for that period. I have played around with different methods of doing this, using different values, using the 'Random' command and not using it, different methods of seeding etc. but nothing seems to work. I am now stuck as I don't know what to try next. Can anyone make any suggestions on how I can achieve my goal of getting a random time delay in the range 1-30 seconds followed by a random choice of either PB1SUB or PB2SUB. The code is below........ Code: 'set timer option_reg = %11011000 'set TMR0 to internal clock 'set I/O pins TRISA = %00000000 'set PORTA pins (unused pins as OP) TRISB = %00010110 'set PORTB pins (unused pins as OP) 'rename pins to logical names PBCONTROL VAR PORTB.0 'rename RB0 to PBCONTROL PB1 VAR PORTB.1 'rename RB1 to PB1 PB2 VAR PORTB.2 'rename RB2 to PB2 PB3 VAR PORTB.4 'rename RB4 to PB3 BUZZER VAR PORTB.3 'rename RB3 to BUZZER GLED VAR PORTB.5 'rename RB5 to GLED RLED VAR PORTB.6 'rename RB6 to RLED 'set pin status (high/low) High PBCONTROL 'set PBCONTROL high Low BUZZER 'set BUZZER low High GLED 'set GLED high Low RLED 'set RLED low 'set variables RND VAR WORD 'set RND as variable 'set LOOP1 & 2 as variables for loop LOOP1 VAR WORD 'set LOOP1 as variable LOOP2 VAR WORD 'set LOOP2 as variable 'start main routine GoTo Main 'goto main routine 'main program Main: IF PB1 = 0 Then PB1SUB 'check PB1 status if low go to PB1SUB IF PB2 = 0 Then PB2SUB 'check PB2 status if low go to PB2SUB IF PB3 = 0 Then PB3SUB 'check PB3 status if low go to PB3SUB GoTo Main 'go back to the top 'subroutine list PB1SUB: Low PBCONTROL 'turn off PB's Low GLED 'turn off Green LED High BUZZER 'turn on BUZZER For LOOP1=1 TO 500 'pause for 5 secs Next LOOP1 Low BUZZER 'turn off buzzer High GLED 'turn on Green LED High PBCONTROL 'turn on PB's GoTo Main 'return to main prog PB2SUB: Low PBCONTROL 'turn off PB's Low GLED 'turn off Green LED For LOOP1=1 TO 30 'set loop1 length High BUZZER 'turn on BUZZER For LOOP2=1 TO 8 'pause Next LOOP2 Low BUZZER 'turn off BUZZER For LOOP2=1 TO 8 'pause Next LOOP2 Next LOOP1 'go back around loop1 until complete High GLED 'turn on Green LED High PBCONTROL 'turn on PB's GoTo Main 'return to main prog PB3SUB: Low PBCONTROL 'turn off PB's Low GLED 'turn off Green LED High RLED 'turn on Red LED RND=TMR0 & $1F 'load last 5 bits of TMR0 into RND Random RND 'randomise RND RND = (RND // 31) + 1 'Returns a number between 1-30 For LOOP1=1 TO (RND*100) 'pause for RND secs Next LOOP1 RND=TMR0 & $1F 'load last 5 bits of TMR0 into RND a 2nd time Random RND 'randomise RND a 2nd time Low RLED 'turn off Red LED RND = (RND // 31) + 1 'Returns a number between 1-30 IF RND>=15 Then GoTo PB1SUB 'if RND is higher than mid point run PB1 sub-routine Else GoTo PB2SUB 'if RND is lower than mid point run PB2 sub-routine EndIF GoTo MAIN End 'end of program Larry | |
| |
| | (permalink) |
| I know it's bad form to reply to your own post ...but what the heck I have some more info that may be relevant! I carried out some more tests today and made an interesting discovery. I was confused as to why the red LED was not lighting in the PB3SUB routine. As a check I added a line to the other subroutines to turn on the red LED after the green LED is turned off. However I left out a line to turn the red LED off again. On running the subroutines I found that the red LED did indeed light but DID NOT go off (as expected) but when I ran PB3SUB the red LED switched off! I concluded from this that PB3SUB ran through its code and turned the LED off when it came to the relevant line. I further concluded the reason the red LED did not light originally was because the chip bypassed all the code that had to do with the random function and the on/off state was so short (a few instruction cycles....milliseconds) that the LED just didn't get a chance to light. This now makes me think that the error lies in the way I am trying to read the TMR0 time into the 'RND' variable as if this is blank everything that depends on this variable is also blank. I am assuming the offending line is the first one in the block of code below....... Code: RND=TMR0 & $1F 'load last 5 bits of TMR0 into RND Random RND 'randomise RND RND = (RND // 31) + 1 'Returns a number between 1-30 For LOOP1=1 TO (RND*100) 'pause for RND secs Next LOOP1 RND=TMR0 & $1F 'load last 5 bits of TMR0 into RND a 2nd time Random RND 'randomise RND a 2nd time Low RLED 'turn off Red LED RND = (RND // 31) + 1 'Returns a number between 1-30 IF RND>=15 Then GoTo PB1SUB 'if RND is higher than mid point run PB1 sub-routine Else GoTo PB2SUB 'if RND is lower than mid point run PB2 sub-routine EndIF I have read the manual and discovered that the 'Random' command works on a 16 bit variable but (according to the data sheet) TMR0 is an 8 bit timer. Could this be the source of the problem? I am also not sure that the 'RND' variable is correctly defined at the start of the program as a 'word', should it be a 'word' or a 'byte'? Any help would be greatly appreciated as this subroutine is key to the function of the device and it is extremely frustrating to be this close to working and yet the goalposts are still so far away! Thanks, Larry | |
| |
| | (permalink) |
| If you are specectomg seconds dela that will not happen. It is hard to say how long is your FOR...NEXT loop will take to execute from 0 to 3100 being 3100 the longest loop. But say exagerating that the FOR...NEXT loop uses 50 instructions per loop, with a 4Mhz crystal that is 1usec to complete each instruction so (50 * 3100 loops) * 1uSec = 155 msec.... at MAX you will have a 155msec delay, you will never notice that..... Make sure that your delay is set to exactly what you want Ivancho | |
| |
| | (permalink) |
| Hi Ivancho, Thanks for replying to my post. I tried increasing the length of the loop to *1000, *10000 and *100000 but it made absolutely no difference. The loops in PB1SUB and PB2SUB work fine so I doubt it is that. I still think it has to do with the way I am trying to write the contents of TMR0 into the 'RND' variable. Does anyone know if I have to 'interupt' the timer before I can read its value or should I be able to read it directly (the manual is not very clear on this point)? Larry | |
| |
| | (permalink) |
| You can always make a small program so that you check if the TMR0 can be read like you want to..... I believe it can be, and it is correct.... I just think is that is happening to fast. Make a program that reads the TMR0, randomize it and send the value serially. Make sure you only send numbers from 0-255 Also try to do the multiplication outside the FOR...NEXT loop..... instead multiply RND before the loop. Say: Code: RND = RND * 100 For LOOP1=1 TO RND 'pause for RND secs Next LOOP1 Ivancho | |
| |
| | (permalink) |
| Hi Ivancho, Thanks for the suggestion but I now have the problem solved and a fully functioning device. I received some help from another source that pointed me in a totally different direction and the code worked first time. I ended up not using TMR0 and the 'Random' command at all. I simply set up a 'double-nested' for-next loop in the main program and used the count value in that to generate the delay. It works perfectly and uses less code too. I guess I was all tied up with the 'Random' problem and not thinking of alternative ways to get the same result! Larry | |
| |
| | (permalink) |
| Hi Tako Kichi, can you please post the the code for the nested loop I work on a pulse generator and I need to do something similar for delays. Thank you Anemos | |
| |
| | (permalink) |
| Hi Anemos, I have included the relevant bits of code below. Here are the 'defines' I set up prior to the main loop executing. Code: 'set variables RND1 VAR WORD 'set Random1 as variable RND30 VAR WORD 'set Random31 as variable x VAR BYTE 'set x as variable Code: 'main program Main: For RND1 = 0 TO 1 'random sound counter For RND30 = 1 TO 30 'random delay counter IF PB1 = 0 Then PB1SUB 'check PB1 status if low go to PB1SUB IF PB2 = 0 Then PB2SUB 'check PB2 status if low go to PB2SUB IF PB3 = 0 Then PB3SUB 'check PB3 status if low go to PB3SUB Next RND30 Next RND1 GoTo Main 'go back to the top Code: PB3SUB: Low PBCONTROL 'turn off PB's Low GLED 'turn off Green LED High RLED 'turn on Red LED For LOOP1=1 TO (RND30*x) 'pause for RND secs Next LOOP1 Low RLED 'turn off Red LED IF RND1=1 Then GoTo PB1SUB 'if RND1 is 1 run PB1 sub-routine Else GoTo PB2SUB 'if RND1 is 0 run PB2 sub-routine EndIF GoTo MAIN Hope that helps. Larry | |
| |