位置:首页 > 自动化 > 测量与控制技术

用MAXQ3210构建温度记录仪

时间:2010-05-09 10:37:23

 概述:环境监测通常需要小巧灵活的微控制器。如果在这类应用中使用个人电脑,对其计算能力和存储容量而言都是一种浪费,可采用一个专用微控制器与温、湿度传感器或其它环境监测传感器通信,读取并存储监测数据。为实现更高的灵活性,这些微控制器可连成网络,各自将监测数据上传到功能更强大的系统中,对整体环境参数进行分析记录。838电子

本篇应用笔记介绍如何使用低功耗微控制器MAXQ3210实现环境监测应用。增加一个通过一根1-Wire®总线实现供电和通信的数字温度传感器DS1822,我们可用最少的元器件构建一个电池供电的非易失温度记录系统。

可以下载相关演示代码。代码采用MAXQ汇编语言编写,在MAX-IDE开发环境自带的标准宏汇编预处理器和汇编器中编译。该代码是为MAXQ3210评估板编写,因此还需要以下器件(图1)。838电子

设计目标

演示代码要完成以下任务(图2):


图2. 温度记录应用的程序流程图

为何使用MAXQ3210?

几乎所有的低功耗MAXQ微控制器都可以实现这一应用,但MAXQ3210更适合用于温度记录。

驱动1-Wire网络

Dallas Semiconductor/Maxim提供一系列使用1-Wire网络接口的传感器和其它器件。该接口的数据通信和供电仅需通过一根数据线再加一根地线,这意味着微控制器仅需一个端口即可与1-Wire传感器通信。

1-Wire网络工作于一主多从模式(多点网络)。时序非常灵活,允许从机以高达16kbps的速率与主机通信。每个1-Wire器件都有一个全球唯一的64位ROM ID,允许1-Wire主机精确选择位于网络任何位置的一个从机进行通信。

1-Wire总线采用漏极开路模式工作,主机(或需要输出数据的从机)将数据线拉低到地表示数据0,将数据线释放为高表示数据1。这通常通过在数据线和VCC之间连一个分立电阻实现,但MAXQ3210的端口引脚支持弱上拉模式,只需将引脚切换到弱上拉模式,数据线即可浮高。因此MAXQ3210不需外接电阻。由于主机和从机仅需将数据线拉低,而从不将数据线主动拉高,因此数据线可以实现“线-或”功能,这可防止多个从机试图同时通过1-Wire总线发送数据时出现冲突。

为驱动1-Wire网络,MAXQ3210利用软件在一个引脚上实现以下类型的时隙。由于1-Wire所有时隙由主机启动,因此当MAXQ3210不与从机通信时不需要监测1-Wire线路。有关1-Wire时序的更多详细信息请参考DS1822的数据资料。

由于MAXQ3210每微秒约等于三个半指令周期(3.58MHz时钟频率下),软件可利用一个端口引脚(P1.6)方便的实现1-Wire协议。

#define OWIN       M0[09h].6   ; PI1.6
#define OWOUT      M0[01h].6   ; PO1.6
#define OWDIR      M0[11h].6   ; PD1.6

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Function    : Reset1Wire
;;  Description : Sends a standard speed 1-Wire reset pulse on P1.6
;;                and checks for a presence pulse reply.
;;  Inputs      : None
;;  Outputs     : C - Cleared on success; set on error (no presence
;;                    pulse detected)
;;  Destroys    : PSF, LC[0]
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Reset1Wire:
   move  OWDIR, #1           ; Output mode
   move  OWOUT, #0           ; Drive low
   move  LC[0], #RESET_LOW
   djnz  LC[0], $

   move  OWOUT, #1           ; Snap high
   move  LC[0], #SNAP
   djnz  LC[0], $

   move  OWDIR, #0           ; Change to weak pullup input
   move  LC[0], #RESET_PRESAMPLE
   djnz  LC[0], $

   move  C, OWIN             ; Check for presence detect

   move  LC[0], #RESET_POSTSAMPLE
   djnz  LC[0], $

   ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Function    : Write1Wire
