Cloning an Arduino Uno and Arduino Mini Pro 3.3V

I do have the installation files. I have 1.6.3, 1.6.7, 1.6.11 and 1.6.12 exe files. However there were so many libraries and versions that I downloaded that were not part of the install. Maybe I'll work it out somehow.

Install the latest IDE, open your sketches (.ino) and try to compile. The compilier will complain about the missing libs. Install the libs and try again. You don't need to use and old IDE.

In any case you should post your code here and we can advise on what libs may be needed.

It's the little things also like brownout setting, lowers to 1.8V, changed to 1mhz, etc, then the correct libraries. I then need to make the receiver as well to test it. It's daunting for me.



Re the code, it's pretty long but I put a "stack" of notes in case the next soccer club volunteer took this on and had to maintain it - but it's now landed back in my lap!
By the way, the reason for all this... There are 2 scoreboards. Each is on a different receiver frequency. One works well. The other had the hand held remote break and has "always" had a bit of difficulty getting going and transmitting from just half way across the pitch. Now that it doesn't work, I'm stumped. Hence the reason I thought I'd just make a new set of boards and see if I could fix it. But quite a daunting task...

/******************************************************************************
  This transmitter is based on an Arduino Mini Pro 3.3V 8MHz Atmega328P processor
  Power supply is 2 x AA alkaline batteries (as these are readily available)
  The transmitter is an nRF24L01+ which operates on a voltage between 1.8V and 3.3V
  The processor has been programmed to also operate on a voltage between 1.9V and 3.3V
  To minimise power use, and extend battery life, the following has been done:

   1.  Avoided using a voltage regulator or step down power supply
   2.  Power is used directly from 2 x AA, 1.5V batteries
   3.  After startup, the processor goes to a deep sleep
   4.  At the same time, the nRF goes into a powerDown mode
   5.  A keybutton press then runs as an interrupt to wake the proccessor and nRF
   6.  After processing the press and transmitting, the unit goes back to sleep
   7.  Action for both a short press and long press has been programmed into the code
   8.  Current draw measured is:
       - 2.26mA during normal operation
       - 0.91mA during "wait"
       - 0.70uA during deep sleep
   9.  To attain these low values, the mini pro has:

         a.  Had the voltage regulator removed
         b.  Had the power led removed
         c.  Re-bootloaded with code that turns off brownout
         d.  Re-bootloaded with code lowers the brownout level to 1.8V
         e.  MHz dropped to 1MHz

   11. Due to the lower base voltage, an led is wired up to blink a green LED once
       when a button is pressed to change the score.  If voltage is measured as being
       under 2.1V, it will blink a red LED three times - warning to change battery
       Note, at 1.97V I found the transmitter wouldn't transmit (hence 2V cutoff)
       I also found at  "myRadio.setPALevel" set to "MIN", min working V = 1.925
       Also found that at "MAX" min working V = 2.030

   12. The above is based on measuring the internal voltage of the processor
       (1.1V).  It has also been adjusted according to the "real" internal voltage

   13. In order to be able to light up an LED at 2.0V, a "voltage doubler" or
       "two stage inverter" is included in the circuitry

  This code utlises the libraries: avr/sleep.h , avr/power.h , SPI.h and RF24.h

  This code transmits data from one nRF24L01 to another.  The input on the
  transmitter is done via a 3 column x 4 row keypad.  When a button is pressed on the
  keypad, a "~" is first sent, followed by the number, followed by a "!".  Each
  key press is an ascii (such as ascii "49" for key 1).  This is then stored to a variable
  as "character" (i.e. A, or B, etc) which also have an ascii character.  This is the ascii
  that is sent to the receiver.  Key presses sent in this code are as follows:
  

     0 = Siren off
     1 = Increment home score by 1
     2 = Nil
     3 - Increment away score by 1
     4 = Decrease home score by 1
     5 = start / pause / resume
     6 = Decrease away score by 1
     7 = Nil
     8 = Turn displays back on (if off)
     9 = Nil
     # = Nil
     * = A prefix to allow for setting the timer
     # = used in cancelling the press combinations

     0 (hold) = siren set to play when time reached
     1 (hold) = reset home score to 00
     2 (hold) = runs a test display of 8's on each "set" of digits
     3 (hold) = reset away score to 00
     5 (hold) = reset timer to 00:00 ready to start
     8 (hold) = turn off all the displays
     # (hold) = reset Date_Time (held down for 2 seconds)
     
     If the scoreboard is in Date_Time reset mode, the following keypad actions happen:
     2 = increment up the flashing digit value
     4 = move to the next digit left to set it
     6 = move to the next digit right to set it
     8 = increment down the flashing digit value
     Note:
       The month is displayed on the home score (bottom left of the board)
       The year is displayed in the timer (middle of the board)
       The date is displayed on the away score (bottom right of the board)
       The current time is displayed in the usual spot (top right of the board)
       The temperature digits are temporarily turned off
     To accept the date_time changes, again hold down "#" for 2 seconds

  Start with radios about 4 feet apart.
   nRF2401 setup:
   GND
   VCC  - to 3.3V
   CE   - to Arduino pin 9
   CSN  - to Arduino pin 10
   SCK  - to Arduino pin 13
   MOSI - to Arduino pin 11
   MISO - to Arduino pin 12
   IRQ  - Not used

  4 x 3 keypad: Rows = pins A0, A1, A2, A3.  Columns = pins 4, 5, 6
*/
//**********************************************************


