AM2320 - temp / humidty

bobladell

New Member
Hi All - done a forum search and seems no one has done anything with the AOSONG AM2320 I2C based temp and humidity sensor.
That right - or have I missed something ?
Thanks
Bob
 

hippy

Technical Support
Staff member
I couldn't find anyone having used an AM2320 but it looks like it could be possible to use it with a PICAXE. There are some mentions in the datasheet about using a custom I2C mode and specific timing requirements but it should be possible to make it work, even if bit-banged I2C is required. The proof of that would however be in the doing of it.

If you have the device, or have experience of using it with something other than a PICAXE, have some understanding of I2C, it's probably worth trying, but also worth considering what else may be available which may be easier to use.

This is a good reference for comparing various humidity sensors -

http://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_many.html

Note the comments about the AM3230 being intermittently unreliable above 50%RH. That may not be a problem if one can re-read the data when it's so obviously wrong ($00/$FF). It may also be an issue related to the timing and needing to wake it from sleep which the datasheet mentions, so may not be faulty operation.
 

bobladell

New Member
Hi Hippy - many thanks for confirming. I have a couple of AM2320 and am trying to get them working on an 18M2+ sitting on an AXE110. They looked dead easy to get running under PICAXE but proving hard work.

I also have an Arduino UNO and have the AM2320 working on that, so the sensors themselves are good, and provide nice stable T and RH figures so would be nice to use on my PICAXE based environmental monitor project.

I've also tried the PICAXE i2c Tutorial and the stuck i2c bus routine from one of the i2c PICAXE references - doesn't seem to be that.

i2c - should be easy..............

Code - AXE110 standard Wizard generated modded just to use a) the DS18B20 to show it's running (it was screwed into the board so why not), and b) the on board RTC, also why not for test, and to show me that the I2C bus is working and that I'm using the hi2c instructions correctly. I'm not working out the time - just getting some numbers back for debug.

main:
gosub read_sensors ; read the sensors
pause 1000
; gosub save_data ; save sensor readings in eeprom
; gosub inc_address ; update address to save to
; gosub wait_time ; wait until ready for next reading
goto main ; take next reading

; ****************************
; ***** Read sensor data *****
; ****************************

