Forum: Mikrocontroller und Digitale Elektronik AVR Unterprogramm


von M. M. (pockined)


Lesenswert?

Guten Abend,

Bin noch recht neu in AVR und bin gerade dabei den PCF 8574P über das 
TWI und einem ATmega 32 zu programmieren. Die Ansteuerung über das TWI 
ist mir bereits  gelungen, jedoch funktioniert das ganze mit 
Unterprogrammen nicht.
Folgendes Problem:

Schreibe ich den Code so funktioniert alles perfekt:
1
 
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <util/twi.h>
5
6
int main(void)
7
{
8
9
  while(1)
10
  {
11
      TWBR = 0x01;
12
      TWSR = (0<<TWPS1) | (0<<TWPS0);
13
      TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
14
      while (!(TWCR & (1<<TWINT)));
15
      TWDR = 0x40;
16
      TWCR = (1<<TWINT)|(1<<TWEN);
17
      while (!(TWCR & (1<<TWINT)));
18
      TWDR = 0x00;
19
      TWCR = (1<<TWINT)|(1<<TWEN);
20
      while (!(TWCR & (1<<TWINT)));
21
      TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
22
  }
23
        return 0;
24
}

jetzt wollte ich das ganze in mehrere Unterprogramme packen:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <util/twi.h>
4
5
void TWI_begin(void)
6
{
7
  TWBR = 0x01;
8
  TWSR = (0<<TWPS1) | (0<<TWPS0);
9
}
10
11
void TWI_send_start(void)
12
{
13
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
14
  while(!(TWCR & (1 << TWINT)));
15
}
16
17
void TWI_send_address(unsigned char add)
18
{
19
  TWDR = add;
20
  TWCR = (1<<TWINT) | (1<<TWEN);
21
  while(!(TWCR & (1<<TWINT)));
22
}
23
24
void TWI_send_data(unsigned char dat)
25
{
26
  TWDR = dat;
27
  TWCR = (1<<TWINT) | (1<<TWEN);
28
  while(!(TWCR & (1<<TWINT)));
29
}
30
31
void TWI_send_stop(void)
32
{
33
  TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
34
}
35
36
37
int main(void)
38
{
39
  while(1)
40
  {
41
    TWI_begin();
42
    TWI_send_start();
43
    TWI_send_address(0x40);
44
    TWI_send_data(0x00);
45
    TWI_send_stop();
46
  }
47
  return 0;
48
}

Allerdings funktioniert dieses nicht und ich komme nicht auf den Fehler 
:(
Ich bitte um eure Hilfe

von Hmm (Gast)


Lesenswert?

Analytisch ist es nicht besonders wertvoll nur festzustellen, das es 
nicht funktioniert. Wesentlich wertvoller wäre es zu beschreiben, was 
nicht funktioniert, an welcher_ Stelle im Code und _woran Du das genau 
bemerkst.

von M. M. (pockined)


Lesenswert?

Soweit ich es feststellen konnte funktioniert das Programm bis zum 
Unterprogramm "TWI_send_data(0x00);" anscheinend bleibit er dort bei der 
Abfrage while(!(TWCR & (1<<TWINT))); hängen.

von Spess53 (Gast)


Lesenswert?

Hi

Von einer Fehlerbehandlung über TWSR scheinst du auch nicht viel zu 
halten.

MfG Spess

von Hmm (Gast)


Lesenswert?

>anscheinend...

Bitte noch präziser. Welches Ereigniss bzw. das Ausbleiben welchen 
Ereignisses konkret vermittelt Dir den Anschein, das es dort hängen 
bleibt ?
Woran merkst Du das? Glaskugel, Pendel, Geomantie, Wahrsagerei? :-)

von M. M. (pockined)


Lesenswert?

tut mir leid bin noch neu in AVR :b

Da das Programm an dieser Stelle nicht mehr weiterläuft und in dieser 
Schleife bleibt.

von Hmm (Gast)


Lesenswert?

Braucht Dir nicht leid tun.

>Da das Programm an dieser Stelle nicht mehr weiterläuft und in dieser
>Schleife bleibt.

Aha. Und wie, auf welche Weise, mit welchen Mitteln stellst Du das fest?
Kartenlegen, Orakel, Innereien-Schau?

von M. M. (pockined)


Lesenswert?

