My I2C Project Not Working on Leonardo

I've created a small project and used an Uno to do so. My project worked fine until I switched out the Uno for a Leonardo.

I have my

  • I2C Clock on A3
  • I2C Data on A4

Thanks for any and all help. :)

Eric

On the UNO, I2C uses pins A4 and A5. Is the Leonardo different?

What does the program do that you don't want? What does the program not do that you do want? Where is the code?

Hello Paul.

This is the code:

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

#include "DHT.h"
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

#define DHTPIN 2     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)

// LED pin for Alarm Indicator 
int humLed = 3;
int tempLed = 4;

DHT dht(DHTPIN, DHTTYPE);

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

void setup() {
  Serial.begin(9600); 
  Serial.println("DHTxx test!");

  pinMode(humLed, OUTPUT);        // sets the digital pin as output
  pinMode(tempLed, OUTPUT);      // sets the digital pin as output

  dht.begin();
  matrix.begin(0x70);  // pass in the address
}

void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } 
  else {
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" *C");

    if (h >= 50.0) {
      digitalWrite(humLed, HIGH);   // sets the LED on
    } 
    else {
      digitalWrite(humLed, LOW);   // sets the LED on
    }

    if (t >= 28.0) {
      digitalWrite(tempLed, HIGH);   // sets the LED on
    } 
    else {
      digitalWrite(tempLed, LOW);   // sets the LED on
    }

  }
  delay(1000);


}

The code works when I don’t include this line:

  matrix.begin(0x70);  // pass in the address

On the Leonardo, I2C is on digital pins 2 and 3.

I can reproduce this. It seems flaky, to say the least.

I have my

I2C Clock on A3 I2C Data on A4

That is the problem.

On the Leonardo the I2C lines are at the top left of the board on separate pins. These just mirror the true I2C pins which are D3 for the clock and D2 for the data. It takes about 8 seconds before an I2C program starts to run from power up.

Really 8 seconds? This must be specific to the Leonardo? Why is that?

Because it does not use a conventional USB / serial converter but one programmed into the processor. See:- http://www.visualmicro.com/post/2012/06/02/Arduino-Leonardo-Upload-Differences.aspx

On the Leonardo... It takes about 8 seconds before an I2C program starts to run from power up.

I suppose I'm confused why you said the above statement. Perhaps you did not mean 'I2C' ?

Yes I do. It is what I just timed an I2C program that flashes some lights with a PCA6985. However it will apply to all programs not just I2C ones if that is what you mean.

On the Uno the same code starts in under a second

Hmm..According to Arduino.cc, you only experience the ~8sec wait period when the USB-reset occurs. On a power-up, the sketch should start automatically, but the board can be reset by "opening/closing the CDC port (USB) at 1200b/s.

The reset is triggered when the Leonardo's virtual (CDC) serial / COM port is opened at 1200 baud and then closed. When this happens, the processor will reset, breaking the USB connection to the computer (meaning that the virtual serial / COM port will disappear). After the processor resets, the bootloader starts, remaining active for about 8 seconds. The bootloader can also be initiated by pressing the reset button on the Leonardo. Note that when the board first powers up, it will jump straight to the user sketch, if present, rather than initiating the bootloader.

Now of course, I do not have a Leonardio so I have no idea what really happens, but if it takes 8 seconds for all sketches to start then it sounds like the board is being reset every time?

then it sounds like the board is being reset every time?

Yes of course it is, when you plug it in and so power it up it is subject to a reset. That is how all electronics work.

Exactly the same happens when you press the reset button.

From Arduino.cc

Note that when the board first powers up, it will jump straight to the user sketch, if present, rather than initiating the bootloader.

Then is statement from Arduino is wrong?

Looks like it.

Armed with this new information, I found that my I2C scanner detected another Arduino running as an I2C slave if and only if I built in at least a 4-second delay in setup. Also I used the SDA/SCL pins marked on the board this time.

However I don’t fully understand this. This is the master side, not the slave side. So if it takes 8 seconds to “boot”, surely once it gets going, I2C should be immediately active? The results seems to suggest that the delay on the master end is required for “something” to settle.

Further tests indicate that it isn’t reliable. I can hit reset, and not have the message repeat. Indeed, any message. This code, for example:

