Hallo,
ich stehe vor einem Problem mit einem Temperatursensor MAX31855 und
einem Sekunden-Timer.
Mein Code funktioniert ohne Timer problemlos nutze ich aber den Timer1
oder andere Timer die einen Interrupt auslösen, kommt entweder keine
Temperaturausgabe oder aber Chaos.
Habe es auch schon mit SREG probiert, da bekam ich zumindest Daten
angezeigt die aber unrealistisch erscheinen(bspw. 16xxx).
Zur ersten "nutzlosen" while-Abfrage, ohne diese Abfrage wäre das erste
Byte mit dem Wert 255 "gefüllt".
Seltsamerweise funktioniert die gleiche Funktion für den Internen
Temperatursensor problemlos.
Wie du siehst sind TABs zur Einrückung ungünstig im Forum.
Da fehlt mal wieder die wichtigste Hälfte, wie string3 und i.
Was ist denn das für eine Stilblüte:
float Temperatur=0;
Temperatur=Temperatur(Temperatur);
Das soll der Compiler kommentarlos gefressen haben?
Hab das ganze nur gekürzt, da ich auch noch mehr auslese auser den
SPI-Bus und Die UART-Ausgabe.
Die anderen Programmteile werden aber für den Test nicht
genutzt(auskommentiert).
Ja, die Namen der Funktion und der Varable sind eigentlich länger. Der
Compiler macht da keine Probleme. Hier noch der Rest vom Code.
#define F_CPU 7372800UL
#include "UART.h"
#include "SPI_Thermoelement.h"
#include <stdlib.h>
#include <avr/interrupt.h>
#include <avr/io.h>
volatile int zeit=0;
volatile int i=0;
void main()
{
float Temperatur=0;
const char* string3[8];
...
}
A.K. hat nichgt so ganz unrecht.
Eine ordentliche und vor allen Dingen konsistente Einrückung ist oft
schon mal die halbe Miete. Auch für Dich!
Es geht nicht darum, dass nicht alles am linken Rand klebt und der Code
ein wenig aufgelockerter erscheint, sondern es geht darum, das man
erkennen kann, welche Codeteile von anderen abhängig sind (welche Teile
zb im then Teil eines if abgearbeitet werden), und welche auf gleicher
Logikstufe stehen.
Ich mach das mal für einen Teil und hinten nach dann eine Frage an dich
1
for(;;)
2
{
3
cli();
4
5
if(i==1)
6
{
7
Temperatur=Temperatur(Temperatur);
8
dtostrf(Temperatur,4,2,string3);
9
UART0_String_SEND(string3);
10
11
sei();
12
13
i=0;
14
}
15
}
16
}
wenn i nicht gleich 1 ist, wird in der Schleife als erstes trotzdem der
cli gemacht. Wie genau stellst du dir dann vor, dass dann jemals ein
Interrupt dir das i auf 1 stellen kann?
1
floatTemperatur(floatTemp)
2
{
3
volatileuint8_tDaten0;
4
volatileuint8_tDaten1;
5
6
PORTB&=~(1<<PB0);
7
SPDR=0x00;
8
while(!(SPSR&(1<<SPIF)))
9
;
10
SPDR;
11
SPSR|=(0<<SPIF);
12
_delay_us(2);
13
SPDR=0x00;
14
while(!(SPSR&(1<<SPIF)))
15
;
16
Daten0=SPDR;
17
SPSR|=(0<<SPIF);
18
_delay_us(2);
19
SPDR=0x00;
20
while(!(SPSR&(1<<SPIF)))
21
;
22
Daten1=SPDR;
23
SPSR|=(0<<SPIF);
24
PORTB|=(1<<PB0);
Schon mal was von Funktionen gehört? Ich hab mir sagen lassen, dass die
Übersicht in einen Code bringen können, indem man immer gleiche Teile in
eine Funktion auslagert und dadurch der Code an der aufrufenden Stelle
vereinfacht wird.
Ts ts
SPSR |=(0<<SPIF);
so löscht man doch nicht ein Bit.
Abgesehen davon ist das ein Interrupt Bit, das wird höchst
wahrscheinlich dadurch gelöscht (Datenblatt nachsehen), dass man eine 1
an die entsprechende Bitposition einschreibt. So gesehen funktioniert
deine Version - aber nur zufällig, weil du Glück hattest.
Karl Heinz Buchegger schrieb:> Ts ts> SPSR |=(0<<SPIF);> so löscht man doch nicht ein Bit.> Abgesehen davon ist das ein Interrupt Bit, das wird höchst> wahrscheinlich dadurch gelöscht (Datenblatt nachsehen), dass man eine 1> an die entsprechende Bitposition einschreibt. So gesehen funktioniert> deine Version - aber nur zufällig, weil du Glück hattest.
Edit:
Gerade im Datenblatt nachgesehen.
Das SPIF Flag löscht sich in deinem Code ganz von alleine, einfach nur
durch Zugriff auf SPDR. D.h. überhaupt keine Aktion notwendig.
Mein Programm ist nur so zerpflügt, weil ich meinen Code ein dutzend mal
umgeschrieben habe. Naja jetzt läufts aber :) Hatte den Code nicht in
Funktionen gepackt, weil das ganze erstmal so laufen sollte.
Nachdem ich die Empfangsfunktion in eine Funktion gesetzt hab, lief es
einwandfrei. Jetzt muss ich nur noch Zweierkomplement einsetzten und
schon läuft alles.
Danke für die Ratschläge, manche Fehler sind mir aus Frust schon nicht
mehr aufgefallen...
uint8_t spi_receive() {
SPDR = 0x00;
while (!(SPSR & (1<<SPIF)))
;
return SPDR;
}
Was mir hier mal wieder auffällt, ist das Fehlen von Kommentaren.
Spätestens in einem halben Jahr hat man vergessen, was die Funktion
Temperatur macht. Dann muss man sein eigenes Programm entschlüsseln.
Warum nicht einfach mal hinschreiben, was das Setzen der Bytes bewirkt,
und worauf die while-Schleifen warten.
Patrick .... schrieb:> umgeschrieben habe. Naja jetzt läufts aber :) Hatte den Code nicht in> Funktionen gepackt, weil das ganze erstmal so laufen sollte.
Und wie man sieht funktioniert das nicht.
Die Einstellung "zuerst bring ichs zum Laufen und dann kümmere ich mich
um die Schönheit" ist ein Trugschluss, wie die alten Hasen wissen.
Codeformatierung, Codestrukturierung SIND essentielle Werkzeuge um Code
verständlich zu machen und um Logikfehler sehen zu können, die aus
Strukturfehlern entstehen. Und das gilt auch, bzw insbesondere, in der
Entwicklungszeit eines Programms. Von Anfang an!
Eine Frage hab ich da noch, mit itoa oder utoa kann man integer bzw.
unsigned integer in strings konvertieren. Diese haben aber nie eine fest
definierte Länge. Ich hab es jetzt erstmal mit dtostrf probiert. Das
funktioniert auch, nur bekomme ich eine Warnung dass dtostrf nicht für
Integer geeignet ist. Gibt es eine saubere Möglichkeit eine feste Länge
einzustellen? Ich will den String später mit einer Software auslesen und
da ist eine feste Stringlänge vorteilhafter?
Es gibt da mehrere Möglichkeiten.
* itua bzw utoa benutzen und dann einfach vorher entsprechend
viele Leerzeichen einfügen bzw. ausgeben um die gewünschte
Länge zu erreichen
* sprintf kann man im Formatstring die Anweisung geben, eine fixe
Feldbreite einzuhalten
* eine eigene Formatierfunktion schreiben.
Am schnellsten benutzt ist die mittlere Variante - sprintf.
Hat man den Speicher und spielt auch die Laufzeit keine Rolle, dann ist
das die einfachste Variante.
Etwas mehr Überlegung erfordert die 3. Variante.
Die Sache ist die: wenn man mal Fehlerbehandlung beiseite lässt, dann
ist die die technisch bei weitem einfachste und schnellste. Denn
eigentlich muss man Aufwand treiben um führende 0-en bzw. Leerzeichen zu
unterdrücken. Mit einer eigenenn Ausgaberoutine vermeidet man diesen
Aufwand und hat als Nebeneffekt eine Ausgaberoutine, die man auf einem
µC mit zb einem LCD gut gebrauchen kann.
Die 1. Variante scheint die am logischten zu sein. Sie hat nur einen
Haken: itoa bzw. utoa treiben Aufwand um die Leerzeichen loszuwerden und
man selbst treibt hinten nach wieder Aufwand um sie wieder
reinzubringen.
> Ich will den String später mit einer Software auslesen> und da ist eine feste Stringlänge vorteilhafter?
Nicht wirklich. Ein Übertragungsformat bzw. Fileformat welches bei
Zahlen auf feste Feldbreiten setzt bringt nichts. Genausowenig wie eine
Eingafunktion die nicht bei Zahlen mit variablen Zeichenzahlen klar
kommt.