;;  Description : Writes a standard speed 1-Wire output byte on P1.6.
;;  Inputs      : GRL - Byte to write to 1-Wire.
;;  Outputs     : None.
;;  Destroys    : PSF, AP, APC, A[0], LC[0], LC[1]
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Write1Wire:
   move  APC, #080h          ; Standard mode, select A[0] as Acc
   move  Acc, GRL
   move  OWDIR, #1           ; Output drive mode
   move  LC[1], #8           ; 8 bits to write

Write1Wire_slot:
   move  OWOUT, #0           ; Drive low for start of write slot

   move  LC[0], #WRITE_PREBIT
   djnz  LC[0], $

   rrc                       ; Get the next bit
   jump  C, Write1Wire_one
Write1Wire_zero:
   move  OWOUT, #0           ; Keep the line low (zero bit)
   jump  Write1Wire_next
Write1Wire_one:
   move  OWOUT, #1
Write1Wire_next:
   move  LC[0], #WRITE_POSTBIT
   djnz  LC[0], $            ; Finish the time slot

   move  OWOUT, #1           ; Drive back high (end of slot)
   move  LC[0], #WRITE_RECOVERY
   djnz  LC[0], $            ; Recovery time period
   
   djnz  LC[1], Write1Wire_slot

   ret

实现读时隙的功能与之类似。注意,在1-Wire总线上所有数据均为低有效位(LSB)先发。

利用MAXQ3210实现1-Wire时序时,另一点需要注意的是:尽管1-Wire总线上拉电阻的阻值与总线上的设备数有关,但通常在4kΩ到5kΩ之间。可是MAXQ3210端口引脚上的弱上拉电阻为50kΩ到100kΩ。为了防止1-Wire总线从低电平到高电平转换的时间过长,演示代码先将P1.6输出设为短暂的高电平,将总线强制拉高,然后变为正常的弱上拉模式。只要该过程不是在从机试图将总线拉低的时候进行,就不会出现问题。另外,还可以在总线上再加一个分立的上拉电阻,这样就可以正常的方式使端口输出低代表0,输出三态代表1。

注意:当构建的1-Wire网络传输距离较远或连接的从机数量较多时,还需要注意其他事项。

用DS1822测量温度

尽管MAXQ3210可以使用上面的代码与大多数1-Wire从机器件通信,在本应用中我们将主要考虑与DS1822通信。DS1822是一个1-Wire从机器件,可实现9到12位的摄氏温度测量,测量结果可被1-Wire主机读取。与多数1-Wire从机一样,DS1822可以完全由1-Wire总线供电,我们称之为寄生供电。

DS1822的测量范围可达-55°C至+125°C,适用于多数的室内外温度测量应用。温度分辨率在9位下为0.5°C,12位下0.0625°C。进行一次温度转换所需时间在低分辨率下约为94ms,在最高分辨率下约为750ms。由于这是一个简单应用,我们选择9位分辨率,并忽略最低位(0.5°C)。这样就可使整个8位带符号温度数据与MAXQ3210的8位累加器匹配。

所有的1-Wire从机器件都支持一个通用指令集,从而使得主机可以判断总线上的从机数目,读取ROM ID,并且可以与某一个从机或一组从机进行通信。一旦某个1-Wire从机被激活,主机可以针对该从机类型向其发送特殊指令。其它所有未被激活的从机均处于等待状态,直到下一个复位脉冲出现,才开始再次监测1-Wire总线。

由于在我们的应用中总线上仅有一个1-Wire器件,我们可以使用最简单的指令集访问从机器件,不需要读取从机的ROM ID。当总线上有多个从机器件时,ROM ID被用来区分不同的从机器件。我们的程序中也读取了一次DS1822的ROM ID,但仅是为了演示。

我们将使用下面的1-Wire指令集,DS1822支持的其它指令请参考其数据资料。