void setup() {
  Serial.begin (115200);
  pinMode (13, OUTPUT);
  for (int j = 0; j < 4; j++)
     {
     digitalWrite (13, HIGH);
     delay (500);
     digitalWrite (13, LOW);
     delay (500);
     }
  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
}
void loop () {}

I only see the “Scanning” message occasionally. Even if I sit there hitting the reset button. And wait for the “L” LED to stop pulsing.

Nick you ned to see http://arduino.cc/en/Guide/ArduinoLeonardo In particular you need to add a

 while(!Serial) ;

Line.

OK, I did that and it works occasionally.

I'm confused now. That page says connecting the serial monitor does not reset the board. Fair enough. So re-opening the monitor does not reset the board. That accounts for why if I re-open it, no message appears.

But it also says if you do reset the board (eg. hit the reset button) the existing monitor disconnects (it breaks the link to the existing monitor). So how, exactly, do I start it up and watch debugging messages?

  • Open monitor, then reset?
  • Reset, then open monitor?
  • Reset, wait X seconds, then open monitor?

I just can't get it to reliably show a message in setup.

Further testing indicates that the serial comms, through the USB, gives disconcerting results.

If I use Serial1 (the hardware serial) and connect that up to the Mac via an FTDI cable, it looks better.

Also, connecting SCL/SDA on the Leonardo (the pins so marked) with A5/A4 on the Uno, I2C seems to work OK.

Hi guys and compliments for the forum, very comprehensive.
I’m following it since 2 years and I must say I’m almost a noob about arduino.
I have a leonardo a wanted ro use this sketch wrote for the uno, the lcd (with i2c interface) lights up but nothing is showed.
I also connect scl and sda to the right digital pins but nothing. The contrast is correct as well.
Ca you help me out? Do I need to modify something on the sketch? Thanks a lot!
Here it is:

#include <Wire.h>
#include <Time.h>
#include <LiquidCrystal_I2C.h>
#include <AlarmController.h>
#include <AlarmSettings.h>
#include <Bounce.h>
#include <Alarm.h>

const uint8_t snoozePin = 2; //Purple
const uint8_t leftPin = 3; //Green
const uint8_t rightPin = 4; //Brown
const uint8_t upPin = 5; //Blue
const uint8_t downPin = 6; //Orange
const uint8_t okPin = 8; //Yellow
const uint8_t cancelPin = 8; //Grey
const uint8_t ledPin = 9; //White

const uint8_t buzzerPin = 13;

const uint8_t bounceDelay = 8;

double fadeValue = 0.0;
unsigned long timeStart = 0;
unsigned long timeHigh = 0;
unsigned long timeOn = 0;
unsigned long timeOnPrev = 0;
unsigned long buzzerStart = 0;
// x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
const int buzzerP = {150,2000,150,2000,150,2000,150,2000,150,80,150,2000,150,80,150,2000,150,80,150,80,150,2000,150,80,150,80,150,2000,150,80,150,80,150,80,150,2000,150,80,150,80,150,80,150,2000,150,80,150,80,150,80,150,80,150,2000,150,80,150,80,150,80,150,80,150,1000};
const int buzzerPL = 64;
const uint8_t buzzerL = 54;
int buzzerPI = 0;

AlarmSettings set;
LiquidCrystal_I2C lcd(0x27,16,2);

AlarmController ac(&set,&lcd,ledPin);

Bounce btnLeft = Bounce(leftPin,bounceDelay);
Bounce btnRight = Bounce(rightPin,bounceDelay);
Bounce btnUp = Bounce(upPin,bounceDelay);
Bounce btnDown = Bounce(downPin,bounceDelay);
Bounce btnOK = Bounce(okPin,bounceDelay);
Bounce btnCancel = Bounce(cancelPin,bounceDelay);
Bounce btnSnooze = Bounce(snoozePin,bounceDelay);

