Forum: Mikrocontroller und Digitale Elektronik ADC per SPI abfragen


von Florian_unbekannto (Gast)


Lesenswert?

Hi,

ich weiß es gibt schon tausend SPI libraries und Beispiele jedoch habe 
ich immer den Eindruck dass die Pollen und damit den Controller 
blockieren. Die Interrupt gesteiuerten arbeiten finde ich komisch. Also 
bitte nicht gleich meckern, habe schon rumgeguckt, aber nichts passendes 
gefunden...

Ich benutze einen Xmega der soll mir einen ADC(MAX31865) auslesen. Ich 
habe das Beispiel bzw den Treiber der AVR Appnote 1309 benutzt. Die 
Interrrupt Variante.

Allerdings verstehe ich den Code so, dass nur ein Clock erzeugt wird 
wenn man selber schreibt. Bzw auch nur dann empfangen wird. Ist das 
richtig?

Das Problem, was ich habe ist, dass die Kommunikation eigentlich so 
gedacht ist:

1. Master(Xmega) zieht CS auf low, dann schreibt er ein Byte. Das 
enthält Adresse und ob es sich um einen Read oder Write Befehl handelt.

2. Jetzt kann der Slave antworten. Er schickt selbst zwei Bytes mit dem 
ADC Wert.(Wenn man z.B das Register angefragt hat) Nur ist ja jetzt der 
Clock aus. Da der Master nicht schreibt. Muss man jetzt Dummydaten 
geschicken, oder kommt der Slave dann durcheinander?

Was ich mir vorgestellt habe, dass man die zu sendenen Daten in ein 
Buffer schreibt und dann das senden startet. Dann kann der uC was 
anderes machen und sobald das flag gesetzt wird, dass das erste Byte 
gesendet ist, wird von der Interruptroutine das nächste rausgehauen. 
Somit gibt es keine Blockierung. Nur bin ich mir nicht sicher, ob ich 
dann weiter Dummydatenschicken soll...bzw muss.

Schonmal Danke!

von Wusel D. (stefanfrings_de)


Lesenswert?

>Da der Master nicht schreibt. Muss man jetzt Dummydaten
> geschicken, oder kommt der Slave dann durcheinander?

Ja, und zwar um einen Takt zu erzeugen. Denn nur der Master taktet.

Anstatt mit komplizierten Seiteneffekten von Interrupt Routinen zu 
hantieren, beschäftige Dich mal mit Zustandsautomaten. Die sind viel 
einfacher korrekt zu implementieren.

von Florian_unbekannto (Gast)


Lesenswert?

was soll ich denn jetzt mit einem zustandsautomaten? da bin ich ja nur 
am warten oder?

von Dennis (Gast)


Angehängte Dateien:

Lesenswert?

Anbei ein bisschen Code,falls du noch probleme hast.

Musst du dir noch auf deinen AVR Anpassen und dich ein wenig 
Durcharbeiten,da es nicht wirklich Sauber geschrieben ist.

Funktioniert bei mir Zumindestens,nicht schön aber klappt.

Ich habs Relativ Projektbezogen Programmiert daher auch die Auswahl des 
Kanals über die Switch Case..

Falls du schon erfahrungen mit dem MAX Gesammelt hast, kleine frage,
Ich hab das Problem das immer bei der Selben Temperatur der Fühler von 
z.b. von 20°C auf 24°C springt und danach irgendwann zurück auf 21°C .
Hast du ein Ähnliches Verhalten?

An der Umrechnung liegt es nicht, der ADC wert vom MAX Springt Selbst 
schon.

von Falk B. (falk)


Lesenswert?

@ Florian_unbekannto (Gast)

>Allerdings verstehe ich den Code so, dass nur ein Clock erzeugt wird
>wenn man selber schreibt.

Der Master.

> Bzw auch nur dann empfangen wird. Ist das  richtig?

Ja.

>1. Master(Xmega) zieht CS auf low, dann schreibt er ein Byte. Das
>enthält Adresse und ob es sich um einen Read oder Write Befehl handelt.

OK.

>2. Jetzt kann der Slave antworten. Er schickt selbst zwei Bytes mit dem
>ADC Wert.(Wenn man z.B das Register angefragt hat) Nur ist ja jetzt der
>Clock aus. Da der Master nicht schreibt. Muss man jetzt Dummydaten
>geschicken,

Ja.

>oder kommt der Slave dann durcheinander?

Nein.

>Was ich mir vorgestellt habe, dass man die zu sendenen Daten in ein
>Buffer schreibt und dann das senden startet. Dann kann der uC was
>anderes machen und sobald das flag gesetzt wird, dass das erste Byte
>gesendet ist, wird von der Interruptroutine das nächste rausgehauen.