当执行Convert Temperature指令时,DS1822需要消耗更多的电流(最多1.5mA),可能超过1-Wire总线弱上拉所能提供的电流。因此,一旦主机发出这一指令,必须对1-Wire总线进行强上拉,直至温度转换结束。在此期间,1-Wire总线上不能有任何通信发生。MAXQ3210简单地通过将P1.6端口从弱上拉切换成输出高电平来满足此要求。MAXQ3210端口驱动器能够输出足够DS1822工作所需的电流。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Function    : ConvertAndReadTemp
;;  Description : Sends commands to measure temperature and read
;;                scratchpad from the DS1822.
;;  Inputs      : None.
;;  Outputs     : GRL - 8-bit signed temperature value, in degrees C.
;;  Destroys    : PSF, AP, APC, A[0], A[1], A[2], LC[0], LC[1]
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ConvertAndReadTemp:
   call  Reset1Wire          ; Reset the DS1822

   move  GRL, #OW_SKIP_ROM   ; Select the DS1822
   call  Write1Wire
   move  GRL, #OW_CONVERT    ; Send temp convert command
   call  Write1Wire

   move  OWDIR, #1           ; Turn on strong pullup for draw current
   move  OWOUT, #1

   move  LC[0], #55          ; About a second
delay:
   move  LC[1], #0
   djnz  LC[1], $
   djnz  LC[0], delay

   call  Reset1Wire          ; Conversion completed; reset again

   move  GRL, #OW_SKIP_ROM   ; Select again
   call  Write1Wire
   move  GRL, #OW_RD_SCRATCH ; Read the scratchpad values
   call  Write1Wire

   call  Read1Wire
   move  A[1], GRL           ; Temp LSB  3210xxxx
   call  Read1Wire
   move  A[2], GRL           ; Temp MSB  sssss654

   move  Acc, A[1]           ; 3210xxxx
   and   #0F0h               ; 3210----
   xchn                      ; ----3210
   move  A[1], Acc
   move  Acc, A[2]           ; sssss654
   and   #00Fh               ; ----s654
   xchn                      ; s654----
   or    A[1]                ; s6543210

   move  GRL, Acc
   ret

将测量结果存储在数据EEPROM中

为防止1-Wire总线偶然出现数据错误,演示代码每次测量都执行三次温度转换(A,B和C),并从中选择一个结果存储,选择的依据为:

被选中的值被写入数据EEPROM的一个字中。由于采样结果为一个字节,每个字的高字节被用来指示该记录(也就是字)是否为空。如果高字节为0,该记录/字为空,如果高字节非0,则低字节为有效温度数据。这样就能区分空记录和存储数据为0°C的有效数据。

;;  Two out of three majority vote, or failing that, the measurement
;;  in the middle of the three.

   move  Acc, A[4]     
   cmp   A[5]
   jump  E, recordTempA      ; If (A==B), use that value
   cmp   A[6]
   jump  E, recordTempA      ; If (A==C), use that value
   
   move  Acc, A[5]
   cmp   A[6]             
   jump  E, recordTempB      ; If (B==C), use that value

   move  Acc, A[4]
   sub   A[5]
   jump  S, B_greaterThan_A  ; Sign is set if (A-B) is negative

