Background: I make an electronic drum to play computer games. The drum is connected to the computer via USB serial port. I've already finished my program to let the drum be identified as a keyboard. However, the keys which could be input and all parameters are fixed. I hope other people can adjust input keys and some variables and then re-burn the program into the electronic drum at any time themselves without seeing my source code. I think I just have the ability to write a program in Python that uploads .hex files into Pro Micro(Opening the serial port at 1200 baud to enter bootloader, then running avrdude)
My Question: Is there any way to let users adjust some specified variables and then upload program into the Pro Micro? (Under the premise of the user cannot see my source code)
Thanks a lot!!!
Maybe you should reconsider the approach? Settings can be stored in EEPROM in the Pro Micro and you can make that updatable through e.g. a terminal program (it does not have to be Serial Monitor).
If you want to update the actual code, the program that is used is avrdude; be aware that you need to issue a reset command first by operning/closing the serial port with a baud rate of 1200 baud. You can export the hexfile so it can be distributed.
You can find the exact avrdude command if you enable verbose output during upload in file → preferences.
Thanks for your answer! However, I don't know how to modifying the EEPROM in Arduino through the PC terminal program. Do you have any suggestions for this?
why not have the Arduino read a pot in real time to adjust the rate? no need to modify/upload the program each time the rate needs to change
The below code makes use of the fact that boards with native USB (e.g. your Pro Micro) can detect if a terminal program has opened the connection with the Pro Micro. The below snip gives you 5 seconds after powering your board to open a connection to the board.
while (!Serial && millis() < 5000) {}
In the code below it has been extended a little to have the RX led flash while it is waiting. Once the waiting time is over, or an application has opened the serial port, the program will check the reason why it aborted the while-loop.
if(Serial)
If the reason is that the application opened the serial port, the code will display a little menu and you can configure.
You will need to specify where in EEPROM the variables of interest will be saved. The below results in consecutive addresses
const uint16_t addr_intA = 0;
const uint16_t addr_boolB = addr_intA + sizeof(intA);
const uint16_t addr_floatF = addr_boolB + sizeof(boolB);
For 3 variables this is still doable; if you have 10s or 100s it becomes a nightmare and you're advised to use a struct to store all your variables in RAM instead of individual variables and read/write that struct to EEPROM.
By using EEPROM.get() and EEPROM.put() you do not have to worry about the size of the individual variables that your want to retrieve or store.
Demo code
#include <EEPROM.h>
// your variables
int intA;
bool boolB;
float floatF;
// your variables in memory
const uint16_t addr_intA = 0;
const uint16_t addr_boolB = addr_intA + sizeof(intA);
const uint16_t addr_floatF = addr_boolB + sizeof(boolB);
// RX LED used as indicator that we're waiting for terminal program to open connection
int RXLED = 17; // The RX LED has a defined Arduino pin
void setup()
{
Serial.begin(115200);
pinMode(RXLED, OUTPUT);
digitalWrite(RXLED, LOW);
// get the saved variables
EEPROM.get(addr_intA, intA);
EEPROM.get(addr_boolB, boolB);
EEPROM.get(addr_floatF, floatF);
// wait for optional terminal connection
while (!Serial && millis() < 5000)
{
digitalWrite(RXLED, HIGH);
delay(100);
digitalWrite(RXLED, LOW);
delay(100);
}
// if application opened serial port
if (Serial)
{
// LED on to indicate that we're in configuration mode
digitalWrite(RXLED, LOW);
configure();
// indicate configuration done; hangs forever
for (;;)
{
digitalWrite(RXLED, HIGH);
delay(500);
digitalWrite(RXLED, LOW);
delay(500);
}
}
// LED off
digitalWrite(RXLED, HIGH);
}
void loop()
{
// put your main code here, to run repeatedly:
}
void configure()
{
char data[32];
char option = 0;
Serial.println(F("Drum box configuration"));
Serial.print(F("1 Change intA; current value = "));
Serial.println(intA);
Serial.print(F("2 Change boolB; current value = "));
Serial.println(boolB);
Serial.print(F("3 Change floatF; current value = "));
Serial.println(floatF);
Serial.println(F("S Save"));
Serial.println(F("X eXit"));
while (true)
{
int numBytes = Serial.readBytesUntil('\n', data, sizeof(data));
if (numBytes != 0)
{
data[numBytes] = '\0';
switch (option)
{
case 0:
if (data[0] == 'S')
{
// save the configuration
Serial.println(F("Saving"));
EEPROM.put(addr_intA, intA);
EEPROM.put(addr_boolB, boolB);
EEPROM.put(addr_floatF, floatF);
Serial.println(F("Saved"));
}
else if (data[0] == 'X')
{
// done
Serial.println(F("Exit"));
return;
}
else
{
// set option (1..3)
option = data[0];
Serial.print(F("option = "));
Serial.println(option);
}
break;
case '1':
Serial.print(F("intA = "));
// convert text to integer
intA = atoi(data);
Serial.println(intA);
// reset option
option = 0;
break;
case '2':
Serial.print(F("boolB = "));
// convert text to integer
boolB = atoi(data);
Serial.println(boolB);
// reset option
option = 0;
break;
case '3':
Serial.print(F("floatF = "));
// convert text to float
floatF = atof(data);
Serial.println(floatF);
// reset option
option = 0;
break;
}
}
}
}
Output example
17:09:16.890 -> Drum box configuration
17:09:16.890 -> 1 Change intA; current value = 789
17:09:16.890 -> 2 Change boolB; current value = 1
17:09:16.890 -> 3 Change floatF; current value = 3.14
17:09:16.890 -> S Save
17:09:16.890 -> X eXit
17:09:23.121 -> option = 1
17:09:25.023 -> intA = 345
17:09:29.486 -> option = 3
17:09:32.450 -> floatF = 2.71
17:09:38.047 -> Saving
17:09:38.047 -> Saved
17:09:42.304 -> Exit
Note:
- You can not store and retrieve String objects with the above approach.
- Changing the type of a variable in your code once the data has been stored in EEPROM can lead to unexpected results.
- Code is not hardened so possible mistakes while entering data can result in unexpected results.
- The RXLED has inverted logic so a HIGH means off.
Thank you, I learned a lot!!!
But I also have one question. Because I realized key input also by Serial port, I suspect it will run the configure() function every time when I plug the Pro Micro into my computer. That way I should only enter the loop() function after I enter 'X'. I want my drums to be plug and play most of the time.
Maybe I misunderstood, please advise!
The code was written with the idea that you usually don't have a laptop connected (or a terminal program connecting to your box).
If that is not the case, you will indeed need something like a keystroke.
Just let me know your specific needs.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.