99-LCD-Text-I2C-Library (STM32F407)

Diese Library dient zum Ansteuern eines Text LC-Display mit HD44780 Treiber, welches seriell über I2C und einem PCF8574 mit dem Mikrocontroller verbunden ist. Dabei sind die I2C Adresse, die Anzahl Zeilen und die Anzahl Zeichen je Zeile konfigurierbar.


Günstige Displays haben z.B. 16×2 oder 20×4 Zeichen und können z.B. hier erworben werden:

Der PCF8574 ist ein via I2C-Bus angeschlossener 8-Bit I/O Port-Expander. Ein seriell an den Baustein gesendeter Wert wird auf dessen Pins parallel ausgegeben. Ein typisches Datenblatt findet ihr z.B. hier. Daraus ersichtlich ist auch die I2C Adressbelegung, welche bei einigen Modulen über Lötbrücken verändert werden kann. Hinweis zu den Angaben der ersten drei Spalten A2, A1 und A0: der Wert VSS bedeutet, dass eine Lötbrücke vorhanden ist, der Wert VDD  bedeutet keine Lötbrücke:

Mein verwendetes Modul ist im Auslieferungszustand auf die I2C Adresse 0x7E eingestellt (keine Lötbrücken). Durch Lötbrücken an A0 bis A2 können bei Bedarf auch andere Adressen (0x77 bis 0x7E) eingestellt werden. Es gibt wohl auch Module, bei denen die I2C Adresse von 0x20 bis 0x27, oder von 0x38 bis 0x3F einzustellen ist, oder auch von 0x47 bis 0x4E geht. Hinweis: In meiner Library habe ich eine PortScan Funktion eingebunden, damit bei unbekannter I2C Adresse diese automatisch erkannt und verwendet werden kann;)

Oberhalb der Lötbrücken (A0 bis A2) ist am I2C Modul ein Drehregler, mit dem der Kontrast geregelt werden kann. Achtung: Oft ist der Kontrast im Auslieferungszustand sehr weit runter geschraubt. Daher sollte man den Kontrast zu beginn mit dem Drehregler ganz nach rechts an den Anschlag drehen. Später, wenn die Ansteuerung funktioniert, dann könnt ihr den Kontrast entsprechend korrigieren.

Zur Ansteuerung werden neben der Versorgungsspannung (5V und GND) nur zwei Leitungen benötigt (SCL, SDA). Hier im Beispiel wurde I2C3 benutzt.

Benutzte Pins :

GND an GND
VCC an +5V
SDA an PC9
SCL an PA8

Als Grundlage der I2C Kommunikation habe ich das I2C LoLevel Library verwendet, wobei ich alle drei Module (I2C1, I2C2 und I2C3) eingebunden habe.

Programmtechnisch muss nach wie vor die Protokollverwaltung des HD44780 umgesetzt werden, denn wie bereits erwähnt ist der PCF8574 „nur“ ein I2C I/O Expander.

Hier habe ich zwei Skizzen für euch, welche die Anbindung schematisch verdeutlichen:

  

Deshalb sind die Funktionen dieser Library sehr ähnlich der Funktionen aus der LCD_2x16-Library. Allerdings wollte ich etwas flexibler sein, was die Konfiguration der Pinbelegung und Display-Einstellung betrifft. Deshalb erfolgt die Konfiguration eines LCD Displays über eine Struktur mit folgenden Attributen:

1
2
3
4
5
6
7
8
9
10
//--------------------------------------------------------------
// Struktur eines LCD Displays
//--------------------------------------------------------------
typedef struct {
	TI2C_t i2c;		// I2C Modul (1=I2C1, 2=I2C2 oder 3=I2C3)
	uint8_t slave_adr;	// I2C Adresse (z.B. 0x27)
	uint8_t maxx;		// Max. Anzahl Zeichen je Zeile (1..20)
	uint8_t maxy;		// Max Anzahl Zeilen (1..4)
	uint8_t backlight;	// LCD Hintergrundbeleuchtung (0=Aus, 1=Ein)
}LCD_TEXT_DISPLAY_t;

Voraussetzungen :