#include <avr/sleep.h>
#include <avr/power.h>
#include <SPI.h>    // Comes with Arduino IDE
#include "RF24.h"   // https://github.com/TMRh20/RF24

// variable for keypad -----------------------
unsigned long currentMillis = 0;               // used in pushbutton timing
unsigned long previousMillis = 0;              // used in pushbutton timing
unsigned long pressStartTime = 0;              // used in pushbutton timing
unsigned long buttonPressLong = 1000;          // min time required for long keypad press
const byte debounceTime = 0;                   // allow time for button to go LOW

enum buttonPress {  // used to mark button press duration
  up,
  down,
  shortPress,
  longPress,
};
int buttonPress = up;   // default - no press

const int numRows = 4;  // number of rows in the keypad
const int numCols = 3;  // number of columns
byte r;
char key;

// array used to nominate pins used for the rows and columns
const int rowPins[numRows] = {14, 15, 16, 17}; // rows 0, 1, 2 and 3
const int colPins[numCols] = {4, 5, 6};        // columns 1, 2 and 2

// Map of the keys on the keypad
const char keymap[numRows][numCols] = {
  { '1', '2', '3' },
  { '4', '5', '6' },
  { '7', '8', '9' },
  { '*', '0', '#' }
};


/**************************************
  Pin change interrupts for info only...
  Pin            Mask   / Flag / Enable
  D0    PCINT16 (PCMSK2 / PCIF2 / PCIE2)
  D1    PCINT17 (PCMSK2 / PCIF2 / PCIE2)
  D2    PCINT18 (PCMSK2 / PCIF2 / PCIE2)
  D3    PCINT19 (PCMSK2 / PCIF2 / PCIE2)
  D4    PCINT20 (PCMSK2 / PCIF2 / PCIE2)
  D5    PCINT21 (PCMSK2 / PCIF2 / PCIE2)
  D6    PCINT22 (PCMSK2 / PCIF2 / PCIE2)
  D7    PCINT23 (PCMSK2 / PCIF2 / PCIE2)
  D8    PCINT0 (PCMSK0 / PCIF0 / PCIE0)
  D9    PCINT1 (PCMSK0 / PCIF0 / PCIE0)
  D10   PCINT2 (PCMSK0 / PCIF0 / PCIE0)
  D11   PCINT3 (PCMSK0 / PCIF0 / PCIE0)
  D12   PCINT4 (PCMSK0 / PCIF0 / PCIE0)
  D13   PCINT5 (PCMSK0 / PCIF0 / PCIE0)
  A0    PCINT8 (PCMSK1 / PCIF1 / PCIE1)
  A1    PCINT9 (PCMSK1 / PCIF1 / PCIE1)
  A2    PCINT10 (PCMSK1 / PCIF1 / PCIE1)
  A3    PCINT11 (PCMSK1 / PCIF1 / PCIE1)
  A4    PCINT12 (PCMSK1 / PCIF1 / PCIE1)
  A5    PCINT13 (PCMSK1 / PCIF1 / PCIE1)
***************************************
*/

