Guten Morgen,
hoffe mir kann jemand helfen.
Ich habe eine Basisplatine auf der ein ATMEGA128A mit 16MHz verbaut ist
die mit der RTC DS1307 über I2C kommuniziert.
Eine zweite Platine, die über einen ATMEGA32A besitzt wird über SPI an
die Basisplatine angeschlossen und soll das eingeleste Datum und Uhrzeit
anzeigen.
Soweit so gut. Eine Anzeige der Uhrzeit etc bekomme ich hin nur habe ich
das Problem, dass manchmal einfach Zahlen wegfallen.
Ich habe versucht mir den heutigen Tag ausgeben zu lassen und zwar 8415.
Manchmal erscheint aber nur 840 dann wieder 8415 dann wieder 840 etc.
Dann habe ich versucht mir mal das alles mit 8:4:15 7:00:01 anzeigen zu
lassen. Manschmal erscheint vorne eine null und alles wird nach links
geschoben und somit verschwindet die 8.
(Hoffe ich konnte mein Problem einigermaßen erklären)
Nun ist die Frage ob es sein kann das ich beim auslesen der RTC müll
bekomme oder ich bei der Konvertierung in einen String einen fehler
mache oder sogar beim übertragen mich vertute.
Zum Quellcode:
1
#include"spi_master_slave.h"
2
3
volatileunsignedchardata;
4
5
// SPI Transmission/reception complete ISR
6
ISR(SPI_STC_vect)
7
{
8
inti;
9
// SWITCH_LED3;
10
11
if(status==0)// Befehl empfangen um Antwort zurück zu senden
12
{
13
data=SPDR;// Ankommende Daten über SPI in Buffer Schreiben
spi_send(string[i],cs);// Senden der Zeichenketten und Antwort in antwort speichern
15
_delay_ms(1);// Zeitverzögerung wird benötigt da sonst das Antworten vom Slave nicht funktioniert
16
}
17
_delay_ms(2);
18
19
// Antwort empfangen
20
for(i=0;i<=MAXANTEEORTLAENGE;i++)
21
{
22
if(i==0)// Erste Byte vernachlässigen
23
{
24
spi_send('0',cs);// Dummybyte senden
25
_delay_ms(1);// Zeitverzögerung wird benötigt da sonst das Antworten vom Slave nicht funktioniert
26
}
27
else
28
{
29
if(i==MAXANTEEORTLAENGE)
30
{
31
*antwort=spi_send('\n',cs);// Senden der Zeichenketten und Antwort in antwort speichern
32
_delay_ms(1);// Zeitverzögerung wird benötigt da sonst das Antworten vom Slave nicht funktioniert
33
}
34
else
35
{
36
*antwort=spi_send('0',cs);// Senden der Zeichenketten und Antwort in antwort speichern
37
antwort++;
38
_delay_ms(1);// Zeitverzögerung wird benötigt da sonst das Antworten vom Slave nicht funktioniert
39
}
40
}
41
}
42
}
43
44
// Senden von Daten über SPI
45
// Beispiel: spi_data = spi_send ('T', PIN_SPI_CS3); // senden von einem Byte auf der SPI-Schnittstelle
46
charspi_send(unsignedchardata,intcs)
47
{
48
PORT_SPI&=~(1<<cs);// SS am Slave Low --> Beginn der Übertragung
49
SPDR=data;// Daten ins Buffer-Register laden und senden mittels Interrupt
50
_delay_us(10);
51
while(!(SPSR&(1<<SPIF)));
52
_delay_us(10);
53
//_delay_ms(1); // Zeitverzögerung wird benötigt da sonst das Antworten vom Slave nicht funktioniert
54
PORT_SPI|=(1<<cs);// SS High --> Ende der Übertragung
55
return(SPDR);// Return received data
56
}
57
58
// Initialize SPI Master Device
59
voidspi_init_master(void)
60
{
61
DDR_SPI|=(1<<PIN_SPI_MOSI)|(1<<PIN_SPI_SCK)|(1<<PIN_SPI_CS1B)|(1<<PIN_SPI_CS3);// MOSI und SCK als Ausgang definieren
62
DDR_SPI&=~(1<<PIN_SPI_MISO);// MISO als Eingang definieren
63
PORT_SPI|=(1<<PIN_SPI_CS3);// SS High
64
65
//SPCR = (1<<MSTR) | (1<<SPIE) | (1<<SPE); // Set as Master, Enable Interrupts, Enable SPI
66
SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR1);// Set as Master, Enable Interrupts, Enable SPI
67
SPSR|=(0<<SPIF);// SPIF zum Start löschen
68
}
aufruf der daten
1
chartmp[22];
2
spi_send_string("TIME\n",&tmp,PIN_SPI_CS3);// Senden von Time\n an Haupteinheit
3
display_write(tmp,0,5);
Denke mal das das alles Relevante ist was benötigt wird um den Fehler zu
finden :-) Falls noch was fehlen sollte sofort bescheid sagen dann
reiche ich es einfach nach.
Dankeschön für eure Hilfe :-)
Ach ja nochwas
als ich versucht habe den String empfangenen String zu zerteilen
(Trennung der einzelnen Zahlen habe ich mit einem ":" gemacht, denke ich
mal das ich auch ein Fehler mache vielleicht könnte ja jemand auch da
drüber schaue4n
1
voidreadsystemtime()
2
{
3
charsystemtimebuffer[50];
4
char*psystemtimetoken[50];
5
// Systemzeit von Basisplatine abfragen und in Struktur schreiben
6
spi_send_string("TIME\n",&systemtimebuffer,PIN_SPI_CS3);// Senden von Time\n an Haupteinheit
7
display_write(systemtimebuffer,0,5);
8
9
psystemtimetoken[0]=strtok(systemtimebuffer,":");
10
while(i<=50)
11
{
12
i++;
13
psystemtimetoken[i]=strtok(NULL,":");
14
}
15
i=0;
16
systemtime.datum.day=atoi(psystemtimetoken[1]);// Tag
ich habe vorhin in der spi_master_slave.c die for-Schleifenbedingung
geändert und nun verschwinden keine Zahlen mehr doch meine Anzeige zeigt
nun 08:4:15:8:0:36 woher kommt denn die erste null? kann es mir leidr
nicht erklären :-(
Mir ist eine andere Sache aufgefallen, da ich auch gerade mit DS1307
arbeite.
Nach dem Senden der Adresse zum Lesen der Uhr sendest du eine
Stop-Condition, und danach eine Repeated Start Condition.
Das Datenblatt von Maxim sagt auf Seite 13 nichts von der
Stop-Condition. Vielleicht kommt die Uhr durcheinander? Kann es jetzt
nicht testen, da nicht am Ort des Geschehens.
hmm wenn ich ehrlich bin glaube ich so langsam das bei der Übertragung
mit SPI etwas schief läuft!
Wenn ich von meiner Displayplatine ein TEMPA\n sende erwate ich ja
eigentlich als Antwort A:WertB:WertC:WertD:Wert (Wert = errechnete
Temperatur)
Aber als Antwort erscheint auf dem Display 0:WertB:WertC:WertD:Wert
Auf der Basisplatine Baue ich ja die Antwort zusammen. Da dürfte
einglich kein Fehler sein oder habe ich da was übersehen?
Marcel P schrieb:> Mir ist eine andere Sache aufgefallen, da ich auch gerade mit> DS1307> arbeite.>> Nach dem Senden der Adresse zum Lesen der Uhr sendest du eine> Stop-Condition, und danach eine Repeated Start Condition.> Das Datenblatt von Maxim sagt auf Seite 13 nichts von der> Stop-Condition. Vielleicht kommt die Uhr durcheinander? Kann es jetzt> nicht testen, da nicht am Ort des Geschehens.
Habe ich ausprobiert und das Ergebnis ist das Gleiche bzw. macht keinen
Unterschied... Schade wäre ja zu schön gewesen :-)
Antwortet der Slave vielleicht nicht rechtzeitig? (Gesperrte Interrupts,
weil du etwas anderes bevorzugt behandeln willst?)
Ist vorher das Interrupt-Flag korrekt gelöscht, sodass nicht gleich die
Warteschleife übersprungen wird?
In dem Fall beinhaltet SPDR nämlich noch '0', wie in spi_send_string()
als Dummy gesendet wird:
GC schrieb:
1
voidspi_send_string(...
2
[...]
3
if(i==MAXANTEEORTLAENGE-1)
4
{
5
*antwort=spi_send('\n',cs);
6
_delay_ms(1);
7
}
8
else
9
{
10
*antwort=spi_send('0',cs);
11
antwort++;
12
_delay_ms(1);
13
}
14
}
15
}
16
}
Sofern ich jetzt nicht verkehrt denke und den Ablauf richtig verfolgt
habe. :D
fehlt auf jeden Fall noch die 0-Terminierung des Strings, ansonsten ist
es Essig mit der Verwendung der str... Funktionen.
1
spi_data_buf[spi_data_pos++]=data;
2
if(data=='\n')
3
{
4
spi_data_buf[spi_data_pos]='\0';// <-----
5
spi_data_pos=0;
6
if(strcmp(spi_data_buf,"TIME\n")==0)
den \n würde ich auch nicht mit abspeichern. Wozu? Es gibt keinen Grund
dazu. Dadurch werden nur die Vergleichsstrings bei den strcmp läner und
du darfst dort auch in Zukunft den \n nicht vergessen.
nicht sehr viel zu sein.
PS: die ganzen %s, in denen du jweils einen ":" reinschiebst, kannst du
dir auch sparen. Fixe Zeichen schreibt man gleich in den Format String.
Dann kann man sie nicht vergessen und die Argumentlisten werden kürzer.
1
sprintf(spi_data_buf,"%d:%d:%d:%d ........
so dermassen lange Strings sind zwar nicht verboten. Ich würde sie
trotzdem nicht benutzen. Da soll die Gegenstelle ruhig ein paar mal nach
spezifischen Daten fragen. Die kann man ja in thematische Gruppen
zusammenfassen.
So dermassen lange printf sind in der Wartung sehr fehleranfällig.
Und noch ein PS:
Man kann in C einen sehr langen String in mehrere Teile aufteilen!
Anstatt
1
"Hallo World"
darf man auch den String in mehreren Teilen schreiben
1
"Hallo "
2
"World"
Beachte: Da ist kein , zwischen den Teilstrings. In so einem Fall ist
der Compiler verpflichtet die einzelnen Teilstrings zu einem kompletten
String zusammenzusetzen. Die beiden Beispiele sind also völlig
identisch.
Der Vorteil für dich: Du kannst deinen elends langen Formatstring in
Teile aufbrechen, damit du nicht den Überblick verlierst, welches %d zu
welchem Argument gehört.
spi_send(string[i],cs);// Senden der Zeichenketten und Antwort in antwort speichern
13
_delay_ms(1);// Zeitverzögerung wird benötigt da sonst das Antworten vom Slave nicht funktioniert
14
}
15
_delay_ms(2);
16
17
// Antwort empfangen
18
for(i=0;i<=MAXANTEEORTLAENGE;i++)
19
{
sind keine gute Idee. Bei Übertragungen, speziell bei Textübertragungen
willst du nicht eine fixe Anzahl an Bytes hin und her schicken.
Sondern: Der eine fordert Daten an und beendet seine Anforderung zb mit
einem \n. Der andere antwortet mit den Daten die er hat und beendet die
Antwort ebenfalls zb mit einem \n. Der jeweilige Empfangspart muss nur
darauf achten, dass er seinen Buffer nicht überläuft. Aber mit so
Annahmen, dass man so und so viele Zeichen zurück bekommen würde, tut
man sich keinen Gefallen. Das ist alles ziemlich schlecht erweiterbar.
Wenn die Datenmenge zunimmt, musst du dann an allen Ecken und Enden
nachbessern. Viel einfacher ist es, wenn die Kommunikation so
funktioniert, dass jeder einfach das sendet was er hat und hinten nach
kommt noch ein Abschlusszeichen, das der Gegenstelle signalisiert "Das
wars".
Und ja. Dein Monster-sprintf könnte schon etwas dauern. D.h. du solltest
der Gegenstelle auch nach der Anforderung die Zeit geben, den
durchzuführen. Oder eben nicht eine einzige Anfrage nach 'Allem'
stellen, sondern einfach mehrere Anfragen für Themenkreise. Dann werden
auch die Antworten kürzer und du läufst bei Erweiterungen wenigr Gefahr,
irgendwo einen Buffer zu überlaufen.
// Systemzeit von Basisplatine abfragen und in Struktur schreiben
6
spi_send_string("TIME\n",&systemtimebuffer,PIN_SPI_CS3);// Senden von Time\n an Hauptei
Die Funktion spi_send_string sollte die Buffergröße beim Aufruf
mitbekommen und nicht davon ausgehen, dass die immer 50 ist. Spart
Speicher. Denn eine Uhrzeit wird wohl kaum 50 Zeichen lang sein.
Das hier
1
psystemtimetoken[0]=strtok(systemtimebuffer,":");
2
while(i<=50)
3
{
4
i++;
5
psystemtimetoken[i]=strtok(NULL,":");
6
}
7
i=0;
8
systemtime.datum.day=atoi(psystemtimetoken[1]);// Tag
ist wieder extrem gefährlich. Du gehst davon aus, dass in der Antwort
schon so viele ':' enthalten sein werden, dass du alle Teile extrahieren
kannst.
machs doch nicht so kompliziert mit dem Pointer-Array. Wenn du das ein
wenig lesbarer machen willst, dann führ dir zb eine Funktion ein
1
uint8_tparseInt()
2
{
3
char*ptr;
4
uint8_tresult=0xFF;
5
6
ptr=strtok(NULL,":");
7
if(ptr)
8
result=atoi(ptr);
9
10
returnresult;
11
}
damit schreibt sich dann deine Zeitroutine so
1
voidreadsystemtime()
2
{
3
charsystemtimebuffer[50];
4
5
// Systemzeit von Basisplatine abfragen und in Struktur schreiben
strtok(systemtimebuffer,":");// erster Wert ist dummy
9
systemtime.datum.day=parseInt();
10
systemtime.datum.month=parseInt();
11
systemtime.datum.year=parseInt();
12
systemtime.time.hour=parseInt();
13
systemtime.time.minute=parseInt();
14
systemtime.time.second=parseInt();
15
systemtime.zeitzone=parseInt();
16
}
Wenn du je in der Ausgabe ein 0xFF (bzw. 255) siehst, dann weisst du,
dass in der Antwort was nicht gestimmt hat. Der Code ruiniert aber sonst
nichts, weil er atoi nicht mit einem NULL Pointer aufruft.
Dafür kannst du dir die Kommentare hier
sparen. Da steht 2 mal das gleiche. Die Zuweisung geht an eine Variable
die 'month' heisst. Da brauchst du nicht dazuschreiben, dass es sich um
das Monat handelt. Das kann jeder der Lesen kann auch so sehen.
Genauso wie auch klar ist, was eine Funktion spi_send_string machen
wird. Das brauchst du nicht kommentieren. Aus
ist für jeden klar ersichtlich ablesbar, was hier passiert. Wenn du
unbedingt noch ausdrücken willst, dass hier ein Kommando gesendet wird,
dann nenn die Funktion nicht spi_send_string sondern spi_send_command.
Generell gibt man immer der Variangte den Vorzug, bei dem man das was
man ausdrücken möchte, direkt im Code ausdrückt und nicht in einem
Kommentar.
Wou wieviele Antworten....
Danke erstmals im Vorraus für euer ganzen Hilfen....
Werde die Anmerkungen sofort umsetzen um meinen Code ausfühlrlicher zu
machen... War einiges dabei was ich so garnicht gesehen hatte :-)
Das Problem mit der 0, also das ich eine Anwort bekomme wie
0:WertB:WertC:WertD:Wert habe ich gelöst indem ich beim SPI-Master
einfach ein wenig länger warte damit mein Slave genug Zeit hat die
Antwort vorzubereiten.Scheint mir merkwürdig zu sein aber es
funktioniert!