;;  If (A > B) {
;;     If (C > A) record A     (C > A > B)
;;     If (B > C) record B,    (A > B > C)
;;           else record C     (A > C > B)

A_greaterThan_B:
   move  Acc, A[4]
   sub   A[6]                ; A-C
   jump  S, recordTempA      ; Sign is set if (A-C) is negative
   move  Acc, A[5]
   sub   A[6]                ; B-C
   jump  S, recordTempC      ; Sign is set if (B-C) is negative
   jump  recordTempB

;;  If (B > A) {
;;     If (C > B) record B     (C > B > A)
;;     If (A > C) record B,    (A > B > C)
;;           else record C     (B > C > A)

B_greaterThan_A:
   move  Acc, A[5]
   sub   A[6]                ; B-C
   jump  S, recordTempB      ; Sign is set if (B-C) is negative
   move  Acc, A[4]
   sub   A[6]                ; A-C
   jump  S, recordTempC      ; Sign is set if (A-C) is negative
   jump  recordTempB

recordTempA:
   move  GRL, A[4]
   jump  recordTemp

recordTempB:
   move  GRL, A[5]
   jump  recordTemp

recordTempC:
   move  GRL, A[6]
   jump  recordTemp

recordTemp:
   move  A[15], GRL

   move  GRL, #'@'
   call  TxCharBB
   move  GR, DP[0]
   move  GRL, GRH
   call  TxHexByteBB
   move  GRL, DP[0]
   call  TxHexByteBB

   move  GRL, #' '
   call  TxCharBB
   move  GRL, #'W'
   call  TxCharBB
      
   move  GRL, A[15]
   call  TxHexByteBB

   move  GRL, A[15]          ; Low byte contains temp data
   move  GRH, #055h          ; High byte marks nonzero entry
   lcall  UROM_loadData      ; Write entry to data EEPROM

   call  IncDP0_EE           ; Move to the next entry position
   move  GR, #0000h          ; Erase any data that exists
   lcall  UROM_loadData      ; Erase the oldest entry

记录采用循环方式,从数据EEPROM地址020h开始到05Fh结束,然后再回到开始处。之后每写入一个新记录,将擦除一个最旧的记录。当通过串行接口向外发送数据时,应用程序通过查找前面是否又有空记录的方式定位最旧的记录数据。

节省功耗

由于本应用每分钟仅记录一次温度数据,而读取DS1822数据并将其存储到EEPROM中仅需几秒钟。多数时间应用都在等待一分钟的延时结束。根据应用的要求,不需更改太多代码即可将温度记录间隔拉长,比如到五分钟、十分钟或三十分钟。为了减少等待期间对电池的消耗,应尽可能降低功耗。

MAXQ3210所能提供的最低功耗模式为待机模式。该模式下,程序停止运行,高频晶振停止工作,电流降到微安量级。由于没有其它器件还在工作,我们需要将MAXQ3210从待机模式周期性的唤醒来测量温度。

这一要求可通过MAXQ3210的唤醒时钟实现。这一时钟依靠在待机模式仍然工作的内部8kHz低电流环形振荡器运行,能以最长两分钟的可编程间隔唤醒微控制器。这种定时唤醒对于我们的应用非常理想,在应用中可将“闹钟”设为一分钟,微控制器工作结束后接着进入待机模式以节省功耗,然后等待被唤醒再次采集数据。

;;  Start the wakeup timer for 60 seconds.

   move   CKCN.6, #1         ; Select ring oscillator mode
waitRing:
   move   C, CKCN.5
   jump   NC, waitRing       ; Wait for RGMD=1 (running from ring)

   move  WUT, #30000         ; 1/8kHz * 30000 * 16 = 60 seconds
   move  WUTC, #0101b        ; Start the wakeup timer (running from ring)

   move  IV, #wakeUpInt      ; Set interrupt handler for wakeup interrupt
   move  IMR.0, #1           ; Enable interrupts from module 0
   move  IC.0, #1            ; Globally enable interrupts

   move  PD0.7, #0           ; Turn off output mode for LED pin
   move  PO0.7, #1           ; Return to default state (weak pullup)
  
   move  CKCN.4, #1          ; Go into Stop mode, wait for wakeup int
   nop

   jump  mainLoop            ; Back for another round

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

wakeUpInt:
   move  PD0.7, #1           ; Turn on output mode for LED port pin
   move  PO0.7, #0           ; Light the LED

   move   CKCN.6, #1         ; Select ring oscillator mode
wakeUp_ring:
   move   C, CKCN.5
   jump   NC, wakeUp_ring    ; Wait for RGMD=1 (running from ring)

   move  LC[0], #4000
   djnz  LC[0], $
   move  PO0.7, #1           ; LED off
   move  LC[0], #4000
   djnz  LC[0], $
   move  WUTC, #0            ; Clear wakeup timer flag

   move  CKCN.6, #0          ; Select crystal mode
wakeUp_xtal:
   move  C, CKCN.5
   jump  C, wakeUp_xtal      ; Wait for RGMD=0 (running from crystal)

   move  GRL, #'W'
   call  TxCharBB
   move  GRL, #'U'
   call  TxCharBB
   move  GRL, #0Dh
   call  TxCharBB
   move  GRL, #0Ah
   call  TxCharBB

   reti                       

上传温度记录数据

每次上电复位后,应用程序向主机系统发送温度记录数据。数据通过10位异步串行接口以9600波特的速率发送(1位开始位,8位数据位,1位停止位)。MAXQ3210不带硬件UART串口,需要使用一个端口引脚模拟实现。由于本应用只需发送,不需接收,所以实现起来比较简单。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Function    : TxCharBB
;;  Description : Transmits a 10-bit serial character (bit-banged)
;;                over P0.0.
;;  Inputs      : GRL   - Character to send
;;  Outputs     : None
;;  Destroys    : PSF, AP, APC, A[0], LC[0], LC[1]
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TxCharBB:
   move  APC, #080h          ; Standard mode, select A[0] as Acc
   move  Acc, GRL
   
   move  PO0.0, #0           ; START bit low
   move  LC[0], #BITLOOP
   djnz  LC[0], $

   move  LC[1], #8           ; 8 bits
TxCharBB_bitLoop:
   rrc                       ; Get the next bit
   jump  C, TxCharBB_one
TxCharBB_zero:
   move  PO0.0, #0
   sjump TxCharBB_next
TxCharBB_one:
   move  PO0.0, #1
TxCharBB_next:
   move  LC[0], #BITLOOP
   djnz  LC[0], $
   djnz  LC[1], TxCharBB_bitLoop

   move  PO0.0, #1           ; STOP bit high
   move  LC[0], #BITLOOP
   djnz  LC[0], $
   move  LC[0], #BITLOOP
   djnz  LC[0], $

   ret

要把温度数据从带符号的2进制、8位摄氏度数值转换成容易识别的ASCII码、华氏度数值,还需要增加较多代码,但这些代码简单易懂。使用BCD (二进制编码的十进制)运算规则执行二进制到十进制的转换,同时完成摄氏度到华氏度的转换。
   move  GR, @DP[0]          ; Get the current entry
   move  Acc, GRH            ; Check the high byte
   jump  Z, endOutput        ; If it's zero we're done
   move  A[15], GRL          ; Save the low byte (temp value)

   move  A[7], #0            ; Hundreds = 0
   move  A[6], #0            ; Tens     = 0
   move  A[5], #0            ; Ones     = 0
   move  A[4], #0            ; Tenths   = 0

   move  A[3], #0            ; Add 01.8 per degree C
   move  A[2], #1
   move  A[1], #8

   move  Acc, A[15]          ; s6543210
   jump  S, tempNegC

tempPosC:
   move  GRL, #'+'
   jump  Z, tempPrint

   move  LC[0], Acc
tempPosC_loop:
   call  AddBCD
   djnz  LC[0], tempPosC_loop
   
   move  A[3], #3
   move  A[2], #2
   move  A[1], #0            ; Add 32.0
   call  AddBCD

   jump  tempPrint

tempNegC:
   move  GRL, #'-'
   neg
   jump  Z, tempPrint        ; Negative zero
   jump  S, tempPrint        ; -128 is outside the sensor range anyhow
   
   move  LC[0], Acc
tempNegC_loop:
   call  AddBCD
   djnz  LC[0], tempNegC_loop

   move  A[3], #3
   move  A[2], #2
   move  A[1], #0            ; Subtract 32.0
   call  SubBCD

   jump  NC, tempPrint
   move  GRL, #'+'           ; Back to positive again
   jump  tempPrint
tempPrint:
   call  TxCharBB            ; Print plus/minus sign
   call  TxTempBB            ; Print temperature value + newline

   call  IncDP0_EE           ; Move to the next entry



由于MAXQ3210的端口输出采用5V电平,在与PC的COM串口连接之前必须使用外部器件(如MAX233ACWP)对输出进行电平转换。完成这一转换后,可以使用任何标准终端仿真程序接收应用输出的数据。

RST
DS1822 Detected : 22A9CC15000000E5

+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 59.0
+ 62.6
+ 69.8
+ 59.0
+ 55.4
+ 55.4
+ 55.4
+ 55.4
+ 55.4
+ 55.4
+ 55.4
+ 57.2
+ 55.4
+ 55.4
+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 57.2
+ 57.2

应用功能扩展

MAXQ3210具有1k x 16 (1024字)的EEPROM程序存储空间,演示代码只占用了其中的60%至70%。可对应用代码进一步优化,使其仅占用50%的程序存储空间。开发了应用的核心功能后,可增加许多额外功能,使其成为功能完备的环境检测系统。

结论

小封装,低功耗,I/O灵活的MAXQ3210是电池供电的环境监测应用的理想选择。许多1-Wire传感器可被用来测量温度、湿度等环境参数,而这些传感器又可仅通过一个端口实现与MAX3210的接口。最后,数据还可以被存贮在MAXQ3210自带的非易失EEPROM存储器中,供以后查询和分析

请您评价
0/250 验证码: