Guten Tag! Ich bin wieder mit meinen (vielleicht dummen) Fragen... Die Aufgabe: es gibt zwei oder drei LCD, die alle mit HD44780 kompatibel sind. Nur sind sie alle unterschiedlich angeschlossen (aber immer in 4-bit-Mode): an verschiedene Pins von Controller oder über SN74HC595 oder über MCP23S17 usw. Offensichtlich sind so gut wie alle Unterschiede zwischen LCD nur in der Weise, wie 4 bit zusammen mit RS und EN ausgegeben werden, und evtl. könnten sich auch Zeichen-pro-Zeile-Zahl und Zeilenadresse unterscheiden. Was ist besser: 1. für jeden LCD einzeln *.c+*.h - Paar mit allen Funktionen zu schreiben? 2. in ihren eigenen *.c+*.h nur Zeichen-pro-Zeile, Zeilenadressen und out_4bit() - Funktion angeben und alles andere in File lcd.c + lcd.h unabhängig von Anschluss machen? Wenn P.2: wie ist dann besser zwischen LCD umschalten? Mit Zeiger auf out_4bit()- Funktion? Oder über globale Variable? Oder eine zusätzliche Variable immer an Funktion für LCD-Steuerung übergeben? Oder anders? Wenn man nur Basisfunktionen verwendet (Zeichen und Zeile ausgeben), dann macht P.1 vielleicht nicht so großen Aufwand. Wenn aber andere Möglichkeiten kommen, dann häufen sich Funktionen... Vielen Dank für eure Tipps im voraus!
Hallo, ich sag mal so, wenn alle LCD unterschiedliche Inhalte tragen, dann kann man auch die Implementierung n-fach anlegen. Oder einfach eine Trennung zwischen Hardware-Level und User-Level anstreben. Die Auswahl der Hardware könnte über eine DISPLAY-ID: 0 1st LCD usw. erfolgen. Der GCC optimiert, wenn man will, da wird dann unbenutzter Code entfernt.
Man schreibt einmal eine lib für ein HD44780. Deren Funktionen gibt man immer ein struct mit dem Context für jedes physikalische Display mit. Darin werden von der lib evt. States für jedes Display gehalten und darin teilt man der lib auch mit, wie und wo das Display angeschlossen ist. Also ob 4- Bit oder 8-Bit Mode und welche Pins und Ports. Die Nutzung sähe dann so aus (ohne Initalisierung des Structs mit den Pins und Ports):
1 | DISPLAY_t lcd1; |
2 | DISPLAY_t lcd2; |
3 | |
4 | lcd_write("Hallo",&lcd1); |
5 | lcd_write("Blubb",&lcd2); |
:
Bearbeitet durch User
Das funktioniert!!! Ich habe zuerst für mich einfacher gemacht. init, lcd_data und lcd_command ließ ich nicht auseinander. Aber größere Funktionen sind für alle LCD dann gemeinsam. Später kann ich das umarbeiten, Hauptsache Prinzip habe ich verstanden. Nun aber logische Frage: da Structur für einzelne LCD während der Arbeit konstant bleibt, wäre es besser, sie vollständig in Flash zu speichern. Wie macht man das? Wie kann man Structurinit ersparen? Eine Flash-Tabelle mit Zeiger in union zusammen? Einfach const __flash vor "display_t dip203g;" zu schreiben reicht leider nicht.
1 | // lcd.h
|
2 | typedef void (*TPF)(void); |
3 | typedef void (*TPFu8)(u8 data); |
4 | |
5 | typedef struct |
6 | {
|
7 | TPF lcdinit; |
8 | TPFu8 lcdcommand; |
9 | TPFu8 lcddata; |
10 | u8 zeilenadr[4]; |
11 | } display_t; |
12 | |
13 | // lcd.c
|
14 | void lcd_init( display_t *lcd ) |
15 | {
|
16 | (lcd->lcdinit)(); |
17 | }
|
18 | |
19 | void lcd_command( uint8_t data, display_t *lcd){ |
20 | (lcd->lcdcommand)(data); |
21 | _delay_us(LCD_COMMAND_US ); |
22 | }
|
23 | |
24 | void lcd_data( uint8_t data, display_t *lcd){ |
25 | (lcd->lcddata)(data); |
26 | _delay_us( LCD_WRITEDATA_US ); |
27 | }
|
28 | |
29 | // * * *
|
30 | |
31 | void lcd_string_P( PGM_P data, display_t *lcd ){ |
32 | uint8_t tmp; |
33 | |
34 | tmp=pgm_read_byte(data); |
35 | while( tmp != '\0' ) { |
36 | (lcd->lcddata)(tmp); |
37 | _delay_us( LCD_WRITEDATA_US ); |
38 | data++; |
39 | tmp = pgm_read_byte(data); |
40 | }
|
41 | }
|
42 | |
43 | // lcd_dip203g.h
|
44 | #define LCD_ZEICHEN_PRO_ZEILE 20
|
45 | #define LCD_DDADR_LINE1 0x00
|
46 | #define LCD_DDADR_LINE2 (LCD_DDADR_LINE1 + LCD_ZEICHEN_PRO_ZEILE)
|
47 | #define LCD_DDADR_LINE3 0x40
|
48 | #define LCD_DDADR_LINE4 (LCD_DDADR_LINE3 + LCD_ZEICHEN_PRO_ZEILE)
|
49 | |
50 | #define BIT_RS 0
|
51 | #define BIT_E 1
|
52 | |
53 | extern display_t dip203g; |
54 | static inline void lcd_dip203g_out( u8 data, u8 rs ) |
55 | {
|
56 | u8 a; |
57 | lcd_adrmode(); |
58 | |
59 | a = (data & 0xf0); |
60 | if(rs) a |= (1<<BIT_RS); |
61 | |
62 | |
63 | spi_master_transmit(a); |
64 | spi_intern_start(); |
65 | asm volatile("lpm"); |
66 | spi_intern_stop(); |
67 | asm volatile("lpm"); |
68 | |
69 | spi_master_transmit(a | (1<<BIT_E)); |
70 | spi_intern_start(); |
71 | asm volatile("lpm"); |
72 | spi_intern_stop(); |
73 | asm volatile("lpm"); |
74 | |
75 | spi_master_transmit(a); |
76 | spi_intern_start(); |
77 | asm volatile("lpm"); |
78 | spi_intern_stop(); |
79 | asm volatile("lpm"); |
80 | }
|
81 | |
82 | // lcd_dip203g.c
|
83 | display_t dip203g; |
84 | |
85 | void lcd_dip203g_structinit(void){ |
86 | dip203g.lcdinit = lcd_dip203g_init; |
87 | dip203g.lcdcommand = lcd_dip203g_command; |
88 | dip203g.lcddata = lcd_dip203g_data; |
89 | dip203g.zeilenadr[0] = LCD_DDADR_LINE1; |
90 | dip203g.zeilenadr[1] = LCD_DDADR_LINE2; |
91 | dip203g.zeilenadr[2] = LCD_DDADR_LINE3; |
92 | dip203g.zeilenadr[3] = LCD_DDADR_LINE4; |
93 | }
|
94 | |
95 | void lcd_dip203g_init(void){ |
96 | _delay_ms( LCD_BOOTUP_MS ); |
97 | |
98 | lcd_dip203g_out( LCD_SOFT_RESET,0 ); // 0x30 |
99 | |
100 | _delay_ms( LCD_SOFT_RESET_MS1 ); // 5 ms |
101 | |
102 | lcd_dip203g_out( LCD_SOFT_RESET,0 ); // 0x30 |
103 | |
104 | _delay_ms( LCD_SOFT_RESET_MS2 ); // 1 ms |
105 | |
106 | lcd_dip203g_out( LCD_SOFT_RESET,0 ); // 0x30 |
107 | |
108 | // * * *
|
109 | }
|
110 | |
111 | void lcd_dip203g_command(u8 data){ |
112 | lcd_dip203g_out( data,0 ); |
113 | lcd_dip203g_out( data<<4,0); |
114 | }
|
115 | |
116 | void lcd_dip203g_data(u8 data){ |
117 | lcd_dip203g_out( data,1); |
118 | lcd_dip203g_out( data<<4,1); |
119 | }
|
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.