📄 sensirionsht11logicp.nc
字号:
/* * Copyright (c) 2005-2006 Arch Rock Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * - Neither the name of the Arch Rock Corporation nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE */#include "Timer.h"#include "SensirionSht11.h"/** * SensirionSht11LogicP contains the actual driver logic needed to * read from the Sensirion SHT11 temperature/humidity sensor. It * depends on 2 underlying GeneralIO interfaces, one for the data pin * and one for the clock pin, and one underlying GpioInterrupt. It * provides the HAL-level SensirionSht11 interface. It's generic, so * you can instantiate it multiple times if you have more than one * Sensirion SHT11 attached to a node. * * <p> * This code assumes that the MCU clock is less than 10 MHz. If you * ever run this on a faster MCU, you'll need to insert a lot of * waits to keep the Sensirion happy. * * @author Gilman Tolle <gtolle@archrock.com> * @version $Revision: 1.4 $ $Date: 2006/12/12 18:23:12 $ */generic module SensirionSht11LogicP() { provides interface SensirionSht11[ uint8_t client ]; uses interface GeneralIO as DATA; uses interface GeneralIO as CLOCK; uses interface GpioInterrupt as InterruptDATA; uses interface Timer<TMilli>; uses interface Leds;}implementation { typedef enum { CMD_MEASURE_TEMPERATURE = 0x3, CMD_MEASURE_HUMIDITY = 0x5, CMD_READ_STATUS = 0x7, CMD_WRITE_STATUS = 0x6, CMD_SOFT_RESET = 0x1E, } sht_cmd_t; enum { TIMEOUT_RESET = 11, TIMEOUT_14BIT = 250, TIMEOUT_12BIT = 250, //70, TIMEOUT_8BIT = 250, //15, } sht_timeout_t; bool on = TRUE; bool busy = FALSE; uint8_t status = 0; sht_cmd_t cmd; uint8_t newStatus; bool writeFail = FALSE; uint8_t currentClient; error_t performCommand(); void initPins(); void resetDevice(); void transmissionStart(); void sendCommand(uint8_t _cmd); void writeByte(uint8_t byte); error_t waitForResponse(); void enableInterrupt(); uint8_t readByte(); void ack(); void endTransmission(); task void readSensor(); task void signalStatusDone(); command error_t SensirionSht11.reset[ uint8_t client ]() { if ( !on ) { return EOFF; } if ( busy ) { return EBUSY; } else { busy = TRUE; } cmd = CMD_SOFT_RESET; currentClient = client; return performCommand(); } command error_t SensirionSht11.measureTemperature[ uint8_t client ]() { if ( !on ) { return EOFF; } if ( busy ) { return EBUSY; } else { busy = TRUE; } cmd = CMD_MEASURE_TEMPERATURE; currentClient = client; return performCommand(); } command error_t SensirionSht11.measureHumidity[ uint8_t client ]() { if ( !on ) { return EOFF; } if ( busy ) { return EBUSY; } else { busy = TRUE; } cmd = CMD_MEASURE_HUMIDITY; currentClient = client; return performCommand(); } /* FIXME: these don't seem to work */ command error_t SensirionSht11.readStatusReg[ uint8_t client ]() { if ( !on ) { return EOFF; } if ( busy ) { return EBUSY; } else { busy = TRUE; } cmd = CMD_READ_STATUS; currentClient = client; return performCommand(); } /* FIXME: these don't seem to work */ command error_t SensirionSht11.writeStatusReg[ uint8_t client ]( uint8_t val ) { if ( !on ) { return EOFF; } if ( busy ) { return EBUSY; } else { busy = TRUE; } cmd = CMD_WRITE_STATUS; newStatus = val; currentClient = client; return performCommand(); } // performCommand() returns both error_t and status reg -- fortunately, error_t is 8bit error_t performCommand() { initPins(); resetDevice(); transmissionStart(); cmd &= 0x1F; // clear the first 3 address bits to 000 sendCommand(cmd); if ( waitForResponse() != SUCCESS ) { busy = FALSE; return FAIL; } switch(cmd) { case CMD_SOFT_RESET: call Timer.startOneShot( TIMEOUT_RESET ); break; case CMD_MEASURE_TEMPERATURE: enableInterrupt(); if ( status & SHT11_STATUS_LOW_RES_BIT ) { call Timer.startOneShot( TIMEOUT_12BIT ); } else { call Timer.startOneShot( TIMEOUT_14BIT ); } break; case CMD_MEASURE_HUMIDITY: enableInterrupt(); if ( status & SHT11_STATUS_LOW_RES_BIT ) { call Timer.startOneShot( TIMEOUT_8BIT ); } else { call Timer.startOneShot( TIMEOUT_12BIT ); } break; case CMD_READ_STATUS: { uint8_t tempStatus; uint8_t crc; tempStatus = readByte(); crc = readByte(); endTransmission(); status = tempStatus; // FIXME: need to check CRC! post signalStatusDone(); } case CMD_WRITE_STATUS: writeByte( newStatus ); if ( waitForResponse() != SUCCESS ) { writeFail = TRUE; } else { status = newStatus; } post signalStatusDone(); } // leave the device busy...we're waiting for an interrupt return SUCCESS; } void initPins() { call CLOCK.makeOutput(); call CLOCK.clr(); call DATA.makeInput(); call DATA.set(); call InterruptDATA.disable(); } void resetDevice() { uint8_t i; call DATA.makeOutput(); call DATA.set(); call CLOCK.clr(); for( i = 0; i < 9; i++ ) { call CLOCK.set(); call CLOCK.clr(); } } void transmissionStart() { call DATA.makeOutput(); call DATA.set(); call CLOCK.clr(); call CLOCK.set(); call DATA.clr(); call CLOCK.clr(); call CLOCK.set(); call DATA.set(); call CLOCK.clr(); } void sendCommand(uint8_t _cmd) { writeByte(_cmd); } void writeByte(uint8_t byte) { uint8_t i; for( i = 0; i < 8; i++ ) { if ( byte & 0x80 ) call DATA.set(); else call DATA.clr(); byte = byte << 1; call CLOCK.set(); call CLOCK.clr(); } } error_t waitForResponse() { call DATA.makeInput(); call DATA.set(); call CLOCK.set(); if (call DATA.get()) { // the device didn't pull the DATA line low // the command wasn't received or acknowledged return FAIL; } call CLOCK.clr(); return SUCCESS; } void enableInterrupt() { call DATA.makeInput(); call DATA.set(); call InterruptDATA.enableFallingEdge(); } event void Timer.fired() { switch(cmd) { case CMD_SOFT_RESET: // driver has waited long enough for device to reset busy = FALSE; signal SensirionSht11.resetDone[currentClient]( SUCCESS ); break; case CMD_MEASURE_TEMPERATURE: // timeout expired with no data interrupt busy = FALSE; signal SensirionSht11.measureTemperatureDone[currentClient]( FAIL, 0 ); break; case CMD_MEASURE_HUMIDITY: // timeout expired with no data interrupt busy = FALSE; signal SensirionSht11.measureHumidityDone[currentClient]( FAIL, 0 ); break; default: // we're in an unexpected state. what to do? break; } } async event void InterruptDATA.fired() { call InterruptDATA.disable(); post readSensor(); } task void readSensor() { uint16_t data = 0; uint8_t crc = 0; if ( busy == FALSE ) { // the interrupt was received after the timeout. // we've already signaled FAIL to the client, so just give up. return; } call Timer.stop(); data = readByte() << 8; data |= readByte(); crc = readByte(); endTransmission(); switch( cmd ) { case CMD_MEASURE_TEMPERATURE: busy = FALSE; signal SensirionSht11.measureTemperatureDone[currentClient]( SUCCESS, data ); break; case CMD_MEASURE_HUMIDITY: busy = FALSE; signal SensirionSht11.measureHumidityDone[currentClient]( SUCCESS, data ); break; default: break; // unknown command - shouldn't reach here } } uint8_t readByte() { uint8_t byte = 0; uint8_t i; for( i = 0; i < 8; i++ ) { call CLOCK.set(); if (call DATA.get()) byte |= 1; if (i != 7) byte = byte << 1; call CLOCK.clr(); } ack(); return byte; } void ack() { call DATA.makeOutput(); call DATA.clr(); call CLOCK.set(); call CLOCK.clr(); call DATA.makeInput(); call DATA.set(); } void endTransmission() { call DATA.makeOutput(); call DATA.set(); call CLOCK.set(); call CLOCK.clr(); } task void signalStatusDone() { bool _writeFail = writeFail; switch( cmd ) { case CMD_READ_STATUS: busy = FALSE; signal SensirionSht11.readStatusRegDone[currentClient]( SUCCESS, status ); break; case CMD_WRITE_STATUS: busy = FALSE; writeFail = FALSE; signal SensirionSht11.writeStatusRegDone[currentClient]( (_writeFail ? FAIL : SUCCESS) ); break; default: // shouldn't happen. break; } } default event void SensirionSht11.resetDone[uint8_t client]( error_t result ) { } default event void SensirionSht11.measureTemperatureDone[uint8_t client]( error_t result, uint16_t val ) { } default event void SensirionSht11.measureHumidityDone[uint8_t client]( error_t result, uint16_t val ) { } default event void SensirionSht11.readStatusRegDone[uint8_t client]( error_t result, uint8_t val ) { } default event void SensirionSht11.writeStatusRegDone[uint8_t client]( error_t result ) { }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -