Thursday, August 31, 2023

Using Z-Wave Multilevel sensor example running on BRD2603A/ZGM230S to read temperature from DS18B20 one-wire sensor

The following example shows you how to use Z-Wave 800 Multilevel sensor example running on BRD2603A/ZGM230S to read temperature from DS18B20 one-wire sensor.

1. Connect DS18B20 Vdd, GND, and DQ (add extra 4.7K pull-high to Vdd) to pin 20, 1, and 2(PB03) on EXP-header of BRD2603A.

2. Install USTIMER, Z-Wave Debug, and Z-Wave Debug Print in project software component to use microsecond delay API USTIMER_DelayIntSafe and DEBUGPRINT to output data to SSv5 console 1.

3. Add the following code into MultilevelSensor_interface_sensor.c

#include "em_gpio.h"
#include "ustimer.h" //For microsecond delay
#include "em_core_generic.h" //For critical section

//Use PB03 on BRD2603A
#define DS_GPIO_PORT 1 //gpioPortB
#define DS_GPIO_PIN  3

#define CMD_CONVERTTEMP 0x44
#define CMD_RSCRATCHPAD 0xbe
#define CMD_WSCRATCHPAD 0x4e
#define CMD_CPYSCRATCHPAD 0x48
#define CMD_RECEEPROM 0xb8
#define CMD_RPWRSUPPLY 0xb4
#define CMD_SEARCHROM 0xf0
#define CMD_READROM 0x33
#define CMD_MATCHROM 0x55
#define CMD_SKIPROM 0xcc
#define CMD_ALARMSEARCH 0xec
#define DECIMAL_STEPS_12BIT 625 //.0625

inline void pullLineLow() {
    GPIO_PinModeSet(DS_GPIO_PORT, DS_GPIO_PIN, gpioModePushPull, 0);
}

inline void releaseLine() {
    GPIO_PinModeSet(DS_GPIO_PORT, DS_GPIO_PIN, gpioModeInputPull, 1);
}

inline void delayUs(uint16_t us) {
  USTIMER_DelayIntSafe(us);
}

inline uint32_t readLineState() {
    return GPIO_PinInGet(DS_GPIO_PORT, DS_GPIO_PIN);
}

void writeBit(uint8_t bit){
  //Pull line low for 1uS
  pullLineLow();
  delayUs(1);
  //If we want to write 1, release the line (if not will keep low)
  if(bit) {
        releaseLine();
    }
  //Wait for a while and release the line
  delayUs(20);
  releaseLine();
  delayUs(1);
}

uint8_t readBit(void){
  uint8_t bit = 0;
  //Pull line low for 1uS
  pullLineLow();
  delayUs(1);
  //Release line and wait for a while
  releaseLine();
  delayUs(8);
  //Read line value
  if(readLineState()){
        bit=1;
    }
  //Wait for a while to return read value
  delayUs(40);
  return bit;
}

uint8_t readByte(void){
  uint8_t i = 8, n = 0;
  while(i--){
    //Shift one position right and store read value
    n >>= 1;
    n |= (readBit() << 7);
  }
  return n;
}

void writeByte(uint8_t b){
  uint8_t i = 8;
  while(i--){
    //Write actual bit and shift one position right to make the next bit ready
    writeBit(b & 1);
    b >>= 1;
  }
}

uint32_t reset(){
  uint32_t i;
  pullLineLow();
  delayUs(300);
  releaseLine();
  delayUs(60);
  i = readLineState(); //(0=OK, 1=ERROR)
  delayUs(300);
  return i;
}

/*
    Returns temperature read from DS18B20
    Reading is returned mutiplied by 10000 i.e.
    for 23.4560 degrees the result will be 234560
*/
uint32_t ds18b20GetTemparature(){
  USTIMER_Init();

  //Enter cirtical section
  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();

  //Reset, skip ROM and start temperature conversion
  if(reset()) {
      DPRINT("DS18B20 is not responding---reset temperature conversion\n");
        return 0;
    }
  writeByte(CMD_SKIPROM);
  writeByte(CMD_CONVERTTEMP);

  //Wait until conversion is complete
  uint16_t timeout = 0xFFFF;
  while(!readBit() && timeout > 0) {
        timeout--;
        //Feed WDG to avoid WDG reboot.
        zpal_feed_watchdog();
    }
    if(0 == timeout) {
        DPRINT("DS18B20 temperature conversion has timed out\n");
        return 0;
    }

  //Reset, skip ROM and send command to read Scratchpad
  if(reset()) {
      DPRINT("DS18B20 is not responding---reset Scratchpad\n");
        return 0;
    }
  writeByte(CMD_SKIPROM);
  writeByte(CMD_RSCRATCHPAD);

  uint8_t scratchpad[2] = {0, 0};
  //Read Scratchpad (only 2 first bytes)
  scratchpad[0] = readByte();
  scratchpad[1] = readByte();

  //Exit critial section.
  CORE_EXIT_CRITICAL();

  USTIMER_DeInit();

  int8_t digit = scratchpad[0] >> 4;
  digit |= (scratchpad[1] & 0x7) << 4;
  //Store decimal digits
  uint16_t decimal = scratchpad[0] & 0xf;
  decimal *= DECIMAL_STEPS_12BIT;

    return digit * 10000 + decimal;
}

4. Use the following two lines to replace "MultilevelSensor_temperature_humidity_sensor_read(&rh_data, &temp_data);" in cc_multilevel_sensor_air_temperature_interface_read_value.

    temp_data=ds18b20GetTemparature();
    temp_data=(int32_t)(temp_data/10);

5. Build and run the firmware on BRD2603A to see the following temperature reading from DS18B20.


 

No comments:

Post a Comment