Forum: Mikrocontroller und Digitale Elektronik Klasse für HD44780 LCDs


von Tim (Gast)


Lesenswert?

Hallo, ich versuche gerade, aus diesem 
(http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD) Tutorial 
eine Klasse für einen ATMEGA88 zu Entwickeln. Mein LCD scheint jedoch 
nicht darauf zu reagieren. Es schreibt nur einen Schwarzen Balken in das 
Feld ganz links und dann sieht man den Cursor im 2ten Feld blinken.
1
#include <avr/io.h>
2
#include <stdint.h>
3
#include <util/delay.h>
4
#include "LCD_HD44780_4Bit.h"
5
6
#define nop() \
7
asm volatile ("nop")
8
9
LCD_HD44780_4Bit::LCD_HD44780_4Bit (
10
    volatile uint8_t *Port, // Der Port, an dem das LCD angeschlossen ist
11
    int DB4, // Der Pin, der mit ... verbunden ist.
12
    int DB5,
13
    int DB6,
14
    int DB7,
15
16
    int RS,
17
    int E,
18
19
    Lines ZeilenZahl,
20
    Pixel PunkteProPixel,
21
    Scrolling Scrollverhalten,
22
    Cursor cursor,
23
    Display display,
24
    CursorFlashing CursorBlinkverhalten,
25
    WritingBehavior Schreibverhalten
26
)
27
{
28
    
29
    this->_Port = Port;
30
  this->_DB4 = DB4;
31
  this->_DB5 = DB5;
32
  this->_DB6 = DB6;
33
  this->_DB7 = DB7;
34
    
35
  this->_RS = RS;
36
  this->_E = E; 
37
    
38
    this->_lines = ZeilenZahl;
39
    this->_pixel = PunkteProPixel;
40
    this->_scrolling = Scrollverhalten;
41
    this->_cursor = cursor;
42
    this->_display = display;
43
    this->_cursorFlashing = CursorBlinkverhalten;
44
    this->_writingBehavior = Schreibverhalten;
45
   
46
}
47
  
