Continue to Site

# PIC math question

Status
Not open for further replies.

#### Tako Kichi

##### New Member
Hi,

I am working on my first PIC project using a 16F818 and have hit a math problem that currently has me stumped. I am writing the program in PIC Basic but can insert assembly code blocks if required. My problem is as follows:

I need to generate a pseudo random number that falls between 1 and 60. I know how to generate the random number (there is a RANDOM command available) and at the moment I have stored this in location 'W1'. However, the number can be between 1 and 65,535 and this is where my math skills are letting me down. I need a way of reducing that random number until it falls into the 1-60 range so that I can then use that figure to generate a delay in seconds based on the new number.

I had thought about trying to 'sample' the last 7 bits of the number and just using those (the idea was that it would be between 1 and 63 which is close enough) but cannot find a way to do that.

I have also thought about dividing by both 32 and 100 to try to 'shift' the number into the required range but again I have had no luck as I do not know what the number is and therefore how many times I would need to go around a loop to reduce it.

Does anyone know of a method where I can either limit the random number to the 1-60 range or a method of reducing some unknown number until it falls into that range?

Any help will be gratefully received as I have now come to a complete stop on this project until I can get this sorted.

Thanks,

Larry

Hmmmmm........I think I may have just found the answer! :lol:

I was just doing some research when I came across information on 'bitwise operators' and I think this will work for me.

Maybe someone can tell me if the following code will work.......

NOTE: W1 has already been 'seeded' with a starting number

Random W1 .......................'randomise W1 and store in W1
W1 = W1 & %00111111.......'apply AND 'mask' to give #<=63
Pause W1 * 1000.................'pause for W1 secs

Can anyone see a problem with the above code?

Larry

Maybe you can multiply the random number W1 with 60 and divide by 65536 (by tuncating the lower 16 bits of the 24-bit product). This results in a random number less than 60. Add the result by 1 and it's 1 to 60 number.

Thanks for that!

I just did some major number crunching on the calculator to check that out and it looks like that will work just fine for what I need.

I guess I should have seen that way out but sometimes you can't see the wood for the trees eh! Plus, I have a disability that sometimes leaves me with 'brain fogs' where even simple mental tasks become major chores. :cry:

Larry

OK....now I have something strange going on and I can't seem to find a cure.....can anyone help?

I have written my code and downloaded the "PIC Simulator IDE" demo program to test it on (a great program BTW!) Everything works fine until it gets to the 'PB3' subroutine where my random number/timer code is. Whenever I run the program it seems to delay for exactly the same time and ALWAYS outputs the 'PB2' subroutine (it should randomly select EITHER 'PB1SUB' or 'PB2SUB').

I have searched this forum and others for clues and have tried a number of variations on the code and I still get the SAME delay and only the 'PB2' output. I originally 'seeded' the random generator with a fixed number but then discovered that it will ALWAYS produce the same number by doing this. So after reading another post (elsewhere) I decided to use the length of time the pushbutton was pressed to seed the random generator, but I still get the same delay and the same 'PB2' output to the buzzer pin.

I wondered if I was having problems with the 'pause' command and changed every pause to a time wasting loop but it still gives the exact same result.

Considering this is my first PIC project I am pleased to have it working this far but I would really like to fully understand this 'random' command and why I can't get the program to actually randomly select one option from a choice of two after a pseudo random time delay of 1-60 seconds.

Once again any help will be greatfully received and I have included my code at the end.

Larry

'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
SPIN VAR WORD 'set SPIN 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

'subroutine list

PB1SUB:
Low PBCONTROL 'turn off PB's
Low GLED 'turn off Green LED
High BUZZER 'turn on BUZZER
For LOOP1=1 TO 5000 'pause for 5 secs
Next LOOP1
Low BUZZER 'turn off buzzer
High GLED 'turn on Green LED
High PBCONTROL 'turn on PB's

PB2SUB:
Low PBCONTROL 'turn off PB's
Low GLED 'turn off Green LED
For LOOP1=1 TO 5 'set loop1 length for 5 secs
High BUZZER 'turn on BUZZER
For LOOP2=1 TO 500 'pause for 0.5 secs
Next LOOP2
Low BUZZER 'turn off BUZZER
For LOOP2=1 TO 500 'pause for 0.5 secs
Next LOOP2
Next LOOP1 'go back around loop1 until complete
High GLED 'turn on Green LED
High PBCONTROL 'turn on PB's

PB3SUB:
While PB3=0 'spin for button press time
Spin=Spin+21 '21 just speeds things up
Wend
Low GLED 'turn off Green LED
High RLED 'turn on Red LED
Low PBCONTROL 'turn off PB's
RND=SPIN 'let RND=SPIN
Random RND 'randomise RND
RND=(RND*60/65535)+1 'truncate RND TO fall between 1 and 60
For LOOP1=1 TO (RND*1000) 'pause for RND secs
Next LOOP1
Random RND 'randomise RND again
RND=(RND*60/65535)+1 'truncate RND TO fall between 1 and 60
Low RLED 'turn off Red LED
IF RND>=30 Then PB1SUB 'if RND is higher than 30 run PB1 sub-routine
GoTo PB2SUB 'if RND is lower than 30 run PB2 sub-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 and check again

End 'end of program

Status
Not open for further replies.

Replies
11
Views
3K
Replies
0
Views
65
Replies
25
Views
3K
Replies
9
Views
1K
Replies
22
Views
3K