// turn off interrupts until we are ready
ISR (PCINT0_vect) {
  PCICR = 0;  // cancel pin change interrupts for D8 to D13
} // end of ISR (PCINT0_vect)

ISR (PCINT1_vect) {
  PCICR = 0;  // cancel pin change interrupts for A0 to A5
} // end of ISR (PCINT1_vect)

ISR (PCINT2_vect) {
  PCICR = 0;  // cancel pin change interrupts for D0 to D07
} // end of ISR (PCINT2_vect)

// ADC control Status Register A.
byte old_ADCSRA;


// variable for low battery warning-----------
byte ledPin = 2;                          // to RGB LED common (anode)
byte ledPinGreen = 7;                     // to RGB LED green pin - battery voltage above 2.1V
byte ledPinRed = 8;                       // to RGB LED red pin - low battery warning
unsigned long ledCurrentMillis = 0;       // used for LED flash timing
const int ledFlashTime = 50;              // used for the above LEDs - 50
float frequencyGreenLED;                  // used to maintain current to green LED
float frequencyRedLED;                    // used to maintain current to red LED
float result;                             // variable to sort the reference voltage


// Transmit data is sent with a ~ at the start and ! at the end to verify the data is valid
byte CmdStart = '~';    // ASCII value = 126
byte CmdEnd   = '!';    // ASCII value = 33

byte FlagKeyN = 0;      // flag the keypad number
byte FlagTimer = 0;     // flag used to set the count down time
byte timerToggle = 0;   // variable used to toggle the timer from start to pause and reset

// When one of the following is transmitted, it is so as an ascii character
// On the receiver program, the ascii is read and program executed as listed in the "case" list

byte Zero = 'A';         // variable used to send the number 0 (ASCII of A = 65)
byte One = 'B';          // variable used to send the number 1 (ASCII of B = 66)
byte Two = 'C';          // variable used to send the number 2 (ASCII of C = 67)
byte Three = 'D';        // variable used to send the number 3 (ASCII of D = 68)
byte Four = 'E';         // variable used to send the number 4 (ASCII of E = 69)
byte Five = 'F';         // variable used to send the number 5 (ASCII of F = 70)
byte Six = 'G';          // variable used to send the number 6 (ASCII of G = 71)
byte Seven = 'H';        // variable used to send the number 7 (ASCII of H = 72)
byte Eight = 'I';        // variable used to send the number 8 (ASCII of I = 73)
byte Nine = 'J';         // variable used to send the number 9 (ASCII of J = 74)

byte Hash = 'K';         // variable used to send a "hash" (ASCII of K = 75)
byte Asterix = 'L';      // variable used to send an asterix (ASCII of L = 76)

byte sirenActive = 'M';  // "0" button held - variable used to activate the siren (ASCII of M = 77)
byte homeReset = 'N';    // "1" button held - variable used to reset the home score (ASCII of N = 78)
byte awayReset = 'O';    // "3" button held - variable used to reset the away score (ACII of O = 79)
byte displayOff = 'P';   // "8" button held - variable used to turn off the led displays (ASCII of P = 80)
byte resetTimer = 'Q';   // "5" button held - variable used to reset the timer to start (ASCII of Q = 81)
byte testDigits = 'R';   // "2" button held - variable used to test each set of digits (ASCII of R = 82)
byte resetTimeDate = 'S';// "#" button held - variable used to set the time and date (ASCII of S = 83)

int number;

// (Create an instance of a radio, specifying the CE and CS pins. )
RF24 myRadio (9, 10);                     // "myRadio" is the identifier you will use in following methods
byte addresses[][6] = {"1Node"};          // Create address for 1 pipe.


//**********************************************************

