0

What are the differences in serial communication between PC <---> Arduino UNO (ATMEGA328p) and PC <---> Arduino Leonardo (ATMEGA32u4)?

I am asking because of a problem related to using these two Arduino boards for data logging in the following way:

  1. PC sends a specific char string to Arduino, via serial port, to initialize datalogging
  2. Arduino measures data, let's say a fixed number of ADC readings
  3. Arduino stops measuring, sends data back to the PC over serial port
  4. Arduino waits until new serial data are received before logging new data

If I send/receive data via the Arduino IDE serial monitor, this procedure works on both boards. However, I want a separate GUI program (Qt) to handle the serial communication, where one clicks a button to send the data in step 1, and plot the data from step 3 on a graph.

I wrote a simple Qt GUI where a button is clicked, and the measured data are printed to the GUI screen. Observations while testing it:

  • Arduino UNO as datalogger: Arduino is plugged into USB socket of PC, then I launch the GUI, then click button to start data acquisition. The data are shown. Program appears to work fine.
  • Arduino Leonardo as datalogger: Arduino is plugged into USB socket of PC, then I launch the GUI, then click button to start data acquisition. The data are not received, program hangs.

Then

  • Arduino Leonardo as datalogger: Arduino is plugged into USB socket of PC, Open Arduino IDE serial monitor, send command to acquire data. Then close Arduino IDE serial monitor, launch the GUI, click button to start data acquisition. The GUI program now works.

Long story, but basically there appears to be a difference when using the two Arduino boards with external programs to do serial communication. Can someone outline the differences and why Leonardo needs the "jump start" I described above using Arduino serial monitor? Ultimately I want to fix the problem and avoid that hack.

Reluctant to post Qt code on Arduino stack exchange, but here is how I start the serial port:

ui->setupUi(this);
microcontroller_is_available = false;
microcontroller_port_name = "false";
microcontroller = new QSerialPort(this);
qDebug() << "Number of available ports: " << QSerialPortInfo::availablePorts().length();
foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) {
    qDebug() << "Has product ID " << serialPortInfo.hasProductIdentifier();
    if(serialPortInfo.hasProductIdentifier()){qDebug() << "Product ID: " << serialPortInfo.productIdentifier();}
    qDebug() << "Has vendor ID " << serialPortInfo.hasVendorIdentifier();
    if(serialPortInfo.hasVendorIdentifier()){qDebug() << "Vendor ID: " << serialPortInfo.vendorIdentifier();}
}

foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) {
   if(serialPortInfo.hasVendorIdentifier() && serialPortInfo.hasProductIdentifier()){
       if(serialPortInfo.vendorIdentifier() == micro_vendor_id){
           if(serialPortInfo.productIdentifier() == micro_product_id){
              microcontroller_port_name = serialPortInfo.portName();
              microcontroller_is_available = true;
           }
       }
   }
}

if(microcontroller_is_available){  // open and configure serialport
    microcontroller->setPortName(microcontroller_port_name);
    microcontroller->open(QSerialPort::ReadWrite);
    microcontroller->setBaudRate(QSerialPort::Baud115200);
    microcontroller->setDataBits(QSerialPort::Data8);
    microcontroller->setParity(QSerialPort::NoParity);
    microcontroller->setStopBits(QSerialPort::OneStop);
    microcontroller->setFlowControl(QSerialPort::NoFlowControl);
}
else{QMessageBox::warning(this, "Port error", "Cannot connect DAQ.");}

Setup part of my Arduino code:

void setup(){
  DDRB  |= B11111111;  // (654210 outputs, miso input)     
  PORTB &= ~_BV(RF_AMPL);
  DDRD  |= B1100010; 
  PORTD |= (_BV(SRAM_HOLD) | _BV(SRAM_SS1)); 
  ADCSRA=0;
  SPCR = B01010000;           // SPI init (could get away with 11010000 on 328p but not 32u4)
  SPSR = B00000001;
  PORTD &= ~_BV(SRAM_SS1);     // Slave init
  SPDR=WRMR;  while(!(SPSR & (1<<SPIF)));
  SPDR=SEQUENTIAL_MODE; while(!(SPSR & (1<<SPIF)));
  PORTD |= _BV(SRAM_SS1); 
  __builtin_avr_delay_cycles(160);
  PORTD &= ~_BV(SRAM_SS1); 
  SPDR=RDMR; while(!(SPSR & (1<<SPIF)));
  SPDR=0x00; while(!(SPSR & (1<<SPIF)));
  PORTD |= (_BV(SRAM_HOLD) | _BV(SRAM_SS1)); 
  state1=0;
  count=0;
  pulse_count=0;
  serial_counter=0;
  Serial.begin(115200);  while(!Serial){}
}
  • Is there a reason why you're not using the SPI library? – Majenko Jul 15 '18 at 14:26
  • I need SPI that is faster than the Arduino SPI library gives. – MichaelT Jul 15 '18 at 14:57
  • what happens if you plug in leonardo -- then reset leonardo -- then start GUI . . . . . . . . . . . . . . . or, plug in -- start GUI -- reset ? – jsotola Jul 15 '18 at 22:53
0

Yes, there are differences.

  • The Uno has an ATMega16U2 as a USB to UART bridge. When you open the serial port the ATMega16U2 signals to the ATMega328p to reset and start your sketch from the beginning.
  • The Leonardo has an ATMega32U4 as the main MCU which is directly connected to the USB port. When you open the serial port you connect to your program wherever it happens to be at the time.

The key thing there is that when you open the Uno's port the board reboots and your sketch restarts. When you open the Leonardo's port the board doesn't reset and your sketch is wherever your sketch happens to be.

So: you have to ensure that your sketch doesn't rely on things in setup() or early on in its execution for making the serial connection work.

  • I already followed the Arduino guide to use Serial.begin(115200); while(!Serial){}. Setup code posted above (minus pin definitions). Can you see anything obviously wrong? Same Arduino sketch is used for UNO and Leonardo. – MichaelT Jul 15 '18 at 14:20
0

I solved this by resetting the Arduino (open serial port at 1200 baud, then close serial port) when launching the Qt program.

Here is the relevant part of the Qt program:

        microcontroller->setPortName(microcontroller_port_name);
        microcontroller->open(QSerialPort::ReadWrite);
        microcontroller->setBaudRate(QSerialPort::Baud1200);
        microcontroller->setDataBits(QSerialPort::Data8);
        microcontroller->setParity(QSerialPort::NoParity);
        microcontroller->setStopBits(QSerialPort::OneStop);
        microcontroller->setFlowControl(QSerialPort::HardwareControl);

        qDebug() << "open 1200 baud";
        Sleep(10);
        microcontroller->close();
        Sleep(10);

        microcontroller->open(QSerialPort::ReadWrite);
        microcontroller->setBaudRate(QSerialPort::Baud115200);
        microcontroller->setDataBits(QSerialPort::Data8);
        microcontroller->setParity(QSerialPort::NoParity);
        microcontroller->setStopBits(QSerialPort::OneStop);
        microcontroller->setFlowControl(QSerialPort::HardwareControl);

Now whenever I launch the Qt program, the Arduino is ready to accept serial data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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