2021-04-03 19:39:24 +00:00
|
|
|
/*
|
2021-04-05 19:18:30 +00:00
|
|
|
* lcd.c
|
|
|
|
*
|
|
|
|
* Created: Mar 2021
|
|
|
|
* Author: Arjan te Marvelde
|
|
|
|
*
|
2021-04-03 19:39:24 +00:00
|
|
|
* Grove 16x2 LCD, HD44780 chip with JHD1804 I2C interface
|
|
|
|
* Display RAM addresses 0x00-0x1f for top row and 0x40-0x5f for bottom row
|
2021-04-07 20:13:13 +00:00
|
|
|
* Character Generator addresses are 0x00-0x07
|
2021-04-03 19:39:24 +00:00
|
|
|
*
|
2021-04-16 17:51:51 +00:00
|
|
|
* Character 0x00:
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000000 | |1| | | |
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000001 |1| | | | |
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000010 | |1| | | |
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000011 |1| | | | |
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000100 | |1| | | |
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000101 |1| | | | |
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000110 | |1| | | |
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
* 000111 | | | | | | <= do not use, cursor
|
|
|
|
* +-+-+-+-+-+
|
|
|
|
*
|
2021-04-03 19:39:24 +00:00
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
2021-04-08 20:32:27 +00:00
|
|
|
#include <string.h>
|
2021-04-03 19:39:24 +00:00
|
|
|
#include "pico/stdlib.h"
|
|
|
|
#include "hardware/i2c.h"
|
|
|
|
#include "hardware/timer.h"
|
|
|
|
#include "hardware/clocks.h"
|
|
|
|
#include "lcd.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// commands
|
2021-04-16 17:51:51 +00:00
|
|
|
#define LCD_CLEARDISPLAY 0x01 // Note: LCD_ENTRYINC is set
|
2021-04-03 19:39:24 +00:00
|
|
|
#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: LCD_ENTRYMODESET
|
2021-04-16 17:51:51 +00:00
|
|
|
#define LCD_ENTRYSHIFT 0x01
|
|
|
|
#define LCD_ENTRYNOSHIFT 0x00
|
|
|
|
#define LCD_ENTRYINC 0x02 // Also applies to CGRAM writes
|
|
|
|
#define LCD_ENTRYDEC 0x00 // Also applies to CGRAM writes
|
2021-04-03 19:39:24 +00:00
|
|
|
|
|
|
|
// flags for display on/off control: LCD_DISPLAYCONTROL
|
|
|
|
#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: LCD_CURSORSHIFT
|
|
|
|
#define LCD_DISPLAYMOVE 0x08
|
|
|
|
#define LCD_CURSORMOVE 0x00
|
|
|
|
#define LCD_MOVERIGHT 0x04
|
|
|
|
#define LCD_MOVELEFT 0x00
|
|
|
|
|
|
|
|
// flags for function set: LCD_FUNCTIONSET
|
|
|
|
#define LCD_8BITMODE 0x10
|
|
|
|
#define LCD_4BITMODE 0x00
|
|
|
|
#define LCD_2LINE 0x08
|
|
|
|
#define LCD_1LINE 0x00
|
|
|
|
#define LCD_5x10DOTS 0x04
|
|
|
|
#define LCD_5x8DOTS 0x00
|
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
#define LCD_DELAY 100
|
|
|
|
#define LCD_COMMAND 0x80
|
|
|
|
#define LCD_DATA 0x40
|
2021-04-03 19:39:24 +00:00
|
|
|
|
|
|
|
/* I2C address and pins */
|
2021-04-16 17:51:51 +00:00
|
|
|
#define I2C_LCD 0x3E
|
|
|
|
#define I2C0_SDA 16
|
|
|
|
#define I2C0_SCL 17
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t cgram[65] = // Write CGRAM
|
|
|
|
{ // 8x8 bytes
|
|
|
|
0x80,
|
|
|
|
0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x00,
|
|
|
|
0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x0b, 0x00,
|
|
|
|
0x08, 0x10, 0x08, 0x10, 0x08, 0x13, 0x0b, 0x00,
|
|
|
|
0x08, 0x10, 0x08, 0x10, 0x0b, 0x13, 0x0b, 0x00,
|
|
|
|
0x08, 0x10, 0x08, 0x13, 0x0b, 0x13, 0x0b, 0x00,
|
|
|
|
0x08, 0x10, 0x0b, 0x13, 0x0b, 0x13, 0x0b, 0x00,
|
|
|
|
0x08, 0x13, 0x0b, 0x13, 0x0b, 0x13, 0x0b, 0x00,
|
|
|
|
0x0b, 0x13, 0x0b, 0x13, 0x0b, 0x13, 0x0b, 0x00
|
|
|
|
};
|
2021-04-03 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
void lcd_init(void)
|
|
|
|
{
|
|
|
|
uint8_t txdata[8];
|
2021-04-16 17:51:51 +00:00
|
|
|
|
2021-04-03 19:39:24 +00:00
|
|
|
/* I2C0 initialisation at 400Khz. */
|
|
|
|
i2c_init(i2c0, 400*1000);
|
|
|
|
gpio_set_function(I2C0_SDA, GPIO_FUNC_I2C);
|
|
|
|
gpio_set_function(I2C0_SCL, GPIO_FUNC_I2C);
|
|
|
|
gpio_pull_up(I2C0_SDA);
|
|
|
|
gpio_pull_up(I2C0_SCL);
|
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
sleep_ms(50);
|
|
|
|
txdata[0] = LCD_COMMAND;
|
|
|
|
|
|
|
|
/* Initialize function set (see datasheet fig 23)*/
|
2021-04-03 19:39:24 +00:00
|
|
|
txdata[1] = LCD_FUNCTIONSET | LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
2021-04-16 17:51:51 +00:00
|
|
|
sleep_us(4500);
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(100);
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
|
|
|
|
/* Initialize display control */
|
|
|
|
txdata[1] = LCD_DISPLAYCONTROL | LCD_DISPLAYOFF | LCD_CURSOROFF | LCD_BLINKOFF;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
|
|
|
|
/* Display clear */
|
|
|
|
txdata[1] = LCD_CLEARDISPLAY;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(1530);
|
|
|
|
|
|
|
|
/* Initialize entry mode set */
|
|
|
|
txdata[1] = LCD_ENTRYMODESET | LCD_ENTRYINC | LCD_ENTRYNOSHIFT;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
|
|
|
|
/* Load CGRAM */
|
|
|
|
txdata[1] = 0x40; //Set CGRAM address 0
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, cgram, 65, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
|
|
|
|
/* Initialize display control */
|
2021-04-03 19:39:24 +00:00
|
|
|
txdata[1] = LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
2021-04-16 17:51:51 +00:00
|
|
|
sleep_us(LCD_DELAY);
|
2021-04-19 20:24:03 +00:00
|
|
|
|
|
|
|
/* Display clear once more */
|
|
|
|
txdata[1] = LCD_CLEARDISPLAY;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(1530);
|
2021-04-03 19:39:24 +00:00
|
|
|
}
|
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
void lcd_clear(void)
|
2021-04-03 19:39:24 +00:00
|
|
|
{
|
2021-04-16 17:51:51 +00:00
|
|
|
uint8_t txdata[3];
|
|
|
|
|
|
|
|
txdata[0] = LCD_COMMAND;
|
|
|
|
txdata[1] = LCD_CLEARDISPLAY;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(1530);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lcd_curxy(uint8_t x, uint8_t y, bool on)
|
|
|
|
{
|
|
|
|
uint8_t txdata[3];
|
|
|
|
|
|
|
|
x &= 0x0f;
|
|
|
|
y &= 0x01;
|
|
|
|
txdata[0] = LCD_COMMAND;
|
|
|
|
txdata[1] = x | 0x80 | (y==1?0x40:0x00);
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
2021-04-03 19:39:24 +00:00
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
txdata[0] = LCD_COMMAND;
|
|
|
|
txdata[1] = LCD_DISPLAYCONTROL | LCD_DISPLAYON | (on?LCD_CURSORON:LCD_CURSOROFF) | LCD_BLINKOFF;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
2021-04-03 19:39:24 +00:00
|
|
|
}
|
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
void lcd_putxy(uint8_t x, uint8_t y, uint8_t c)
|
2021-04-03 19:39:24 +00:00
|
|
|
{
|
2021-04-08 20:32:27 +00:00
|
|
|
uint8_t txdata[3];
|
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
x &= 0x0f;
|
|
|
|
y &= 0x01;
|
|
|
|
txdata[0] = LCD_COMMAND;
|
|
|
|
txdata[1] = x | 0x80 | (y==1?0x40:0x00);
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
|
|
|
|
txdata[0] = LCD_DATA;
|
2021-04-08 20:32:27 +00:00
|
|
|
txdata[1] = c;
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
2021-04-16 17:51:51 +00:00
|
|
|
sleep_us(LCD_DELAY);
|
2021-04-08 20:32:27 +00:00
|
|
|
}
|
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
void lcd_writexy(uint8_t x, uint8_t y, uint8_t *s)
|
2021-04-08 20:32:27 +00:00
|
|
|
{
|
|
|
|
uint8_t i, len;
|
|
|
|
uint8_t txdata[18];
|
|
|
|
|
2021-04-16 17:51:51 +00:00
|
|
|
x &= 0x0f;
|
|
|
|
y &= 0x01;
|
|
|
|
txdata[0] = LCD_COMMAND;
|
|
|
|
txdata[1] = x | 0x80 | ((y==1)?0x40:0x00);
|
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, 2, false);
|
|
|
|
sleep_us(LCD_DELAY);
|
|
|
|
|
2021-04-08 20:32:27 +00:00
|
|
|
len = strlen(s);
|
2021-04-16 17:51:51 +00:00
|
|
|
len = (len>(16-x))?(16-x):len;
|
|
|
|
txdata[0] = LCD_DATA;
|
|
|
|
for(i=0; i<len; i++) txdata[i+1]=s[i];
|
2021-04-08 20:32:27 +00:00
|
|
|
i2c_write_blocking(i2c0, I2C_LCD, txdata, len+1, false);
|
2021-04-16 17:51:51 +00:00
|
|
|
sleep_us(LCD_DELAY);
|
2021-04-07 20:13:13 +00:00
|
|
|
}
|
|
|
|
|
2021-04-08 20:32:27 +00:00
|
|
|
|
2021-04-07 20:13:13 +00:00
|
|
|
void lcd_test(void)
|
|
|
|
{
|
2021-04-08 20:32:27 +00:00
|
|
|
uint8_t chr[17];
|
2021-04-07 20:13:13 +00:00
|
|
|
int i, j;
|
|
|
|
|
2021-04-08 20:32:27 +00:00
|
|
|
chr[16] = 0;
|
2021-04-16 17:51:51 +00:00
|
|
|
lcd_clear();
|
2021-04-07 20:13:13 +00:00
|
|
|
for (i=0; i<16; i++)
|
|
|
|
{
|
|
|
|
for(j=0; j<16; j++) chr[j] = (uint8_t)(16*i+j);
|
2021-04-16 17:51:51 +00:00
|
|
|
lcd_writexy(0, 0, chr);
|
2021-04-07 20:13:13 +00:00
|
|
|
sleep_ms(800);
|
2021-04-16 17:51:51 +00:00
|
|
|
lcd_writexy(0, 1, chr);
|
2021-04-07 20:13:13 +00:00
|
|
|
}
|
2021-04-16 17:51:51 +00:00
|
|
|
lcd_clear();
|
2021-04-03 19:39:24 +00:00
|
|
|
}
|