News:

;) This forum is the property of Proton software developers

Main Menu

Really Random number generator Library

Started by top204, Mar 28, 2021, 08:41 PM

Previous topic - Next topic

top204

All microcontroller's and microprocessors generate "pseudo" random values, and not "actual" random values. So there is a repetition to them at some point, depending on the size of the variables internally used to store the newly generated pseudo random values.

The Proton8 and Proton24 (soon to be re-named Position8 and Positron16 compilers), use a 16-bit internal system variable and rely on the Seed command to give the compiler's random number generating Asm code its initial start for the pseudo value generation. However, if the same value is placed in the Seed command at the start of a program, the same sequence of pseudo random values will be produced from the Random command, and that can be a problem. If the microcontroller has an RTC (Real Time Clock) attached to it, its values can be used for the Seed command's parameter, because they will always be different because time and dates change constantly.

There are ways to get, close to, true random numbers, but they rely on the outside world's "noise". Noise in so much as electronic noise generated by stray RF or AC signals or a PN junction from a noisy transitor or diode.

The Really Random library uses an open-ended ADC channel to produce random noise, and this noise triggers the creation of a set or cleared bit, and within a loop, the bits are built into 8-bit or 16-bit variables by gathering X amount of random bits and joining them together in a variable of the correct size.

Sounds simple doesn't it? And it is. Below is the Really Random library code listing for Proton8, and you can see that the random bit generation uses the ADC channel "AN0", but this can easily be changed to another ADC channel:
$ifndef _real_random_inc_
$define _real_random_inc_
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Produce really random values from an open ADC channel on the device.
' Uses the AN0 ADC channel to create a random bit, then uses the bit to build random bytes or words.
'
' Written by Les Johnson for the Proton8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
' Create a global variable for the procedures to share
'
    Dim Rand_bIndex As Byte

'----------------------------------------------------------------------------------------
' Create a random bit from an open AN0 ADC channel
' Input     : None
' Output    : Returns the random bit value
' Notes     : Make sure that no connection is made to the ADC channel being used
'           : Also make sure it is not near a continuous signal device, such as a USB keyboard, AC light bulb etc...
'           : A noisy transistor or diode circuit would work well connected to the ADC's input
'
Proc hCreateRawBit(), Bit
    Set ANSELA.0                            ' Set RA0 (AN0) to analogue
    Low PORTA.0                             ' Pull the ADC pin low
    Set PORTA.0                             ' Set the ADC pin high
    Input PORTA.0                           ' Make the ADC pin an input
    Result = ADIn(0)                        ' Return bit-0 of the the ADC value
EndProc

'----------------------------------------------------------------------------------------
' Software whiten bits using a Von-Neumann algorithm
' Input     : None
' Output    : Bit STATUS.0 (Carry Flag) holds the random bit value
' Notes     : None
'
Proc Rand1(), STATUSbits_C
    Dim bTemp1 As Byte
    Dim bTemp2 As Byte

    Do                                              ' Create loop
        bTemp1 = hCreateRawBit()                    ' Create a raw bit in bTemp1 from an ADC reading
        bTemp2 = hCreateRawBit()                    ' Create a raw bit in bTemp2 from another ADC reading
        bTemp2 = bTemp2 << 1                        ' Rotate bit-0 into bit-1 position
        bTemp1 = bTemp1 | bTemp2                    ' Or in the first random bit read
        If bTemp1 = 1 Then Result = 0 : ExitProc    ' 1 to 0 transition, so return a zero bit
        If bTemp1 = 2 Then Result = 1 : ExitProc    ' 0 to 1 transition, so return a one bit
    Loop                                            ' Loop until a valid value is found
EndProc

'--------------------------------------------------------------------------
' Create a random 16-bit integer value between minimum and maximum values
' Input     : pMin holds the minimum random value to return
'           : pMax holds the maximum random value to return
' Output    : Returns a random value
' Notes     : Maximum 16-bit return (0 to 65535)
'           : Uses the equation (Random Value // (pMax - pMin)) + pMin
'
Proc Rand16(pMin As Word, pMax As Word), Word
    If pMax < 65535 Then
        pMax = pMax + 1
    EndIf
    For Rand_bIndex = 15 To 0 Step -1       ' Create a loop to make a random word
        Rand1()                             ' Get a random bit into the Carry bit
        Rol Result                          ' Rotate the Carry bit into the Result variable
    Next
    pMax = pMax - pMin
    Result = Result // pMax
    If pMin <> 0 Then
        Result = Result + pMin
    EndIf
EndProc