read_sensors:
high B.3 ; flash green LED
readtemp C.7, data7 ; read Temperature - DS18B20 - one wire
low B.3 ; end of green LED flash
;debug data7
sertxd ("DS Temp = ",#data7,CR,LF)

read_time:
hi2csetup i2cmaster, %11010000, i2cslow, i2cbyte ;Addr $D0
hi2cin 0,(secs,mins,hours,temp_byte,day,month)
pause 100
sertxd ("H = ",#hours," Min = ", #mins,CR,LF)

;AM2320 - temp and humidity I2C
hi2csetup i2cmaster, %10111000, i2cslow, i2cbyte ;Addr $B8
pause 1
hi2cout ($03,$00,$04) ;Addr+W (=$10), FnCode, StartAddr, No of Reg
pause 10
hi2cin (b20,b21,b22,b23,b24,b25,b27,b26) ;Am2320 response Address+R - $03,$04,RHHi,RHLo,THi,TLo,CRCLo,CRCHi
;AM reply
sertxd ("AM reply = ",#b20," FCode = ",#b21,CR,LF)

;RH Calc
;debug w11 ;b22, b23 = RH
sertxd ("RH = ",w11,CR,LF) ;RH to PC screen

;T Calc
;debug w12 ;b24, b25 = Temp
sertxd ("Temp = ",w12,CR,LF) ;Temp to PC screen

return

Tried changing the pauses from zero to about 2S, no difference. Also re-including the AM i2c address on the hi2cout and hi2cin lines......

I'm only getting zero's back from the Am2320 in the b2x registers - so indications are that I'm talking i2c OK - but not speaking the AM2320 language...........



Any ideas gratefully received

Bob
 

bobladell

New Member
.....and - the Arduino library contains the line #define AM2320_address (0xB8 >> 1) - so it seems to be using 7 bit addressing instead of PICAXE 8 bit. I've tried shifting right and using address $5C as well, also no luck.

Don't know what the PICAXE (or Arduino) do for the wake up mentioned in the AM2320 spec but would have thought that reading it as often as I am would be enough to wake it up ??

Bob
 

Aries

New Member
The Arduino code seems to be something like this ...
Code:
     Wire.beginTransmission(AM2320_address);      
     Wire.endTransmission();      
     // запрос 4 байт (температуры и влажности)      
     Wire.beginTransmission(AM2320_address);      
     Wire.write(0x03);// запрос      
     Wire.write(0x00); // с 0-го адреса      
     Wire.write(0x04); // 4 байта      
     if (Wire.endTransmission(1) != 0) return 1;      
     delayMicroseconds(1600); //>1.5ms      
     // считываем результаты запроса      
     Wire.requestFrom(AM2320_address, 0x08);       
     for (int i = 0; i < 0x08; i++) buf[i] = Wire.read();
This suggests you need to send a "wake-up" first which seems to be an empty message. The datasheet implies that the AM2320 shuts down after a temperature and humidity reading, so you will always need to wake it up, even if you are continuously communicating with it. I'm not sure how you send an empty message with hi2cout - I'm sure someone with more experience than I have can help you out.
 

hippy

Technical Support
Staff member
It does all look a little complicated reading the datasheet but the code in Post #3 looks reasonable enough and pretty close to what I would have tried as a first effort -
Code:
#Picaxe 18M2
#Terminal 4800
#No_Data

TestProgram:
  Do
    Pause 2000
    For b13 = 1 To 5
      Gosub ReadData
      If w0 = $0304 Then
        SerTxd( "Okay " )
      Else
        SerTxd( "FAIL " )
      End If
    Next
    SerTxd( CR, LF )
  Loop

ReadData:

  ; .-----.-----.-----.
  ; | $03 | $00 | $04 |
  ; `-----^-----^-----'
  ;  Read   Reg   Len
  ;
  ;       w0          w1          w2          w3
  ; .-----------.-----------.-----------.-----------.
  ; | $03 | $04 | $hh | $hh | $tt | $tt | crc | crc |
  ; `-----------^-----------^-----------^-----------'
  ;    b1    b0    b3    b2    b5    b4    b7    b6

  HI2cSetup I2CMASTER, $B8, I2CSLOW, I2CBYTE
  HI2cOut ( $03, $00, $04 )
  HI2cIn  ( b1,b0, b3,b2, b5,b4, b7,b6 )
  Return
I would expect that to hopefully show "FAIL Okay Okay Okay Okay" on each line. If so it means we are managing to wake the device up and get some results back.

I would then move on to seeing what the returned data is -
Code:
TestProgram:
  Do
    Pause 2000
    Do
      Gosub ReadData
    Loop Until w0 = $0304
    Gosub ReadData
    SerTxd( "T=", #w2, TAB, "H=", #w1, CR, LF )
  Loop
That should show temperature (T) and humidity (H) ten times greater than it is, for example T=254 H=345 means 25.4C and 34.5%RH.

If we're getting something which looks realistic it seems we're on the path to having something working.
 

Aries

New Member
Section 8.2 of the AM2320 manual (on the Adafruit link) says
AM2320 sensor I2C address of the (SLAVEADDRESS) 0xB8, on the basis of I2C standard protocol
0xB8 is 0x5C shifted once to the left to accommodate the read/write flag
 

bobladell

New Member
Aries - you are correct, the AM2320 needs a wake up after every read - the question was how to send it. See below on how to do it - I just used the ($B8) as a convenient filler, probably OK with $00.

Hippy - many thanks - I see your code reached the same conclusion as mine.
I also looked at the link you included and not surprised that he found unreliable readings at 70% RH etc as he uses a very caustic solution to create the constant RH test environment. Correct method but the AM2320 / DHTxx etc are damaged by highly aggressive chemical environments - see data sheet section 9, 2.

Pongo - the Arduino must do something differently in handling the low level I2C bus with regard to bit 0, the R/W bit, I'm guessing it inserts the clock bit and level separately in the form address +R/W, as indicated in the AM2320 data sheet, and hence does the shift right to use 7 bit addressing of $5C. Different interpretation of the I2C spec.........?

And the solution is :-

Rich (BB code):
main:
        gosub read_sensors                 ; read the sensors
        pause 1000
        goto main                               ; take next reading

; ****************************
; ***** Read sensor data *****
; ****************************

read_sensors:
        high B.3                                    ; flash green LED
        readtemp C.7, data7                ; read Temperature - DS18B20 - one wire
        low B.3                                     ; end of green LED flash
        sertxd ("DS Temp = ",#data7,CR,LF)
      
read_time:
        hi2csetup i2cmaster, %11010000, i2cslow, i2cbyte    ;Addr $D0
        hi2cin 0,(secs,mins,hours,temp_byte,day,month)
        pause 100
        sertxd ("H = ",#hours,"  Min = ", #mins,CR,LF)     
      
;AM2320 - temp and humidity I2C     
      hi2csetup i2cmaster, $B8, i2cslow, i2cbyte    ;Addr $B8
      hi2cout $B8,($B8)                 ;Wake Up AM2320
      ;pause 1
      hi2cout ($03,$00,$04)            ;Addr+W (=$10), FnCode, StartAddr, No of Reg
        ;pauseus 1600                     ;AM2320 states delay >1.5mS, Arduino code 1600uS - but works without a delay on PICAXE (guess it is inherent in PICAXE constructs)
        hi2cin (b20,b21,b22,b23,b24,b25,b27,b26)          ;Am2320 response Address+R - $03,$04,RHHi,RHLo,THi,TLo,CRCLo,CRCHi
;AM reply
    sertxd ("AM reply = ",#b20,"  FCode = ",#b21,CR,LF)
      
;RH Calc
    sertxd ("RH = ",#b22,"  ",#b23,CR,LF)    ;RH to PC screen

;T Calc
    sertxd ("Temp = ",#b24,"  ",#b25,CR,LF)    ;Temp to PC screen
    
    return
Many thanks guys - as usual it just needs some extra eyes and prompts to get the thoughts straight.

Bob
 

Rickg1

New Member
guys, this maybe has a simple answer, but how does one do math on those registers? eg. do a correction th the humidity ( add 5% ) or change C to F?
Any pointing anywhere to a answer is much needed. Thanks
 

AllyCat

Senior Member
Hi,

Convert the separate digits to a single word variable, for example w1 = b22 * 10 + b23 , then do the maths and convert back to separate digits with (for example) b22 = w1 / 10 : b23 = w1 // 10 .

The difficult part might be deciding if you want to "Add 5 to the percentage" or "Scale up by 5%". Normally you would scale up with, for example, w1 = w1 * 105 /100 for +5%. There's a lot of difference with say 20%, i.e. 20 + 5 = 25 (%), or 20 * 105 / 100 = 21 (%). Also, you might want to use a w1 = w1 MAX 99 after (or within) the calculation.

For C to F use w1 = w1 * 9 / 5 +32 (and you may need to add a third digit e.g. b24).

Cheers, Alan.
 
Last edited:

Rickg1

New Member
OK, now i'm lost, if temp is b24 and b25 why w1 ( b3.b2)? not done any of this "converting" before, might take a while and a "little" thinking to get it down. Are you saying to use some other "word" to copy the data into ( doing the math on that data) and adding them together with the "+" sign?
Thanks Alan.

PS Buy the way I used the code from #10, and an 08m2+. Shorten it a little. I have 3 2320 and each one gives a different reading, hence the wanting to do some "correcting" to the data. Address $b8 works ,
 

AllyCat

Senior Member
Hi,

You can use almost any variables you like, I just normally use W1 (and B1) for "intermediate" or "temporary" words or bytes. In this particular example a single byte would have been sufficient, but it's "safer" to use words when scaling (i.e. multiplying and dividing).

The point about your calculation is that b24 and b25 contain individual digits of the complete number; b24 represents the "tens", i.e. 10, 20, 30, etc. and b25 the "units", 1, 2, 3, etc.. For simple addition you could work directly with the digits, e.g. for "2 7" + "(0) 5" , 7 + 5 = 12 ,12 = 10 + 2 , 2 (0) + 1 (0) = 3 (0) so the result is "3 2" . But it makes much more sense to combine the digits into a complete number (e.g. tens * 10 + units) into any convenient Word or Byte variable, do the maths (which could be much more complicated) and then split the number back into separate digits to display it.

Cheers, Alan.
 
Last edited:

hippy

Technical Support
Staff member
if temp is b24 and b25 why w1 ( b3.b2)?
Word variables are formed from two byte variabless, 'w0' is also bytes 'b1' and 'b0', 'w1' is also 'b3' and 'b2'. The correlation is 'wN' is fromed from 'b(N*2+1)' and 'b(N*2)'. The odd numbered byte variables are the most significant byte of the word variable, the even numbered byte variables the least significant byte.

In the case of the code in Post #10, this characteristic of word variables is not respected; b24 is used as the MSB of the temperature, b25 is used as the LSB of the temperature word.

Also the code uses raw variable names. Ideally those variables would have been give more readable names using SYMBOL statements -
Code:
Symbol header       = w0 ; b1:b0
Symbol header.lsb   = b0
Symbol header.msb   = b1

Symbol humidity     = w1 ; b3:b2
Symbol humidity.lsb = b2
Symbol humidity.msb = b3

Symbol temp         = w2 ; b5:b4
Symbol temp.lsb     = b4
Symbol temp.msb     = b5

Symbol crc          = w3 ; b7:b6
Symbol crc.lsb      = b6
Symbol crc.msb      = b7
Then the data could be read from the AM2320 with -
Code:
HI2cIn ( header.msb,header.lsb, humidity.msb,humidity.lsb, temp.msb,temp.lsb, crc.msb,crc.lsb )
We read the component byte parts here because the AM2320 only sends out byte data, not word data.

But because of the way we have defined those variables, when we set 'temp.msb' and 'temp.lsb' byte variables it also automatically sets the 'temp' word variable. Thus we could show the temperature using -
Code:
SerTxd( "T=", 'temp, CR, LF )
And, because 'temp' is an actual temperature, that can be adjusted, such as by adding 5 to it -
Code:
temp = temp + 5
SerTxd( "T=", 'temp, CR, LF )
 

MGU

Senior Member
Hi All - done a forum search and seems no one has done anything with the AOSONG AM2320 I2C based temp and humidity sensor.
That right - or have I missed something ?
Thanks
Bob
Hello,
Thank you Google Translate.
It seems that picaxes are not fast enough to directly read the Maxdetect protocol for DHT11 or DHT22 type sensors.
I wrote a page a few years ago on this topic: http://electromag1.wifeo.com/dht11-et-picaxes.php
There is a translation option at the top right of the page
The GY-21 is a better choice:

MM
 

AllyCat

Senior Member
@Rickg1,

Apologies, I misunderstood your question. Without reading the data sheet, I assumed that the Program in #10 was outputting "meaningful" (or "human readable") digit values for Humidity and Temperature. But it appears to be just Test/Diagnostic data (bytes).

However, as hippy has indicated, if the bytes had been (or are) grouped and ordered in the "correct" sequence, then any maths corrections shouldn't be difficult to apply.

Cheers, Alan.
 

hippy

Technical Support
Staff member
It is always difficult figuring out what's going on, especially when there is 'theoretical code' plus 'proof of concept code' but no 'final code'.

Merging together the theoretical code and proof of concept code, I would try this ...
Code:
Symbol header       = w0 ; b1:b0
Symbol header.lsb   = b0
Symbol header.msb   = b1

Symbol humidity     = w1 ; b3:b2
Symbol humidity.lsb = b2
Symbol humidity.msb = b3

Symbol temp         = w2 ; b5:b4
Symbol temp.lsb     = b4
Symbol temp.msb     = b5

Symbol crc          = w3 ; b7:b6
Symbol crc.lsb      = b6
Symbol crc.msb      = b7

TestProgram:
  Do
    Pause 2000
    Do
      Gosub ReadData
    Loop Until w0 = $0304
    SerTxd( "T=", #temp, TAB, "H=", #humidity, CR, LF )
  Loop

ReadData:

  ; .-----.-----.-----.
  ; | $03 | $00 | $04 |
  ; `-----^-----^-----'
  ;  Read   Reg   Len
  ;
  ;     header     humidity      temp      checksum
  ; .-----------.-----------.-----------.-----------.
  ; | $03 | $04 | $hh | $hh | $tt | $tt | crc | crc |
  ; `-----------^-----------^-----------^-----------'
  ;   msb   lsb   msb   lsb   msb   lsb   msb   lsb

  HI2cSetup I2CMASTER, $B8, I2CSLOW, I2CBYTE
  HI2cOut ( $03, $00, $04 ) ; Wake-up
  HI2cOut ( $03, $00, $04 ) ; Request data
  HI2cIn ( header.msb,header.lsb, humidity.msb,humidity.lsb, temp.msb,temp.lsb, crc.msb,crc.lsb )
  Return
 

MGU

Senior Member
Hello,
By reading the datasheet, I see that the AM2320 has, in addition to the One Wire, a standard I2C protocol.
My previous post, dedicated to DHT11 and DHT22 is therefore without interest
MM
 

Rickg1

New Member
hippy;;; thank you so so much. code works so good. readouts are good. But can you tell me why the to c to f ( *9/5+32) convertion will not work. For 26.1 C I get 50.2F. ( no matter how I enter the formula)
my line is ( added to your code #18 ):
TestProgram:
Do
Pause 2000
Do
Gosub ReadData
Loop Until w0 = $0304
SerTxd( "T=", #temp, TAB, "H=", #humidity, CR, LF )

w2 = w2 * 9 :w2=w2 /5 :w2=w2 + 32

SerTxd( "T=", #temp,"F", TAB, "H=", #humidity, CR, LF )
 

hippy

Technical Support
Staff member
It would be better to use the 'temp' name rather than 'w2' and the entire calculation can be done in one hit 'temp = temp * 9 / 5 + 32". But note that temp is scaled by 10 so you need to scale the +32 as well; +320 ...
Code:
temp = 261 ; = 26.1C
SerTxd( "T=", #temp,"C", TAB, "H=", #humidity, CR, LF )
temp = temp * 9 / 5 + 320
SerTxd( "T=", #temp,"F", TAB, "H=", #humidity, CR, LF )
Code:
T=261C      H=0
T=789F      H=0
26.1C => 78.9F
 
Last edited:

AllyCat

Senior Member
Hi,

Presumably you're entering 26.1 degrees as 261. That's reasonable, provided that you keep a watch on any potential overflows (past 65535), but you need to also scale the 32 (i.e. 32.0) as 320.

BTW there's no need to separate the elements,: w2 = w2 * 9 / 5 +32{0} should work fine. (I make it 78.9) or you could make it w2 = w2 * 9 + 2 / 5 + 320 to "round" the result to the nearest integer (or decimal part). The "2" is approximately half of the divisor 5.

Ah, beaten by hippy again. ;)

Cheers, Alan.
 

hippy

Technical Support
Staff member
Are you ever going to be seeing negative temperatures ? They can get quite tricky ...
Code:
temp = -415 ; = -41.5C
If temp >= $8000 Then
  w0 = -temp
  SerTxd( "T=-", #w0,"C", TAB, "H=", #humidity, CR, LF )
Else
  SerTxd( "T=", #temp,"C", TAB, "H=", #humidity, CR, LF )
End If

If temp >= $8000 Then
  temp = -temp * 9 / 5
  temp = -temp + 320
Else
  temp = temp * 9 / 5 + 320
End If
If temp >= $8000 Then
  w0 = -temp
  SerTxd( "T=-", #w0,"F", TAB, "H=", #humidity, CR, LF )
Else
  SerTxd( "T=", #temp,"F", TAB, "H=", #humidity, CR, LF )
 End If
 

Rickg1

New Member
thanks again guys, but please explain why the +32 gave 50.1 and +320 gives 78.9?
The 320 gives the correct 78.9.
 

Rickg1

New Member
There is so so much to learn about these little guys, thank you for the forum and all the answers to a lot of questions.
 

hippy

Technical Support
Staff member
Question: how do I put a clear display in a program using the pic terminal?
First, open the Terminal from PE6. Then, in Terminal, select the Settings menu, Special Control Functions, and tick "Clear screen on FF [0C]" - FF means Form-Feed and $0C is the byte value for that character.

Back in the actual editor ...
Code:
Do
  SerTxd( #w0, CR, LF )
  Pause 1000
  w0 = w0 + 1
  SerTxd( $0C )                   ; <--  Clear Terminal Screen
Loop
Simulate that and it should clear the display rather write a new number on each line.

In Terminal, choose Settings and untick "Display non-ASCII as hex", if you are getting the [0C] shown. Or just use SerTxd( $0C,CR,LF) if you need to see non-ASCII.
 
Top