48
void LCD_HD44780_4Bit::init()
49
{
50
  
51
  // LCD-Kontroller Zeit für seine eigene Initialisierung zu geben
52
  Pause_ms(250);
53
  // 3 muss zur Initialisierung 3mal hintereinander gesendet werden
54
  Write4BitToPort(3, 0); // 0b00000011
55
  // 1
56
  enable();             
57
  Pause_ms(5);
58
  // 2
59
  enable();                 
60
  Pause_ms(5);
61
  // und 3!
62
     enable();            
63
  Pause_ms(5);
64
  // 4bit-Modus einstellen
65
  Write4BitToPort(2, 0); // 0b00000010
66
  enable();
67
  Pause_ms(5);
68
    
69
     
70
  uint8_t Konfiguration = 
71
        (1<<5) | // Bit gibt die Konfigurations-Art an
72
        (0<<4) | // 4-Bit Interface
73
        (this->_lines<<3) | // Wird durch this->_lines = 1- oder 2-Zeilig bestimmt. Der enum wert wird in einen Int-konvertiert (0 oder 1)
74
        (this->_pixel<<2);  // Wie this->_lines
75
    this->command(Konfiguration);
76
        
77
    
78
    uint8_t On_Off_control =
79
        (1<<3) | // Bit gibt die Konfigurations-Art an
80
        (this->_display<<2) | // Wird durch this->_display = On oder Off bestimmt. Der enum wert wird in einen Int-konvertiert (1 oder 0)
81
        (this->_cursor<<1) | // Wird durch this->_cursor = On oder Off bestimmt. Der enum wert wird in einen Int-konvertiert (1 oder 0)
82
        (this->_cursorFlashing<<0);  // Wird durch this->_cursorFlashingy = Yes oder No bestimmt. Der enum wert wird in einen Int-konvertiert (1 oder 0)
83
  this->command(On_Off_control);
84
        
85
      uint8_t Entry_mode = 
86
        (1<<2) | // Bit gibt die Konfigurations-Art an
87
        (this->_writingBehavior<<1) | // Wird durch this->_writingBehavior = decrement oder increment bestimmt. Der enum wert wird in einen Int-konvertiert (0 oder 1)
88
        (this->_scrolling<<0); // Wird durch this->_scrolling = No oder Yes bestimmt. Der enum wert wird in einen Int-konvertiert (0 oder 1)
89
    this->command(Entry_mode);
90
91
  return;
92
}
93
94
uint8_t LCD_HD44780_4Bit::SWAP(uint8_t val)
95
{
96
  // Trennen der Bits und setzen der passenden Nibbles auf 0
97
  uint8_t upper = val & 0xF0; // 0b11110000 -> Oberes Nibble bleibt erhalten
98
  uint8_t lower = val & 0x0F; // 0b00001111 -> Unteres Nibble bleibt erhalten
99
    
100
  // Verschieben der Bits um 4 stellen durch Addition sind die Nibbles dann vertauscht
101
  upper >>= 4;
102
  lower <<= 4;
103
    
104
  // Rückgben der Summe
105
  return upper | lower;
106
}
107
108
void LCD_HD44780_4Bit::enable()
109
{
110
  // Enable high
111
  *this->_Port = (1<<this->_E);
112
  // mindestens 3 Taktzyklen warten
113
  nop();
114
  nop();
115
  nop();
116
  nop();
117
  // Enable wieder low
118
  *this->_Port = (0<<this->_E);
119
  // Und wieder zurück
120
  return;
121
}
122
123
124
125
void LCD_HD44780_4Bit::Write4BitToPort(uint8_t val, bool RS )
126
{
127
  // Filtern der Passenden Bits...
128
    /* Durch die UND-Verknüpfung zwischen val und dem Bit wird geprüft, ob das jeweilige Bit gesetzt ist. Wenn es
129
     * gesetzt ist, ist der Wert >= 1. Dieser bool-Wert wird dann auf den Jeweiligen Pin geschoben. */
130
    uint8_t b1 = (((val & (1 << 0)) >= 1) << this->_DB4); // Normalerweise: 0000|0001
131
    uint8_t b2 = (((val & (1 << 1)) >= 1) << this->_DB5); // Normalerweise: 0000|0010
132
    uint8_t b3 = (((val & (1 << 2)) >= 1) << this->_DB6); // Normalerweise: 0000|0100
133
    uint8_t b4 = (((val & (1 << 3)) >= 1) << this->_DB7); // Normalerweise: 0000|1000
134
  *this->_Port = (b1 | b2 | b3 | b4 | (RS<<this->_RS));
135
    
136
    return;
137
}
138
139
void LCD_HD44780_4Bit::command(uint8_t command)
140
{
141
   // wie lcd_data, nur RS=0
142
     
143
   // Beide Nibble-Blöcke werden in Zwei Variablen zerlegt
144
   // Oberes Nibble
145
   uint8_t upper = SWAP(command);
146
   // Unteres Nibble
147
   uint8_t lower = (command);
148
   // Oberes Nibble übertragen
149
   Write4BitToPort(upper, 0);
150
   enable();
151
   // Unteres Nibble übertragen
152
   Write4BitToPort(lower, 0);
153
   enable();
154
   // Kurze Pause
155
   Pause_us(50);
156
   return;
157
}
158
  