'--------------------------------------------------------------------------
' Create a random 8-bit integer value between minimum and maximum values
' Input     : pMin holds the minimum random value to return
'           : pMax holds the maximum random value to return
' Output    : Returns a random value
' Notes     : Maximum 8-bit return (0 to 255)
'           : Uses the equation (Random Value // (pMax - pMin)) + pMin
'
Proc Rand8(pMin As Byte, pMax As Byte), Byte
    If pMax < 255 Then
        pMax = pMax + 1
    EndIf
    For Rand_bIndex = 7 To 0 Step -1        ' Create a loop to make a random byte
        Rand1()                             ' Get a random bit into the Carry bit
        Rol Result                          ' Rotate the Carry bit into the Result variable
    Next
    pMax = pMax - pMin
    Result = Result // pMax
    Result = Result + pMin
EndProc

'--------------------------------------------------------------------------------
' Create a floating point random number between 0 and 1
' Input     : None
' Output    : A floating point value of 0 to 1
' Notes     : None
'
Proc fRand(), Float
    For Rand_bIndex = 15 To 0 Step -1       ' Create a loop for the 16-bits
        Rand1()                             ' Get a random bit into the Carry bit
        Rol Result.Word                     ' Rotate the Carry bit into the Result variable cast as a word type
    Next
    Result = Result.Word / 65536.0
EndProc

$endif

The library works realy well, as long as the open ADC channel is not too near a signal that has repetition to it that can cause organised noise. i.e. Too close to a USB cable or unit, or AC light bulbs etc...

A better way, would be to use a simple circuit using a transistor or diode that generates random white noise, attached to the ADC input. They are simple circuits that consist of about 3 or 4 components. An internet search for "random noise generator" or "white noise generator" will give many circuits to use: Random and White Noise Generator Circuits 

I used  this type of white noise circuit when I was a boy to make snare drum circuits and cymbal circuits for a drum synthesiser. :-)

The ADC's VREF+ could be brought to a low voltage, so a low voltage output from the single or double transistor white noise generator will give good ADC sample values, without an intermediate amplifier, because, remember, it is only bit-0 of the ADC's reading value that is used to build the random variables.

Below is a demo program using the Really Random library that displays dice faces on a serial terminal based upon random numbers between 1 and 6. The demos I have written and tested do not have any external circuitry attached to the ADC input, it is just left floating, and they still give excellent random numbers because of environmental noise.
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Display Dice faces on the serial terminal using the real random library
' Uses AN0 as the ADC channel for the random bit generator, but this can be changed within the library code
'
' Written by Les Johnson for the Proton8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F26K40                       ' Tell the compiler what device the code is being compiled for
    Declare Xtal = 16                       ' Tell the compiler that the device will be running at 16MHz
'
' Setup the USART1 peripheral
'
    Declare Hserial_Baud = 9600             ' Set the Baud rate for USART1
    Declare HRSOut_Pin = PORTC.6            ' Choose the TX pin for USART1

    Include "Real_Random.inc"               ' Load the Real Random library into the program
'
' Create some variables for the demo
'
    Dim wRandomValue As Word               ' Holds a 16-bit random value
    Dim bRandomValue As Byte               ' Holds an 8-bit random value
    Dim bFoundSix    As Byte = 0           ' Holds the amount of random number 6s that have been created
    Dim bFoundFive   As Byte = 0           ' Holds the amount of random number 5s that have been created
    Dim bFoundFour   As Byte = 0           ' Holds the amount of random number 4s that have been created
    Dim bFoundThree  As Byte = 0           ' Holds the amount of random number 3s that have been created
    Dim bFoundTwo    As Byte = 0           ' Holds the amount of random number 2s that have been created
    Dim bFoundOne    As Byte = 0           ' Holds the amount of random number 1s that have been created

'------------------------------------------------------------------------------------------------
' The main program loop starts here
' Create the faces of a dice on the serial terminal
' and show how many times a number is chosen
'
Main:
    ADC_Setup()                             ' Setup the ADC peripheral for a PIC18F26K40 device

    Do                                      ' Create an infinite loop
        HRSOut 1                            ' Clear the serial terminal, if it supports it
TryAgain:
        bRandomValue = Rand8(1, 6)          ' Create a random value between 1 and 6
        Select bRandomValue                 ' Check the value of the random number
            Case 6
                HRSOut "-----------\r"
                HRSOut "| O     O |\r"
                HRSOut "|         |\r"
                HRSOut "| O     O |\r"
                HRSOut "|         |\r"
                HRSOut "| O     O |\r"
                HRSOut "-----------\r"
                Inc bFoundSix
            Case 5
                HRSOut "-----------\r"
                HRSOut "| O     O |\r"
                HRSOut "|         |\r"
                HRSOut "|    O    |\r"
                HRSOut "|         |\r"
                HRSOut "| O     O |\r"
                HRSOut "-----------\r"
                Inc bFoundFive
            Case 4
                HRSOut "-----------\r"
                HRSOut "| O     O |\r"
                HRSOut "|         |\r"
                HRSOut "|         |\r"
                HRSOut "|         |\r"
                HRSOut "| O     O |\r"
                HRSOut "-----------\r"
                Inc bFoundFour
            Case 3
                HRSOut "-----------\r"
                HRSOut "| O       |\r"
                HRSOut "|         |\r"
                HRSOut "|    O    |\r"
                HRSOut "|         |\r"
                HRSOut "|       O |\r"
                HRSOut "-----------\r"
                Inc bFoundThree
            Case 2
                HRSOut "-----------\r"
                HRSOut "|       O |\r"
                HRSOut "|         |\r"
                HRSOut "|         |\r"
                HRSOut "|         |\r"
                HRSOut "| O       |\r"
                HRSOut "-----------\r"
                Inc bFoundTwo
            Case 1
                HRSOut "-----------\r"
                HRSOut "|         |\r"
                HRSOut "|         |\r"
                HRSOut "|    O    |\r"
                HRSOut "|         |\r"
                HRSOut "|         |\r"
                HRSOut "-----------\r"
                Inc bFoundOne
            Case Else
                GoTo TryAgain
        EndSelect
        '
        ' Display how many times a particular random number is generated
        '
        HRSOut "Amount of times found\r"
        HRSOut "6: (", Dec3 bFoundSix, ") ", Rep "*"\bFoundSix, 13
        HRSOut "5: (", Dec3 bFoundFive, ") ", Rep "*"\bFoundFive, 13
        HRSOut "4: (", Dec3 bFoundFour, ") ", Rep "*"\bFoundFour, 13
        HRSOut "3: (", Dec3 bFoundThree, ") ", Rep "*"\bFoundThree, 13
        HRSOut "2: (", Dec3 bFoundTwo, ") ", Rep "*"\bFoundTwo, 13
        HRSOut "1: (", Dec3 bFoundOne, ") ", Rep "*"\bFoundOne, 13

        wRandomValue = Rand16(500, 1000)    ' Get a random value between 500 and 1000
        DelayMS wRandomValue                ' Delay by the random number of milliseconds
    Loop

'------------------------------------------------------------------------------------------------
' Setup the ADC peripheral for a PIC18F26K40 device
' Input     : None
' Output    : None
' Notes     : Set for 10-bit operation
'
Proc ADC_Setup()
    ADLTHL  = %00000000
    ADLTHH  = %00000000
    ADUTHL  = %00000000
    ADUTHH  = %00000000
    ADSTPTL = %00000000
    ADSTPTH = %00000000
    ADRPT   = %00000000
    ADPCH   = %00000000
    ADCAP   = %00000000
    ADCON0  = %10000100         ' Right justify for 10-bit operation, FRCADGO stop, ADON enabled, ADCONT disabled  , ADCS is ADCLK
    ADCON1  = %00000000         ' ADDSEN disabled, ADGPOL digital_low, ADIPEN disabled, ADPPOL VSS
    ADCON2  = %00000000         ' ADCRS 0, ADMD Basic_mode, ADACLR disabled, ADPSIS ADRES
    ADCON3  = %00000000         ' ADCALC First derivative of Single measurement, ADTMD disabled, ADSOI ADGO not cleared
    ADSTAT  = %00000000         ' ADAOV ACC or ADERR not Overflowed
    ADREF   = %00000000         ' ADNREF VSS, ADPREF VDD
    ADACT   = %00000000         ' ADACT disabled
    ADCLK   = %00000100         ' FOSC/16 (FOSC / (2 * (n + 1)))
    ADACQ   = %00000000
EndProc

On a serial terminal, the above program produces the display:
-----------
| O     O |
|         |
| O     O |
|         |
| O     O |
-----------
Amount of times found
6: (011) ***********
5: (006) ******
4: (015) ***************
3: (004) ****
2: (012) ************
1: (003) ***
The above was copied after the demo program was running for a few minutes.

If using a different device to the PIC18F26K40 in the demo and library procedures, the ADC will need to be set up differently to suit the device being used.

The attached zip file has the Really Random library and some demo programs showing it working.