CMSIS_BOOT, M4_CMSIS_CORE
stm32_ub_i2c1.c (ab Version 1.3)
stm32_ub_i2c2.c (ab Version 1.3)
stm32_ub_i2c3.c (ab Version 1.3)
printf.c (ab Version 07.11.2013)

Funktionen :

1
2
3
4
5
6
7
8
9
10
11
12
void UB_I2C_Init(LCD_TEXT_DISPLAY_t *lcd);
void UB_LCD_TEXT_I2C_Delay(uint32_t delay);
void UB_LCD_TEXT_I2C_Init(LCD_TEXT_DISPLAY_t *lcd);
void UB_LCD_TEXT_I2C_Clear(LCD_TEXT_DISPLAY_t *lcd);
void UB_LCD_TEXT_I2C_SetMode(LCD_TEXT_DISPLAY_t *lcd, TLCD_TEXT_I2C_MODE_t mode);
void UB_LCD_TEXT_I2C_String(LCD_TEXT_DISPLAY_t *lcd, uint8_t x, uint8_t y, char *ptr);
void UB_LCD_TEXT_I2C_WriteCG(LCD_TEXT_DISPLAY_t *lcd, uint8_t nr, uint8_t *pixeldata);
void UB_LCD_TEXT_I2C_PrintCG(LCD_TEXT_DISPLAY_t *lcd, uint8_t x, uint8_t y, uint8_t nr);
void UB_LCD_TEXT_I2C_Backlight_On(LCD_TEXT_DISPLAY_t *lcd);
void UB_LCD_TEXT_I2C_Backlight_Off(LCD_TEXT_DISPLAY_t *lcd);
void UB_LCD_TEXT_I2C_Backlight_Toggle(LCD_TEXT_DISPLAY_t *lcd);
uint8_t UB_LCD_TEXT_I2C_PortScan(LCD_TEXT_DISPLAY_t *lcd, uint8_t start, uint8_t ende);

Beispiel :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//--------------------------------------------------------------
// File     : main.c
// Datum    : 24.02.2018
// Version  : 1.01
// Autor    : Manfred Becker (MB)
// EMail    : -
// Web      : http://mikrocontroller.bplaced.net/
// CPU      : STM32F407 (Discovery-Board)
// IDE      : CooCox CoIDE 1.7.8
// GCC      : 4.7 2012q4
// Module   : CMSIS_BOOT, M4_CMSIS_CORE
//          : stm32_ub_i2c1.c (ab Version 1.3)
//          : stm32_ub_i2c2.c (ab Version 1.3)
//          : stm32_ub_i2c3.c (ab Version 1.3)
//          : stm32_ub_lcd_text_i2c.c (ab Version 1.0)
//          : printf.c (ab Version 07.11.2013)
// Funktion : Demo der LCD Text Anbindung ueber I2C-LoLevel-Library
// Hinweis  : Diese zwei Files muessen auf 8MHz stehen
//              "cmsis_boot/stm32f4xx.h"
//              "cmsis_boot/system_stm32f4xx.c"
//--------------------------------------------------------------
 
#include "main.h"
#include "stm32_ub_lcd_text_i2c.h"
#include "stdio.h" // fuer sprintf() Funktion
 
