1

I am working on a small RF sensor powered by a battery. I used the code from Mr K. (https://arduino.stackexchange.com/a/55516/65870) as base and adapted it to the RH Ask protocol:

#define F_CPU 8000000  // This is used by delay.h library

#include <util/delay.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <util/crc16.h>

#define LED_PIN           0

#define TX_PIN            4 //3
#define TX_BAUDRATE       2000
#define TX_MILLIINTERVAL  (1000UL/TX_BAUDRATE)
#define TX_MICROINTERVAL  (1000000UL/TX_BAUDRATE)
#define TX_MAXLEN         12
#define RFRepetitions 3
byte RollingCounter = 0;


// Define sensor IDs (for MQTT)
#define SensorIDMoisture 6

// Define moisture sensor variables
#define MoistureSensorPinA    A1
#define MoistureSensorPinD    10
#define MoisturePowerOutPin   1
#define RFPowerPin            3 //4

inline void led(const bool onOff) { digitalWrite(LED_PIN, onOff ? HIGH : LOW); }
inline void tx(const bool onOff) { digitalWrite(TX_PIN, onOff ? HIGH : LOW); }

const uint8_t header[8] = { 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x38, 0x2C };
const uint8_t conv4to6[16] = { 0x0D, 0x0E, 0x13, 0x15, 0x16, 0x19, 0x1A, 0x1C,
                               0x23, 0x25, 0x26, 0x29, 0x2A, 0x2C, 0x32, 0x34 };


// Watchdog timer
#ifndef cbi
  #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
  #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


// Important: Sleep time equals the wdt_length setting multiplied by the wdt_loops_max
#define wdt_loops_max 225
#define wdt_length 9 // 9 = 8 seconds

volatile int wdt_loops = wdt_loops_max; // Start with maximum value in order to have a measurement when powering on the system


void rawSend(const uint8_t * p, uint8_t len) {
  while (len--) {
    const uint8_t val = *p++;
    for (uint8_t mask = 1; mask != 0x40; mask <<= 1) {
      tx(val & mask);
      delayMicroseconds(TX_MICROINTERVAL);
      
//      _delay_ms(TX_MILLIINTERVAL);
    }
  }
}

void send(const uint8_t * buf, const uint8_t len) {
  #define RH_ASK_HEADER_LEN 4
  //  First create the payload ...
  static uint8_t payload[(TX_MAXLEN+3+RH_ASK_HEADER_LEN)*2];
  uint8_t * p = payload;
  uint16_t crc = 0xFFFF;
  uint8_t v = len + 3 + RH_ASK_HEADER_LEN;
  crc = _crc_ccitt_update(crc, v);
  *p++ = conv4to6[v >> 4];
  *p++ = conv4to6[v & 0x0F];

  uint8_t _txHeaderTo = 0xff;
  uint8_t _txHeaderFrom = 0xff;
  uint8_t _txHeaderId = 0;
  uint8_t _txHeaderFlags = 0;
  
    // Encode the headers
    crc = _crc_ccitt_update(crc, _txHeaderTo);
    *p++ = conv4to6[_txHeaderTo >> 4];
    *p++ = conv4to6[_txHeaderTo & 0xf];
    crc = _crc_ccitt_update(crc, _txHeaderFrom);
    *p++ = conv4to6[_txHeaderFrom >> 4];
    *p++ = conv4to6[_txHeaderFrom & 0xf];
    crc = _crc_ccitt_update(crc, _txHeaderId);
    *p++ = conv4to6[_txHeaderId >> 4];
    *p++ = conv4to6[_txHeaderId & 0xf];
    crc = _crc_ccitt_update(crc, _txHeaderFlags);
    *p++ = conv4to6[_txHeaderFlags >> 4];
    *p++ = conv4to6[_txHeaderFlags & 0xf];


  for (uint8_t l = len; l--;) {
    v = *buf++;
    crc = _crc_ccitt_update(crc, v);
    *p++ = conv4to6[v >> 4];
    *p++ = conv4to6[v & 0x0F];
  }
  crc = ~crc;
  v = (uint8_t)crc;
  *p++ = conv4to6[v >> 4];
  *p++ = conv4to6[v & 0x0F];
  v = (uint8_t)(crc >> 8);
  *p++ = conv4to6[v >> 4];
  *p++ = conv4to6[v & 0x0F];

  //  Now transmit the header and the payload ...
  rawSend(header, sizeof(header));
  rawSend(payload, (len + 3 + RH_ASK_HEADER_LEN)*2);
  tx(false);

  //Serial.print("CRC: ");Serial.println(crc);
}

ISR(WDT_vect) 
{
  wdt_loops++;
}

// Sleep
void system_sleep() {
  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();

  sleep_mode();                        // System sleeps here

  sleep_disable();                     // System continues execution here when watchdog timed out
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}

// Setup for Watchdog
void setup_watchdog(int ii) {
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;

  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCR = bb;
  WDTCR |= _BV(WDIE);
}


void setup()   /*----( SETUP: RUNS ONCE )----*/
{
//  pinMode(LEDPin, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  led(false);

  // Initialize moisture sensor
  pinMode(MoistureSensorPinD, INPUT);

  // RF sensor initialization
  //driver.init();

  setup_watchdog(wdt_length); // approximately 8 seconds sleep

}/*--(end setup )---*/



void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{
  if(wdt_loops >= wdt_loops_max)
  {
    //digitalWrite(LEDPin, HIGH);
    led(true);

    
    wdt_loops = 0;
    moisture_measurement();
    
    led(false);
  }  
  system_sleep();


}/* --(end main loop )-- */

void moisture_measurement()
{
  // Activate sensor
  analogWrite(MoisturePowerOutPin,255);  
  analogWrite(RFPowerPin,255);
  _delay_ms(150);
  

  // Turn On RF transmitter
  

  float MoistureMedian   = 0;
 // float sensorValue;
  for(int i = 0;i<=100;i++)
  {
    float sensorValue = analogRead(MoistureSensorPinA);
//    moisture_percentage = ( 100 - ( (sensorValue/1023.00) * 100 ) );
//    moistureSensorSum += moisture_percentage;

    MoistureMedian += ( 1 - ( (sensorValue/1023.00) * 1 ) );
    //delay(1);
    _delay_ms(1);
  }

  // Read digital values
  bool digitalValue = digitalRead(MoistureSensorPinD);

  // Switch off sensor
  analogWrite(MoisturePowerOutPin,0);

  // Transmit value
  TransmitSensorValue(SensorIDMoisture,MoistureMedian);

  _delay_ms(150);
  // Turn Off RF transmitter
  analogWrite(RFPowerPin,0);

}


void MessageEncrypt(int adressIn, int parameterIn, float payloadIn, byte pByteArray[])
{
  pByteArray[0] = (byte)adressIn;

  byte * payloadBArray = (byte *)&payloadIn;
  pByteArray[1] = payloadBArray[0];
  pByteArray[2] = payloadBArray[1];
  pByteArray[3] = payloadBArray[2];
  pByteArray[4] = payloadBArray[3];
    
  RollingCounter = RollingCounter + 1;
  if(RollingCounter > 2)
    RollingCounter = 0;

  pByteArray[5] = RollingCounter;
}

//CRC-8 - based on the CRC8 formulas by Dallas/Maxim
//code released under the therms of the GNU GPL 3.0 license
byte CRC8(const byte *data, byte len) {
  byte crc = 0x00;
  while (len--) {
    byte extract = *data++;
    for (byte tempI = 8; tempI; tempI--) {
      byte sum = (crc ^ extract) & 0x01;
      crc >>= 1;
      if (sum) {
        crc ^= 0x8C;
      }
      extract >>= 1;
    }
  }

  return crc;
}

void TransmitSensorValue(int SensorID, float SensorValue)
{
  byte MessageOut[6];
  MessageEncrypt(SensorID, 1, SensorValue, MessageOut);

    for(int i=0;i<RFRepetitions;i++)
    {
      send((const uint8_t *)&MessageOut, sizeof(MessageOut));
    }  
}

The code runs like a dream as long as I use 2000 as baudrate. As soon as I use another baudrate (500 or 1000) my test receiver does not receive any messages.

Any ideas what is going wrong here?

Thanks :)

0

1 Answer 1

1

I found the problem. I used 2 2032 battery to power the attiny85. The internal clock of the chip is not precise enough when running at 6V. To solve the issue I removed 1 battery. The alternative would be to set the baudrate of the transmitter and receiver to different values (I had to set the receiver to 520 bdps to receive the messages from the transmitter with 500 bdps).

Maybe somebody can reuse my code for his project.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.