I don’t know about you, but I quickly got bored of always starting the ball in the same place. I’ve added some code to make that position random. The PSoC 6 device has an on-board true random number generator but, I’ll be honest, I’ve not looked up how to use it yet! So I shall use the poor-man’s option – read the noise on a pin with the ADC. Maybe I’ll circle back to this in the future and do it right!
The ADC on the PSoC 6 connects to port 10 and, after a quick scan of the kit silk screen I found that P10.7 has nothing connected to it (other than a solder hole). OK, that’s a lie. It was not quick and I did not find it. It’s been years since I could read a silk screen with my clapped-out old peepers. I had to go find a teenager and bribe him to read it for me. Why am I so honest with you on this blog???
Anyway, this pin will have enough noise to be a good random number seed. Note that I will not use the noise itself as the random number because it does not have a wide range of values. I’d just get a varying number in a small area of the screen. Instead I am going to use a pair of C stdlib run-time library functions. Start by including the header file.
Write this simple function to get a random number from the library rand() function and constrain it to a desired range.
uint32_t getRandomInRange( uint32_t lo, uint32_t hi )
uint32_t num = rand();
num %= ( hi - lo );
num += lo;
Then change the bounce() function to call this function instead of hard-coding the values.
uint16_t xPos = getRandomInRange( BOX_LEFT + radius, BOX_RIGHT - radius );
uint16_t yPos = getRandomInRange( BOX_TOP + radius, BOX_BOTTOM - radius );
The last job is to get the random number and use it as a seed. I did this in a function with a pin as argument so I could experiment with different pins and verify that P10.7 is a good choice. The function initializes the ADC and selects a channel for the desired pin, then it reads the voltage at the pin and passes that value to srand() as the seed argument. Then it dutifully deinitializes the ADC like a good function should.
void initRandomNumber( cyhal_gpio_t noisy_pin )
/* Turn on the ADC for the specified pin */
cyhal_adc_init( &adc, noisy_pin, (cyhal_clock_divider_t*)NULL );
cyhal_adc_channel_init( &channel, &adc, noisy_pin );
/* Read the noise (random) and use it as the seed */
seed = cyhal_adc_read_u16( &channel );
srand( seed );
/* Turn off the ADC */
cyhal_adc_channel_free( &channel );
cyhal_adc_free( &adc );
Call this function from main(), with the argument “P10_7”, which is defined in the BSP, before you call bounce().
initRandomNumber( P10_7 );
Program the kit with the new program and you’ll see that it (probably) does not start the ball in the center of the box. Good eh? Try resetting the kit a few times and the start point should change every time.
As before I have attached a copy of the main.c source file for your reference. I think we have had as much fun as you can have with just one ball now. Next time, I am going to add an RTOS to my project and spawn multiple ball-bouncing tasks…