[code] ;======================================================================================================= ; AM2320 (AOSONG) Temperatur+Luftfeuchte-Sensor ; "ONE-WIRE" AVR-ASM-Lese-Routine mit TimeOut+CRC. ; Hier @8Mhz RC, 1-Param-adaptierbar für andere µC-Clocks ; J. Müller, 7/2021 ;======================================================================================================= ; HINTERGRUND: ; AM2320 misst Temperatur+Luftfeuchte und bietet dazu 2 Interfaces: ; ; 1) I2C, (nicht ganz kompatibel, viel-Trallala, ..) viele Berichte "reagiert nicht/hängt", etc. ; Scheinbar nur stabil "wenn er alleine im Bus sitzt". ; ; 2) Sog. "One-Wire-Protokoll" (auch wieder sehr-abseits des bekannten Dallas-One-Wire(c)) ; bis dato ~6 Monate bei Abfragefrequenz alle 10min absturzfrei. ; ; FEATURES: ; - "ONE-WIRE" kompakte AVR-ASM-Lese-Routine @8Mhz-R/C ; andere µC-Clocks adaptierbar per 1 Parameter. ; - CRC-Prüfung + TimeOut-Check. ; - Wenig Code, kommentiert. ; ; BESCHALTUNG (NUR für diese Variante, NICHT für I2C): ; --------- ; | o o o o |---- SCL (an GND legen, so erkennt AM2320 den "OneWire-Modus") ; | o o o |---- GND ; | o o o o |---- SDA (an den µC-PortPin) ; | o o o |---- +5V ; --------- ; ; HINWEISE + FUNKTIONSWEISE DER @AM2320-DATENLEITUNG: ; - AM2320-Protokoll hat NIX mit dem "Dallas-One-Wire(c)" zu tun, irrtümlich im AM2320-DB so genannt. ; - Während dieser ASM-Routine MÜSSEN alle INT abgeschaltet sein, sonst gerät das Timing aus-dem-Tritt. ; - Erstmal ist Ruhe, µC auf Input+PullUp (Datenleitung=H), AM2320 schweigt. ; - µC zieht die Datenleitung zm Start für +1ms auf "L" (1ms-20ms nominell) ; dann schaltet µC für DEN REST DES PROTOKOLLS zurück auf auf H=Eingang. ; - DIES ist wesentlicher! Unterschied zum "DALLAS-ONE-WIRE-PROTOKOLL", ; denn der µC/Host synchronisiert beim AM2320 nicht selbst! ; - zunächst wartet µC auf 2* ~80µs "Response-Pegelwechsel" und bricht anderenfalls ab (timeOut) ; - nun werden H->L Flanken erkannt, die Zeit=Takte dazwischen ergeben Bits: "kurz=0 lang=1". ; - 40bit=5Byte werden SO eingelesen (jeweils mit timeOut und ggf. Abbruch-mit-Fehler) ; - Alle Bytes werden in AM2320_DAT abgelegt, 1-4 zudem addiert und mit Byte-5 verglichen. CR-OK bei Gleichheit. ; - Auslesen liefert stets VORHERIGES Ergebnis und triggert Neu-Messung, also nach PowerUp 1.Messung verwerfen! ; - Routine sichert KEINE Register, mit paar PUSH-POPS aber nachrüstbar. ; ; PORT: ; .EQU AM23_DDR = DDRx ; .EQU AM23_PORT = PORTx ; .EQU AM23_PIN = PINx ; .EQU AM23_BIT = x ; ; BENÖTIGTE REGISTER/SRAM: ; .DEF data = R16 Note: ; .DEF count = R17 meine Standard-Register-Namen, ; .DEF temp = R18 kann jeder beliebig umbenennen! ; .DEF crcsum = R19 ; vordefinierte ZH, ZL, YH, YL werden ebenfalls genutzt und versaut. ; ; .DSEG ; AM2320_DAT: .BYTE 5 enthält dann: [+0]HiHumi [+1]LoHumi [+2]HiTemp [+3]LoTemp [+4]originalCRC ; AM2320_ERR: .BYTE 1 ErgebnisFlag: 0=OK 1=timingError 2=crcError ; ; TIMING: ; |----------MASTER--------|--SLAVE RESPONSE--|---0---|-----1-----| ... BYTE-1: hi-Humidity (msbFirst) ; _ _ ________ __ ______ BYTE-2: lo-Humidity (msbFirst) ; | 1-10 |/| 80 | 80 | 50 |26| 50 | 70 | BYTE-3: hi-Temp (msbFirst) ; | ms |/| µs | µs | µs |µs| µs | µs | BYTE-4: lo-Temp (msbFirst) ; |______________________|/|________| |____| |____| |_ ... BYTE-5: CRC(1+2+3+4) (msbFirst) ; ; AUSWERTUNG: ; Temp+Feuchte liegen jeweils direkt in 1/10 vor, Bit.15=Vorzeichen, Beispiele: ; hiTemp loTemp hiHumi loHumi ; 00000000 01100101 = 101 = 10.1° 00000010 10010001 = 657 = 65.7% rH ; 10000000 01100101 = s101 = -10.1° ;======================================================================================================= .EQU AM23_InitLen = 6500 ;ergibt >1ms sowohl für 8/16Mhz, muss also nicht unbedingt adaptiert werden .EQU AM23_BitLen0 = 95 ;@8Mhz, Bitlängen-Grenze, MUSS für andere µC-CLK adaptiert werden: ;für>8Mhz: schrittweise erhöhen bis Empfang+CRC OK, dann noch etwas Zugabe AM23_READ: ldi temp,0 sts AM2320_ERR,temp ;=0, erstmal keinen fehler annehmen cbi AM23_PORT,AM23_BIT ;portbit=L sbi AM23_DDR,AM23_BIT ;output ldi zl,LOW(AM23_initlen) ;>1ms warten ldi zh,HIGH(AM23_initlen) sbiw zh:zl,1 brne PC-1 sbi AM23_PORT,AM23_BIT cbi AM23_DDR,AM23_BIT ;wieder auf H=input+pullup ;---- warte auf antwort (oder timeout) ldi zl,0 ;init timeoutCounter, zählt abwärts ldi zh,4 ;wert "reicht" für 8mhz-16mhz µC-clock aus ldi count,2 ;warte auf 2 H->L Flanken am23_resp: sbiw zh:zl,1 ;timeoutCounter herunterzählen. Bei 0 war es zu lange. breq am23_err ;dann also raus mit fehler lsl temp sbic AM23_PIN,AM23_BIT ;aktuellen PIN-Zustand links in pegelMemo schieben ori temp,1 andi temp,0b00000011 ;nur die letzten beiden PIN-Pegel betrachten cpi temp,0b00000010 ;vorher-H und nun-L, also H->L Flanke erkannt? brne am23_resp ;nein: dann weiter warten dec count ;sonst: HL-Flankenzähler-1 brne am23_resp ;und erneut warten bis 2 HL-Flanken erkannt wurden ;---- lese 40bits (oder timeout) ldi crcsum,0 ;CRCsumme=0, da werden die Empfangsbytes 1-4 addiert ldi count,40 ;bitCounter, zählt abwärts, 40bit=5bytes ldi yl,LOW(AM2320_DAT) ldi yh,HIGH(AM2320_DAT) ;YH:YL zeigt nun auf die empfangenen Bytes am23_rd: ldi zl,0 ;bitlenCounter=0, zählt aufwärts am23_wt: inc zl cpi zl,250 ;zu lange keine H->L flanke? brsh am23_err ;dann raus mit fehler lsl temp sbic AM23_PIN,AM23_BIT ;aktuellen PIN-Zustand links in pegelMemo schieben ori temp,1 andi temp,0b00000011 ;nur die letzten 2 pegel betrachten cpi temp,0b00000010 ;H->L flanke erkannt? brne am23_wt ;nein: weiter warten lsl data cpi zl,AM23_bitlen0 ;bitlänge klein genug? brlo PC+2 ;dann ist es eine 0 ori data,1 ;sonst eine 1 dec count ;bitcounter-1 mov zl,count andi zl,0b00000111 ;ganzes byte fertig? brne am23_nxt ;nein: normal weiter st y+,data ;ja: byte sichern cpi count,8 brlo am23_nxt ;nur bei byte 1..4 add crcsum,data ;crc=crc+byte am23_nxt: cpi count,0 ;alle 40 bits fertig? brne am23_rd ;nein: nächstes bit ;---- CRC prüfen ldi temp,2 ;"FehlerFlag=2" vorbereiten cpse crcsum,data ;summe von byte 1..4, data=immer noch byte 5(crc) sts AM2320_ERR,temp ;crc<>summe? dann halt fehler-2 setzen (crcError) rjmp am23_x ;ansonstens ist es ok und fertig am23_err: ldi temp,1 ;einsprung für timeOut-Error sts AM2320_ERR,temp ;fehler-1 setzen am23_x: ret ;======================================================================================================= ; eof ;======================================================================================================= [/code]