Merge pull request #7 from kholia/better-init-for-displays

Add more robust init for 16x2 I2C LCD displays
This commit is contained in:
IOsetting 2023-04-06 12:18:24 +08:00 committed by GitHub
commit 5f3be03480
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 209 additions and 81 deletions

View File

@ -0,0 +1,102 @@
#include "LCD1602.h"
uint8_t portLcd = 0;
static void LCD_WriteByte(uint8_t bt) {
HAL_I2C_Master_Transmit(&LCD_I2C, ADRESS_I2C_LCD, &bt, 1, 1000);
}
static void LCD_SendCmd_8bit(uint8_t bt) {
LCD_WriteByte(portLcd |= 0x04);
HAL_Delay(1);
LCD_WriteByte(portLcd | bt);
LCD_WriteByte(portLcd &= ~ 0x04);
HAL_Delay(1);
}
static void LCD_SendCmd(uint8_t bt) {
bt <<= 4;
LCD_SendCmd_8bit(bt);
}
static void LCD_SendByte(uint8_t bt, uint8_t mode) {
if (mode == 0) {
LCD_WriteByte(portLcd &= ~ 0x01); // RS = 0;
}
else {
LCD_WriteByte(portLcd |= 0x01); // RS = 1;
}
uint8_t tempBuf = 0;
tempBuf = bt >> 4;
LCD_SendCmd(tempBuf);
LCD_SendCmd(bt);
}
void LCD_Init(void) {
HAL_Delay(50);
LCD_SendCmd(0x03);
HAL_Delay(5);
LCD_SendCmd(0x03);
HAL_Delay(1);
LCD_SendCmd(0x03);
HAL_Delay(10);
LCD_SendCmd(0x02); // 0x02 // 4bit mode
HAL_Delay(2);
LCD_SendByte(0x38, 0);
HAL_Delay(2);
LCD_SendByte(0x02, 0);
HAL_Delay(2);
LCD_SendByte(0x0C, 0);
HAL_Delay(2);
LCD_SendByte(0x01, 0);
HAL_Delay(2);
LCD_SendByte(0x06, 0);
HAL_Delay(1);
//---------------------------------------------------------------------------------
LCD_WriteByte(portLcd |= 0x08);
LCD_WriteByte (portLcd &= ~ 0x02);
}
void LCD_PrintString(char* str) {
uint8_t i = 0;
while (str[i] != 0) {
LCD_SendByte(str[i], 1);
i++;
}
}
void LCD_Clear(void) {
LCD_SendByte(0x01, 0);
HAL_Delay(2);
}
void LCD_SetCursor(uint8_t x, uint8_t y) {
switch (y) {
case 0:
LCD_SendByte(x | 0x80, 0);
HAL_Delay(1);
break;
case 1:
LCD_SendByte(( 0x40 + x) | 0x80, 0);
HAL_Delay(1);
break;
case 2:
LCD_SendByte(( 0x14 + x) | 0x80, 0);
HAL_Delay(1);
break;
case 3:
LCD_SendByte(( 0x54 + x) | 0x80, 0);
HAL_Delay(1);
break;
default:
break;
}
}

View File

