// Clock Generator Code for JRC-65 Computer // Generate clock pulses between 0.1 Hz - 14 MHz // // // Arduino Nano with an AD9833 module // // // Set Program Info String ProgramBanner = "JRC-65 Computer Clock Generator"; String Revision = "1.01"; String RevDate = "2024-05-05"; String Author = "JRC Bralla"; // // Arduino I/O Pin and Internal Register Usage // // D0 - USB - Receive // D1 - USB - Transmit // D2 - Pushbutton (Stop) // D3 - Pushbutton (Start) // D4 - PUshbutton (Single Cycle) // D5 - Pushbutton (Min Speed - 0.1 Hz) // D6 - Pushbutton (Slow Speed - 1 Hz) // D7 - Pushbutton (Medium Speed - 1 KHz) // D8 - Pushbutton (Full Speed - 1 MHz) // D9 - Pushbutton (Max Speed - 14 MHz // D10 - SPI AD9833 - Sync // D11 - SPI AD9833 - Data // D12 - SPI AD9833 - CLock // D13 - Onboard LED - Heartbeat LED // A0 - LCD - Enable // A1 - LCD - Register Select // A2 - LCD - Data 4 // A3 - LCD - Data 5 // A4 - LCD - Data 6 // A5 - LCD - Data 7 // A6 - AVAILABLE // NOTE: A6 & A7 are NOT for digital output on the Arduino Nano // A7 - AVAILABLE // // Timer 0 - ( 8 bits; 62.5ns - 16.4ms) Arduino delay functions // Timer 1 - (16 bits; 62.5ns - 4.2s ) Heartbeat Timing // Timer 2 - ( 8 bits; 62.5ns - 16.4ms) Arduino tone() function // // #include // Library for the AD9833 Signal Generator #include // Library for LCD display // Set the initial frequency float Frequency = 1.0; // Clock Frequency in Hz // ### Heartbeat Info ### // ### Heartbeat Info ### // ### Heartbeat Info ### // Assign heartbeat LED // Pin 13 has an LED connected on most Arduino boards. int HeartbeatLED = 13; // Heartbeat times float Heartbeat_1_Time = 100; // Pulse On Time (Beat #1) float Heartbeat_2_Time = 100; // Pulse Off Time float Heartbeat_3_Time = 150; // Pulse On Time (Beat #2) float Heartbeat_4_Time = 650; // Pulse Off Time (Heart rest time) int HeartbeatCounter = 1; // Heartbeat calculations // // Need delays between 100 ms and 650 ms // Don't want to use Timer 0, since it is used for stock timer functions on Arduino // // TimeDelay = (Prescaler)*(TicksCount)/ClockFrequency // TicksCount = (TimeDelay)*(ClockFrequency)/Prescaler // For Overflow, Counter = 65535 - TicksCount // on Arduino Nano, ClockFrequency = 16 MHz // Example (100 ms) : Counter = 65535 - (.100 * 16,000,000 / 64) = 40535 // Example (100 ms) : Counter = 65535 - (.100 * 16,000,000 / 256) = 59286 [Use this one] // Example (100 ms) : Counter = 65535 - (.100 * 16,000,000 / 1024) = 63973 // Example (150 ms) : Counter = 65535 - (.150 * 16,000,000 / 256) = 56160 [Use this one] // Example (650 ms) : Counter = 65535 - (.650 * 16,000,000 / 256) = 24910 [Use this one] // Example (650 ms) : Counter = 65535 - (.650 * 16,000,000 / 1024) = 55379 // unsigned int Heartbeat_1_Ticks = 65535 - ( (Heartbeat_1_Time/1000)*16000000/(256) ); unsigned int Heartbeat_2_Ticks = 65535 - ( (Heartbeat_2_Time/1000)*16000000/(256) ); unsigned int Heartbeat_3_Ticks = 65535 - ( (Heartbeat_3_Time/1000)*16000000/(256) ); unsigned int Heartbeat_4_Ticks = 65535 - ( (Heartbeat_4_Time/1000)*16000000/(256) ); // ### Push button Info ### // ### Push button Info ### // ### Push button Info ### // Set up push buttons to control speed const int PushButton_Stop = 2; // Stop const int PushButton_Start = 3; // Start const int PushButton_Single = 4; // Single Cycle const int PushButton_Min = 5; // Minimum speed 0.1 Hz const int PushButton_Slow = 6; // Slow speed 1 Hz const int PushButton_Med = 7; // Medium Speed 1 KHz ( 1,000 Hz) const int PushButton_High = 8; // High Speed 1 MHz ( 1,000,000 Hz) const int PushButton_Max = 9; // Maximum speed 14 MHz (14,000,000 Hz) int DebounceDelay = 100; // Microseconds to delay when button press is detected int SingleStepDelay = 350; // 350 Microseconds (.35 seconds) to pause to allow for a single cycle // ### LCD Display Data ### // ### LCD Display Data ### // ### LCD Display Data ### // Set data lines to LCD Display const int LCDEnable = A0; // Enable const int LCDRegisterSelect = A1; // Register Select (Command or Data) const int LCDData4 = A2; // Data Bit 4 (4-bit mode) const int LCDData5 = A3; // Data Bit 5 const int LCDData6 = A4; // Data Bit 6 const int LCDData7 = A5; // Data Bit 7 // NOTE: A6 & A7 are NOT for digital output on the Arduino Nano LiquidCrystal lcd(LCDRegisterSelect, LCDEnable, LCDData4, LCDData5, LCDData6, LCDData7); // ### SPI Communication to AD9833 Info ### // ### SPI Communication to AD9833 Info ### // ### SPI Communication to AD9833 Info ### // Pins for SPI comm with the AD9833 IC const uint8_t PIN_DATA = 11; // SPI Data pin number const uint8_t PIN_CLK = 12; // SPI Clock pin number const uint8_t PIN_FSYNC = 10; // SPI Load pin number (FSYNC in AD9833 usage) // Set the SPI pins (Have to assign the pins explicitely) MD_AD9833 AD(PIN_DATA, PIN_CLK, PIN_FSYNC); // Arbitrary SPI pins // ### Setup the program ### // ### Setup the program ### // ### Setup the program ### void setup() { // Initialize the serial monitor output Serial.begin(115200); // Set to max baud rate Serial.println("#######################################"); Serial.println(); Serial.println(); Serial.println(ProgramBanner); Serial.println(); Serial.println(" Author: " + Author); Serial.println("Version: " + Revision); Serial.println(" Date: " + RevDate); Serial.println(); // initialize the Heartbeat LED pin as an output. pinMode(HeartbeatLED, OUTPUT); // Heartbeat Timer for Overflow Interrupts TCCR1A = 0; // Initialize Timer1A TCCR1B = 0; // Initialize Timer1B TCCR1B |= B00000100; // Timer2 Prescaler = 1024 TCNT1 = Heartbeat_1_Ticks; // Timer2 Preloading TIMSK1 |= B00000001; // Enable Timer2 Overflow Interrupts // Serial.println("Heartbeat_1_Ticks: " + String(Heartbeat_1_Ticks)); // Serial.println("Heartbeat_2_Ticks: " + String(Heartbeat_2_Ticks)); // Serial.println("Heartbeat_3_Ticks: " + String(Heartbeat_3_Ticks)); // Serial.println("Heartbeat_4_Ticks: " + String(Heartbeat_4_Ticks)); // Initialize the LCD lcd.begin(16,2); // 2-line LCD by 16 characters lcd.noAutoscroll(); // Set noAutoscroll mode lcd.noBlink(); // No blinking cursor lcd.setCursor(0,0); // Cursor to home position (Column, Row) lcd.print(" JRC-65 Clock "); // First line lcd.setCursor(0,1); // Cursor to first character in second line if (Frequency == 0.1 ) { lcd.print(" 0.1 Hz "); } if (Frequency == 1 ) { lcd.print(" 1 Hz "); } if (Frequency == 1000 ) { lcd.print(" 1 KHz "); } if (Frequency == 1000000 ) { lcd.print(" 1 MHz "); } if (Frequency == 14000000 ) { lcd.print(" 14 MHz "); } // Initialize the Push Buttons pinMode(PushButton_Stop, INPUT_PULLUP); // No resistor required pinMode(PushButton_Start, INPUT_PULLUP); // No resistor required pinMode(PushButton_Single, INPUT_PULLUP); // No resistor required pinMode(PushButton_Min, INPUT_PULLUP); // No resistor required pinMode(PushButton_Slow, INPUT_PULLUP); // No resistor required pinMode(PushButton_Med, INPUT_PULLUP); // No resistor required pinMode(PushButton_High, INPUT_PULLUP); // No resistor required pinMode(PushButton_Max, INPUT_PULLUP); // No resistor required // Initialize the AD9833 Signal Generator AD.begin(); // Start the signal generator AD.setFrequency(MD_AD9833::CHAN_0, Frequency/2); // Set it to the desired frequency in Hz (enter half the freq to be correct) AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode } // ### Heartbeat Interrupt Routine ### // ### Heartbeat Interrupt Routine ### // ### Heartbeat Interrupt Routine ### ISR(TIMER1_OVF_vect) { switch (HeartbeatCounter) { case 1: TCNT1 = Heartbeat_1_Ticks; // Reset the counter digitalWrite(HeartbeatLED, HIGH); // Turn on Heartbeat LED HeartbeatCounter = 2; break; case 2: TCNT1 = Heartbeat_2_Ticks; // Reset the counter digitalWrite(HeartbeatLED, LOW); // Turn off Heartbeat LED HeartbeatCounter = 3; break; case 3: TCNT1 = Heartbeat_3_Ticks; // Reset the counter digitalWrite(HeartbeatLED, HIGH); // Turn on Heartbeat LED HeartbeatCounter = 4; break; case 4: TCNT1 = Heartbeat_4_Ticks; // Reset the counter digitalWrite(HeartbeatLED, LOW); // Turn off Heartbeat LED HeartbeatCounter = 1; break; } } // ### Main Regular Program Loop to Detect and React to Button presses ### // ### Main Regular Program Loop to Detect and React to Button presses ### // ### Main Regular Program Loop to Detect and React to Button presses ### // ### Main Regular Program Loop to Detect and React to Button presses ### // NOTE: Cannot do interrupts because only 2 pins are connected to IRQs on the Arduino Nano void loop() { // Stop Button if (digitalRead(PushButton_Stop) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_Stop) == LOW) // Is button still held? { // Set Frequency to zero to stop the clock AD.setFrequency(MD_AD9833::CHAN_0, 0); // Stop the clock AD.setMode(MD_AD9833::MODE_OFF); // Turn off the square wave (set LOW) // Display the Frequency Serial.println("Clock Stopped"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" Clock Stopped "); } } // Start Button if (digitalRead(PushButton_Start) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_Start) == LOW) // Is button still held? { // Reset the Frequency to restart the clock AD.setFrequency(MD_AD9833::CHAN_0, Frequency/2); // Restart the clock AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode Serial.println("Clock Restarted to " + String(Frequency) + " Hz"); lcd.setCursor(0,1); // First character at line 2 if (Frequency == 0.1 ) { lcd.print(" 0.1 Hz "); } if (Frequency == 1 ) { lcd.print(" 1 Hz "); } if (Frequency == 1000 ) { lcd.print(" 1 KHz "); } if (Frequency == 1000000 ) { lcd.print(" 1 MHz "); } if (Frequency == 14000000 ) { lcd.print(" 14 MHz "); } } } // Single Step Button if (digitalRead(PushButton_Single) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_Single) == LOW) // Is button still held? { Serial.println("Single Cycle"); // // Stop the clock AD.setMode(MD_AD9833::MODE_OFF); // Turn off the square wave (set LOW) AD.setFrequency(MD_AD9833::CHAN_0, 0); // Set Frequency to zero AD.reset(); // Reset the clock generator Serial.println("Single Cycle: Clock Stopped"); // // Set Frequency to 1 Hz and restart the clock AD.setFrequency(MD_AD9833::CHAN_0, 0.05); // Turn on clock at 0.1 Hz AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode Serial.println("Single Cycle: Clock Started at 0.1 Hz"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" Single Cycle "); delay(SingleStepDelay); // // Stop the clock again AD.setMode(MD_AD9833::MODE_OFF); // Turn off the square wave (set LOW) AD.setFrequency(MD_AD9833::CHAN_0, 0); // Set Frequency to zero AD.reset(); // Reset the clock generator Serial.println("Single Cycle: Clock Stopped Again"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" Clock Stopped "); } } // Min Button if (digitalRead(PushButton_Min) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_Min) == LOW) // Is button still held? { // Set the Frequency to to 0.1 Hz Frequency = 0.1; AD.setFrequency(MD_AD9833::CHAN_0, Frequency/2); AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode Serial.println("Clock Reset to " + String(Frequency) + " Hz"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" 0.1 Hz "); } } // Slow Button if (digitalRead(PushButton_Slow) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_Slow) == LOW) // Is button still held? { // Set the Frequency to to 1 Hz Frequency = 1; AD.setFrequency(MD_AD9833::CHAN_0, Frequency/2); AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode Serial.println("Clock Reset to " + String(Frequency) + " Hz"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" 1 Hz "); } } // Med Button if (digitalRead(PushButton_Med) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_Med) == LOW) // Is button still held? { // Set the Frequency to to 1 KHz Frequency = 1000; AD.setFrequency(MD_AD9833::CHAN_0, Frequency/2); AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode Serial.println("Clock Reset to " + String(Frequency) + " Hz"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" 1 KHz "); } } // High Button if (digitalRead(PushButton_High) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_High) == LOW) // Is button still held? { // Set the Frequency to to 1 MHz Frequency = 1000000; AD.setFrequency(MD_AD9833::CHAN_0, Frequency/2); AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode Serial.println("Clock Reset to " + String(Frequency) + " Hz"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" 1 MHz "); } } // Max Button if (digitalRead(PushButton_Max) == LOW) // LOW = Button Pressed { delay(DebounceDelay); if (digitalRead(PushButton_Max) == LOW) // Is button still held? { // Set the Frequency to to 14 MHz Frequency = 14000000; AD.setFrequency(MD_AD9833::CHAN_0, Frequency/2); AD.setMode(MD_AD9833::MODE_SQUARE1); // Set square wave output mode Serial.println("Clock Reset to " + String(Frequency) + " Hz"); lcd.setCursor(0,1); // First character at line 2 lcd.print(" 14 MHz "); } } }