void setup() {
pinMode(ledPin, OUTPUT);
pinMode(snoozePin, INPUT);
pinMode(leftPin, INPUT);
pinMode(rightPin, INPUT);
pinMode(upPin, INPUT);
pinMode(downPin, INPUT);
pinMode(okPin, INPUT);
pinMode(cancelPin, INPUT);
pinMode(buzzerPin, OUTPUT);
timeStart = millis();
timeOn = millis();
timeOnPrev = timeOn;
lcd.init();
lcd.setBacklight(1);
lcd.home();

lcd.print(F("setup "));

uint8_t ledOff[8] = {0b00000,
0b00000,
0b00000,
0b00000,
0b00100,
0b01110,
0b01110,
0b01110 };
uint8_t ledOn[8] = {0b00100,
0b10101,
0b10101,
0b00000,
0b00100,
0b01110,
0b01110,
0b01110 };

uint8_t checkbox1[8] = {0b00000,
0b11111,
0b10001,
0b10001,
0b10001,
0b10001,
0b11111,
0b00000 };

uint8_t checkbox2[8] = {0b00000,
0b11111,
0b10001,
0b10101,
0b10101,
0b10001,
0b11111,
0b00000 };

lcd.createChar(0b00000, ledOff);
lcd.createChar(0b00001, ledOn);

lcd.createChar(0b00010, checkbox1);
lcd.createChar(0b00011, checkbox2);

digitalWrite(buzzerPin, LOW);
analogWrite(ledPin, 0);

ac.setMakeLight(analogWrite);
}

void loop() {
//update time
timeOn = millis();
if(timeOn<timeOnPrev) { //overflow!!
set.getTime()->addMillis((4294967295ul - timeOnPrev) + timeOn);
}
else{
set.getTime()->addMillis(timeOn - timeOnPrev);
}
timeOnPrev = timeOn;

//update AlarmState
ac.checkAlarmState();

//make noise?
if(ac.mustMakeNoise()) {
if(buzzerPI % 2 == 0) {
digitalWrite(buzzerPin, HIGH);
}
else {
digitalWrite(buzzerPin, LOW);
}
if(abs(millis() - buzzerStart) > buzzerP[buzzerPI]) {
buzzerPI++;
if(buzzerPI == buzzerPL)
buzzerPI = buzzerL;
buzzerStart = millis();
}
}
else {
buzzerPI = 0;
digitalWrite(buzzerPin, LOW);
}

//update LCD
ac.printLCD();

//check snooze-button
btnSnooze.update();
if(btnSnooze.risingEdge()) {
ac.doSnooze();
if(ac.getAlarmState() == 0) {
timeStart = millis();
btnSnooze.update();
ac.printLCD();
fadeValue = 0.0;
analogWrite(ledPin,round(fadeValue));
while(btnSnooze.read() == HIGH) {
if(abs(millis() - timeStart) > 600) {
//fadeValue += 15;
fadeValue += (fadeValue / 600) + 1;
if(fadeValue > 255) {
fadeValue = 255.0;
}
analogWrite(ledPin,round(fadeValue));
delay(10);
}
btnSnooze.update();
}
}
}

//Check other buttons
btnLeft.update();
btnRight.update();
btnUp.update();
btnDown.update();
btnOK.update();
btnCancel.update();

if(btnOK.risingEdge()) {
ac.doOK();
}
else if(btnCancel.risingEdge()) {
ac.doCancel();
}
else if(btnLeft.risingEdge()) {
ac.doLeft();
}
else if(btnLeft.fallingEdge()) {
ac.endLeft();
}
else if(btnRight.risingEdge()) {
ac.doRight();
}
else if(btnRight.fallingEdge()) {
ac.endRight();
}
else if(btnUp.risingEdge()) {
ac.doUp();
btnUp.update();
timeStart = millis();
ac.printLCD();
while(btnUp.read() == HIGH) {
if(abs(millis() - timeStart) > 800) {
ac.doUp();
ac.printLCD();
delay(140);
}
btnUp.update();
}
}
else if(btnDown.risingEdge()) {
ac.doDown();
btnUp.update();
timeStart = millis();
ac.printLCD();
while(btnDown.read() == HIGH) {
if(abs(millis() - timeStart) > 800) {
ac.doDown();
ac.printLCD();
delay(140);
}
btnDown.update();
}
}

}

Please use code tags.

Read this before posting a programming question

Which pins did you connect them to exactly? The Leonardo has different pins for SDA/SCL.