void setup() {
  clock_prescale_set(clock_div_2);        // speed conversion due to Mini Pro running at 8MHz for power saving
  // clock_prescale_set(clock_div_4);     // comment the above and uncomment this line to keep the 4MHz overall clock speed

  Serial.begin(9600);
  delay(500);  // just gives some time for starting the serial monitor
  Serial.println(F("RF24/Simple Transmit data Check"));

  pinMode(ledPinGreen, OUTPUT);           // Sets the digital pin as output
  pinMode(ledPinRed, OUTPUT);             // Sets the digital pin as output
  digitalWrite(ledPinGreen, LOW);         // Start with LED off
  digitalWrite(ledPinRed, LOW);           // Start with LED off

  // pin change interrupt masks (see above list)
  PCMSK1 |= bit (PCINT8);                 // pin 14
  PCMSK1 |= bit (PCINT9);                 // pin 15
  PCMSK1 |= bit (PCINT10);                // pin 16
  PCMSK1 |= bit (PCINT11);                // pin 17

  old_ADCSRA = ADCSRA;                    // Only necessary if you want to reenable the ADC at some point.
  ADCSRA = 0;                             // Turn off ADC power
  ACSR |= _BV(ACD);                       // turn off analog comparator.
  power_all_disable();

  power_timer2_enable();
  power_timer0_enable();                  // if you want to use mills(), micros(), or delay().
  power_usart0_enable();                  // if you want to use Serial.
  power_spi_enable();                     // for the nRF24 module.

  for (byte row = 0; row < numRows; row++) {
    pinMode (rowPins[row], INPUT);        // this sets the row pins as inputs
    digitalWrite (rowPins[row], HIGH);    // set high
  } // end for

  for (byte column = 0; column < numCols; column++) {
    pinMode (colPins[column], OUTPUT);    // this sets the column pins as outputs
    digitalWrite (colPins[column], HIGH);// set high
  } // end for

  myRadio.begin();                        // Start up the physical nRF24L01 Radio
  myRadio.setChannel(108);                // Above most Wifi Channels (note 116 = remote 1 and 108 = remote 2)

  // PA level can be MIN, HIGH or MAX. RF24_PA_MAX is default.
  //  myRadio.setPALevel(RF24_PA_MIN);    // Uncomment for less power
  myRadio.setPALevel(RF24_PA_MAX);        // Uncomment for more power
  myRadio.openWritingPipe( addresses[0]); // Use the first entry in array 'addresses' (Only 1 right now)
  // look up how to set retries time
  // ditto for set low data rate to save power
  delay(1000);
} // end void setup

//*****************************************

void loop() {
  if (buttonPress == up) {
    goToSleep();
  }
  char key = getKey();
  checkDuration ();
  shortDown();
  longDown();
} // end void loop

//*****************************************

// returns with the key pressed, or 0 if no key is pressed
char getKey() {
  if ( buttonPress == up) {
    key = 0; // 0 indicates no key pressed
    for (byte column = 0; column < numCols; column++) {
      digitalWrite(colPins[column], LOW);       // Activate the current column.
      for (byte row = 0; row < numRows; row++) { // Scan all rows for a key press.
        if (digitalRead(rowPins[row]) == LOW && millis() - currentMillis > debounceTime) { // Is a key pressed?
          previousMillis = currentMillis;
          pressStartTime = millis();
          read_Vcc();
          flash();
          buttonPress = down;
          key = keymap[row][column];           // Remember which key was pressed.
          r = row;
          return key;
        } // end if
      } // end for
      digitalWrite(colPins[column], HIGH);
    } // end for
  } // end if
} // end getKey

//*****************************************

void checkDuration () {
  currentMillis = millis();
  if (buttonPress == down) {
    // if button has been released and debounce time expired, do the following
    if (digitalRead(rowPins[r]) == HIGH && currentMillis - previousMillis > debounceTime) {
      previousMillis = currentMillis;
      buttonPress = shortPress;
      currentMillis = millis();
      return;  // exit this function as key has been pressed and released
    } // end if

    // if button is still pressed, and long press time expired, do the following
    if (digitalRead(rowPins[r]) == LOW && currentMillis - pressStartTime > buttonPressLong) {
      previousMillis = currentMillis;
      buttonPress = longPress;
    } // end if
  } // end if
} // end void checkDuration

//*****************************************