159
void LCD_HD44780_4Bit::WriteChar( unsigned char val)
160
{
161
    // Trennen der Nibbles
162
    uint8_t upper = SWAP(val); 
163
    uint8_t lower = val; 
164
    
165
    // Über RS wird ausgewählt, ob man einen Befehl oder ein Datenbyte an das LCD schicken möchte.
166
    // Beim Schreiben gilt: ist RS Low, dann wird das ankommende Byte als Befehl interpretiert;
167
    // Ist RS high, wird das Byte auf dem LCD angezeigt (genauer: ins Data-Register geschrieben, kann auch für den CG bestimmt sein).
168
    
169
    // Oberes Nibble ausgeben
170
    Write4BitToPort(upper, 1);
171
    // Enable, damit das LCD das Datenbyte interpretiert
172
  enable();          
173
       
174
  // Unteres Nibble ausgeben
175
    Write4BitToPort(lower, 1);
176
    // Enable, damit das LCD das Datenbyte interpretiert
177
    enable();
178
    
179
    // 50µs warten
180
    Pause_us(50);
181
    
182
  return;
183
}
184
185
void LCD_HD44780_4Bit::Clear()
186
{
187
    command(1);
188
    Pause_ms(5);
189
    return;
190
}
191
192
193
194
void * LCD_HD44780_4Bit::operator new( size_t size )
195
{
196
    return malloc(size);
197
}
198
199
void LCD_HD44780_4Bit::operator delete( void * ptr )
200
{
201
    free(ptr);
202
}
203
204
void LCD_HD44780_4Bit::Pause_us(double duration)
205
{
206
    for (int i = 0; i < duration; i++)
207
    _delay_us(1);
208
}
209
void LCD_HD44780_4Bit::Pause_ms(double duration)
210
{
211
    for (int i = 0; i < duration; i++)
212
    _delay_ms(1);
213
}

von Tim (Gast)


Lesenswert?

1
DDRD = 0xFF;
2
    LCD_HD44780_4Bit lcdController(
3
        &PORTD,
4
        PIND0,
5
        PIND1,
6
        PIND2,
7
        PIND3,
8
    
9
        PIND4,
10
        PIND5,
11
12
        LCD_HD44780_4Bit::Lines_1Line,
13
        LCD_HD44780_4Bit::Pixel_5x7Pixel,
14
        LCD_HD44780_4Bit::Scrolling_No,
15
        LCD_HD44780_4Bit::Cursor_Off,
16
        LCD_HD44780_4Bit::Display_On,
17
        LCD_HD44780_4Bit::CursorFlashing_No,
18
        LCD_HD44780_4Bit::WritingBehavior_increment);
19
    
20
    lcdController.init();
21
    
22
    lcdController.Clear();
23
    lcdController.WriteChar(65);
24
    lcdController.WriteChar(66);
25
    lcdController.WriteChar(67);
26
    lcdController.WriteChar(68);

von Klaus W. (mfgkw)


Lesenswert?

Das hier hat bei mir schon regelmäßig funktioniert:
Beitrag "Re: LCD Library gesucht für HD44780"

von Peter D. (peda)


Lesenswert?

Zwar kein C++, dafür aber sehr einfach und sehr kleiner Code:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=102296


Peter

von Karl H. (kbuchegg)


Lesenswert?

1
void LCD_HD44780_4Bit::enable()
2
{
3
  // Enable high
4
  *this->_Port = (1<<this->_E);
5
  // mindestens 3 Taktzyklen warten
6
  nop();
7
  nop();
8
  nop();
9
  nop();
10
  // Enable wieder low
11
  *this->_Port = (0<<this->_E);
12
  // Und wieder zurück
13
  return;
14
}

Du bist ein wenig sehr optimistisch, was Bit setzen und löschen an einem 
Port anbelangt.

> *this->_Port = (1<<this->_E);
Gratuliere: Du hast soeben alle anderen Bits am Port auf 0 gesetzt

>   *this->_Port = (0<<this->_E);
Gratuliere, du hast soeben möglichst kompliziert
   *_Port = 0;
geschrieben.


(Warum das stört? Weil am besagten Port ja auch noch das R/S Signal bzw. 
die Datenbits liegen. Und das wird nicht gut kommen, wenn du die alle 
auf 0 zwingst, nur weil du E toggeln willst)

Bitmanipulation

Das funktioniert in C++ auch nicht anders als in C.


(und spar dir das ewige this. Deine Member Variablen hast du ohnehin 
eindeutig bezeichnet [wenn auch schlecht], so dass du dir das this-> 
sparen kannst.)

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.