Datum:
Hallo zusammen, nachdem ich bisher immer gut aus dem (hier) vorhandenen Know How meine Probleme lösen konnte, ist es jetzt so weit, ich finde den Fehler nicht und brauche mal 4 bis (x*2) Augen ;-) Mein Problem ist, das ich die 1wire Kommunikation mit dem DS18B20 trotz zahlreicher libs nicht hinbekomme. Aus Verzweiflung habe ich dann mir auch nochmal die Appnotes von Dallas durchgelesen und versucht umzusetzen. Auch das ohne Erfolg. Der 'Witz' ist, das es mit BASCOM sofort geklappt hat. Anbei mal der aktuelle Stand, vielleicht kann mir jemand die Tomaten von den Augen reißen. 1000 Dank Oliver
#ifndef F_CPU #define F_CPU 16000000 #endif #include <avr/io.h> #include <avr/interrupt.h> #include <avr/eeprom.h> #include <util/delay.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include "uart.h" #define BAUD 19200 #define READ_ROM 0x33 uint8_t ow_buffer[10]; char msg[10]; #define T_PORT PORTA #define T_DDR DDRA #define T_PIN PINA #define T_DQ PA1 #define T_INPUT T_DDR&=~(1<<T_DQ) #define T_OUTPUT T_DDR|=(1<<T_DQ) #define T_LOW T_PORT&=~(1<<T_DQ) #define T_HIGH T_PORT|=(1<<T_DQ) inline unsigned char owReset() { uint8_t r = 0; T_OUTPUT; T_LOW; _delay_us(480); // 480us warten T_INPUT; // als eingang setzen _delay_us(70); // auch warten, das der sensor den bus wieder auf low zieht r = (bit_is_clear(T_PIN, T_DQ) ? 1 : 0); // bit clear also muss der DS18B20 den pin auf low gezogen haben T_OUTPUT; // als ausgang setzen _delay_us(410); return(r); } inline void owWriteBit(uint8_t bit_value) { cli(); T_OUTPUT; if (bit_value) // Write 1 { T_LOW; // jetzt auf low ziehen _delay_us(6); // 6 us auf Low lassen T_INPUT; // als eingang setzen _delay_us(64); // 64us warten } else // Write 0 { _delay_us(60); // 60us auf Low lassen T_INPUT; // als eingang setzen _delay_us(10); } sei(); } void owWriteByte(unsigned char byte_value) { uint8_t i = 8; while(i--) { owWriteBit(byte_value & 0x01); // das rechts stehende Bit senden byte_value = byte_value >> 1; // um 1 Stelle nach rechts schieben } } inline uint8_t owReadBit(void) { uint8_t r=0; cli(); T_OUTPUT; T_LOW; // jetzt auf low ziehen _delay_us(6); // 6 us warten T_INPUT; // als eingang setzen _delay_us(9); // warten und dann messen //r = (bit_is_set(T_PIN, T_DQ) ? 1 : 0); if (T_PIN&(1<<T_DQ)) r = 1; _delay_us(55); sei(); return (r); } uint8_t owReadByte(void) { uint8_t i = 8; uint8_t data = 0; while(i--) { data >>= 1; //bits schieben if (owReadBit()) data |= 0x80; // Bit 7 setzen } return(data); } void owReadROMCode(void) { uint8_t i; owReset(); owWriteByte(READ_ROM); for (i = 0; i < 8; i++) ow_buffer[i] = owReadByte(); // nun steht der ROM-Code in ow_buffer uart_putc(13); for (i = 0; i < 8; i++) // ROM-Code ausgeben { uart_puts(utoa(ow_buffer[i], msg, 16)); uart_putc(' '); } } int main( void ) { uint8_t i = 0; uint8_t tmp = 0; uint16_t T = 0; uint16_t T1 = 0; uart_init((UART_BAUD_SELECT((BAUD),F_CPU))); sei(); uart_puts_P( "\rVersuch eines 1 Wire Protokolls\r" ); uart_puts_P( "-------------------------------------------\r" ); while(1) { owReset(); owWriteByte(0xCC); owWriteByte(0x44); _delay_ms(1000); owWriteByte(0xCC); owWriteByte(0xBE); for (i = 0; i < 9; i++) ow_buffer[i] = owReadByte(); for (i = 0; i < 9; i++) { uart_puts(utoa(ow_buffer[i], msg, 16)); uart_putc(' '); } uart_putc(13); } } |
und in BASCOM
// BASCOM $regfile = "m16def.dat" $crystal = 16000000 $baud = 38400 Config 1wire = Porta.1 Dim Daten(9) As Byte Dim I As Byte Dim Tmp As Byte Dim Crc As Byte Dim T As Integer Dim T1 As Integer Lblmain: 1wreset 1wwrite &H33 Daten(1) = 1wread(8) For I = 1 To 8n Print Hex(daten(i)); Print " "; Next 1wreset 1wwrite &HCC 1wwrite &H44 Waitms 1000 1wreset 1wwrite &HCC 1wwrite &HBE Daten(1) = 1wread(9) Tmp = Daten(1) And 1 If Tmp = 1 Then Decr Daten(1) T = Makeint(daten(1) , Daten(2)) T = T * 50 T = T - 25 T1 = Daten(8) - Daten(7) T1 = T1 * 100 T1 = T1 / Daten(8) T = T + T1 T = T / 10 Print "Temp := "; Print T Goto Lblmain |
Datum:
Nach dem 1s Delay fehlt offensichtlich der 1wreset vor der Aufforderung an den Sensor die Daten zu senden.
Datum:
Super schnelle Antwort, in der Sache richtig, lößt aber leider mein Problem nicht. Habe den Reset eingebaut bekomme aber immernoch nur ff ff ff ff ff ff ..... Trotzdem vielen Dank!
Datum:
Angehängte Dateien:Deine Resetfunktion ist buggy, der Rest funktioniert. Im Anhang ist mein Debugcode mit ein paar Zeitmessungen. Achtung: ich musste den 1-Wirepin auf PD2 legen, weil ich mit einem Atmega8 (@ 12 MHz) getestet habe. Und ich habe 9600 Baud benutzt. Vor dem Testen bitte eigene Quellen backuppen. Die Temperaturberechnung ist quick&dirty zur Plausibilitätsabschätzung :) Wie es genau geht hast du ja im BASCOM Code.
Datum:
Ähm noch drei Kommentare zu meiner Debugfunktion
1/ Die ausgegebenen time_reset_... "Zeiten" sind Schätzeisen. Durch den
Schleifenoverhead sind die tatsächlichen Delays länger. Die Taktrate hat
da einen großen Einfluß, Aufpassen, wenn es zu niedrigen Taktraten geht.
2/ Die Schleifen sollten besser so geschrieben werden, um den
Seiteneffekt -- in der Bedingungsabfrage zu vermeiden:
timeout = xxx;
while ( timeout && <bedingung2> )
{
_delay_us(1);
timeout--;
}
3/ Bei der Berechnung des 480 µs Enddelays kann (und tut) ein uint8_t
Overflow stattfinden (bei meinem Sensor: 480-1-18-67). An der Stelle
also einen uint16_t für das Ergebnis einsetzen.
Datum:
Hallo Stefen, vielen Dank für Deine umfangreiche Analyse! Da hab ich wohl beim Reset was falsch verstanden. Asche über mein Haupt. Werde ich heute nach der Arbeit mal ausprobieren, und mich wieder melden. Oliver
Datum:
Hallo Stefan, hat geklappt! Also nochmal vielen Dank für Deine Hilfe. Oliver