void shortDown() {
  // execute SHORT keypress action
  if (buttonPress == shortPress) {
    myRadio.powerUp();
    FlagKeyN = key;   // Set the FlagKeyN variable to the currently pressed key number
    delay(10);        // this allows the radio to fully wake up before sending the signal
    switch (FlagKeyN) {

      case  48:
        // keypad 0 pressed
        SendCommand(Zero); // this transmits the value 'A' in ascii = 65
        break;

      case  49:
        // keypad 1 pressed
        SendCommand(One); // this transmits the value 'B' in ascii = 66
        break;

      case  50:
        // keypad 2 pressed
        SendCommand(Two); // this transmits the value 'C' in ascii = 67
        break;

      case  51:
        // keypad 3 pressed
        SendCommand(Three); // this transmits the value 'D' in ascii = 68
        break;

      case  52:
        // keypad 4 pressed
        SendCommand(Four); // this transmits the value 'E' in ascii = 69
        break;

      case  53:
        // keypad 5 pressed
        SendCommand(Five); // this transmits the value 'F' in ascii = 70
        break;

      case  54:
        // keypad 6 pressed
        SendCommand(Six); // this transmits the value 'G' in ascii = 71
        break;

      case  55:
        // keypad 7 pressed
        SendCommand(Seven); // this transmits the value 'H' in ascii = 72
        break;

      case  56:
        // keypad 8 pressed
        SendCommand(Eight); // this transmits the value 'I' in ascii = 73
        break;

      case  57:
        // keypad 9 pressed
        SendCommand(Nine); // this transmits the value 'J' in ascii = 74
        break;

      case  35:
        // keypad * pressed
        SendCommand(Hash); // this transmits the value 'K' in ascii = 75
        break;

      case  42:
        // keypad # pressed
        SendCommand(Asterix); // this transmits the value 'L' in ascii = 76
        break;

    } // end switch

    // serial print statements below simply used for checking
    printKey ();

    for (byte column = 0; column < numCols; column++) {
      digitalWrite(colPins[column], HIGH);
    } // end for
    buttonPress = up;
  } // end if SHORT keypress
} // end void shortDown

//*****************************************

void longDown() {
  // execute LONG keypress action
  if (buttonPress == longPress) {
    myRadio.powerUp();
    FlagKeyN = key;   // Set the FlagKeyN variable to the currently pressed key number
    delay(10);        // this allows the radio to fully wake up before sending the signal
    switch (FlagKeyN) {

      case  48:
        // keypad 0 held pressed
        SendCommand(sirenActive); // this transmits the value 'M' in ascii = 77
        break;

      case  49:
        // keypad 1 held pressed to reset home score to 00
        SendCommand(homeReset); // this transmits the value 'N' in ascii = 78
        break;

      case  51:
        // keypad 3 held pressed to reset away score to 00
        SendCommand(awayReset); // this transmits the value 'O' in ascii = 79
        break;

      case  56:
        // keypad 8 held pressed to turn off led displays
        SendCommand(displayOff); // this transmits the value 'P' in ascii = 80
        break;

      case  53:
        // keypad 5 held pressed to reset home time to 00
        SendCommand(resetTimer); // this transmits the value 'Q' in ascii = 81
        break;

      case  50:
        // keypad 2 held pressed to test each set of digits
        SendCommand(testDigits); // this transmits the value 'R' in ascii = 82
        break;

      case  35:
        // keypad # held pressed to change the current time and date
        SendCommand(resetTimeDate); // this transmits the value 'S' in ascii = 83
        break;

    } // end switch

    printKey ();
    while (digitalRead(rowPins[r]) == LOW) {
      power_nap();
      ; // just wait until button is released
    } // end while
    for (byte column = 0; column < numCols; column++) {
      digitalWrite(colPins[column], HIGH);
    } // end for
    buttonPress = up;
  } // end if LONG keypress
} // end void longDown

//**********************************************************

// function below used for checking only
void printKey () {
  // serial print statements below simply used for checking
  Serial.print(".  i = ");
  Serial.print(FlagKeyN);
  Serial.print("  Key no. ");
  Serial.print(key);
  Serial.println(" pressed.");
} // end void

//**********************************************************

// Send Command via Radio
void SendCommand(byte KeyCmd) {
  myRadio.write(&CmdStart, sizeof(CmdStart));
  myRadio.write(&KeyCmd, sizeof(KeyCmd));
  myRadio.write(&CmdEnd, sizeof(CmdEnd));

  Serial.print(F("Command Sent = "));
  Serial.print(KeyCmd);
} // end void SendCommand

//**********************************************************