int main(void)
{
	LCD_TEXT_DISPLAY_t myLCD = { 
	TI2C3,	// I2C Modul (1=I2C1, 2=I2C2 oder 3=I2C3)
	0,		// I2C Adresse des LCD Displays. Falls unbekannt dann auf 0 setzen und PortScan laufen lassen.
	16,		// Anzahl Zeichen je Zeile
	2, 		// Anzahl Zeilen
	1		// LCD Hintergrundbeleuchtung (0=Aus, 1=Ein)
	};
 
	SystemInit(); // Quarz Einstellungen aktivieren
 
	// Init der I2C1-Schnittstelle
	UB_I2C_Init(&myLCD);
 
	// I2C Port Scan starten?
	if (myLCD.slave_adr==0x00)
	{
		uint8_t n;
 
 
		// I2C Port Scan starten von 0x01 bis 0x7F
		if ((myLCD.slave_adr = UB_LCD_TEXT_I2C_PortScan(&myLCD, 0x01, 0x7F)) != 0x00)
		{
			char txt[16];
			sprintf(txt,"I2C-Adr: 0x%02x", myLCD.slave_adr);
 
			// Init vom LC-Display
			UB_LCD_TEXT_I2C_Init(&myLCD);
 
			// Text auf Zeile-1 ausgeben
			UB_LCD_TEXT_I2C_String(&myLCD,0,0,txt);
			UB_LCD_TEXT_I2C_Delay(150);
			for (n=0; n < 11; n++)
			{
				UB_LCD_TEXT_I2C_Backlight_Toggle(&myLCD);
				UB_LCD_TEXT_I2C_Delay(50);
			}
			UB_LCD_TEXT_I2C_Backlight_On(&myLCD);
			UB_LCD_TEXT_I2C_Delay(3000);
		}
		else
		{
			//ToDo: Fehlerbehandlung
		}
	}
 
	// Init vom LC-Display
	UB_LCD_TEXT_I2C_Init(&myLCD);
 
	// Text auf Zeile-1 ausgeben
	UB_LCD_TEXT_I2C_String(&myLCD,0,0,"Hello STM32F407-");
 
	// Text auf Zeile-2 ausgeben
	UB_LCD_TEXT_I2C_String(&myLCD,0,1,"Mikrocontroller!");
	UB_LCD_TEXT_I2C_Delay(2000);
 
	// 4-Zeilen LCD Display?
	if (myLCD.maxy>=4)
	{
		// Clear
		UB_LCD_TEXT_I2C_Clear(&myLCD);
		UB_LCD_TEXT_I2C_SetMode(&myLCD, TLCD_TEXT_I2C_BLINK); // Display=EIN, Cursor=EIN, Blinken=EIN
 
		// Text auf Zeile-1 bis 4 ausgeben
		UB_LCD_TEXT_I2C_String(&myLCD,0,0,"1");
		UB_LCD_TEXT_I2C_String(&myLCD,5,1,"5");
		UB_LCD_TEXT_I2C_String(&myLCD,10,2,"10");
		UB_LCD_TEXT_I2C_String(&myLCD,15,3,"15");
		UB_LCD_TEXT_I2C_Delay(2000);
 
		UB_LCD_TEXT_I2C_SetMode(&myLCD, TLCD_TEXT_I2C_ON); // Display=EIN, Cursor=AUS, Blinken=Aus
	}
 
 
	// Clear
	UB_LCD_TEXT_I2C_Clear(&myLCD);
 
	// Definition eines Sonderzeichens in 8 Bytes
	uint8_t buf[8];
	buf[0]=0b01000000;
	buf[1]=0b01100000;
	buf[2]=0b01110000;
	buf[3]=0b01111000;
	buf[4]=0b01111100;
	buf[5]=0b01111110;
	buf[6]=0b01111111;
	buf[7]=0b00000000;
 
	UB_LCD_TEXT_I2C_WriteCG(&myLCD, 0, buf); // Speichern eines Sonderzeichens im CG-RAM vom Display
 
	uint8_t x,y,n;
	char* ch;
 
	for (y=0; y < myLCD.maxy; y++)
		for (x=0; x < myLCD.maxx; x++)
			UB_LCD_TEXT_I2C_PrintCG(&myLCD, x, y, 0); // Ausgabe des Sonderzeichens bei Pos. x,y
 
	UB_LCD_TEXT_I2C_Delay(2000);
 
	while(1)
	{
		// Testfunktion im Dauerlauf
		UB_LCD_TEXT_I2C_Clear(&myLCD);
		UB_LCD_TEXT_I2C_String(&myLCD,0,0,"LCD Txt I2C Test");
		UB_LCD_TEXT_I2C_String(&myLCD,0,1,"Please wait.....");
		UB_LCD_TEXT_I2C_Delay(2000);
 
		x=0; y=0;
		for (n=0; n < 256; n++)
		{
			ch=(char)n;
			UB_LCD_TEXT_I2C_String(&myLCD,x,y,&ch);
			if ((++x)>=myLCD.maxx)
			{
				x=0;
				if ((++y)>=myLCD.maxy)
				{
					y=0;
					UB_LCD_TEXT_I2C_Delay(500);
				}
			}
		}
	}
}

 

Downloads: 

STM32F407_stm32_ub_lcd_text_i2c

