Hallo Leute,
ich habe nach einem One Wire Dokumentation/Tutorial diesen Code hier für
einen ATMega portiert bzw. geschrieben. Allerdings funktioniert aus mir
unerfindlichen Gründen das Auslesen nicht.
Ich erhalte beim Auslesen statt der richtigen Temperatur nur "lauter
Einsen" (= Temperatur von 255).
Die "Bibliothek" ist eigentlich sehr minimal und von der Funktion habe
ich sie auch soweit mit der von Herrn Danegger verglichen, wobei mir
nichts die Funktion Beeinträchtigendes auffiel.
Deswegen bitte ich falls möglich um eine kurze Analyse des Code und
vielleicht den Test bei euch, falls Hardware vorhanden.
Vielen Dank, es grüßt
Alibi schrieb:> ... vielleicht den Test bei euch, falls Hardware vorhanden.
Dafür müßte man wissen, welche Hardware, insbesondere auf welchem
Prozessor das laufen soll und mit welcher Taktfrequenz der µC betrieben
wird (int/ext, Wert, Einstellungen der Fuses).
Mike schrieb:> Alibi schrieb:>> ... vielleicht den Test bei euch, falls Hardware vorhanden.>> Dafür müßte man wissen, welche Hardware, insbesondere auf welchem> Prozessor das laufen soll und mit welcher Taktfrequenz der µC betrieben> wird (int/ext, Wert, Einstellungen der Fuses).
Hallo Mike,
ich probierte die Lib erfolglos auf verschiedenen Prozessoren,
hauptsächlich aber dem ATMega8A, 16 MHz, Fuses bspw. hfuse = C9, lfuse =
FF.
Dein delay_us ist sehr ungenau, sofern es nicht inlined wird. Die
Schleife braucht für sich selbst mehrere Takte, was bei z.B. 16 Takten
pro Mikrosekunde nicht vernachlässigbar ist.
Wird der Sensor parasitär versorgt? Wenn ja, dann verhungert er beim
Messvorgang.
A. K. schrieb:> Dein delay_us ist sehr ungenau, sofern es nicht inlined wird. Die> Schleife braucht für sich selbst mehrere Takte, was bei z.B. 16 Takten> pro Mikrosekunde nicht vernachlässigbar ist.>> Wird der Sensor parasitär versorgt? Wenn ja, dann verhungert er beim> Messvorgang.
Nein, der Sensor wird über eine eigene Leitung mit Spannung versorgt.
Natürlich mit 4,7k Pullup.
Tibi schrieb:> Ist das bei in dieser Weise konstruierten Delay Funktionen immer so?
Du musst den Aufwands der Schleife im Verhältnis zum festen Delay
beachten. Bei _delay_us(10) und damit 160 Takten bei 16MHz fällt der
Aufwand der Schleife kaum noch ins Gewicht. Bei _delay_us(1) und 16
Takten kann es hingegen schon relevant sein, ob da noch einige Takte für
die Schleife hinzu kommen.
Deine Methode ist eigentlich nur dann angebracht, wenn das Delay nicht
konstant ist. Ist es hier aber durchgängig.
Ein paar Kleinigkeiten:
Ich würde empfehlen, ständig wiederholten Kram wie
PORTB &= ~(1 << T_PIN);
in Makros wie beispielsweise
OW_LOW()
zu verbuddeln. Liest sich besser.
Du hast zwar den Reset von Interrupts geschützt, der mit seiner halben
Millisekunde nicht so empfindlich ist, nicht aber den dabei sehr
empfindlichen Bitzyklus.
Spätestens wenn du die CRC kontrollieren willst, was ich nahelegen
würde, wird das mit der 16-Bit Lesefunktion etwas unhandlich.
Vor allem ist es völlig sinnlos, sich solche Schleifen für konstante
delays selber zu basteln, Die Bibliotheksfunktionen aus delay.h können
das sehr viel genauer und besser.
Die Schleifenkonstruktion braucht es nur bei nicht-konstanten delays.
Oliver
Vielen Dank, werde die Vorschläge ergänzen.
Bzgl. des CRC: Zur Berechnung muss ich ja das gesamte Scratchpad
auslesen, richtig? Sollte ich dafür einfach eine zweite längere Read
Funktion implementieren? (Theoretisch kann ich ja bei jedem Auslesen das
CRC berechnen!? D.h. nur eine Read Funktion)
Tibi schrieb:> Vielen Dank, werde die Vorschläge ergänzen.>
Noch was.
Das hier
1
...
2
unsignedinttemp=ds18b20_read();
3
if(temp<0x8000){
4
returntemp;
5
}else{
6
temp=(~temp)+1;
7
returntemp;
8
}
braucht es nicht.
Da dir der DS18B20 die 16 Bits schon im 2-er Komplement genau so
schickt, wie du es im Programm benötigst, ist ein
1
intds18b20_data(){
2
ow_reset();
3
ow_write(DS1820_SKIP_ROM);
4
ow_write(DS1820_READ_SCRATCHPAD);
5
inttemp=(int)ds18b20_read();
6
returntemp;
7
}
schon korrekt.
Dann klappts auch mit negativen Temperaturen.
In deinem Code würden negative Temperturen als positiv weiter
verarbeitet werden.
> Bzgl. des CRC: Zur Berechnung muss ich ja das gesamte Scratchpad> auslesen, richtig?
müsste man.
Kommt drauf an, wozu du das Ganze überhaupt brauchst.
Wenn es nur um einen Anzeige geht, kann man den CRC Teil auch weg
lassen. Da es im Keller keine +85°C haben wird, weißt du durch den
unsinnigen Wert auch so, dass das Ergebnis nicht korrekt sein kann.
Anders sieht es natürlich aus, wenn die Messung irgendeine Automatik mit
Werten bedient.
Nicht speziell auf diesen Fall bezogen sondern allgemein solltest du
deine Funktionsdeklarationen in C präzisieren. Wenn in C eine Funktion
keinen Übergabeparameter empfangen soll, sollte das bei der Deklaration
in den Klammern hinter dem Funktionsnamen durch ein void klargestellt
werden, z.B.
1
uint8_tfunktion(void)
Die Variante
1
uint8_tfunktion()
findet sich oft, kann aber eine Fehlerquelle sein, weil der Compiler
nicht meckert, wenn man dieser Funktion, die eigentlich keine Parameter
erhalten soll, auf einmal welche übergibt.
Tibi schrieb:> Bzgl. des CRC: Zur Berechnung muss ich ja das gesamte Scratchpad> auslesen, richtig?
Ja. Und die CRC-Berechnung funktioniert am besten byteweise. Weshalb die
Lesefunktion üblicherweise byteweise arbeitet.
aus dem Code raus.
Du brauchst sie nicht, weil du bei konstanten Werten auf die _delay_ms
bzw. _delay_us Funktionen zurückgreifen kannst. Wenn du hingegen
variable Delays in deinem Code hast, dann machst du grundsätzlich etwas
falsch.
Derartige Delay Funktionen bringen nur Ärger. In deinem Fall wird das
Timing, speziell in der delay_us bei weitem nicht stimmen.
Hier
1
unsignedcharow_reset(void)
2
{
3
unsignedcharerror;
4
cli();
5
PORTB&=~(1<<T_PIN);
6
DDRB|=(1<<T_PIN);
7
delay_us(480);
hast du nämlich vergessen, den Aufruf auszutauschen. Lösch die
Funktionen raus, dann passiert dir sowas nicht.
Karl Heinz schrieb:> ernsthaft:>> Lösch die beiden Funktionenvoid delay_ms(int ms) {> while(ms--) {> _delay_ms(1);> }> }>> void delay_us(int us)> ...>> aus dem Code raus.
Werde ich machen, aber ist denn bei _delay_us nicht die maximale delay
Zeit durch 768 / F_CPU (in MHz) begrenzt? Das heißt, ich würde mehrerer
Aufrufe aneinanderhängen müssen. Oder geht das einfacher?
Tibi schrieb:> Karl Heinz schrieb:>> ernsthaft:>>>> Lösch die beiden Funktionenvoid delay_ms(int ms) {>> while(ms--) {>> _delay_ms(1);>> }>> }>>>> void delay_us(int us)>> ...>>>> aus dem Code raus.>> Werde ich machen, aber ist denn bei _delay_us nicht die maximale delay> Zeit durch 768 / F_CPU (in MHz) begrenzt?
Das war mal. Im letzten Jahrtausend. Kurz nachdem wir von den Bäumen
runter gekommen sind.
Karl Heinz schrieb:> Tibi schrieb:> Karl Heinz schrieb:> ernsthaft:>> Lösch die beiden Funktionenvoid delay_ms(int ms) {> while(ms--) {> _delay_ms(1);> }> }>> void delay_us(int us)> ...>> aus dem Code raus.>> Werde ich machen, aber ist denn bei _delay_us nicht die maximale delay> Zeit durch 768 / F_CPU (in MHz) begrenzt?>> Das war mal. Im letzten Jahrtausend. Kurz nachdem wir von den Bäumen> runter gekommen sind.
OK.
Ich implementiere jetzt das byteweise Auslesen und CRC. Beim Verstehen
habe ich aber noch ein kleines Problem.
Auf mehreren Seiten, Threads etc. findet sich als hex Zahl 0x8C für das
Maxim Polynom
(http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html#ga37b2f691ebbd917e36e40b096f78d996)
obwohl doch 2^8+2^5+2^4+2^0 = 304 = 0x131 ist. Warum?
Das liegt an der Art und Weise, wie die Eingangsdaten bei der CRC von
Maxim durch die Schieberegister geschleust werden. Die Maxim-CRC8 ist
eine LSB-first-CRC, daher muss das Polynom gespiegelt werden und aus
0x31 wird 0x8C.
Der Wert bei x^8 - also im neunten Bit - ist bei einer CRC8 zwingend
immer 1, deshalb wird er bei der Angabe des Polynoms weggelassen.
Eine sehr anschauliche Beschreibung der Maxim-CRC8 gibt es in
http://www.maximintegrated.com/app-notes/index.mvp/id/27, eine Funktion
zur Berechnung namens _crc_ibutton_update (uint8_t __crc, uint8_t
__data) ist bereits in AVR-GCC hinterlegt. Hierzu muss man
<util/crc16.h> inkludieren.
Hallo Leute,
ich bins mal wieder. Habe jetzt meine Schaltung noch mal neu auf dem
Steckbrett und danach auf Lochraster aufgebaut und es will einfach nicht
funktionieren.
Der ATMega8A, den ich benutze, hat folgende Aufgabe:
- Temperatur vom DS18B20 holen
- Temperatur als Binärzahl auf dem USART ausgeben
Schaltung ist einfach nur Atmega an ISP Programmer (darüber auch VCC),
16 MHz Quarz und 22pF Kondis, DS18B20 im 3 Pin Modus (nicht parasite
powered), und ne LED an einem Port.
Das ganze habe ich jetzt mit einem Logic Analyzer überwacht und
festgestellt, dass sowohl der Reset-Befehl als auch die SKIP_ROM,
READ_SCRATCHPAD etc Befehle ausgegeben werden und der Temperatursensor
darauf mit der Ausgabe des Scratchpads beginnt. Bilder habe ich mal
angehängt.
Jedoch funktioniert das Ausgeben auf dem USART aus mir unerfindlichen
Gründen immer noch nicht. Ausgabe geschieht ganz einfach durch itoa und
dann handelsübliche USART Send Funktion. Einzelne Buchstaben sowie
Stringketten funktionieren tadellos, also liegt es mMn nicht am USART,
sondern wahrscheinlich irgendwie am Timing des Auslesens durch den µC.
Hat jemand ne Ahnung, was bei dem Atmega schief laufen könnte?
es grüßt
Tibi
Ganz so wirr finde ich den Wert eigentlich nicht. Wenn man bedenkt, dass
du die Bytes falschrum zusammengesetzt hast. Es also 0x01C2 sind, 28°C
entsprechend, nicht 0xC201.