void read_Vcc() {
  // Re-enable ADC clock and power.
  power_adc_enable();
  ADCSRA = old_ADCSRA;

  // Set external reference and
  // bandgap input channel.
  ADMUX = 1 << REFS0 | 14 << MUX0;

  // perform first dummy conversion.
  // Don't care about this result, just
  // let's the bandgap settle after being turned on.
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA, ADSC));
  delayMicroseconds(150);

  // The real one, keep this result.
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA, ADSC));

  result;
  result = ADC;

  // Disable ADC.
  ADCSRA = 0;
  power_adc_disable();

  // Calculate reference (battery) voltage based on 1100 mV bandgap input.
  // Calibrate the 1100 value to match the real bandgap value, or use an accurate
  // external reference.
  // return 1100*1024L / (result);

  result = 1127419UL / (1000 * result); // Back-calculate Vcc in mV
  // I added the 1000 above so the printout shows it in the correct decimal format
  //  Serial.print("Battery voltage = ");
  //  Serial.print(result, 3);              // display to 3 decimal places
  //  Serial.println("V");

  // During testing using 3.3V supply, limit the result
  if (result > 3.0) {
    result = 3.0;
  }

  // Now let's convert the frequency to suit the current voltage
  // For green, is a reciprical function y = k/x (approx.  y = 1000(V-1.5)  )
  frequencyGreenLED  = (1000 / ( result - 1.5));
  // For red, is a also a reciprical, but in the low voltage almost linear y=-2033x+5413
  frequencyRedLED  = ( (-2033 * result) + 5413 );
  //  Serial.print("FrequencyLED = ");
  //  Serial.println(frequencyLED);
} // end read_Vcc

//********************************************************

void goToSleep () {
  byte i;
  // set up to detect a keypress
  for (i = 0; i < numCols; i++) {
    pinMode (colPins [i], OUTPUT);
    digitalWrite (colPins [i], LOW);   // columns low
  }  // end for

  for (i = 0; i < numRows; i++) {
    pinMode (rowPins [i], INPUT);
    digitalWrite (rowPins [i], HIGH);  // rows high (pull-up)
  }  // end for

  // now check no pins pressed (otherwise we wake on a key release)
  for (i = 0; i < numRows; i++) {
    if (digitalRead (rowPins [i]) == LOW) {
      for (byte column = 0; column < numCols; column++) {
        digitalWrite(colPins[column], HIGH);
      } // end for
      return;
    } // end if
  }  // end for

  //  Serial.println("Going to sleep now...");
  //  Serial.println("Zzzzzzzzz");

  myRadio.powerDown();  // this should sleep the nRF to save power

  // at this point, pressing a key should connect the high in the row to the
  // to the low in the column and trigger a pin change

  set_sleep_mode (SLEEP_MODE_PWR_DOWN);

  Serial.flush();
  cli();
  sleep_enable();
  PCIFR  |= bit (PCIF0) | bit (PCIF1) | bit (PCIF2);   // clear any outstanding interrupts
  PCICR  |= bit (PCIE0) | bit (PCIE1) | bit (PCIE2);   // enable pin change interrupts
  sleep_bod_disable();
  sei();
  sleep_cpu ();

  // cancel sleep as a precaution
  sleep_disable();

  // put keypad pins back how they are expected to be
  for (byte column = 0; column < numCols; column++) {
    digitalWrite(colPins[column], HIGH);
  } // end for
  currentMillis = millis();
  //  Serial.println("Waking up now?");
}  // end of goToSleep

//**********************************************************

void flash() {
  ledCurrentMillis = millis();
  if (result > 2.100) {
    // voltage is OK so lets single flash the green LED
    Serial.println("So since voltage is GREATER than 2.100V, blink green LED");
    tone(ledPin, frequencyGreenLED);
    digitalWrite(ledPinRed, LOW);
    digitalWrite(ledPinGreen, HIGH);
    while (millis() - ledCurrentMillis < ledFlashTime)
      ;
    digitalWrite(ledPinGreen, LOW);
    noTone(ledPin);
  } // end if
  else {
    // voltage is low so lets flash the red LED 3 times
    Serial.println("So since voltage is LOWER than 2.100V, blink red LED");
    for (byte i = 0; i < 3; i++) {
      ledCurrentMillis = millis();
      tone(ledPin, frequencyRedLED);
      digitalWrite(ledPinGreen, LOW);
      digitalWrite(ledPinRed, HIGH);
      while (millis() - ledCurrentMillis < ledFlashTime)
        ;
      digitalWrite(ledPinRed, LOW);
      noTone(ledPin);
      ledCurrentMillis = millis();
      while (millis() - ledCurrentMillis < 5 * ledFlashTime)
        ;
    } // end for
  } // end else
} // end void flash

