The Initialization of the HD44780 isnt working. I went through every Step, on the data sheet, but couldnt make any progress. Im operating on a 4-Bit Interface. I used on purpose no libraries, because i wanted to understand the code first, before using libraries. This is the Code with all the functions and the initialization. In the main, I tried to use the initialization function, and make the cursor blink at the end.
I tried to work through every step, in the official data sheet. I rewrote the code again and again, and made sure, that the initialization would be successful. Im expecting the cursor to appear on the display and start to blink.
Here is the data sheet: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
On page 46 are the instructions for initialization.
Here is my code:
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
//#define LCD_Port PortB
// Pinbelegung für das LCD
#define LCD_DDR DDRB
#define LCD_D4 PB4
#define LCD_D5 PB5
#define LCD_D6 PB6
#define LCD_D7 PB7
// LCD Steuersignale RS und EN
#define LCD_RS PB0
#define LCD_EN PB2
//LCD Ausführungszeiten
#define LCD_BOOTUP_MS 15
#define LCD_ENABLE_US 1
#define LCD_WRITEDATA_US 46
#define LCD_COMMAND_US 42
#define LCD_SOFT_RESET_MS1 5
#define LCD_SOFT_RESET_MS2 1
#define LCD_SOFT_RESET_MS3 1
#define LCD_SET_4BITMODE_MS 5
#define LCD_CLEAR_DISPLAY_MS 2
#define LCD_CURSOR_HOME_MS 2
#define LCD_SOFT_RESET 0x30
#define LCD_SET_FUNCTION 0x20
#define LCD_FUNCTION_4BIT 0x00
#define LCD_FUNCTION_2LINE 0x08
#define LCD_FUNCTION_5X7 0x00
// Set Entry Mode
#define LCD_SET_ENTRY 0x04
#define LCD_ENTRY_DECREASE 0x00
#define LCD_ENTRY_INCREASE 0x02
#define LCD_ENTRY_NOSHIFT 0x00
#define LCD_ENTRY_SHIFT 0x01
// Set Display
#define LCD_SET_DISPLAY 0x08
#define LCD_DISPLAY_OFF 0x00
#define LCD_DISPLAY_ON 0x04
#define LCD_CURSOR_OFF 0x00
#define LCD_CURSOR_ON 0x02
#define LCD_BLINKING_OFF 0x00
#define LCD_BLINKING_ON 0x01
#define LCD_CURSOR_HOME 0x02
// Clear Display
#define LCD_CLEAR_DISPLAY 0x01
static void lcd_enable (void){
PORTB |= (1<<LCD_EN); // Enable auf 1 setzen
_delay_us(LCD_ENABLE_US); // Pause
PORTB &= ~(1<<LCD_EN); // Enable auf 0 setzen
}
void lcd_out (uint8_t data) {
//wandelt 8-Bit System in ein 4-Bit System um
// Sende die oberen 4 Bits
//high nippel
PORTB |= (data & 0xF0);
lcd_enable();
//low nippel
PORTB |= ((data << 4) & 0xF0);
lcd_enable();
}
void lcd_command( uint8_t data ) {
PORTB &= ~(1<<LCD_RS); // RS auf 0 setzen
lcd_out( data ); // zuerst die oberen,
lcd_out( data<<4); // dann die unteren 4 Bit senden
_delay_us(LCD_COMMAND_US );
}
void lcd_home( void )
{
lcd_command( LCD_CURSOR_HOME );
_delay_ms( LCD_CURSOR_HOME_MS );
}
void lcd_clear( void ) {
lcd_command( LCD_CLEAR_DISPLAY );
_delay_ms( LCD_CLEAR_DISPLAY_MS );
}
void lcd_init (void){
// verwendete Pins auf Ausgang schalten
uint8_t pins = (0x0F << LCD_D4) | // 4 Datenleitungen
(0x0F << LCD_D5) |
(0x0F << LCD_D6) |
(0x0F << LCD_D7) |
(1<<LCD_RS) | // R/S Leitung
(1<<LCD_EN); // Enable Leitung
LCD_DDR |= pins;
// initial alle Ausgänge auf Null
PORTB &= ~pins;
// warten auf die Bereitschaft des LCD
_delay_ms(LCD_BOOTUP_MS);
// Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
lcd_out(LCD_SOFT_RESET);
_delay_ms(LCD_SOFT_RESET_MS1);
lcd_enable();
_delay_ms(LCD_SOFT_RESET_MS2);
lcd_enable();
_delay_ms(LCD_SOFT_RESET_MS3);
// 4-bit Modus aktivieren
lcd_out (LCD_SET_FUNCTION | LCD_FUNCTION_4BIT );
_delay_ms (LCD_SET_4BITMODE_MS );
// 4-bit Modus / 2 Zeilen / 5x7
lcd_command( LCD_SET_FUNCTION |
LCD_FUNCTION_4BIT |
LCD_FUNCTION_2LINE |
LCD_FUNCTION_5X7 );
// Display ein / Cursor aus / Blinken aus
lcd_command(LCD_SET_DISPLAY |
LCD_DISPLAY_ON |
LCD_CURSOR_OFF |
LCD_BLINKING_OFF);
// Cursor inkrement / kein Scrollen
lcd_command( LCD_SET_ENTRY |
LCD_ENTRY_INCREASE |
LCD_ENTRY_NOSHIFT );
lcd_clear();
}
int main (void){
/* Replace with your application code */
lcd_init();
lcd_command(LCD_DISPLAY_ON);
lcd_command(LCD_CURSOR_ON);
lcd_command(LCD_BLINKING_ON);
lcd_home();
while (1)
{
}
return 0;
}
Okay i fixed it. Now the initialization is working. I used another library and changed my code to following:
HD44780.c
#include "hd44780.h"
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const unsigned char row_offset[] = {0x00, 0x40};
static inline void lcd_pulseEn();
static void lcd_setDDR(unsigned char ddr);
void lcd_init(void)
{
LCD_DDR = 0xFF;
LCD_PORT = 0x00;
_delay_ms(40);
lcd_sendByte(0x03);
_delay_ms(15);
lcd_sendByte(0x03);
_delay_ms(1);
lcd_sendByte(0x03);
_delay_ms(1);
lcd_sendByte(0x02);
_delay_us(40);
lcd_sendCommand(0x28);
lcd_sendCommand(0x0C);
lcd_sendCommand(0x06);
lcd_sendCommand(0x01);
_delay_ms(10);
}
void lcd_sendCommand(unsigned char command)
{
lcd_waitBusy();
LCD_PORT &= ~(1 << LCD_RS);
lcd_send(command);
}
void lcd_sendData(unsigned char data)
{
lcd_waitBusy();
LCD_PORT |= (1 << LCD_RS);
lcd_send(data);
}
void lcd_sendByte(unsigned char byte)
{
LCD_PORT &= ~(1 << LCD_RS);
LCD_PORT |= (byte << 4);
lcd_pulseEn();
LCD_PORT &= 0x0F; // Clean data pins
}
void lcd_send(unsigned char byte)
{
// high nibble
LCD_PORT |= (byte & 0xF0);
lcd_pulseEn();
LCD_PORT &= 0x0F; // clean data pins
// low nibble
LCD_PORT |= ((byte << 4) & 0xF0);
lcd_pulseEn();
LCD_PORT &= 0x0F; // clean data pins
}
void lcd_waitBusy()
{
unsigned char busy = 0;
lcd_setDDR(INPUT);
LCD_PORT &= ~(1 << LCD_RS);
LCD_PORT |= (1 << LCD_RW);
do
{
LCD_PORT |= (1 << LCD_EN);
_delay_us(10);
busy &= ~(1 << LCD_D7);
busy |= ((LCD_PIN & (1 << LCD_D7)) << LCD_D7);
LCD_PORT &= ~(1 << LCD_EN);
} while (busy & (1 << LCD_D7) ? 1 : 0);
lcd_setDDR(OUTPUT);
LCD_PORT &= ~(1 << LCD_RW);
_delay_us(100);
}
void lcd_clear()
{
lcd_sendCommand(0x01);
}
void lcd_setCursor(uint8_t row, uint8_t col)
{
lcd_sendCommand(0x80 | (col + row_offset[row]));
}
void lcd_print(char *text)
{
int len = strlen(text);
for (int i = 0; i != len; i++)
{
lcd_sendData(text[i]);
}
}
void lcd_printChar(unsigned char byte)
{
lcd_sendData(byte);
}
void lcd_printInt(int num)
{
int length = snprintf(NULL, 0, "%d", num);
// Allocate memory for the string
char *strInt = (char *)malloc((length + 1) * sizeof(char));
if (strInt == NULL)
return;
snprintf(strInt, length + 1, "%d", num);
lcd_print(strInt);
free(strInt);
}
void lcd_printDouble(double dnum, int precision)
{
int length = snprintf(NULL, 0, "%f", dnum);
// Allocate memory for the string
char *strValue = malloc(length + 1);
if (strValue == NULL)
return;
dtostrf(dnum, 4, precision, strValue);
// Print
lcd_print(strValue);
free(strValue);
}
static inline void lcd_pulseEn()
{
LCD_PORT |= (1 << LCD_EN);
_delay_us(1);
LCD_PORT &= ~(1 << LCD_EN);
}
unsigned char lcd_read()
{
unsigned char status = 0;
lcd_waitBusy();
lcd_setDDR(INPUT);
LCD_PORT &= ~(1 << LCD_RS);
LCD_PORT |= (1 << LCD_RW);
// high nibble
LCD_PORT |= (1 << LCD_EN);
_delay_us(10);
status |= (LCD_PIN & (1 << LCD_D4));
status |= (LCD_PIN & (1 << LCD_D5));
status |= (LCD_PIN & (1 << LCD_D6));
LCD_PORT &= ~(1 << LCD_EN);
// low nibble
LCD_PORT |= (1 << LCD_EN);
_delay_us(10);
status |= (LCD_PIN & (1 << LCD_D4)) >> 4;
status |= (LCD_PIN & (1 << LCD_D5)) >> 4;
status |= (LCD_PIN & (1 << LCD_D6)) >> 4;
status |= (LCD_PIN & (1 << LCD_D7)) >> 4;
LCD_PORT &= ~(1 << LCD_EN);
lcd_setDDR(OUTPUT);
LCD_PORT &= ~(1 << LCD_RW);
return status;
}
static void lcd_setDDR(unsigned char ddr)
{
if (ddr == 0)
{
LCD_DDR &= ~((1 << LCD_D4) | (1 << LCD_D5) | (1 << LCD_D6) | (1 << LCD_D7));
}
else
{
LCD_DDR |= ((1 << LCD_D4) | (1 << LCD_D5) | (1 << LCD_D6) | (1 << LCD_D7));
LCD_PORT &= ~((1 << LCD_D4) | (1 << LCD_D5) | (1 << LCD_D6) | (1 << LCD_D7));
}
}
HD44780.h
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#ifndef _HD44780_H_
#define _HD44780_H_
#include <avr/io.h>
/* Configuration */
// LCD size
#define LCD_Size 1602
// LCD I/O Port/Pin
#define LCD_DDR DDRB
#define LCD_PORT PORTB
#define LCD_PIN PINB
#define LCD_RS 0
#define LCD_RW 1
#define LCD_EN 2
#define LCD_BL 3
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7
// Macros
#define INPUT 0
#define OUTPUT 1
#define PERCENT 37
#define DEGREE 223
/* Functions */
void lcd_init(void);
void lcd_sendCommand(unsigned char command);
void lcd_sendData(unsigned char data);
void lcd_sendByte(unsigned char byte);
void lcd_send(unsigned char byte);
void lcd_waitBusy();
void lcd_clear();
void lcd_setCursor(uint8_t row, uint8_t col);
void lcd_print(char *text);
void lcd_printChar(unsigned char byte);
void lcd_printInt(int num);
void lcd_printDouble(double dnum, int precision);
unsigned char lcd_read();
#endif