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.
:
Bearbeitet durch User
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.
Ist das bei in dieser Weise konstruierten Delay Funktionen immer so?
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.
:
Bearbeitet durch User
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 | unsigned int temp = ds18b20_read(); |
3 | if(temp<0x8000) { |
4 | return temp; |
5 | } else{ |
6 | temp = (~temp)+1; |
7 | return temp; |
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 | int ds18b20_data() { |
2 | ow_reset(); |
3 | ow_write(DS1820_SKIP_ROM); |
4 | ow_write(DS1820_READ_SCRATCHPAD); |
5 | int temp = (int)ds18b20_read(); |
6 | return temp; |
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_t funktion(void) |
Die Variante
1 | uint8_t funktion() |
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.
So, habe mal den Code etwas überarbeitet. Kann ihn leider erst nächstes WE in der Schaltung testen, ist er denn so theoretisch funktionsfähig? :D
ernsthaft: Lösch die beiden Funktionen
1 | void delay_ms(int ms) { |
2 | while(ms--) { |
3 | _delay_ms(1); |
4 | }
|
5 | }
|
6 | |
7 | void delay_us(int us) |
8 | ...
|
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 | unsigned char ow_reset(void) |
2 | {
|
3 | unsigned char error; |
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.
:
Bearbeitet durch User
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
P.S.: Ausgegeben wurde am USART beim hochgeladenen Scratchpad folgende Bitfolge: 1100001000000001 Also einfach Wirrwarr
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.
:
Bearbeitet durch User
... Funktioniert! Danke ;) Manchmal sieht man halt den Wald vor lauter ...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.