//**********************************************************

void power_nap()
{
  set_sleep_mode(SLEEP_MODE_IDLE);
  cli();
  sleep_enable();
  sei();
  sleep_cpu();
  sleep_disable();
}

Well the only lib you need to install is the RF24.
Use the library manager to install it.

@jim-p , I'm not sure if I should start a new thread here under "programming" or continue here.
In the end I couldn't clone so easily, so I tried my old code on a new mini pro. But I'm now stuck on brownout setting.

I started with a fresh empty Arduino Mini, 3.3V, 8MHz.
I ended up loading Arduino 1.8.19, loaded a new "Time-master" library, RF24 and DS3232RTC from memory. There was some coding changes suggested by chatgpt which in the end started to work!

I had to abandon my user made "Low Voltage Mini Pro" bootloader setup with 1.8V brownout setting and 8MHZ (1MHz bootloader). Could get the baud rate working between the receiver program and transmitter.

So I downloaded MiniCore board setup so I could get my 1.8V brownout setting.
I loaded the ArudinoISP to an Uno, then loaded the new bootloader to the Mini Pro. That worked. But now in uploading the sketch, I get an error as follows:

Arduino: 1.8.19 (Windows 10), Board: "ATmega328, Yes (UART0), EEPROM retained, 115200, 328P / 328PA, BOD 2.7V, LTO enabled, External 8 MHz"

Sketch uses 880 bytes (2%) of program storage space. Maximum is 32384 bytes.

Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.

Warning: attempt 1 of 10: not in sync

Warning: attempt 2 of 10: not in sync

Warning: attempt 3 of 10: not in sync

Warning: attempt 4 of 10: not in sync

Warning: attempt 5 of 10: not in sync

Warning: attempt 6 of 10: not in sync

Warning: attempt 7 of 10: not in sync

Warning: attempt 8 of 10: not in sync

Warning: attempt 9 of 10: not in sync

Warning: attempt 10 of 10: not in sync

Warning: programmer is not responding; try -x strict and/or vary -x delay=100

Error: unable to open port COM5 for programmer urclock

Error: unable to open port COM5 for programmer urclock





This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Unfortunately chatgpt isn't as smart as he thinks he is, and is asking me to abandon the 1.8V brownout setting. Any suggestions?

Don’t start a new topic, your problem is basically the same

So you have the Uno programmer disconnected and you are trying to upload via USB using the upload button, is that correct?

Yes, I was trying to upload "blink" to start with.
But I've kept experimenting and found when I changed the baud rate from 115200 to 9600, it uploaded. Infact I found that anywhere between 9600 and 67600 works. So all good so far... Sorry for the inconvenience.

The latest version of Minicore uses a new bootloader called Urboot. Others have had similar problems with that bootloader and solved it by going back to an old version of Minicore that used Optiboot. Version 2.2.2 was the last that used Optiboot.

I see that there are quite a few version in the board manager. Should I removed 3.1.2 and load an earlier version then?

Yes. Remove 3.1.2 close the IDE and reopen it then install 2.2.2
If you burn the bootloader again it will use Optiboot which is probably the bootloader used on your original boards.

Then you will also have the option to select Arduino Pro Mini from the board manager when uploading code.

It might be helpful to future readers if you could provide information on what you tried to do, and what went wrong, in the cloning process.

If you still have an arduino_as_ISP setup, you can use AVRDudess to change the BOD voltage. It's just changing a fuse byte value.

I've never been able to use 115200 on an 8MHz Pro Mini. It's just not reliable. But 57600 works ok.

@ShermanP , in the end I didnt end up cloning.

I was not confident in using AVRDudess in case I stuffed up my original transmitter. So instead I started from scratch using old code and a new mini.

Connecting to my existing mini pro on the circuit board with an NRF24L01 as well as some discrete components turned out to be problematic. Even loading bootloader again. So simply started again on a new mini pro.

I got it to talk to the receiver, but now I've stuffed up my NFR due to mis wiring, so I'll have to wait for a new unit until I continue. Those nfrs seem to be quite tempramental.

@ShermanP and @jim-p , just a thanks for your advice and suggestions on this cloning.

