Hallo an alle... Zuerst: Controller: ATmega8 Compiler: AVR-GCC Taktrate: 8 Mhz Ich verwende zur Ansteuerung eines Displays diese lib: http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmierung Das hat immer wunderbar funktioniert. Doch jetzt macht auf einmal die set_curosor() - Funktion Probleme. Sobald diese irgendwo im Code aufgerufen wird zeit das LCD in der ersten Zeile nur die schwarzen Blöcke an. Allerdings sind diese nicht wirklich schwarz, eher kaum zu erkennen. Für mich sieht es so aus als würde das LCD ständig gelöscht und dann die Balken geschrieben werden. Hab ich im code nirgends die set_cursor() - Funktion drin funzt das Display einwandfrei... Hat jemand eine Idee woran das liegen könnte? Danke schonmal im Voraus
>Hab ich im code nirgends die set_cursor() - Funktion drin funzt das >Display einwandfrei... Welcher Code? Vieleicht legt dein Code ne Bauchlandung wegen Stacküberlauf hin. Aber das kann man nicht beurteilen solange man ihn nicht kennt.
Hier ist die Timerroutine:
1 | ISR(TIMER2_COMP_vect) |
2 | {
|
3 | _CLI(); |
4 | cnt++; |
5 | if (cnt==50) |
6 | {
|
7 | |
8 | switch(MenuVal) |
9 | {
|
10 | case 0: |
11 | temperature = gettemp(); |
12 | if (temperature < 120) |
13 | {
|
14 | temperature = temperature / 4; // MAX6675-Wert durch vier teilen da Auflösung 0,25 |
15 | dtostrf(temperature, 2,2, temp); |
16 | lcd_clear(); |
17 | set_cursor(0,2); |
18 | lcd_string(temp); |
19 | OUT_PORT |= (1<<HEAT_OUT); |
20 | }else |
21 | {
|
22 | temperature = temperature / 4; // MAX6675-Wert durch vier teilen da Auflösung 0,25 |
23 | dtostrf(temperature, 2,2, temp); |
24 | lcd_clear(); |
25 | lcd_string(temp); |
26 | OUT_PORT &=~ (1<<HEAT_OUT); |
27 | }break; |
28 | }
|
29 | cnt = 0; |
30 | }
|
31 | |
32 | |
33 | _SEI(); |
34 | }
|
Und das ist der Code für die LCD-Funktionen:
1 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
|
2 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
|
3 | //
|
4 | // Die Pinbelegung ist über defines in lcd-routines.h einstellbar
|
5 | |
6 | #include <avr/io.h> |
7 | #include "lcd-routines.h" |
8 | #include <util/delay.h> |
9 | |
10 | // sendet ein Datenbyte an das LCD
|
11 | |
12 | void lcd_data(unsigned char temp1) |
13 | {
|
14 | unsigned char temp2 = temp1; |
15 | |
16 | LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen |
17 | |
18 | temp1 = temp1 >> 4; |
19 | temp1 = temp1 & 0x0F; |
20 | LCD_PORT &= 0xF0; |
21 | LCD_PORT |= temp1; // setzen |
22 | lcd_enable(); |
23 | |
24 | temp2 = temp2 & 0x0F; |
25 | LCD_PORT &= 0xF0; |
26 | LCD_PORT |= temp2; // setzen |
27 | lcd_enable(); |
28 | |
29 | _delay_us(42); |
30 | }
|
31 | |
32 | // sendet einen Befehl an das LCD
|
33 | |
34 | void lcd_command(unsigned char temp1) |
35 | {
|
36 | unsigned char temp2 = temp1; |
37 | |
38 | LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen |
39 | |
40 | temp1 = temp1 >> 4; // oberes Nibble holen |
41 | temp1 = temp1 & 0x0F; // maskieren |
42 | LCD_PORT &= 0xF0; |
43 | LCD_PORT |= temp1; // setzen |
44 | lcd_enable(); |
45 | |
46 | temp2 = temp2 & 0x0F; // unteres Nibble holen und maskieren |
47 | LCD_PORT &= 0xF0; |
48 | LCD_PORT |= temp2; // setzen |
49 | lcd_enable(); |
50 | |
51 | _delay_us(42); |
52 | }
|
53 | |
54 | // erzeugt den Enable-Puls
|
55 | void lcd_enable(void) |
56 | {
|
57 | // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen
|
58 | // http://www.mikrocontroller.net/topic/81974#685882
|
59 | LCD_PORT |= (1<<LCD_EN); |
60 | _delay_ms(1); // kurze Pause |
61 | // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
|
62 | // http://www.mikrocontroller.net/topic/80900
|
63 | LCD_PORT &= ~(1<<LCD_EN); |
64 | }
|
65 | |
66 | // Initialisierung:
|
67 | // Muss ganz am Anfang des Programms aufgerufen werden.
|
68 | |
69 | void lcd_init(void) |
70 | {
|
71 | LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | (1<<LCD_EN); // Port auf Ausgang schalten |
72 | |
73 | // muss 3mal hintereinander gesendet werden zur Initialisierung
|
74 | |
75 | _delay_ms(15); |
76 | LCD_PORT &= 0xF0; |
77 | LCD_PORT |= 0x03; |
78 | LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 |
79 | lcd_enable(); |
80 | |
81 | _delay_ms(5); |
82 | lcd_enable(); |
83 | |
84 | _delay_ms(1); |
85 | lcd_enable(); |
86 | _delay_ms(1); |
87 | |
88 | // 4 Bit Modus aktivieren
|
89 | LCD_PORT &= 0xF0; |
90 | LCD_PORT |= 0x02; |
91 | lcd_enable(); |
92 | _delay_ms(1); |
93 | |
94 | // 4Bit / 2 Zeilen / 5x7
|
95 | lcd_command(0x28); |
96 | |
97 | // Display ein / Cursor aus / kein Blinken
|
98 | lcd_command(0x0C); |
99 | |
100 | // inkrement / kein Scrollen
|
101 | lcd_command(0x06); |
102 | |
103 | lcd_clear(); |
104 | }
|
105 | |
106 | // Sendet den Befehl zur Löschung des Displays
|
107 | |
108 | void lcd_clear(void) |
109 | {
|
110 | lcd_command(CLEAR_DISPLAY); |
111 | _delay_ms(5); |
112 | }
|
113 | |
114 | // Sendet den Befehl: Cursor Home
|
115 | |
116 | void lcd_home(void) |
117 | {
|
118 | lcd_command(CURSOR_HOME); |
119 | _delay_ms(5); |
120 | }
|
121 | |
122 | // setzt den Cursor in Zeile y (1..4) Spalte x (0..15)
|
123 | |
124 | void set_cursor(uint8_t x, uint8_t y) |
125 | {
|
126 | uint8_t tmp; |
127 | |
128 | switch (y) { |
129 | case 1: tmp=0x80+0x00+x; break; // 1. Zeile |
130 | case 2: tmp=0x80+0x40+x; break; // 2. Zeile |
131 | case 3: tmp=0x80+0x10+x; break; // 3. Zeile |
132 | case 4: tmp=0x80+0x50+x; break; // 4. Zeile |
133 | default: return; // für den Fall einer falschen Zeile |
134 | }
|
135 | lcd_command(tmp); |
136 | }
|
137 | |
138 | // Schreibt einen String auf das LCD
|
139 | |
140 | void lcd_string(char *data) |
141 | {
|
142 | while(*data) { |
143 | lcd_data(*data); |
144 | data++; |
145 | }
|
146 | }
|
Du solltest mal an den Routinen arbeiten die du hier nicht gepostet hast. Du verschwendest vermutlich zu viel RAM.
>>Naja, da ist nicht mehr drin außer die main ;) Och das würde ich so nicht sagen ;) temperature = gettemp(); gettemp() fehlt. > dtostrf(temperature, 2,2, temp); Muss temperature float sein? Wie groß ist das temp Array? Fragen über Fragen.
@Rush, Ein Tipp. Gewöhne dir das _CLI() / _SEI() in der ISR ab, denn ... A) das macht schon der Compiler. B) es kann Probleme machen wenn du es zusätzlich selbst machst (rätselhaft Abstürze etc.). C) Sind in <avr/interrupt.h> definiert als sei() / cli(). P.S. Schrecklich - Hinweis mit zwei P schreiben zu müssen (grusel). Zumal für uns Franken, da gibt es diesen Buchstaben nicht ;-) Übersetzung P -> B; T -> D P.P.S. Und "delay" in einer ISR ... noch mehr Gruseln + Schaudern.
Die Funktion fehlt, stimmt ;-) Die gettemp() gibt einen uint_16 zurück. Da ich diesen Wert aber noch durch 4 teilen muss brauche ich doch einen float, sonst komme ich nicht an die Kommastellen rein. Was den Code angeht: Ich habe testweise einfach den aus dem Tutorial verwendet
1 | //
|
2 | // Anpassungen im makefile:
|
3 | // ATMega8 => MCU=atmega8 im makefile einstellen
|
4 | // lcd-routines.c in SRC = ... Zeile anhängen
|
5 | //
|
6 | #include <avr/io.h> |
7 | #include "lcd-routines.h" |
8 | |
9 | int main(void) |
10 | {
|
11 | lcd_init(); |
12 | |
13 | lcd_data('T'); |
14 | lcd_data('e'); |
15 | lcd_data('s'); |
16 | lcd_data('t'); |
17 | |
18 | set_cursor(0,2); |
19 | |
20 | lcd_string("Hello World!"); |
21 | |
22 | while(1) |
23 | {
|
24 | }
|
25 | |
26 | return 0; |
27 | }
|
Der funktioniert auch nicht. Aber auf einem Mega16 per JTAG geflasht läuft er komischerweise. Den neusten Compiler habe ich auch schon installiert, ohne Erfolg :-(
Werner B. wrote: > Gewöhne dir das _CLI() / _SEI() in der ISR ab, denn ... > A) das macht schon der Compiler. Nein, das macht die Hardware. Peter
@Werner B. Ich habe doch garkein delay in der ISR drin. und was _CLI und _SEI angeht, meinste ich soll das einfach weglassen, oder sei() und cli() benutzen?
Rush wrote: > Ich habe doch garkein delay in der ISR drin. Doch, in den LCD-Funktionen. > und was _CLI und _SEI angeht, meinste ich soll das einfach weglassen, > oder sei() und cli() benutzen? Komplett weglassen.
>Der funktioniert auch nicht. Aber auf einem Mega16 per JTAG geflasht >läuft er komischerweise. Also wenn dein Minicode (ohne Interrupt) schon nicht funktioniert wird es wohl an etwas anderem liegen. Hast du den Code auch für einen ATMega8 neu compiliert? Oder vieleicht die falsche HEX-Datei erwischt?
alles neu kompiliert, im AVR-Studio auch ein anderes Device angelegt, die Taktraten angepasst und direkt ausm AVR-Studio draufgeflasht. Tut sich nichts. Eben habe ich es mit einem zweiten Mega8 probiert, ebenfalls nichts.
"direkt ausm AVR-Studio draufgeflasht" deswegen musst du trotzdem die richtige *.hex vorher einstellen
Da der mega8 kein JTAG hat starte ich das Programm mit "Built and Run" im Simulator. Um das Proggi zu flashen wähle ich dann kein HEX-File sondern nehme die Option "Use current Simulator/Emulator Flash memory". Und ich flashe auch das Flash und schreibe nicht ins EEPROM.
Hast du vieleicht ne Wackelkontakt/Lötbrücke am Mega8 Baord die nur schaden bei diesem Speziellem Befehl erzeugt? Vieleicht geht der Mega8 auch in Reset. Ich würd das mal prüfen das du ne LED am Anfang des Programms einschaltest und nach dem Setcursor aus. Wenn die LED ausbleibt dan hängt das LCD sonst resetet vermutlich der AVR.
Also bei dem Programm:
1 | #include <avr/io.h> |
2 | #include "lcd-routines.h" |
3 | extern void lcd_data(unsigned char temp1); |
4 | extern void lcd_command(unsigned char temp1); |
5 | extern void lcd_enable(void); |
6 | extern void lcd_init(void); |
7 | extern void lcd_home(void); |
8 | extern void lcd_clear(void); |
9 | extern void set_cursor(uint8_t x, uint8_t y); |
10 | |
11 | void main(void) |
12 | {
|
13 | DDRD |= (1<<PD4); |
14 | PORTD |= (1<<PD4); |
15 | lcd_init(); |
16 | // set_cursor(0,1);
|
17 | lcd_data('T'); |
18 | set_cursor(0,2); |
19 | lcd_string("Hallo"); |
20 | PORTD &=~ (1<<PD4); |
21 | |
22 | while(1){} |
23 | }
|
geht die LED an und auch wieder aus. Display bleibt leer. Kommentiere ich das set_cursor(0,2) aus, schreibt er mir in die erste Zeile "THallo" rein.
Set cursor sollte eigentlich nur werte > 0 aktzeptieren oder seh ic das jezt gerade falsch?
der erste wert steht für die stelle in der zeile und der zweite eben für die zeile. Also (0,2) wäre in dem Fall die erste Stelle in der zweiten zeile. (1,2) wäre die zweite Stelle in der zweiten Zeile. Wobei ich das mal testweise versucht habe und es klappt.... Schreibt dann in die zweite Zeile aber auch in die zweite Stelle. Also akzeptiert die funktion die 0 nicht, nur warum ?
Vieleicht hat dein Display ein etwas anderes Speicherlayout als das welches Im Tutorial verwendet wird. Einige Controller haben da ihre eigene Ansichten (Datenblatt zu dem auf dem Display verwendeten Controller kann darüber aufschluß geben). Kannst natürlich die Funktion auch das +1 überlassen ;)
1 | void set_cursor(uint8_t x, uint8_t y) |
2 | {
|
3 | uint8_t tmp; |
4 | |
5 | switch (y) { |
6 | case 1: tmp=0x80+0x00+x+1; break; // 1. Zeile |
7 | case 2: tmp=0x80+0x40+x+1; break; // 2. Zeile |
8 | case 3: tmp=0x80+0x10+x+1; break; // 3. Zeile |
9 | case 4: tmp=0x80+0x50+x+1; break; // 4. Zeile |
10 | default: return; // für den Fall einer falschen Zeile |
11 | }
|
12 | lcd_command(tmp); |
13 | }
|
Das seltsame ist ja dass die Funktion schon mit dem Display was ich in diesem Fall verwende immer einwandfrei funktioniert hat. Nur eben jetzt komischerweise nicht. das mit dem +1 wäre ja machbar, dann verliere ich aber immer die 1. Stelle der Zeile, bei set_cursor(1,2) wird der Text erst ab der zweiten Stelle des LCD dargestellt.
Kannst du probehalber einfach statt setcursor(0,2); mal lcd_command(0xC0); ausführen?
lcd_command(0xC0) geht auch nicht, lcd_command(192) geht auch nicht, set_cursor(1,2); set_cursor(2,2); set_cursor(3,2) bis set_cursor(15,2) funktioniert, ich kann nur nicht die erste Stelle in der Zeile ansprechen. Die Funktion an sich wird auch durchlaufen, denn danach lasse ich eine LED aufleuchten und die leuchtet auch.
>lcd_command(0xC0) geht auch nicht,
Jetzt wirds aber ziemlich unheimlich.
Also dein Display funktioniert auf ATMega16.
Hast du nach dem umstellen des Prozessors mal
ein "Rebuild all" oder "make clean" gemacht?
Nicht das die LCD Routinen noch als Objektfile
vom ATMega16 gelinkt werden.
Noch vergessen: Probiers doch auch mal über ein richtiges Hexfile.
Ich habe diesen minicode in einem eigenständigen Projekt geschrieben, also nicht einfach das Projekt vom mega16 genommen und den Controllertyp gewechselt. Make clean, Rebuild all... hab ich alles schon probiert. Ich habe geschrieben das selbe Display mit einem mega16 funzt. Vielleicht habe ich mich etwas falsch ausgerückt... Mit "das selbe Display" meine ich ein vom Typ identisches, hatte damals 6 Stück bei ebay gekauft. Also eins habe ich am mega16 hängen, das andere in meiner Schaltung an der ich rumdoktor.... PS: habe die Schaltung zum x-ten mal durchgemessen... alles OK. Kann es sein das das Display aus welchem Grund auch immer einen Schaden hat, dass es mit den ersten stellen der Zeilen nicht klar kommt ?
>Kann es sein das das Display aus welchem Grund auch immer einen Schaden >hat, dass es mit den ersten stellen der Zeilen nicht klar kommt ? Das sieht zumindest so aus. Kannst du die Displays nicht mal durchtauschen? Das wär das erste was ich machen würde.
Das ist das letzte was ich machen würde bzw. wohl muss :( Die Sch****e ist nur das die Lötstellen jetzt nur schwer zugänglich sind da die Schaltung schon komplett aufgebaut ist :-( Das ist seltsam, das Teil lief ja schonmal ohne Probleme, dann lag es ne zeit lang rum ohne dass ich was dran gemacht hatte. Bis ich dann auf die Idee kam die Software umzugestalten, dann gings auf einmal nicht.
Aber ist doch komisch, wenn ich doch auf die 2. Stelle einer Zeile springen kann, kann es doch auch nicht kaputt sein ?!
>Aber ist doch komisch, wenn ich doch auf die 2. Stelle einer Zeile >springen kann, kann es doch auch nicht kaputt sein ?! Zumindest nicht ganz kaputt. Vieleicht doch noch irgendwo am Code gefummelt? Poste das fehlerhafte Projekt doch mal komplett als ZIP.
So, hier das komplette Projekt als Zip. In der lcd-routines.c habe ich die Zeit in der lcd_enable() Funktion auf 90ms gesetzt. So sehe ich bei Ausführung des angehängten codes wie die erste Zeile dargestellt wird und anschließend das LCD wieder gelöscht wird. Die LED zum Schluss des Programms geht an!
Info an alle hier Beteiligten... Das LCD hat einen Schlag.... hab es eben mal ausgetauscht und siehe da es funzt auf Anhieb.. Einene derartigen Defekt habe ich jetzt garnicht erwartet. Vielen Dank für eure Bemühungen Gruß, Konrad
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.