Hallo,
versuche gerade das RS232 Protokoll zu verstehen. Ich fange ganz langsam
damit an in dem ich versuche einen Pin 104 µs auf hight und low
zusetzten.
Hier scheitert es schon:
Folgendes Programm habe ich dazu geschrieben:
1
2
#include<avr/io.h>
3
#include<stdint.h>
4
#include<avr/interrupt.h>
5
#include<util/delay.h>
6
#include"var.h"
7
#include"lcd.h" ...
8
9
...lcd_init();
10
lcd_loeschen();
11
lcd_string("Test");
12
while(1)
13
{
14
PORTA|=(1<<PA7);
15
_delay_us(104);
16
PORTA&=~(1<<PA7);
17
_delay_us(104);
18
}
Problemm:
Es sind keine 104µs sondern ca. 1ms.
Ich bin auf folgen Beitrag gestoßen und habe denke alles beachtet.
Beitrag "delay us liegt weit daneben"
Komisch an der Sache ist, schalte ich die Optimierung ein, funktioniert
das Display nicht und der Pin bleibt auf Low.
Wo ist der Hacken?
Danke für eure Hilfe.
PS: Bitte verzeiht mir meine Rechtschreibung.
Kein Plann schrieb:> Komisch an der Sache ist, schalte ich die Optimierung ein, funktioniert> das Display nicht und der Pin bleibt auf Low.
Und ohne Optimierung bekanntermassen nicht das Delay. Was folgt daraus?
Du hast kein Problem mit dem Delay, sondern mit dem LCD-Code.
Kein Plann schrieb:> Problemm:> Es sind keine 104µs sondern ca. 1ms.
Weil du die Optimierung ausgeschaltet hast?
> Ich bin auf folgen Beitrag gestoßen und habe denke alles beachtet.> Beitrag "delay us liegt weit daneben"
Sicher?
>> Komisch an der Sache ist, schalte ich die Optimierung ein, funktioniert> das Display nicht und der Pin bleibt auf Low.
Weil deine Displayroutine hängen bleibt und er garnicht bis zur Schleife
kommt?
> Wo ist der Hacken?
In deiner Display Routine.
>PS: Bitte verzeiht mir meine Rechtschreibung.
Gleichfalls!
mfg Andreas
Kein Plann schrieb:> Wie bekomme ich nun raus wo's in der Routine hängt?
(1) Selber suchen.
(2) Suchen lassen.
Die Voraussetzung für (2) zu erkennen überlasse ich dir. ;-)
Mit Schweiß und Verstand... oder man nimmt sich einen Debugger zur Hand.
Vielleicht wirft der Compiler auch die eine oder andere Warnung die von
dir ingoriert werden... Möglicherweise auch den einen oder anderen
volatilen Fehler.
A. K. schrieb:> (2) Suchen lassen.
Habe die Routine mal angehängt. Aber bitte vorher setzten. Sie sieht
katastrophal aus. Ist von einem Lehrer programmiert wurden, der glaube
selber keine Ahnung hatte. Wir haben nur die Befehle bekommen. Was sie
macht, kein Plan.
Coder schrieb:> Vielleicht wirft der Compiler auch die eine oder andere Warnung die von> dir ingoriert werden...
Warnungen ignorieren, wie kommst Du den darauf? ;-)
Ne, es werden nur 2 Stück ausgegeben. Beide weisen mich darauf hin das
Delay nur mit Optimierung funktioniert.
Wie sieht "wartems" aus?
Ausserdem wärs sehr wohl denkbar, dass 1-2 NOPs zu wenig sind. Einfach
mal alle diese Multi-NOP-Delays durch jeweils ein einziges _delay_us(1)
ersetzen.
Kein Plann schrieb:> Habe die Routine mal angehängt. Aber bitte vorher setzten. Sie sieht> katastrophal aus. Ist von einem Lehrer programmiert wurden, der glaube> selber keine Ahnung hatte.
Danke für die Warnung.
Deine Lehrer sollte man ....
Das einzige was ich auf die schnelle sehen kann, was hängen könnte ist
hier
1
voidDISPLAY_BUSY(void)
2
{
3
uint8_tj;
4
j=1;
5
DDRC=0x00;
6
while(!(j==0))
7
{
8
RS_L;
9
RW_S;
10
EN_S;
11
12
if(!(PINC&(1<<PIN7)))
13
{
14
j=0;
15
}
16
17
EN_L;
18
RW_L;
19
}
20
DDRC=0xFF;
21
}
Schmeiss probehalber den Teil mal raus und ersetze ihn durch ein
1
voidDISPLAY_BUSY(void)
2
{
3
_delay_ms(30);
4
}
(Include Files für den Delay nicht vergessen)
Aber ganz ehrlich. Den LCD Code sollte man ausdrucken und ihm solange um
die Ohren dreschen, bis nur noch Konfetti übrig sind. Das ein LCD auch
ein Timing braucht, scheint er noch nie gehört zu haben. Und über die
Zahlenausgaben breiten wir lieber den Mantel des Schweigens. (PS die
letzte Routine ist falsch.)
Karl Heinz Buchegger schrieb:> Das ein LCD auch> ein Timing braucht, scheint er noch nie gehört zu haben.
Doch, er hat. Sonst hätte er nicht all diese lustigen NOPs verstreut.
Nur kapiert hat ers wohl nicht, oder geht fest von 1MHz Takt oder so
aus. Ich habe hier aber schon schlimmeren Anfängercode gesehen.
Selbiges: Array Overflow.
Ich korrigiere mich: Nach der Konfetti Produktion sollte man ihn teeren
und federn und die Lizenz zum Lehren von Programmiersprachen entziehen,
solange bis er die erfolgreiche ABsolvierung eines Anfängerkurses
nachweisen kann.
A. K. schrieb:> Ich habe hier aber schon schlimmeren Anfängercode gesehen.
Aber nicht viel schlimmer.
Die meisten Anfänger haben den Dreh schnell raus, dass
* in C bei 0 begonnen wird zu zählen (siehe die Cursor Positionierung
* daraus folgt, dass der maximal mögliche Array Index um 1 kleiner
ist, als die definierte Größe.
Noch schlimmer ist allerdings, dass dieses Machwerk von seinem Lehrer
stammt, der eigentlich kein Anfänger sein sollte.
Karl Heinz Buchegger schrieb:> void DISPLAY_BUSY(void)> {> _delay_ms( 30 );> }
Okay, auch das hat funktioniert.
Aber damit vergeude ich nun Zeit?
Wo liegt nun in der Routine der Fehler?
Ihr seit wie immer spitze!!!
Danke!
Kein Plan schrieb:> Karl Heinz Buchegger schrieb:>> void DISPLAY_BUSY(void)>> {>> _delay_ms( 30 );>> }>>> Okay, auch das hat funktioniert.> Aber damit vergeude ich nun Zeit?> Wo liegt nun in der Routine der Fehler?
Wahrscheinlich darin, dass er sich einen Dreck um Timings geschi....
hat.
Man kann nicht einfach 'Pin hoch' - 'Pin runter'. Da muss eine Wartezeit
dazwischen. Dem LCD muss man schon einen Puls mit Mindestbreite zeigen,
damit es auch eine Chance hat, den Puls als solchen zu sehen.
Wie ist denn die Pinbelegung im lcd.h?
(Dass er da einfach den Port C komplett von Ein auf Ausgang umschaltet,
stösst mir auch sauer auf. Wozu gibts denn die schönen #define in der
lcd.h! Amateur)
denn da fragt er den Pin ab, noch bevor E überhaupt richtig oben ist.
Jedenfalls wenns ein ATmega ist. Bei einem 1MHz AT90 hingegen dürfte das
funktionieren, da denen die Input-Latch-Kette zur Vermeidung
metastabiler Zustände fehlt und daher zwischen der Aktivierung von E und
dem abgefragten Zustand etwas Zeit bleibt.
Karl Heinz Buchegger schrieb:> Man kann nicht einfach 'Pin hoch' - 'Pin runter'. Da muss eine Wartezeit> dazwischen. Dem LCD muss man schon einen Puls mit Mindestbreite zeigen,> damit es auch eine Chance hat, den Puls als solchen zu sehen.
Wie meinst Du das?
Im Anhang noch die LCD.h.
> denn da fragt er den Pin ab, noch bevor E überhaupt richtig oben ist.
Jo, hätt ich jetzt auch gesagt.
Ich weiß aber nicht auswendig, welche Wartezeit da angemessen ist.
Ich würds mal mit ein paar µs versuchen. Sagen wir mal 50. KLeiner gehen
kann man immer noch (oder im Datenblatt nachsehen)
Kein Plan schrieb:> Wie meinst Du das?
Schau mal ins aktuelle Datasheet vom ATmega8 (wegen der Seitennummer)
auf Seite 53. Der Abschnitt "Reading the Pin Value".
Karl Heinz Buchegger schrieb:> Ich würds mal mit ein paar µs versuchen. Sagen wir mal 50.
_delay_us(1) reicht.
A. K. schrieb:> Wie sieht "wartems" aus?
Guter Einwand.
Sollte man auch durch die gcc-Standard Routine ersetzen. Wer weiß, was
da wieder dahinter steckt.
Wenns damit erst mal klappt, dann machen wir den nächsten Schritt.
Ich kann nämlich dieses Elend nicht mehr sehen.
Die Zahlenausgaben ersetzt du durch
1
voidlcd_char(charc)
2
{
3
RS_S;
4
DISPLAY_PORT=c;
5
DISPLAY_EN();
6
DISPLAY_BUSY();
7
}
8
9
voidlcd_string(constchar*str)
10
{
11
while(*str)
12
lcd_char(*str++);
13
}
14
15
voidlcd_uint8(uint8_tuint8)
16
{
17
charstr[4];
18
19
utoa(uint8,str,10);
20
lcd_string(str);
21
}
22
23
voidlcd_uint16(uint16_tuint16)
24
{
25
charstr[6];
26
27
utoa(uint16,str,10);
28
lcd_string(str);
29
}
30
31
staticvoidlcd_nibble(uint8_tnibble)
32
{
33
nibble&=0x0F;
34
35
if(nibble<10)
36
lcd_char(nibble+'0');
37
else
38
lcd_char(nibble-10+'A');
39
}
40
41
voidlcd_hex8(uint8_thexvar8)
42
{
43
lcd_nibble(hexvar8>>4);
44
lcd_nibble(hexvar8);
45
}
46
47
voidlcd_hex16(uint16_thexvar16)
48
{
49
lcd_nibble(hexvar8>>12);
50
lcd_nibble(hexvar8>>8);
51
lcd_nibble(hexvar8>>4);
52
lcd_nibble(hexvar8);
53
}
Das ist übrigens keine Frage der Schönheit. Die Originalroutinen sind
schlicht und ergreifend fehlerhaft (mal ganz davon abgesehen, dass sie
horrend umständlich programmiert sind).
Und über die lcd_komma reden wir nochmal, wenn du sie brauchst. Die ist
auch falsch.
Kein Plan schrieb:> "utoa" habe ich gerade gelesen braucht viel Speicher.
utoa braucht auch nicht viel Speicher. Du verwechselst das mit printf.
Abegesehen davon. Was glaubst du, was der Original-Code da braucht? Wer
sowas schreibt, dem spreche ich das Recht ab, sich über
Speicherverbrauch Gedanken zu machen :-)
Kein Plan schrieb:> Ich brauche eine Funktion die unsigned char ausgibt.
Möchtest du einen Buchstaben auf dem LCD haben oder einen Hexwert? Für
den Hexwert hat Karl Heinz eigentlich alles vorbereitet:
1
staticvoidlcd_nibble(uint8_tnibble)
2
{
3
nibble&=0x0F;
4
5
if(nibble<10)
6
lcd_char(nibble+'0');
7
else
8
lcd_char(nibble-10+'A');
9
}
10
11
voidlcd_hex8(uint8_thexvar8)
12
{
13
lcd_nibble(hexvar8>>4);
14
lcd_nibble(hexvar8);
15
}
An lcd_hex übergibst du den Wert, der dann als Hex (00-FF) auf dem LCD
angezeigt wird.
Kein Plan schrieb:> Danke für die Antworten.>> Kurz mein Vorhaben:> Zitat aus der I2C Routine von Peter Fleury:>
1
>unsignedchari2c_readAck(void)
2
>{
3
>TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
4
>while(!(TWCR&(1<<TWINT)));
5
>
6
>returnTWDR;
7
>
8
>}
>> Denn erhaltenen Wert würde ich gerne als dezimal Zahl ausgeben.
die lcd_uint8 von oben macht das.
unsigned char ist auch nichts anderes als ein uint8_t