<1> 介绍
当我们进行湿度测量时, 我们处于工作的习惯, 仍然期待选择一款数字式的传感器. 实际上, 因为我们供货商的推荐, 我们选用了 SENSIRION 的 SHT1x 温湿度数字传感器. 这是一只有着2只数据脚的 sensor. 一根 sck, 一根 data. 本文中, 我们记录下若干驱动过程中遇到一些有兴趣的要点, 或者可以与诸位同仁进行更深入的讨论.
<2> 参考文档
1. Datasheet: from webpage of sensirion
<3> 驱动流程
我们记录下我们的理解如下:
1. Send a command 是一个固有约定格式的过程.
2. 在一个下降沿中, 保持 low. 同时在下一个上升沿中保持 data 为 low. 表示发送开始.
3. 一个字节的 cmd byte.
4. 多送一个 0 bit, 表示确认发送结束.
5. release data, 等待 sensor 将 data 拉底, 通知测量结束.
6. 每次读取完毕一个 byte, 在新的 low 被拉低通知后, 应该主动进行一个 ACK 脉冲, 进行确认. 完毕确认后, 如果还有跟随需要 readout 的 byte, 则可以再次读取.
7. 被读取的温度数据或者湿度数据, 都会在此跟随一个 CRC byte. 读取了 CRC byte, 并完成 ACK, 那么整个测量的过程, 就算结束. 不过, SHT1x 也提供了我们一个小的技巧, 可以不去读 CRC(假设CRC 在我们的应用中没有使用). 这就是, 在读取完毕最后一个有效温度或者湿度数据后, 我们不进行 ACK. 也就是保持 release data. 那么 datasheet 告诉我们, SHT1x 将 明白, 我们打算忽略 CRC byte. SHT1x 将结束这次(温度湿度数据)的发送过程, 并在此进行到 sleep (待机)状态.
<4> 实际操作中对 transstart 和 connection reset 的使用
尽管我们会习惯性感觉, 每次 measure 的过程, 是否只用做 transstart 就可以开始. 但是实际使用中, Allen 发现单纯依赖 transstart 总是似乎没有那么可靠. 最后的代码中, 我们在每次 measure 之前, 都使用了 connectionreset, 来保证每次通讯的可靠性.
那么在我们的调试中为什么会出这个 condition? 我们猜测: 存在这样的可能, 就是在调试的过程中, 我们常常并没有一个完成的 write + read 的 whole process. 这样就造成了 sensor 无法判断上一个 measure 的过程是否结束. 从而会导致 connection event 的连接失效. 但是既然存在着这样的 invalid 的可能性, 我们每次执行 connectionreset, 也应该是合理的?
<5> 完成温度转化的时间
Datasheet 说, 完成 14bit 的温度测量的时间, 要长过完成 12bit 的湿度测试量的时间. Datasheet 给出的标准的温度测量的时间是 320ms. 我们的调试结果是, 不到 300ms, 温度的转换过程即可实现.
<6> 代码的例子
首先我们要声明, 从 SENSIRION 的网站上, 下载 dirver sample code, 是必须的. 而我们这里提供的, 被我们调试过的代码, 由于我们在硬件上的保护电路的使用. 我们把单一的 data 拆成了 input 和 output 两路.
因此, 可能会给阅读我们的 code sample 带来不便. 同时, 我们还必须指出, 保护电路至少带给我们 4us 的延时. 而在一个典型的 sensor 电路中, 应该不会有这样 delay 的存在. 我们对这些不便之处表示歉意.
/*
* sht1x.c
*
* DESCRIPTION:
* Measure Temparature and relative humidity.
*
* FUNCTION:
* @ Use sht1x_measure() to answer uart measure command.
* @ Use sht1x_do_convert() to do convert process.
* @ After about 500ms, use TBD() to get vaule with timer.
*
* NOTE:
* We use input/output trax unit to do out/in job, we think it will protect the mcu io.
*
* $Author: Allen Zhan; ; ;
* $Create Date: 2010/08/29 10:59 Beijin Timezone $
*
* Copyright 2010 Shenzhen GV Technology Co., Ltd. <>. All rights reserved.
*
*/
#include "..\inc\config.h"
#include "..\inc\utils.h"
#include "..\inc\sht1x.h"
//// predefine
#define noACK 0
#define ACK 1
//adr command r/w
#define STATUS_REG_W 0x06 //000 0011 0
#define STATUS_REG_R 0x07 //000 0011 1
#define MEASURE_TEMP 0x03 //000 0001 1
#define MEASURE_HUMI 0x05 //000 0010 1
#define RESET 0x1e //000 1111 0
// writes a byte on the Sensibus and checks the acknowledge
U8 sht1x_write_byte(U8 value)
{
U8 error = 0;
// send byte to sensor
for(U32 i=0x80; i>0; i/=2) {
if (i & value)
IO0CLR = SENSIBUS_DATA_OUT_PIN; // data=1
else
IO0SET = SENSIBUS_DATA_OUT_PIN; // data=0
IO0CLR = SENSIBUS_SCK_PIN; // sck=1
delay_mcu(32); // pulswith approx. 8us in our system
IO0SET = SENSIBUS_SCK_PIN; // sck=0
delay_mcu(32); // 4us for our min trax module
}
// check ack from sensor
IO0CLR = SENSIBUS_DATA_OUT_PIN; // data=1, release DATA-line
IO0CLR = SENSIBUS_SCK_PIN; // sck=1, clk #9 for ack
delay_mcu(32); // 4us for our min trax module
if( (IO0PIN&SENSIBUS_DATA_IN_PIN) == 0x00 ) // check ack (DATA will be pulled down by SHT11, data=1)
error = 1; // data=1, still high shows error
else
error = 0; // data=0, sensor pull low data line as acknowledge
IO0SET = SENSIBUS_SCK_PIN; // sck=0
// do system delay waiting data line release and return to data=1
delay_mcu(32);
return error; //error=1 in case of no acknowledge
}
// reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"
U8 sht1x_read_byte(U8 ack)
{
U8 val = 0;
// read byte from sensor
IO0CLR = SENSIBUS_DATA_OUT_PIN; // data=1, release DATA-line
delay_mcu(32); // 4us
for(U32 i=0x80; i>0; i/=2) {
IO0CLR = SENSIBUS_SCK_PIN; // sck=1
delay_mcu(32); // 4us
if( (IO0PIN&SENSIBUS_DATA_IN_PIN) == 0x00 ) // if data==1
val=(val | i); //read bit
IO0SET = SENSIBUS_SCK_PIN; // sck=0
delay_mcu(32); // 4us
}
// in case of "ack==1" pull down DATA-Line
if(ack)
IO0SET = SENSIBUS_DATA_OUT_PIN; // data=0
else
IO0CLR = SENSIBUS_DATA_OUT_PIN; // data=1
delay_mcu(32); // 4us
IO0CLR = SENSIBUS_SCK_PIN; // sck=1, clk #9 for ack
delay_mcu(32); // 4us
IO0SET = SENSIBUS_SCK_PIN; // sck=0
IO0CLR = SENSIBUS_DATA_OUT_PIN; // data=1, release DATA-line
delay_mcu(32); // 4us
return val;
}
文章评论(0条评论)
登录后参与讨论