Generating truly random numbers on a microcontroller is a known difficult task.

One way is to run two different clocks, and measure the clock drift between them.

The PIC16F1783 which I'm using does have two clocks. One using an external crystal and the LFINTOSC which powers the watchdog.

Is there any way to get at the LFINTOSC, while running from the external crystal clock?

One idea I had was to let the watchdog expire, and check the value of TMR2, but it doesn't work because TMR2 is reset by watchdog resets.

One could write a counter to EEPROM in a tight loop and let the watchdog expire, and then inspect the contents of EEPROM, but this seems very inelegant. Edit: It's much better to write to RAM, as suggested in one of the comments.

Is there a better way? Without using external circuitry, and without relying on ADC-noise (which might not always be present)?

Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/40001579E.pdf

Edit: I want the random number to generate a GUID to be able to tell apart multiple devices sharing the same RS485 bus. My idea is to use something similar to 1-wire device discovery. But to do this I need to have different GUID on different devices, and I'd like to avoid the hassle of having to program them with unique ID:s.

  • 1
    \$\begingroup\$ +1 no answer but nice question. A useful aim if achievable. A noise diode MAY be easier albeit needing hardware and a pin. . \$\endgroup\$
    – Russell McMahon
    Jun 14, 2015 at 19:56
  • 1
    \$\begingroup\$ Make use of the "Temperature Indicator Module" that is present. \$\endgroup\$
    – user16222
    Jun 14, 2015 at 20:14
  • 1
    \$\begingroup\$ The temperature itself does not really matter; you are interested in the noise generated during the ADC operation (you could use any other source for the ADC, but the temperature sensor does not need external hardware). \$\endgroup\$
    – CL.
    Jun 14, 2015 at 20:21
  • 1
    \$\begingroup\$ Why would you write to EEPROM, instead of RAM? \$\endgroup\$ Jun 14, 2015 at 20:23
  • 1
    \$\begingroup\$ Microchip cannot break the laws of nature. But in practice, you have to measure how much of a difference you get when the temperature stays mostly constant. (And break all of Microchip's recommendations of how to reduce noise, i.e., use shorter sample times.) \$\endgroup\$
    – CL.
    Jun 15, 2015 at 8:57

1 Answer 1


Okay, I've found a way to do exactly what I asked in the question, without involving the WDT.

It's a bit of a hack, to say the least, and sacrifices two pins (EDIT: only one pin is sacrificed) (but requires no external components, so if you have two unused pins it will be "for free").

The idea is to use the PSMC (Programmable Switch Mode Control) of the PIC16F1783.

This can be clocked from the INTOSC, by way of connecting the HFINTOSC to the 4x PLL, yielding a 64MHz frequency to clock the PWM output.

The PWM output can then be routed to another pin on the PCB.

Now, using the external crystal to clock the CPU, the PWM signal can be read in a tight loop. Since the two clocks are not synchronized, there should jitter between the two clocks, and the PWM input should contain some unpredictable jitter.

On way to use this jitter to build random values could be to have a 16 byte checksum array. The TMR1 could then be configured to run as fast as possible, and every time the PWM signal changes, the TMR1 value could be written to the start of the array. Then the MD5 sum of of the array could be taken, and written back to the same array.

By iterating this procedure a few thousand times, a 16 byte MD5 hash could be built, which should be entirely random.

However, a MD5 checksumming algorithm barely fits on the PIC16F1783, so this is more of use on slightly more powerful chips. The same idea could be used though, by simply incrementing a byte by the TMR1 value, and let it wrap around a few thousand times before considering it "random enough".

The only way this could fail is if the internal 500kHz source would somehow sync up to the crystal oscillator. I have no idea if that is possible.


The following code seems to work in practice in my lab:

#define RAND_SIZE 255
unsigned char random_data[RAND_SIZE];
void make_random_data()
//Used output pin: RC3. Make sure it is unconnected!
PSMC1PRH=0x0; //choose a very short period period

PSMC1DCH=0x00; //set 50% duty



PSMC1CLK=1; //64mhz    

// Zero the id, to make sure any previous value does not influence result.
for(int i=0;i<RAND_SIZE;++i)

// Generate the new random id:
for(int pass=0;pass<1000;++pass)
    for(int j=0;j<RAND_SIZE;++j)
        unsigned char bitmask=1;
        for(signed char bitnum=7;bitnum>=0;--bitnum)
            if (PORTCbits.RC3)
                random_data[j] ^= bitmask;

Update 2:

Only one pin is sacrificed, since it is possible to read the output PWM pin, you don't need to route it to an input and read that.

  • 1
    \$\begingroup\$ Certain types of clocks will tend to sync themselves to other clocks, so this concern may be valid. Not all types do that, so a bit of research would be in order. \$\endgroup\$
    – AaronD
    Jun 15, 2015 at 17:08
  • \$\begingroup\$ Hmm. Maybe the temp sensor idea is better in practice then. \$\endgroup\$
    – avl_sweden
    Jun 15, 2015 at 17:37
  • 1
    \$\begingroup\$ I'd be interested in seeing some test of randomness applied to the output (but not interested enough to do it myself!). Is this something you could do conveniently? \$\endgroup\$ Jun 15, 2015 at 21:20
  • \$\begingroup\$ I've tested both the PSMC clock jitter and temperature sensor approach. Both work, and both can generate a 16 byte serial number in a few seconds on a PIC16F1783. \$\endgroup\$
    – avl_sweden
    Jun 15, 2015 at 21:38
  • \$\begingroup\$ Here is a random string generated using only the clock jitter approach: 1a7b2fecfbb0447fcce418089ea1f56082367cd921a041155181455ac437a8557d2ff122429790b170846df01434ae3c31f9ccd499882b8e38ab30f0adf550abf9ac223cc7e4820bb1956b6960c51ceeb7a59edad202b09cdb1fbd228a0ee63a586368869acc527489fed9f67073aab1f7d2ccd8259bf5980d74802add17caacdcd6f82374bfaedd092b66bc702d4cf84de320b678f2a712685c334c79741cce2c7632a5771d887d32fb52667bc190cc5517a1b0104d28a4b4644662e4dd6ad5dcf7470883de22ea9a399bc0b94a7fc4a5a2233b26900b27fdb16bc15e14bbfdaace1d6ee0568bee186985ab914058128d8208e095e3adac7284f7cce36e69 \$\endgroup\$
    – avl_sweden
    Jun 15, 2015 at 21:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.