2

I'm in the middle of a small project with ATmega8. I would like to read temperature from DS18B20 sensor, and then send results using rf433 transmitter. Everything is fine, but size of my source... ATmega has only 7 168 bytes of memory but yet my binary is 8 310 bytes. I removed any unnessesary things and still it's too much. Could you help me reducing size? I'm using Arduino IDE to write the code, maybe in pure C it would be lighter?

Any help appreciated :)

Code:

// RF433
#include <VirtualWire.h>
// Dallas
#include <DallasTemperature.h>
#include <OneWire.h> 

//const char *message; // Our message to send
const int ONE_WIRE_BUS = 2; //DS18S20 Signal pin on digital 2

//Temperature chip i/o
OneWire oneWire(ONE_WIRE_BUS); // on digital pin 2

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature Sensors(&oneWire);

void setup() {
  // RF433
  vw_set_ptt_inverted(true);
  vw_setup(2000);

  Sensors.begin();
}

void loop() {
  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  Sensors.requestTemperatures(); // Send the command to get temperatures

  float dTmp = Sensors.getTempCByIndex(0);
  // Why "byIndex"? 
  // You can have more than one IC on the same bus. 
  // 0 refers to the first IC on the wire

  char buf[6];
  dtostrf(dTmp, 6, 3, buf);

  char Msg[9];
  strcpy(Msg, "TP:");

  strncat(Msg, buf, 6);

  // Send temp.
  for (int i = 0; i < 10; ++i) // avoid loosing packets
  {
    vw_send((uint8_t *)Msg, strlen(Msg));
    vw_wait_tx();
    delay(300);
  }

  // Sleep 1 min.
  delay(60000);
}
pablo7890
  • 65
  • 9
  • 2
    You are using system functions provided by some library. How do you know the size of those, added up, are not already more than you have? – Jongware Dec 27 '14 at 16:53
  • Agreed. Drop the libraries. Or use a bigger device. – Ignacio Vazquez-Abrams Dec 27 '14 at 16:57
  • Because code like this: // RF433 #include // Dallas #include #include void setup() { } void loop() { } gives only 1506 bytes. So it's not their fault :( – pablo7890 Dec 27 '14 at 16:58
  • 1
    That test is ineffectual. Including the header files isn't enough to link in the libraries; the functions must also actually be called. – Ignacio Vazquez-Abrams Dec 27 '14 at 16:59
  • Thanks. I did few tests and it seems that function dtostrf(dTmp, 6, 3, buf); takes about 1500 bytes. Is there any way to replace that? – pablo7890 Dec 27 '14 at 17:03
  • Also there are few proofs on the Internet that it is possible to do, like here a man says his code fits. I don't know how he did that. For me his code is over 8400 bytes... http://www.robertoinzerillo.com/wordpress/?p=74 – pablo7890 Dec 27 '14 at 17:06
  • 1
    Finally, someone asking for optimization that's not premature! – Kevin Dec 27 '14 at 17:11
  • 1
    Did you try compiler flags? `-Os`? – Kevin Dec 27 '14 at 17:14
  • His code *barely* fit. And he's probably using older versions of the libraries with fewer features. – Ignacio Vazquez-Abrams Dec 27 '14 at 17:15
  • Kevin, thanks for replying! Yes, I just did try this flag as you said, but nothing happened. Ignacio, thanks! I'm gonna look for older libs, because I really doesn't need all stuff is offered in new versions, but getting temp. – pablo7890 Dec 27 '14 at 17:25
  • Well, I tried those old libs and they are not cooperating with my version of IDE anymore.. Any ideas about main question? – pablo7890 Dec 27 '14 at 17:36
  • 3
    If you can live with not sending plain text but rather packed binary representations of your data (i.e. changing the protocol), then you could drop the call to dtostrf(). Even without, a few bytes and useless copying could be saved by using `char msg[9] = "TP:"; dtostrf(dTmp, 6, 3, msg + 3);`. Also, the length of that string should be fixed, or? So no need to strlen() it on every loop iteration afterwards. That said, is this really C code or rather C++ or some derivative of them? I ask because `Sensors.getFoo()` doesn't look like C and if it is, it contains a replacable function pointer. – Ulrich Eckhardt Dec 27 '14 at 17:47
  • Hi. I tried `char msg[9] = "TP:"; dtostrf(dTmp, 6, 3, msg + 3);` and binary is only 7 bytes lighter, so it doesn't help much. I dont fully understand, how to send packed binary representations of data? Arduino language is based on C and C++ with it's own components, heh ;) Thanks – pablo7890 Dec 27 '14 at 18:03
  • 2
    As @UlrichEckhardt said, you shoud try to not use any string in your embedded software. String handling can be very heavy. You could transmit only the binary data and format them as a string on the a PC-based software, for example. – JF002 Dec 27 '14 at 18:58
  • @up Thanks, now I get the point. I made a function: `void sendData(float f) {byte * b = (byte *) &f; Serial.write(b[0]); Serial.write(b[1]); Serial.write(b[2]); Serial.write(b[3]);}` but now how can I "decode" it on Arduino-Receiver (ATMega328P so there's plenty of space)? – pablo7890 Dec 27 '14 at 19:18
  • 1
    Just read 4 bytes into a 32-bit variable. – Ignacio Vazquez-Abrams Dec 29 '14 at 05:14
  • @UlrichEckhardt: The Arduino IDE is g++ with a custom build process that hides away the details such as including common headers and linking libraries. – Ignacio Vazquez-Abrams Dec 31 '14 at 17:50

1 Answers1

0

Thanks all of you, guys. Yesterday I found a way how to accomplish this task. Maybe someone will be looking for the answer in the future, so here it is: I gave up on Dallas library, finally it turned out that it's not first need.

Programming ATmega8 to work with DS18B20 Temperature Sensor and RF433Mhz Transmitter:

#include <OneWire.h> 
// RF433
#include <VirtualWire.h>

int DS18S20_Pin = 2; //DS18S20 Signal pin on digital 2

//Temperature chip i/o
OneWire ds(DS18S20_Pin); // on digital pin 2
int led = 13;
void setup(void) {
  // RF433
  vw_set_ptt_inverted(true);
  vw_setup(2000);

  pinMode(led, OUTPUT);
}

void loop(void) {
  float dTmp = getTemp();
  char buf[6];
  dtostrf(dTmp, 6, 3, buf);

  char Msg[10];
  strcpy(Msg, "TMP:");

  strncat(Msg, buf, 6);
  digitalWrite(led, HIGH);
  for (int i = 0; i < 10; ++i) // avoid loosing packets in the air
  {
    vw_send((uint8_t *)Msg, strlen(Msg));
    vw_wait_tx();
    delay(300);
  }
  digitalWrite(led, LOW);

  // Sleep 15 s.
  delay(15000);
}


float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
    //no more sensors on chain, reset search
    ds.reset_search();
    return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
    //   Serial.println("CRC is not valid!");
    return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
    //   Serial.print("Device is not recognized");
    return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);  
  ds.write(0xBE); // Read Scratchpad


  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }

  ds.reset_search();

  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;

  return TemperatureSum;

}

Above code as a binary takes about 6300 bytes, so there is still a little space left for some improvements.

Hope you'll find it usefull :)

pablo7890
  • 65
  • 9