Forum: Mikrocontroller und Digitale Elektronik Mehrere Geräte von gleichem Typ steuern


von Maxim B. (max182)


Lesenswert?

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!

von Karl M. (Gast)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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
von Maxim B. (max182)


Lesenswert?

Vielen Dank!
Ich versuche es mit Lib.

von Maxim B. (max182)


Lesenswert?

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
Noch kein Account? Hier anmelden.