Mit der Noobmethode, dass ich einfach ein LED einmal vor der Schleife 
und einmal nach der Schleife am Port D eingeschaltet habe und dabei 
bemerkt habe, dass der Befehl vor der Schleife ausgeführt wird, danach 
allerdings nicht mehr und auch im folgenden Programmteil wird nichts 
mehr ausgeführt.

von holger (Gast)


Lesenswert?

>Mit der Noobmethode, dass ich einfach ein LED einmal vor der Schleife
>und einmal nach der Schleife am Port D eingeschaltet habe

Warum zeigst du dann nicht den Code mit den LEDs?

von Hmm (Gast)


Lesenswert?

>...dass ich einfach ein LED einmal vor der Schleife
>...und einmal nach der Schleife am Port D eingeschaltet habe

Gut. Das hätte schon mal ins erste Posting gehört, dann braucht man 
nicht erst nachzufragen.
Wir können nicht ohne Zauberei einzusetzen, einschätzen ob eine 
Behauptung auf konkreten Informationen beruht oder nur auf Annahmen.

Was hast Du an Werkzeugen? JTAG-Debugger? (z.B. JTAG-ICE MKII)

Spess hat ja schon das TWSR-Register erwähnt. Kannst Du feststellen, was 
darin steht? Etwa über den Debugger oder Ausgabe auf einen Port?
Hast Du die Beschreibung schon gelesen?

von Hmm (Gast)


Lesenswert?

Es hängt auch davon ab, wie die Person einzuschätzen ist. Wenn Spess uns 
schreibt, das er in der while-Schleife hängen bleibt, dann glauben wir 
ihm das unbesehen (bis es ernste Anzeichen gibt, das es nicht so ist). 
Aber uns selbst und Unbekannten, glauben wir es erst wenn wir sicher 
sind und materielle Beweise dafür vorliegen.
Nimm das Nachbohren also nicht so schwer. Ist nichts persönliches. Rein 
geschäftlich. :-)

von M. M. (pockined)


Lesenswert?

Ok hätte mir klar sein sollen :)

Programmiert wird über den Prog-s von Atmel auf dem Atmel 
Evaluationboard.
Ich werden es versuchen jedoch dachte ich das es sich um einen 
Anfängerfehler handelt, da das Programm ohne Unterprogramme einwandfrei 
funktioniert hat und danach, wo ich es doch nur aufgeiteil habe nicht 
mehr.

von Spess53 (Gast)


Lesenswert?

Hi

>Wenn Spess uns schreibt, das er in der while-Schleife hängen bleibt, dann
>glauben wir ihm das unbesehen ....

Da ich notorischer Assemblerprogrammierer bin, wäre das eher ein 
Anzeichen geistiger Umnachtung.

MfG Spess

von Hmm (Gast)


Lesenswert?

>... dachte ich das es sich um einen Anfängerfehler handelt ...

Nein, tut es wohl nicht. Sei beruhigt. Falls ich nichts übersehen habe, 
sollte der Code eigentlich genauso funktionieren. Du hast ja lediglich 
die Zeilen aus der While-Schleife in Funktionen gepackt.

Dieser "Prog S" ist mitnichten von Atmel sondern von DIAMEX. (Immer 
schön genau hingucken, gelle :-) )
Damit kannst Du leider nicht debuggen.

Es bleibt also nur, das TWSR-Register irgendwie auszugeben. Serielle 
Schnittstelle, Port, Display oder sonstwie.

Was hast Du an Messmitteln? Multimeter? Oszilloskop? Aber zur Not gehts 
auch mit ner LED.

von Hmm (Gast)


Lesenswert?

>Da ich notorischer Assemblerprogrammierer bin...

OK. Ich korrigiere mich: Wenn Spess sagt, das er in einer LD, CPI, 
BRNE-Schleife hängenbleibt, glauben wir ihm das unbesehen. Grins.

von M. M. (pockined)


Lesenswert?

Ok werde versuchen mit einem Display etwas verwertbares aus dem Register 
zu bekommen :)

von M. M. (pockined)


Lesenswert?