@ -0,0 +1,34 @@
#ifndef _LCD1602_H
#define _LCD1602_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "py32f0xx_hal.h"
#include "py32f0xx_hal_i2c.h"
#include "main.h"
#include "LCD1602_config.h"
extern uint8_t portLcd;
#ifdef LCD1602_I2C
extern I2C_HandleTypeDef I2cHandle;
#endif
void LCD_Init(void);
void LCD_PrintString( char* str );
void LCD_Clear(void);
void LCD_SetCursor( uint8_t x, uint8_t y );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,23 @@
#ifndef _LCD1602_CONFIG_H
#define _LCD1602_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#define LCD1602_I2C
#if defined (LCD1602_I2C)
#define LCD_I2C I2cHandle
#define ADRESS_I2C_LCD (0x27 << 1) // (0x27 << 1) (0x3F << 1)
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -4,93 +4,30 @@
#include "py32f0xx_hal_i2c.h"
#include "py32f0xx_bsp_printf.h"
#define I2C_ADDRESS 0xA0 /* host address */
#include "LCD1602.h"
#define I2C_ADDRESS 0xA0 // host address
I2C_HandleTypeDef I2cHandle;
void APP_ErrorHandler(void);
static void APP_I2C_Config(void);
#define SLAVE_ADDRESS_LCD 0x4E // PCF8574
int SLAVE_ADDRESS_LCD = 0; // PCF8574
// LCD handling functions are borrowed from https://controllerstech.com/i2c-lcd-in-stm32/
void lcd_send_cmd (char cmd)
{
char data_u, data_l;
uint8_t data_t[4];
data_u = (cmd&0xf0);
data_l = ((cmd<<4)&0xf0);
data_t[0] = data_u|0x0C; // en=1, rs=0
data_t[1] = data_u|0x08; // en=0, rs=0
data_t[2] = data_l|0x0C; // en=1, rs=0
data_t[3] = data_l|0x08; // en=0, rs=0
HAL_I2C_Master_Transmit (&I2cHandle, SLAVE_ADDRESS_LCD,(uint8_t *) data_t, 4, 100);
}
int find_lcd_i2c_address() {
int ret = -1;
void lcd_send_data (char data)
{
char data_u, data_l;
uint8_t data_t[4];
data_u = (data&0xf0);
data_l = ((data<<4)&0xf0);
data_t[0] = data_u|0x0D; // en=1, rs=0
data_t[1] = data_u|0x09; // en=0, rs=0
data_t[2] = data_l|0x0D; // en=1, rs=0
data_t[3] = data_l|0x09; // en=0, rs=0
HAL_I2C_Master_Transmit (&I2cHandle, SLAVE_ADDRESS_LCD,(uint8_t *) data_t, 4, 100);
}
void lcd_clear (void)
{
lcd_send_cmd (0x80);
for (int i=0; i<70; i++) {
lcd_send_data (' ');
}
}
void lcd_put_cur(int row, int col)
{
switch (row) {
case 0:
col |= 0x80;
break;
case 1:
col |= 0xC0;
break;
for (int i = 1; i < 128; i++) {
ret = HAL_I2C_IsDeviceReady(&I2cHandle, (uint16_t)(i << 1), 3, 1000);
if (ret != HAL_OK) {
}
else if (ret == HAL_OK) {
return i;
}
}
lcd_send_cmd (col);
}
void lcd_init (void)
{
// 4 bit initialisation
HAL_Delay(50); // wait for > 40ms
lcd_send_cmd (0x30);
HAL_Delay(5); // wait for > 4.1ms
lcd_send_cmd (0x30);
HAL_Delay(1); // wait for > 100us
lcd_send_cmd (0x30);
HAL_Delay(10);
lcd_send_cmd (0x20); // 4bit mode
HAL_Delay(10);
// display initialisation
lcd_send_cmd (0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)
HAL_Delay(1);
lcd_send_cmd (0x08); // Display on/off control --> D=0, C=0, B=0 ---> display off
HAL_Delay(1);
lcd_send_cmd (0x01); // clear display
HAL_Delay(1);
HAL_Delay(1);
lcd_send_cmd (0x06); // Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
HAL_Delay(1);
lcd_send_cmd (0x0C); // Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
}
void lcd_send_string (char *str)
{
while (*str) lcd_send_data (*str++);
return -1;
}
int main(void)
@ -102,12 +39,15 @@ int main(void)
APP_I2C_Config();
lcd_init ();
SLAVE_ADDRESS_LCD = find_lcd_i2c_address();
SLAVE_ADDRESS_LCD = (SLAVE_ADDRESS_LCD << 1);
lcd_send_string ("HELLO WORLD!");
LCD_Init();
LCD_SetCursor(0, 0);
LCD_PrintString("HELLO WORLD!");
HAL_Delay(1000);
lcd_put_cur(1, 0);
lcd_send_string("HOWDY!");
LCD_SetCursor(0, 1);
LCD_PrintString("HOWDY!");
HAL_Delay(2000);
while(1);

View File

@ -0,0 +1,29 @@
// Copyright 2021 IOsetting <iosetting(at)outlook.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
void APP_ErrorHandler(void);
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */