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

Da raspibo.
Jump to navigation Jump to search
Riga 35: Riga 35:
  
 
const char *ssid = "ESPap";
 
const char *ssid = "ESPap";
const char *password = "thereisnospoon";
+
const char *password = "knife";
  
 
WiFiServer server(23);
 
WiFiServer server(23);
Riga 144: Riga 144:
 
#define command(v) send((v),LOW);
 
#define command(v) send((v),LOW);
  
 
+
void lcd_clear (void)
  void
 
lcd_clear (void)
 
 
{
 
{
 
   command (LCD_CLEARDISPLAY);  // Clear display, set cursor position to zero.
 
   command (LCD_CLEARDISPLAY);  // Clear display, set cursor position to zero.
Riga 152: Riga 150:
 
}
 
}
  
  void
+
void lcd_home (void)
lcd_home (void)
 
 
{
 
{
 
   // Set cursor position to zero and undo any scrolling that is in effect.
 
   // Set cursor position to zero and undo any scrolling that is in effect.
Riga 160: Riga 157:
 
}
 
}
  
  void
+
void lcd_set_cursor_position (uint8_t col, uint8_t row)
lcd_set_cursor_position (uint8_t col, uint8_t row)
 
 
{
 
{
 
   // If given an invalid row number, display on last line.
 
   // If given an invalid row number, display on last line.
Riga 174: Riga 170:
 
}
 
}
  
  void
+
void lcd_display_off (void)
lcd_display_off (void)
 
 
{
 
{
 
   displaycontrol_flags &= ~LCD_DISPLAYON;
 
   displaycontrol_flags &= ~LCD_DISPLAYON;
Riga 181: Riga 176:
 
}
 
}
  
  void
+
void lcd_display_on (void)
lcd_display_on (void)
 
 
{
 
{
 
   displaycontrol_flags |= LCD_DISPLAYON;
 
   displaycontrol_flags |= LCD_DISPLAYON;
Riga 188: Riga 182:
 
}
 
}
  
  void
+
void lcd_blinking_cursor_off (void)
lcd_blinking_cursor_off (void)
 
 
{
 
{
 
   displaycontrol_flags &= ~LCD_BLINKON;
 
   displaycontrol_flags &= ~LCD_BLINKON;
Riga 195: Riga 188:
 
}
 
}
  
  void
+
void lcd_blinking_cursor_on (void)
lcd_blinking_cursor_on (void)
 
 
{
 
{
 
   displaycontrol_flags |= LCD_BLINKON;
 
   displaycontrol_flags |= LCD_BLINKON;
Riga 202: Riga 194:
 
}
 
}
  
 
+
void lcd_underline_cursor_off (void)
  void
 
lcd_underline_cursor_off (void)
 
 
{
 
{
 
   displaycontrol_flags &= ~LCD_CURSORON;
 
   displaycontrol_flags &= ~LCD_CURSORON;
Riga 210: Riga 200:
 
}
 
}
  
  void
+
void lcd_underline_cursor_on (void)
lcd_underline_cursor_on (void)
 
 
{
 
{
 
   displaycontrol_flags |= LCD_CURSORON;
 
   displaycontrol_flags |= LCD_CURSORON;
Riga 217: Riga 206:
 
}
 
}
  
void
+
void lcd_scroll_left (void) {
lcd_scroll_left (void) {
 
 
   command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
 
   command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
 
}
 
}
  
void
+
void lcd_scroll_right (void) {
lcd_scroll_right (void) {
 
 
   command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
 
   command (LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
 
}
 
}
  
  size_t
+
size_t lcd_write (char value)
lcd_write (char value)
 
 
{
 
{
 
   send ((uint8_t) value, HIGH);
 
   send ((uint8_t) value, HIGH);
Riga 234: Riga 220:
 
}
 
}
  
  size_t
+
size_t lcd_write_string (const char *buffer)
lcd_write_string (const char *buffer)
 
 
{
 
{
 
   size_t size = strlen (buffer);
 
   size_t size = strlen (buffer);
Riga 242: Riga 227:
 
     n += lcd_write ((uint8_t) (*buffer++));
 
     n += lcd_write ((uint8_t) (*buffer++));
 
   }
 
   }
 
 
   return n;
 
   return n;
 
}
 
}
  
  int
+
int lcd_printf (const char *format, ...)
lcd_printf (const char *format, ...)
 
 
{
 
{
 
   char message_buffer[LCD_MAX_MESSAGE_LENGTH + 1];
 
   char message_buffer[LCD_MAX_MESSAGE_LENGTH + 1];
Riga 304: Riga 287:
 
   command (LCD_ENTRYMODESET | entrymodeset_flags);
 
   command (LCD_ENTRYMODESET | entrymodeset_flags);
 
}
 
}
 
#define LCD_MAX_MESSAGE_LENGTH 40
 
#define LCD_DISPLAY_LINES      2 
 
  
 
int nline=0;
 
int nline=0;

Versione delle 10:12, 27 giu 2016

This project permits to control a remote LCD display connected via an i2c port expander via Wifi.

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).
  • an lcd-plug by jeelabs including the display
  • 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>
#include <ESP8266WiFi.h>

const char *ssid = "ESPap";
const char *password = "knife";

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.write((byte)MCP_IODIR);
  Wire.write((byte)0);
  Wire.endTransmission();
}

void turnoff(void)
{
  Wire.beginTransmission(DISP_ADDRESS);
  Wire.write((byte)MCP_GPIO);
  Wire.write((byte)0);
  Wire.endTransmission();
}

void write1byte(unsigned int value)
{
  Wire.beginTransmission(DISP_ADDRESS);
  Wire.write((byte)MCP_GPIO);
  Wire.write((byte)(value | MCP_BACKLIGHT));
  Wire.endTransmission();
}

void write4bits(unsigned int value)
{
  write1byte(value);
  delayMicroseconds(2);
  write1byte(value | MCP_ENABLE);
  delayMicroseconds(2);
  write1byte(value);
  delayMicroseconds(100);
}

void send(unsigned int value, unsigned int mode)
{
  //printf("SEND %x %d\n",value,mode);
  if (mode)
    mode = MCP_REGSEL;
  write4bits((value>>4) | mode);
  write4bits((value &0xf) | mode);
}

#define command(v) send((v),LOW);

void lcd_clear (void)
{
  command (LCD_CLEARDISPLAY);  // Clear display, set cursor position to zero.
  delayMicroseconds(2000);   // This command takes a long time.
}

void lcd_home (void)
{
  // 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.
  }

  // Positions of the beginnings of rows in LCD DRAM.
  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);
    }
  }
}

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.