So habe jetzt das TWSR zu meinem Erstaunen erfolgreich ausgelesen und zu 
meiner Überraschung konnte ich keine Fehler entdecken.
Hab das Register mit 5 LED's ausgelesen.
Ich poste hier noch schnell den Code mit Ergebnissen:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <util/twi.h>
4
5
void TWI_begin(void)
6
{
7
  TWBR = 0x01;
8
  TWSR = (0<<TWPS1) | (0<<TWPS0);
9
}
10
11
void TWI_send_start(void)
12
{
13
  int x = 4;
14
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
15
  while(!(TWCR & (1 << TWINT)));
16
  for(int i=7; i>=3; i--)
17
  {
18
    PORTD |= ((TWSR>>i) & 0x01) << x;    //Ergebnis: 0b0000 1xxx --> 0x08 --> A START condition has been transmitted 
19
    x--;
20
  }
21
  _delay_ms(1000);
22
  PORTD = 0x00;
23
  _delay_ms(1000);
24
}
25
26
void TWI_send_address(unsigned char add)
27
{
28
  int x = 4;
29
  TWDR = add;
30
  TWCR = (1<<TWINT) | (1<<TWEN);
31
  while(!(TWCR & (1<<TWINT)));
32
  for(int i=7; i>=3; i--)
33
  {
34
    PORTD |= ((TWSR>>i) & 0x01) << x;    //Ergebnis: 0b0010 0xxx --> 0x20 --> SLA+W has been transmitted NOT ACK has been received
35
    x--;
36
  }
37
  _delay_ms(1000);
38
  PORTD = 0x00;
39
  _delay_ms(1000);
40
}
41
42
void TWI_send_data(unsigned char dat)
43
{
44
  int x = 4;
45
  TWDR = dat;
46
  TWCR = (1<<TWINT) | (1<<TWEN);
47
  while(!(TWCR & (1<<TWINT)));
48
  for(int i=7; i>=3; i--)
49
  {
50
    PORTD |= ((TWSR>>i) & 0x01) << x;    //Ergebnis: 0b0011 0xxx  --> 0x30 --> Data byte has been transmitted NOT ACK has been received
51
    x--;
52
  }
53
  _delay_ms(1000);
54
  PORTD = 0x00;
55
  _delay_ms(1000);
56
}
57
58
void TWI_send_stop(void)
59
{
60
  TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
61
}
62
63
64
int main(void)
65
{
66
  DDRD = 0xFF;
67
  while(1)
68
  {
69
    TWI_begin();
70
    TWI_send_start();
71
    TWI_send_address(0x40);
72
    TWI_send_data(0x00);
73
    TWI_send_stop();
74
  }
75
  return 0;
76
}

Ich konnte auch kein hängen an der Schleife entdecken.
Das Programm läuft ohne Probleme durch nur Funktioniert es nicht :(
Defekt am Portexpander ist auszuschließen, das es mit dem anderen 
Programm ohne Probleme funktioniert.

von Hmm (Gast)


Lesenswert?

Nun ja. Du hast gerade mehrere Sachen auf einmal geändert, was Die 
Ursache dafür sein kann, das sich das Verhalten geändert hat.

Nimm zunächst mal die delays raus. Auch den Port brauchst Du nicht auf 
Null zu setzen. (Denke ich).

Auch diese Schleife ist unnötig kompliziert.
1
void TWI_send_data(unsigned char dat)
2
{
3
  // int x = 4;
4
  TWDR = dat;
5
  TWCR = (1<<TWINT) | (1<<TWEN);
6
  while(!(TWCR & (1<<TWINT)));
7
  // for(int i=7; i>=3; i--)
8
  //{
9
    PORTD TWSR & 0xF8;
10
  //  x--;
11
  //}
12
  //_delay_ms(1000);
13
  //PORTD = 0x00;
14
  //_delay_ms(1000);
15
}

Ändere das auch in den anderen Funktionen.

Vielleicht ist das mit den Ausgaben allein nicht hinreichend. Schau Dir 
mal die Codebeispiele im Datenblatt an. Dort wird bei den entsprechenden 
Bedingungen zu Fehlern verzweigt. Vielleicht ist es besser dort 
entsprechende Portbits zu setzen und in einen Endlos-Schleife zu gehen.

Fehlendes ACK ist natürlich ungünstig.

von Hmm (Gast)


Lesenswert?

Ooops.
1
PORTD TWSR & 0xF8;

muss natürlich heissen:
1
PORTD = TWSR & 0xF8;

von M. M. (pockined)


Lesenswert?

Problem gelöst!
Bei den Fusebits waren die CKOPT Oscillator Options aktiviert.
Hab mich wohl beim setzen verlesen :)
Trotzdem danke für euere Hilfe!

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.