Hier die Library 99-LCD-Text-I2C-Library (STM32F407) zum Download.

 

STM32F407_Demo_99_LCD_Text_I2C

Hier der komplette CooCox-Projektordner zum Download :

Viel Spass damit,
Manfred

PS: Dieses Library gibt’s auch für den STM32F429 Disco.

4 Kommentare zu 99-LCD-Text-I2C-Library (STM32F407)

  1. admin_mb sagt:

    Hallo, hier noch kurz ein Beispiel, wie man zwei LCD Displays am selben I2C Port betreibt:

    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    
    int main(void)
    {
    	LCD_TEXT_DISPLAY_t myLCD1 = {
    	TI2C3,	// I2C Modul (1=I2C1, 2=I2C2 oder 3=I2C3)
    	0x7e,	// I2C Adresse des LCD Displays 1.
    	16,	// Anzahl Zeichen je Zeile (1..20)
    	2, 	// Anzahl Zeilen (1..4)
    	1	// LCD Hintergrundbeleuchtung (0=Aus, 1=Ein)
    	};
     
    	LCD_TEXT_DISPLAY_t myLCD2 = {
    	TI2C3,	// I2C Modul (1=I2C1, 2=I2C2 oder 3=I2C3)
    	0x4e,	// I2C Adresse des LCD Displays 2.
    	20,	// Anzahl Zeichen je Zeile (1..20)
    	4, 	// Anzahl Zeilen (1..4)
    	1	// LCD Hintergrundbeleuchtung (0=Aus, 1=Ein)
    	};
     
    	SystemInit(); // Quarz Einstellungen aktivieren
     
    	// Init der I2C1-Schnittstelle
    	UB_I2C_Init(&myLCD1);
    	UB_I2C_Init(&myLCD2);
     
    	// Init vom LC-Display
    	UB_LCD_TEXT_I2C_Init(&myLCD1);
    	UB_LCD_TEXT_I2C_Init(&myLCD2);
     
    	// Text auf LCD1 ausgeben
    	UB_LCD_TEXT_I2C_String(&myLCD1,0,0,"Hello  16x2  LCD");
    	UB_LCD_TEXT_I2C_String(&myLCD1,0,1,"Mikrocontroller!");
     
    	// Text auf LCD2 ausgeben
    	UB_LCD_TEXT_I2C_String(&myLCD2,0,0,"Hello 20x4 Text LCD!");
    	UB_LCD_TEXT_I2C_String(&myLCD2,0,1,"STM32F407/F429-Disco");
    	UB_LCD_TEXT_I2C_String(&myLCD2,0,2,"http://mikrocontroll");
    	UB_LCD_TEXT_I2C_String(&myLCD2,0,3,"er.bplaced.net");
     
    	// Pause
    	UB_LCD_TEXT_I2C_Delay(2000);
     
    	// Clear
    	UB_LCD_TEXT_I2C_Clear(&myLCD1);
    	UB_LCD_TEXT_I2C_Clear(&myLCD2);
     
    	uint8_t x,y;
    	char *ch = '0';
     
    	while(1)
    	{
    		for (y=0; y < myLCD1.maxy; y++)
    			for (x=0; x < myLCD1.maxx; x++)
    				UB_LCD_TEXT_I2C_String(&myLCD1,x,y,&ch);
     
    		for (y=0; y < myLCD2.maxy; y++)
    			for (x=0; x < myLCD2.maxx; x++)
    				UB_LCD_TEXT_I2C_String(&myLCD2,x,y,&ch);
     
    		if (++ch > 128) ch='0';
     
    		UB_LCD_TEXT_I2C_Delay(200);
    	}
    }
  2. Michael DD4MS sagt:

    Hallo Manfred,

    ich habe die Library in mein aktuelles Projekt eingebunden und es funktioniert bestens.

    Gruß Michael

  3. Guilherme Cavalheri sagt:

    good night,
    I would like to know how to use the function „UB_LCD_TEXT_I2C_PrintCG (& myLCD, x, y, 0)“ to remove the black squares, ie how can I delete the black squares with this function? I am using a potentiometer, but I can only print the black squares on the LCD and do not remove them. Thanks for listening.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.