The idea is to chain 8bit registers together, select some of the registers, feed into an XOR gate and feedback the output of the XOR gate into register zero
I chose to use eight 8 bit shift registers (giving 64 registers numbered 0 to 63) and take the output of registers 61 and 62 to drive the XOR gate.
See the attached drawing 'Shift Register 1'
The shift gates are controlled by a PIC18F46K22 on an Olimex40 pin board. See drawing 'Olimex Shift Register.'
The stream of 1s and 0s have some surprising properties:
- Quasi-random with a cycle length that is amazingly long - thousands of years when run at 100MHz.
- Statistics - The probability of consecutive 1s is 50%. So, if 30 consecutive 1s occur 42 times, consecutive 29 will occur 21 times - and so on.
The code is below along with the two drawings
Code: Select all
////////////////////////////////////////////////////////////////////////////////
// Project: Shift Register //
// File: Shift_Register.c //
// Function: Drive the 74HC595 8bit shift registers in a 64bit chain //
// with feedback taps at 61 and 62 //
// MCU: PIC18F64K22 //
// Board: Olimex 40 pin //
// Power 5V //
// Compiler: mikroC PRO for PIC version 7.6.0 //
// Programmer: ICD3 //
// Author: WVL //
// Date: August 2021 //
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// 74HC595 8_bit shift register: //
// 1. CMOS to 57MHz //
// 2. ENABLE active low //
// 3. RESET active low //
// 4. CLOCK edge is L->H //
// 5. LATCH L->H puts previous state of register onto parallel op //
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Defines //
#define RESET LATB3_bit // Master reset //
#define CLOCK LATB2_bit // CLOCK //
#define LATCH LATB1_bit // LATCH //
#define DATA_OUT LATB0_bit // DATA to shift registers //
#define DATA_IN PORTB.B0 // Set if 1 is output by the XOR gate //
#define LED_RED LATA0_bit // //
#define LED_GREEN LATA2_bit //
#define LED_YELLOW LATA3_bit //
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// function - send PrintOut stream to the PC via UART1 //
void PCTU1(char c){ //
UART1_Write(c); //
} //
////////////////////////////////////////////////////////////////////////////////
sbit FASTER at PORTC.B0; // white button active low
sbit SLOWER at PORTC.B1; // yellow button active low
void main() {
unsigned int x = 0;
unsigned int count = 0; // index of array 'consecutive_1s'
unsigned int delay = 100; // delay in mS
unsigned long consecutive_1s[64]; // record number of consecutive pulses
unsigned long pulses = 0; // count of all is and os
// Ports and pins
ANSELA = 0b00000000; // 1=analog 0=digital
ANSELB = 0b00000000; // 1=analog 0=digital
ANSELC = 0b00000000; // 1=analog 0=digital
ANSELD = 0b00000000; // 1=analog 0=digital
ANSELE = 0b00000000; // 1=analog 0=digital
WPUB = 0b00000000; // pull up 1=enabled 0=disabled
TRISA = 0b11110010; // LEDs on RA0,RA2,RA3
TRISB = 0b00000000; // B1 LATCH, B2 CLOCK, B3 RESET, B4 DATA OUT
TRISC = 0b00000011; // C0 BUTTON UP, C1 BUTTON DN, C6 RX RS232, C7 TX RS232
TRISD = 0b11111111; // all inputs. RD2 detects op of shift register 63
TRISE = 0b11111111; // Unused all inputs
// Peripherals
PMD1 = 0b00011111; // CCP1MD to CCP5MD off
UART1_Init(57600); // use RC6/Tx1 RC7/Rx1
delay_ms(5);
UART1_Write_Text("Shift Register at 80MHz\r\n");
delay_ms(100);
// Set initial conditions
CLOCK = 0;
LATCH = 0;
// Empty the registers
RESET = 0;
// Initial shift register conditions
CLOCK = 0;
LATCH = 0;
RESET = 1; // cancell the reset
// Load 1 into first shift register and start shifting
DATA_OUT = 1; // logic 1 at input
CLOCK = 1; // all registers shift once
LATCH = 1; // move data from registers to display
CLOCK = 0;
LATCH = 0;
DATA_OUT = 0;
TRISB0_bit = 1; // float data pin so XOR drives from now on
for(x=0;x<=63;x++){
consecutive_1s[x] = 0;
}
while(1){
if(FASTER==0){
LED_GREEN = 1;
delay = delay>>1;
if(delay<= 2)delay = 1;
}
else LED_GREEN = 0;
if(SLOWER==0){
LED_YELLOW = 1;
delay = delay<<1;
if(delay>=1000)delay = 1000;
}
else LED_YELLOW = 0;
// Move the data one space along the shift registers
CLOCK = 1;
CLOCK = 0;
LATCH = 1;
LATCH = 0;
// Count consecutive '1s'
if(DATA_IN==1){
LED_RED = 1;
count ++;
consecutive_1s[count]++;
if(count>63)count=63;
}
else{
count=0;
LED_RED = 0;
}
// Send data to pc every 10,000 cycles
if(pulses%10000==0){
Printout(PCTU1,"Total Pulses:\t%Lu\r\n",pulses);
for(x=1;x<=63;x++){
if(consecutive_1s[x]==0)break; // don't print zero results
Printout(PCTU1,"Pulse_count %u\t %Lu\r\n",x,consecutive_1s[x]);
}
}
// Housekeeping
pulses++;
Vdelay_ms(delay);
}
}
Good luck from Bill Legge in Australia