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.

Pic Basic Pro / PIC Problem

Status
Not open for further replies.

Tako Kichi

New Member
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

Thanks,

Larry
 
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

Does anyone know if this is the correct way to load a TMR0 value into a variable for use by the 'Random' command? Or if not what is the correct way to do it

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
 
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
 
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
 
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

Good Luck

Ivancho
 
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
 
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
 
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

Here is the nested loop in the main program.

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

It runs around in the inner loop before incrementing the outer loop. The loop count is then used to set the random delay in the 'PB3SUB' subroutine as shown below.

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

The device is set up so that the operator can select one of four maximum delay times on power up. The software checks if any buttons are held down at power up and assigns a value to 'X' accordingly.

Hope that helps.

Larry
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top