Differenze tra le versioni di "Arduino, ESP and i2c devices"

Da raspibo.
Jump to navigation Jump to search
m
 
Riga 1: Riga 1:
This project permits to control a remote LCD display connected via an i2c port expander via Wifi.
+
This project permits to list the Id-s of the devices conncted to the I2C bus.
  
 
I have successfully tested this program on an ESP-12 (ESP8266) using the Arduino IDE.
 
I have successfully tested this program on an ESP-12 (ESP8266) using the Arduino IDE.
Riga 7: Riga 7:
 
The hardware "ingredients" needed for this experiments are:
 
The hardware "ingredients" needed for this experiments are:
 
* a ESP8266 (in the example it is a ESP12).
 
* a ESP8266 (in the example it is a ESP12).
* an lcd-plug by jeelabs including the display
+
* some i2c devices (I use several jeelabs' plugs like I/O expander, Lux, pressure, lcd).
 
* A "console cable" (but any USB to TTL converter is okay).
 
* A "console cable" (but any USB to TTL converter is okay).
  
Riga 29: Riga 29:
 
=== Software ===
 
=== Software ===
  
Here is the source code. (I have left in the code several unused functions for the management of the display that can be useful in other applications.
+
Here is the source code.
(the code is deeply inspired by Jeelabs libraries).
 
  
 
<source lang=C>
 
<source lang=C>
 
#include <Wire.h>
 
#include <Wire.h>
#include <ESP8266WiFi.h>
 
  
const char *ssid = "ESPap";
+
void setup()
const char *password = "forknife";
 
 
 
WiFiServer server(23);
 
WiFiClient client;
 
 
 
#define DISP_ADDRESS      (0x24) 
 
#define LCD_MAX_MESSAGE_LENGTH 40
 
#define LCD_DISPLAY_LINES      2 
 
#define HIGH 1
 
#define LOW 0
 
enum {
 
  MCP_IODIR, MCP_IPOL, MCP_GPINTEN, MCP_DEFVAL, MCP_INTCON, MCP_IOCON,
 
  MCP_GPPU, MCP_INTF, MCP_INTCAP, MCP_GPIO, MCP_OLAT
 
};
 
 
 
// bits 0..3 and D4..D7, the rest is connected as follows
 
#define MCP_BACKLIGHT  0x80
 
#define MCP_ENABLE      0x40
 
#define MCP_OTHER      0x20
 
#define MCP_REGSEL      0x10
 
 
 
// Commands
 
#define LCD_CLEARDISPLAY 0x01
 
#define LCD_RETURNHOME 0x02
 
#define LCD_ENTRYMODESET 0x04
 
#define LCD_DISPLAYCONTROL 0x08
 
#define LCD_CURSORSHIFT 0x10
 
#define LCD_FUNCTIONSET 0x20
 
#define LCD_SETCGRAMADDR 0x40
 
#define LCD_SETDDRAMADDR 0x80
 
 
 
// Flags for display entry mode
 
#define LCD_ENTRYRIGHT 0x00
 
#define LCD_ENTRYLEFT 0x02
 
#define LCD_ENTRYSHIFTINCREMENT 0x01
 
#define LCD_ENTRYSHIFTDECREMENT 0x00
 
 
 
// Flags for display/cursor on/off control
 
#define LCD_DISPLAYON 0x04
 
#define LCD_DISPLAYOFF 0x00
 
#define LCD_CURSORON 0x02
 
#define LCD_CURSOROFF 0x00
 
#define LCD_BLINKON 0x01
 
#define LCD_BLINKOFF 0x00
 
 
 
// Flags for display/cursor shift
 
#define LCD_DISPLAYMOVE 0x08
 
#define LCD_CURSORMOVE 0x00
 
#define LCD_MOVERIGHT 0x04
 
#define LCD_MOVELEFT 0x00
 
 
 
// Flags for function set
 
#define LCD_8BITMODE 0x10
 
#define LCD_4BITMODE 0x00
 
#define LCD_2LINE 0x08
 
#define LCD_1LINE 0x00
 
#define LCD_5x10DOTS 0x04
 
#define LCD_5x8DOTS 0x00
 
 
 
static int file;
 
static uint8_t functionset_flags;
 
static uint8_t displaycontrol_flags;
 
static uint8_t entrymodeset_flags;
 
 
 
void setupmcp(void)
 
 
{
 
{
   Wire.beginTransmission(DISP_ADDRESS);
+
   Wire.begin();
  Wire.write((byte)MCP_IODIR);
 
  Wire.write((byte)0);
 
  Wire.endTransmission();
 
}
 
  
void turnoff(void)
+
   Serial.begin(115200);
{
+
   Serial.println("\nI2C Scanner");
  Wire.beginTransmission(DISP_ADDRESS);
 
  Wire.write((byte)MCP_GPIO);
 
   Wire.write((byte)0);
 
   Wire.endTransmission();
 
 
}
 
}
  
void write1byte(unsigned int value)
+
void loop()
 
{
 
{
   Wire.beginTransmission(DISP_ADDRESS);
+
   byte error, address;
  Wire.write((byte)MCP_GPIO);
+
   int nDevices;
  Wire.write((byte)(value | MCP_BACKLIGHT));
 
   Wire.endTransmission();
 
}
 
  
void write4bits(unsigned int value)
+
   Serial.println("Scanning...");
{
 
  write1byte(value);
 
  delayMicroseconds(2);
 
  write1byte(value | MCP_ENABLE);
 
  delayMicroseconds(2);
 
  write1byte(value);
 
   delayMicroseconds(100);
 
}
 
  
void send(unsigned int value, unsigned int mode)
+
  nDevices = 0;
{
+
  for(address = 1; address < 127; address++ )
  //printf("SEND %x %d\n",value,mode);
+
  {
  if (mode)
+
    // The i2c_scanner uses the return value of
     mode = MCP_REGSEL;
+
    // the Write.endTransmisstion to see if
  write4bits((value>>4) | mode);
+
     // a device did acknowledge to the address.
  write4bits((value &0xf) | mode);
+
    Wire.beginTransmission(address);
}
+
    error = Wire.endTransmission();
  
#define command(v) send((v),LOW);
+
    if (error == 0)
 +
    {
 +
      Serial.print("I2C device found at address 0x");
 +
      if (address<16)
 +
        Serial.print("0");
 +
      Serial.print(address,HEX);
 +
      Serial.println("  !");
  
void lcd_clear (void)
+
      nDevices++;
{
+
    }
  command (LCD_CLEARDISPLAY); // Clear display, set cursor position to zero.
+
    else if (error==4)
  delayMicroseconds(2000);  // This command takes a long time.
+
    {
}
+
      Serial.print("Unknow error at address 0x");
 
+
      if (address<16)
void lcd_home (void)
+
        Serial.print("0");
{
+
      Serial.println(address,HEX);
  // Set cursor position to zero and undo any scrolling that is in effect.
+
     }
  command (LCD_RETURNHOME);
 
  delayMicroseconds(2000);  // This command takes a long time.
 
}
 
 
 
void lcd_set_cursor_position (uint8_t col, uint8_t row)
 
{
 
  // If given an invalid row number, display on last line.
 
  if ( row >= LCD_DISPLAY_LINES ) {
 
     row = LCD_DISPLAY_LINES - 1;    // We count rows starting from 0.
 
 
   }
 
   }
 +
  if (nDevices == 0)
 +
    Serial.println("No I2C devices found\n");
 +
  else
 +
    Serial.println("done\n");
  
   // Positions of the beginnings of rows in LCD DRAM.
+
   delay(5000);           // wait 5 seconds for next scan
  const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
 
 
 
  command (LCD_SETDDRAMADDR | (col + row_offsets[row]));
 
}
 
 
 
void lcd_display_off (void)
 
{
 
  displaycontrol_flags &= ~LCD_DISPLAYON;
 
  command (LCD_DISPLAYCONTROL | displaycontrol_flags);
 
}
 
 
 
void lcd_display_on (void)
 
{
 
  displaycontrol_flags |= LCD_DISPLAYON;
 
  command (LCD_DISPLAYCONTROL | displaycontrol_flags);
 
 
}
 
}
  
void lcd_blinking_cursor_off (void)
 
{
 
  displaycontrol_flags &= ~LCD_BLINKON;
 
  command (LCD_DISPLAYCONTROL | displaycontrol_flags);
 
}
 
 
void lcd_blinking_cursor_on (void)
 
{
 
  displaycontrol_flags |= LCD_BLINKON;
 
  command (LCD_DISPLAYCONTROL | displaycontrol_flags);
 
}
 
 
void lcd_underline_cursor_off (void)
 
{
 
  displaycontrol_flags &= ~LCD_CURSORON;
 
  command (LCD_DISPLAYCONTROL | displaycontrol_flags);
 
}
 
 
void lcd_underline_cursor_on (void)
 
{
 
  displaycontrol_flags |= LCD_CURSORON;
 
  command (LCD_DISPLAYCONTROL | displaycontrol_flags);
 
}
 
 
void lcd_scroll_left (void) {
 
  command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
 
}
 
 
void lcd_scroll_right (void) {
 
  command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
 
}
 
 
size_t lcd_write (char value)
 
{
 
  send ((uint8_t) value, HIGH);
 
  return 1;  // Assume success
 
}
 
 
size_t lcd_write_string (const char *buffer)
 
{
 
  size_t size = strlen (buffer);
 
  size_t n = 0;
 
  while ( size-- ) {
 
    n += lcd_write ((uint8_t) (*buffer++));
 
  }
 
  return n;
 
}
 
 
int lcd_printf (const char *format, ...)
 
{
 
  char message_buffer[LCD_MAX_MESSAGE_LENGTH + 1];
 
 
  va_list ap;
 
  va_start (ap, format);
 
  int chars_written
 
    = vsnprintf (message_buffer, LCD_MAX_MESSAGE_LENGTH, format, ap);
 
  va_end (ap);
 
 
  lcd_write_string (message_buffer);
 
 
  return chars_written;
 
}
 
 
void setup() {
 
  Wire.begin();
 
  delay(1000);
 
  Serial.begin(115200);
 
  Serial.println();
 
  Serial.print("Configuring access point...");
 
  /* You can remove the password parameter if you want the AP to be open. */
 
  WiFi.softAP(ssid, password);
 
 
  IPAddress myIP = WiFi.softAPIP();
 
  Serial.print("AP IP address: ");
 
  Serial.println(myIP);
 
 
  server.begin();
 
  server.setNoDelay(true);
 
 
  Serial.println("i2s lcd driver\n");
 
 
  setupmcp();
 
  write4bits(0x03);
 
  delayMicroseconds(4500);
 
  write4bits(0x03);
 
  delayMicroseconds(4500);
 
  write4bits(0x03);
 
  delayMicroseconds(150);
 
  write4bits(0x02);
 
 
  functionset_flags = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
 
  // Finally, set # lines, font size, etc.
 
  command (LCD_FUNCTIONSET | functionset_flags);
 
 
  // Turn the display on with no cursor or blinking cursor.
 
  displaycontrol_flags = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
 
  command (LCD_DISPLAYCONTROL | displaycontrol_flags);
 
 
  // Clear display.
 
  lcd_clear ();
 
 
  // Initialize to supported text direction (for romance languages).
 
  entrymodeset_flags = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
 
  command (LCD_ENTRYMODESET | entrymodeset_flags);
 
}
 
 
int nline=0;
 
int nchar=0;
 
char contents[LCD_DISPLAY_LINES][LCD_MAX_MESSAGE_LENGTH+1];
 
void loop()
 
{
 
  if (!client.connected()) {
 
    if (client) client.stop();
 
    if (server.hasClient())
 
      client = server.available();
 
  } else {
 
    int incomingByte = 0;
 
 
    if (client.available() > 0) {
 
      incomingByte = client.read();
 
 
      if (incomingByte == '\r' || incomingByte == '\n') {
 
        Serial.println();
 
        client.println();
 
        lcd_home ();
 
        lcd_clear ();
 
        lcd_set_cursor_position(0,0);
 
        lcd_printf(contents[0]);
 
        lcd_set_cursor_position(0,1);
 
        lcd_printf(contents[1]);
 
        nline = (nline + 1) % LCD_DISPLAY_LINES;
 
        nchar = 0;
 
      } else if (incomingByte == 5) { //ctrl-E
 
        for (nline=0; nline<LCD_DISPLAY_LINES; nline++)
 
          contents[nline][0]=0;
 
        nchar = nline = 0;
 
        turnoff();
 
      } else if (nchar < LCD_MAX_MESSAGE_LENGTH) {
 
        contents[nline][nchar++]=incomingByte;
 
        contents[nline][nchar]=0;
 
        Serial.print((char)incomingByte);
 
        client.print((char)incomingByte);
 
      }
 
    }
 
    if(Serial.available()){
 
      client.write(Serial.read());
 
      delay(1);
 
    }
 
  }
 
}
 
 
</source>
 
</source>
  
Riga 343: Riga 93:
 
If GP00 is unconnected, the program is restarted at power up.
 
If GP00 is unconnected, the program is restarted at power up.
  
When this program is running, your ESP is a Wi-FI access point (you'll see it on your devices under the name, or ESSID, "ESPap".  
+
Use a terminal emulator to "talk' with yout ESP.  
The password is "forknife".)
+
<pre>
 +
screen /dev/ttyUSB0 115200
 +
</pre>
  
It does not provide a DHCP server so too automagic connectivity tools like those running on smartphones and dumb operating systems
+
You'll get the list of i2c devices (each 5 seconds).
may have troubles to connect.
 
It you use linux you can get a connection. The Esp itself will get the address 192.168.4.1/24 so you should assign by hand another
 
address on the same subnet (say 192.168.4.2/24) to your wlan interface.
 
  
Now you can connect to your ESP using nc or socat. I prefer socat;
 
 
<pre>
 
<pre>
socat /dev/tty,rawer,escape=0x03 TCP:192.168.4.1:23
+
Scanning...
 +
I2C device found at address 0x24  !
 +
done
 +
 
 +
Scanning...
 +
I2C device found at address 0x24  !
 +
done
 +
 
 +
Scanning...
 +
I2C device found at address 0x20  !
 +
I2C device found at address 0x24  !
 +
done
 +
 
 +
Scanning...
 +
I2C device found at address 0x20  !
 +
I2C device found at address 0x24  !
 +
done
 +
 
 +
Scanning...
 +
I2C device found at address 0x24  !
 +
done
 +
 
 +
Scanning...
 +
No I2C devices found
 
</pre>
 
</pre>
 
* each line typed in will be shown on the display (when you type return)
 
* crtl-E turns the display off (handled by the program on ESC).
 
* crtl-C terinates the connection (socat parameter escape=0x03).
 

Versione attuale delle 10:58, 27 giu 2016

This project permits to list the Id-s of the devices conncted to the I2C bus.

I have successfully tested this program on an ESP-12 (ESP8266) using the Arduino IDE.

hardware

The hardware "ingredients" needed for this experiments are:

  • a ESP8266 (in the example it is a ESP12).
  • some i2c devices (I use several jeelabs' plugs like I/O expander, Lux, pressure, lcd).
  • A "console cable" (but any USB to TTL converter is okay).

wiring

i2c: SDA is GP04, SCL is GP05. The pins of jeelabs' lcd plug (this cabling works for all i2c based jeelabs' plugs):

  • P -> +5V or disconnected (unused for lcd-plug)
  • D -> GP04 (SDA)
  • G -> GND
  • + -> +3V3
  • A -> GP05 (SCL)
  • I -> NC (unused for lcd-plug, can be connected to another GPIO for other boards providing useful interrupts).

Console cable: using an Adafruit like cable:

  • Black -> GROUND
  • While -> TXD on ESP
  • Green -> RXD on ESP

DO NOT CONNECT THE RED PIN TO YOUR ESP! The red pin is +5V while ESP need +3V3 so either you have a step-down circuit to convert 5V to 3.3V or you'll need another power source of the right voltage for yout ESP.

Software

Here is the source code.

#include <Wire.h>

void setup()
{
  Wire.begin();

  Serial.begin(115200);
  Serial.println("\nI2C Scanner");
}

void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

Testing

Load the program on you ESP. Remember that GP00 must be connected to ground at power-up to set the ESP in "flashing mode".

Unplug GP00 otherwise at the next power cycle your ESP will be in "flashing mode" again. If GP00 is unconnected, the program is restarted at power up.

Use a terminal emulator to "talk' with yout ESP.

screen /dev/ttyUSB0 115200

You'll get the list of i2c devices (each 5 seconds).

Scanning...
I2C device found at address 0x24  !
done

Scanning...
I2C device found at address 0x24  !
done

Scanning...
I2C device found at address 0x20  !
I2C device found at address 0x24  !
done

Scanning...
I2C device found at address 0x20  !
I2C device found at address 0x24  !
done

Scanning...
I2C device found at address 0x24  !
done

Scanning...
No I2C devices found