Kann man machen. Da aber SPI oft mit hohen Taktraten arbeitet, lohnen 
sich Interrupts eher wenig. Bei XMEGA gbt es ja DMA, wahrscheinlich 
auch für SPI. Dort kann man ordentlich Leistungszuwachs erreichen.

>Somit gibt es keine Blockierung. Nur bin ich mir nicht sicher, ob ich
>dann weiter Dummydatenschicken soll...bzw muss.

Sicher.

von Florian_unbekannto (Gast)


Lesenswert?

Hi, Danke dir,
bin jetzt aber soweit, dass ich selbst einen laufenden Code 
habe.(Interrruptbasiert)
Das mit dem springen der Temperatur habe ich noch nicht beobachtet. Habe 
erst paar Messungen gemacht und das was ich hatte, war extrem konstant. 
War ich richtig überrascht.
Naja Gründe könnten sein, dass sich da Fehler einschleichen, alo Bits 
kippen. Das wäre allerdings unlogisch, wenn du mehrmals 24C hast. Das 
würde bei einer Übertragung passieren können. Und es sollte auch nicht 
wiederholbar sein.

Nochwas:

Dein Umwandlugscode sieht mir sehr abendteuerlich aus.(falls du keinen 
Hardwaremultiplizierer im Code hast)

Du solltest mal messen, wie viele Zyklen eine Umwamndlung allein kostet.
Ich habe mich lange damitbeschäftigt und habe etwas schnelles gebaut. 
Was auch vorallem noch die Temperatur als Ascii codierten String 
ausgibt. Vielleicht ist das ja was für dich.

Die Werte sind allerdings für 2k ref und pt1000. wenn du 200 und pt100 
hast, sollte es passen.
1
void deztoa( int32_t snumber, char* ascii )
2
{
3
  uint8_t i;
4
  uint32_t number;
5
  uint16_t number2;
6
  
7
  if( snumber < 0 ) {
8
    ascii[0] = '-';
9
    number = -snumber;
10
  }
11
  else {
12
    number = (uint32_t)snumber;
13
    ascii[0] = '+';
14
  }
15
16
  i = 0;
17
  while( number > 1000000 )
18
  {
19
    i++;
20
    number -= 1000000;
21
  }
22
  ascii[1] = i + '0';
23
24
  i = 0;
25
  while( number > 100000 )
26
  {
27
    i++;
28
    number -= 100000;
29
  }
30
  ascii[2] = i + '0';
31
  i = 0;
32
  while( number > 10000 )
33
  {
34
    i++;
35
    number -= 10000;
36
  }
37
  ascii[3] = i + '0';
38
  i = 0;
39
  number2 = number;
40
  while( number2 > 1000 )
41
  {
42
    i++;
43
    number2 -= 1000;
44
  }
45
  ascii[4] = i + '0';
46
47
  ascii[5] = '\0';
48
}
49
50
void generateASCIItemp(char* output, uint16_t adcValue )
51
{
52
  adcsigned = adcValue - 16384;
53
  newadc = (int32_t)adcsigned*1585;
54
  deztoa(newadc,&output[0]);
55
}

von Florian_unbekannto (Gast)


Lesenswert?

Multiplizierer im MC meinte ich natürrlich^^

von Dennis (Gast)


Lesenswert?

Läuft auf einem Mega2561,

da ich eh nur alle 0,5s eine temperatur brauche ist das nicht weiter 
schlimm wenn es bissi länger dauert, bremst mein programm jedenfalls 
nicht aus.

mich interresiert eigentlich nur der Temperaturbereich von -200 bis 
-50°C (0°C) und diesen brauch ich jenachdem relativ genau.


wenn ich mein PT100 erwärme geht es von 18 auf 20 in 0,1°C schritten
und jedesmal bei 20°C springt er auf 24°C dann wieder in 0,1 bis ca 24,8 
und dann zack auf 21°C

Am Code Liegt es nicht.
der ADC Wert Selbst Springt.

Der IC Läuft wirklich erstaunlich gut und Stabil,

das einzige Problem was ich habe ist dieser Sprung.

von Dennis (Gast)


Lesenswert?

Problem ist gelöst bei meinem Code:

die ints low high und data sind in unsigned zu ändern.

jetzt ist alles Wunderbar.

von Florian_unbekannto (Gast)


Lesenswert?

Dennis schrieb:
> Am Code Liegt es nicht.
> der ADC Wert Selbst Springt.

;-)



Dennis schrieb:
> Problem ist gelöst bei meinem Code:
>
> die ints low high und data sind in unsigned zu ändern.
>
> jetzt ist alles Wunderbar.

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.