uSDR-pico/lcd.c

245 wiersze
6.8 KiB
C
Czysty Zwykły widok Historia

/*
* lcd.c
*
* Created: Mar 2021
* Author: Arjan te Marvelde
*
2021-12-12 19:19:06 +00:00
* Select LCD_TYPE:
*
* Grove 16x2 LCD HD44780, with integrated JHD1804 I2C bridge (@ 0x3E)
* Display RAM addresses 0x00-0x1f for top row and 0x40-0x5f for bottom row
2021-12-12 19:19:06 +00:00
* Available character Generator addresses are 0x00-0x07
2021-04-16 17:51:51 +00:00
*
2021-12-12 19:19:06 +00:00
* Standard 16x2 LCD HD44780, with backpack PCF8574 based I2C bridge (@ 0x27)
* Same registers, but interface uses 4 bits for data/comand, in bits 3..7
* bit 0 is unused
* bit 1 is Register Select (0 for command, 1 for data)
* bit 2 is Enable, data/command is transferred on falling edge
* bit 3..6 data or command nibble (write high nibble first)
* bit 8 is backlight (1 for on)
*
*/
#include <stdio.h>
2021-04-08 20:32:27 +00:00
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/timer.h"
#include "hardware/clocks.h"
#include "lcd.h"
2021-12-12 19:19:06 +00:00
/* Select LCD type matching your HW */
#define LCD_1804 0
#define LCD_8574 1
#define LCD_TYPE LCD_1804
2021-12-12 19:19:06 +00:00
/* I2C address */
#define I2C_LCD 0x3E
//#define I2C_LCD 0x27
2021-12-12 19:19:06 +00:00
/* HD44780 interface */
// commands
2021-04-16 17:51:51 +00:00
#define LCD_CLEARDISPLAY 0x01 // Note: LCD_ENTRYINC is set
#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
// 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-12-12 19:19:06 +00:00
#define LCD_DELAY 100 // Delay for regular write
2021-04-16 17:51:51 +00:00
#define LCD_COMMAND 0x80
#define LCD_DATA 0x40
2021-12-12 19:19:06 +00:00
/* 8574-based specific bitmasks */
#define LCD2_BACKLIGHT 0x80
#define LCD2_DATA 0x02
#define LCD2_ENABLE 0x04
/*
2021-12-12 19:19:06 +00:00
* User defined (CGRAM) characters
*/
2021-12-12 19:19:06 +00:00
uint8_t cgram[8][8] =
{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00: blank
{0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00}, // 0x01: Level 1
{0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x00}, // 0x02: Level 2
{0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x00, 0x00}, // 0x03: Level 3
{0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00}, // 0x04: Level 4
{0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00}, // 0x05: Level 5
{0x00, 0x04, 0x04, 0x04, 0x1f, 0x0e, 0x04, 0x00}, // 0x06: Receive arrow down
{0x04, 0x0e, 0x1f, 0x04, 0x04, 0x04, 0x00, 0x00} // 0x07: Transmit arrow up
2021-04-16 17:51:51 +00:00
};
2021-12-12 19:19:06 +00:00
/*
* Transfer 1 byte to LCD
* This function is interface dependent
*/
void lcd_sendbyte(uint8_t command, uint8_t data)
{
#if LCD_TYPE == LCD_1804
uint8_t txdata[2];
// Write command/data flag and data byte
txdata[0] = (command?LCD_COMMAND:LCD_DATA);
txdata[1] = data;
i2c_write_blocking(i2c1, I2C_LCD, txdata, 2, false);
sleep_us(LCD_DELAY);
#elif LCD_TYPE == LCD_8574
uint8_t txdata;
// Write high nibble
txdata = (command?0:LCD2_DATA)|LCD2_ENABLE|((data&0xf0)<<1)|LCD2_BACKLIGHT;
i2c_write_blocking(i2c1, I2C_LCD, &txdata[0], 1, false);
sleep_us(LCD_DELAY);
tx_data &= ~LCD2_ENABLE;
i2c_write_blocking(i2c1, I2C_LCD, &txdata[0], 1, false);
sleep_us(LCD_DELAY);
tx_data |= LCD2_ENABLE;
sleep_us(LCD_DELAY);
// Write low nibble
txdata = (command?0:LCD2_DATA)|LCD2_ENABLE|((data&0xf0)>>3)|LCD2_BACKLIGHT;
i2c_write_blocking(i2c1, I2C_LCD, &txdata[0], 1, false);
sleep_us(LCD_DELAY);
tx_data &= ~LCD2_ENABLE;
i2c_write_blocking(i2c1, I2C_LCD, &txdata[0], 1, false);
sleep_us(LCD_DELAY);
tx_data |= LCD2_ENABLE;
sleep_us(LCD_DELAY);
#endif
}
void lcd_init(void)
{
uint8_t i;
2021-12-12 19:19:06 +00:00
sleep_ms(100);
#if LCD_TYPE == LCD_1804
2021-04-16 17:51:51 +00:00
/* Initialize function set (see datasheet fig 23)*/
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS);
2021-04-16 17:51:51 +00:00
sleep_us(4500);
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS);
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS);
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS);
#elif LCD_TYPE == LCD_8574
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS);
sleep_us(4500);
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS);
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS);
lcd_sendbyte(true, LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS);
#endif
2021-04-16 17:51:51 +00:00
/* Initialize display control */
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_DISPLAYCONTROL | LCD_DISPLAYOFF | LCD_CURSOROFF | LCD_BLINKOFF);
2021-04-16 17:51:51 +00:00
/* Display clear */
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_CLEARDISPLAY);
sleep_ms(2);
2021-04-16 17:51:51 +00:00
/* Initialize entry mode set */
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_ENTRYMODESET | LCD_ENTRYINC | LCD_ENTRYNOSHIFT);
2021-04-16 17:51:51 +00:00
/* Load CGRAM */
for (i=0; i<8; i++)
{
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_SETCGRAMADDR | (i<<3)); //Set CGRAM address
for (int j=0; j<8; j++)
lcd_sendbyte(false, cgram[i][j]); // One byte at a time
}
2021-04-16 17:51:51 +00:00
/* Initialize display control */
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
2021-04-19 20:24:03 +00:00
/* Display clear once more */
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_CLEARDISPLAY);
sleep_ms(2);
}
2021-04-16 17:51:51 +00:00
void lcd_clear(void)
{
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, LCD_CLEARDISPLAY);
sleep_ms(2);
2021-04-16 17:51:51 +00:00
}
void lcd_curxy(uint8_t x, uint8_t y, bool on)
{
uint8_t txdata[3];
2021-12-12 19:19:06 +00:00
x &= 0x0f; // Clip range
2021-04-16 17:51:51 +00:00
y &= 0x01;
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, (x | 0x80 | (y==1?0x40:0x00)));
lcd_sendbyte(true, LCD_DISPLAYCONTROL | LCD_DISPLAYON | (on?LCD_CURSORON:LCD_CURSOROFF) | LCD_BLINKOFF);
}
2021-04-16 17:51:51 +00:00
void lcd_putxy(uint8_t x, uint8_t y, uint8_t c)
{
2021-12-12 19:19:06 +00:00
x &= 0x0f; // Clip range
2021-04-16 17:51:51 +00:00
y &= 0x01;
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, (x | 0x80 | (y==1?0x40:0x00)));
lcd_sendbyte(false, c);
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;
2021-12-12 19:19:06 +00:00
x &= 0x0f; // Clip range
2021-04-16 17:51:51 +00:00
y &= 0x01;
2021-12-12 19:19:06 +00:00
lcd_sendbyte(true, (x | 0x80 | (y==1?0x40:0x00)));
2021-04-16 17:51:51 +00:00
2021-04-08 20:32:27 +00:00
len = strlen(s);
2021-12-12 19:19:06 +00:00
len = (len>(16-x))?(16-x):len; // Clip range
for(i=0; i<len; i++)
lcd_sendbyte(false, s[i]);
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++)
{
2021-12-12 19:19:06 +00:00
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();
}