Today I bit the bullet and thought I'd give cloning a go. It actually went really smoothly. I did the following:

  • downloaded and installed AVRDUDESS (what an odd name!) on my laptop
  • It self started when installed
  • connected my Arduino Uno via USB cable to the laptop
  • opened Arduino, uploaded the example file ArduinoISP
  • wired the Uno to the Mini pro as follows
    • D10 β†’ RESET
    • D11 β†’ D11
    • D12 β†’ D12
    • D13 β†’ D13
    • 5V β†’ VCC
    • GND β†’ GND
  • connected a 47uF cap across GND and reset on the Uno
  • in Avrdudess, selected:
    • Programmer = "Arduino (Arduino bootloader using STK500)"
    • MCU = ATmega328P
    • Baud = 19200
    • Port = COM5 in my case
    • pressed the "detect" button to check the MCU
      (came up with "Detected 1e950f = ATmega328P") - all good so far
  • In the "flash" section, I noted the hex name and path to save it
  • Picked the "read" radio button and "Intel Hex" and format
  • Then the "GO" radio button
    This read the full flash perfectly first go!
  • I then connected the new mini pro
  • picked the "write" radio button, then the "go" button

This flashed the drive first go. I checked by then trying to upload a new sketch using the same board details using my CH340 and it worked. So I re-flashed again with AVR.

BTW, I tried to then ask chatgpt to convert the hex file to an ino. Hmmmm. Let's just say part of it got converted, and the rest, well, it probably thought the whole thing about changing the score via different button presses didn't really matter much :slight_smile:

Glad you got it working.

It may not matter for the 328P, but I think the correct programmer is arduino_as_isp. See the following excerpt from the .conf file.

#------------------------------------------------------------
# arduino_as_isp
#------------------------------------------------------------

# Not to be confused with arduinoISP, this is the same as `-c stk500v1`
# but treats EEPROM r/w correctly for arduino_as_isp programmers
# See https://docs.arduino.cc/built-in-examples/arduino-isp/ArduinoISP/
# for details.

programmer # arduino_as_isp
    id                     = "arduino_as_isp";
    desc                   = "AVR as programmer with Arduino-as-ISP FW";
    type                   = "stk500";
    prog_modes             = PM_ISP;
    connection_type        = serial;
    baudrate               = 19200;
;

Also, if the old 328P was set to have the 1.8V BOD voltage, then you need to do the same process for the fuses so the new one will also have that voltage.

Set everything up again with the old processor, then in AVRDudess over on the right click "read" next to the "L" fuse, and it should read all three fuses - Low, High, and Extended. Don't mess with the lock bits.

Write down those three values. Then connect up the new processor and do the same. My prediction is that the Low and High fuses will be the same on both, but the Extended fuse will be 0xFE on the old one, and 0xFD on the new one. If that's the case, just change that fuse to 0xFE, and click "Write". Then Read it back again to make sure it took.

If you get something else when reading the fuses, post the results here and we'll try to figure it out.

By the way, per the datasheet, at 8MHz the processor is good down to 2.4V. But it may well work at lower voltage, so 1.8V is a good choice for the 3.3V 8Mhz Pro Mini running directly on a battery. The default is BOD of 2.7V.

Somewhere along the line I did change the fuses. I "think" it was when I loaded minicore. My bootloader burn said:
writing 1 byte efuse ...
verifying efuse memory against 0b11111110.

I believe this is 0b11111110 in binary, which is 0xFE in hex, which is :
1.8V brownout on ATmega328P.

Then when I tried to clone this with avrdudess, from memory, the "read" I did prior to write and clone confirmed this setting. It does now have BOD as 1.8V listed in the board option in ate arduino menu for boards.

As for the "Arduino to ISP" vs "AVRISP mkll", your probably correct. I'll set it back.

By the way, I had quite a hard time uploading altered code from the mini to PC via the CH340. In the end I connected the mini directly to the ch340 pins and bingo. So a cable 350mm long is toooooo long. Lesson for me to learn there.

Also, for a mini pro, my ch340 has 6 pins (DRT, RXD, TXD, VCC, CTS and GND), as well as a toggle for 3V3 and 5V. I don't use CTS, but with the mini pro need DRT. However when I look online, the vast majority of these don't have DRT. Why?