Attiny85 sending 400 bytes with cheap 433MHz module

Hello everyone, this is my first time to enter the community.
I’m doing a little project recently. I need to use the ADC of attiny85 to read the external voltage and convert it into 8-bit data. I want to read voltage every 1 ms, 400 times, and store all the data in an array, like adc_data[400], and then send the 400 bytes data in turn or together? the shorter the sending time, the better. After sending, attiny85 enters sleep mode for 10 seconds. Then it starts reading data 400 times again, and then sending it again. It goes on and on.
I use the Manchester library to send and receive data. The current problem is that my receiver can only receive dozens of bytes at most, and the remaining hundreds of bytes cannot be received. And the sending last time is around 3s, which means a lot of energy would be consumed. I don’t know what the problem is? Can someone help me? Thank you very much.
I’ve also tried using the virtualwire library, but it can only send up to about 12 bytes at a time.
I use the attiny85 and the cheap 433MHz transmitter module at the transmitter end.
The receiver is Arduino uno and 433MHz receiver module.
Attiny85 uses internal clock of 8MHz.
Here is the code I am using.
Thank you very much. If someone can help me.

Sending codes

#include <Manchester.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
/*

Manchester Transmitter example
   In this example transmitter will send one 16 bit number per transmission  

try different speeds using this constants, your maximum possible speed will depend on various factors like transmitter type, distance, microcontroller speed, ...

  MAN_300 0
  MAN_600 1
  MAN_1200 2
  MAN_2400 3
  MAN_4800 4
  MAN_9600 5
  MAN_19200 6
  MAN_38400 7

*/
#define TX_PIN 1  //pin where your transmitter is connected
uint8_t adc_data[400]; // to hold the high byte of the ADC register (ADCH)

ISR(WDT_vect)
  {
  wdt_disable(); 
  }

void myWatchdogEnable(const byte interval)
  {

  noInterrupts();

  wdt_reset();
   
  MCUSR = 0;                          // reset various flags
  WDTCR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCR =  0b01000000 | interval;    // set WDIE, and appropriate delay
 
  ADCSRA &= ~_BV(ADEN);

  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  sleep_bod_disable();
  interrupts();
  sleep_mode();     
 
  }


void setup() {
  
   man.setupTransmit(TX_PIN, MAN_9600);
  
}

void loop() {

 ADMUX =
            (1 << ADLAR) |     // left shift result
            (0 << REFS2) |     // Sets ref. voltage to internal 1.1V, bit 2
            (1 << REFS1) |     // Sets ref. voltage to internal 1.1V, bit 1   
            (0 << REFS0) |     // Sets ref. voltage to internal 1.1V, bit 0
            (0 << MUX3)  |     // use ADC2 for input (PB4), MUX bit 3
            (0 << MUX2)  |     // use ADC2 for input (PB4), MUX bit 2
            (1 << MUX1)  |     // use ADC2 for input (PB4), MUX bit 1
            (0 << MUX0);       // use ADC2 for input (PB4), MUX bit 0

  ADCSRA = 
            (1 << ADEN)  |     // Enable ADC 
            (1 << ADPS2) |     // set prescaler to 64, bit 2 
            (1 << ADPS1) |     // set prescaler to 64, bit 1 
            (0 << ADPS0);      // set prescaler to 64, bit 0  
 for (int i  = 0; i < 400; i++){           
 ADCSRA |= (1 << ADSC);         // start ADC measurement
 while (ADCSRA & (1 << ADSC) ); // wait till conversion complete 
  adc_data[i] = ADCH;               // get the sample value from ADCL 
 delay(1);
 }
 
 for (int i  = 0; i < 400; i++)   
 man.transmit(adc_data[i]);
   
for (int i = 0; i < 10; i++){
  myWatchdogEnable (0b000110);  // 1 second
  // sleep bit patterns:
//  1 second:  0b000110
//  2 seconds: 0b000111
//  4 seconds: 0b100000
//  8 seconds: 0b100001
  }
}

Receicing codes

#include "Manchester.h"
/*

Manchester Receiver example

  In this example receiver will receive one 16 bit number per transmittion

Try different speeds using this constants, your maximum possible speed will 

  depend on various factors like transmitter type, distance, microcontroller speed, ...

  MAN_300 0
  MAN_600 1
  MAN_1200 2
  MAN_2400 3
  MAN_4800 4
  MAN_9600 5
  MAN_19200 6
  MAN_38400 7

*/

#define RX_PIN 7

void setup() {
  Serial.begin(19200);
  man.setupReceive(RX_PIN, MAN_9600);
  man.beginReceive();
}

void loop() {
  if (man.receiveComplete()) {
    uint8_t m = man.getMessage();
    Serial.println(m);
    man.beginReceive(); //start listening for next message right after you retrieve the message
  }
}

400 bytes of data is a LOT for a device that has just 512 bytes of RAM.

What is the transmission speed of those unspecified 433 MHz modules?

How do they communicate with the ATtiny?

wvmarle:
400 bytes of data is a LOT for a device that has just 512 bytes of RAM.

What is the transmission speed of those unspecified 433 MHz modules?

How do they communicate with the ATtiny?

Thanks for your reply. I use this 433MHz module.

the transmission speed of this module is less than 10Kbps.

So usually what is the maxmum bytes can be sent?

No direct experience with those devices, other people may have.

You appear to use 9600 kbps, that's normally 960 Bps (assuming one start and one stop bit). So in ideal conditions getting to this maximum speed you'd need just over 0.4 seconds at the very least just to transmit your 400 bytes of data.

You send the data one byte at a time with that Manchester library, which very likely adds its own overhead to it - such as one or more packet start and stop bytes. Then you're very quickly getting to 3 seconds.

wvmarle:
No direct experience with those devices, other people may have.

You appear to use 9600 kbps, that’s normally 960 Bps (assuming one start and one stop bit). So in ideal conditions getting to this maximum speed you’d need just over 0.4 seconds at the very least just to transmit your 400 bytes of data.

You send the data one byte at a time with that Manchester library, which very likely adds its own overhead to it - such as one or more packet start and stop bytes. Then you’re very quickly getting to 3 seconds.

Manchester library provides the examples of sending and receiving array. Can I use that to send hundreds of bytes at a time? I am a newbie. Sincerely thank you for your help.

Transmitter codes

#include <Manchester.h>

/*

  Manchester Transmitter example
  
  In this example transmitter will send 10 bytes array  per transmittion

  try different speeds using this constants, your maximum possible speed will 
  depend on various factors like transmitter type, distance, microcontroller speed, ...

  MAN_300 0
  MAN_600 1
  MAN_1200 2
  MAN_2400 3
  MAN_4800 4
  MAN_9600 5
  MAN_19200 6
  MAN_38400 7

*/

#define TX_PIN  5  //pin where your transmitter is connected
#define LED_PIN 13 //pin for blinking LED

uint8_t moo = 1; //last led status
uint8_t data[20] = {11, '1','2', '3', '4', '5', '6', '7', '8', '9','1','2','3','4','5','6','7','8','9'};

void setup() 
{
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, moo);
  man.workAround1MhzTinyCore(); //add this in order for transmitter to work with 1Mhz Attiny85/84
  man.setupTransmit(TX_PIN, MAN_9600);
}


uint8_t datalength=2;   //at least two data
void loop() 
{

  data[0] = datalength;

  man.transmitArray(datalength, data);
  moo = ++moo % 2;
  digitalWrite(LED_PIN, moo);


  delay(800);
  datalength++;
  if(datalength>18) datalength=2;
}

Receiver Codes

#include "Manchester.h"

/*

  Manchester Receiver example
  
  In this example receiver will receive array of 10 bytes per transmittion

  try different speeds using this constants, your maximum possible speed will 
  depend on various factors like transmitter type, distance, microcontroller speed, ...

  MAN_300 0
  MAN_600 1
  MAN_1200 2
  MAN_2400 3
  MAN_4800 4
  MAN_9600 5
  MAN_19200 6
  MAN_38400 7

*/

#define RX_PIN 4
#define LED_PIN 13

uint8_t moo = 1;
#define BUFFER_SIZE 22
uint8_t buffer[BUFFER_SIZE];

void setup() 
{
  pinMode(LED_PIN, OUTPUT);  
  digitalWrite(LED_PIN, moo);
  Serial.begin(19200);
  man.setupReceive(RX_PIN, MAN_9600);
  man.beginReceiveArray(BUFFER_SIZE, buffer);
}

void loop() 
{
  if (man.receiveComplete()) 
  {
    uint8_t receivedSize = 0;

    //do something with the data in 'buffer' here before you start receiving to the same buffer again
    receivedSize = buffer[0];
    for(uint8_t i=1; i<receivedSize; i++)
      Serial.write(buffer[i]);
    
    Serial.println();

    man.beginReceiveArray(BUFFER_SIZE, buffer);
    moo = ++moo % 2;
    digitalWrite(LED_PIN, moo);
  }
}

What happens when you try it out?

wvmarle:
What happens when you try it out?

I just cannot receive anything using the sending-array codes.
And I can't understand the loop section in the transmitting codes. Why not just use man.transmitArray(10, data);

uint8_t datalength=2;   //at least two data
void loop() 
{

  data[0] = datalength;

  man.transmitArray(datalength, data);
  //moo = ++moo % 2;
  //digitalWrite(LED_PIN, moo);


  delay(800);
  datalength++;
  if(datalength>18) datalength=2;
}

I'm curious, because I've "played" with these occaisonally so here's some questions.

Why does it have to be an AtTiny?
Why the rest of the needed specifications? (They are very limiting/very specific, especially the 400 readings @ 1ms sampling rate and 10s sending/update period)
Where does the data go off to after it's been received?
What is the implication of losing any bytes in each of those (long) blocks of data?
Do you know what "broadcast" protocols are, and what they look like? (udp for example), including at the low level "on the wire"?
Are you familiar as much as possible with the chararcteristics of the 433 modules? And transmitting rf data in general?

Do you have access to an oscillosope?

Have you considered any other modules that may be more suited to larger payloads/faster/more reliable throughput?

What range do you need - I'm gessing that you already believe it's within the capability of 433 modules, so it must be short?

What makes you think that a packet payload of say 8 bytes at a time, prevents the use of virtual wire? (from
memory it's designed for modules like these), apart from the 400b, 10s update time?

Have you tried virtual wire with smaller payloads, or is that (12) just the stated limit?
That's enough q for now!

azeo:
I'm curious, because I've "played" with these occaisonally so here's some questions.

Why does it have to be an AtTiny?
Why the rest of the needed specifications? (They are very limiting/very specific, especially the 400 readings @ 1ms sampling rate and 10s sending/update period)
Where does the data go off to after it's been received?
What is the implication of losing any bytes in each of those (long) blocks of data?
Do you know what "broadcast" protocols are, and what they look like? (udp for example), including at the low level "on the wire"?
Are you familiar as much as possible with the chararcteristics of the 433 modules? And transmitting rf data in general?

Do you have access to an oscillosope?

Have you considered any other modules that may be more suited to larger payloads/faster/more reliable throughput?

What range do you need - I'm gessing that you already believe it's within the capability of 433 modules, so it must be short?

What makes you think that a packet payload of say 8 bytes at a time, prevents the use of virtual wire? (from
memory it's designed for modules like these), apart from the 400b, 10s update time?

Have you tried virtual wire with smaller payloads, or is that (12) just the stated limit?
That's enough q for now!

In fact, what I want to achieve are as follows:
The first is ultra-low power consumption, because it is ready to be applied to the back end of piezoelectric energy harvesting system. Then, I need to collect the voltage data from a sensor as many as possible and transmit them wirelessly for subsequent analysis. I don't care about the transmission distance now, as long as I can get a lot of data collected accurately.
Is there any other better solution?

NICKLONG:
The first is ultra-low power consumption

Then the ATtiny85 is a pretty poor choice - it's an old design. It still uses about 2µA in power-down mode, WDT off and 3V power supply; 5 mA at 8 MHz/5V when active.

Even the ATmega328P (as used in the Arduino) betters it: 0.1 µA at the same conditions, 4 mA at 8 MHz/5Vwhen active.

The new ATtiny814 and siblings also offer excellent power consumption.

Do read the data sheets! Don't think "it's smaller so uses less power" as that's not necessarily related.

I’ve also tried using the virtualwire library, but it can only send up to about 12 bytes at a time.

That is not true. The default is 80 bytes maximum per transmission.

VirtualWire is one of the best choices, as it is small and very reliable. To send 400 bytes, send 5x80 byte or 8x50 byte records.

Most of the AT series of microprocessors have similar, ultra low power consumption, if you use them correctly, so there is no point in using anything smaller than the ATmega328. To learn how to do that, study this outstanding tutorial on low power operation: https://www.gammon.com.au/power

Example of micropower (solar) remote sensing Arduino: https://www.gammon.com.au/forum/?id=12821

NICKLONG:
..... Is there any other better solution?

That's something you will have to continue to investigate yourself, you have some great leads to follow up.
Here are a few more leads;

The virtual wire library was updated a while ago, and now includes a variety of protocols/packetising methods for various rf modules including ASK (like TX/C1 type) and wire-wire.
http://www.airspayce.com/mikem/arduino/RadioHead/
It seems to have a default data rate of 2000bps so you may want to do some spreadsheeting of time vs payload/bps/overhead.

The TX433 type units seem to have a quoted maximun of 100kbps, I don't know whether to believe that but you would need to do some futher benchtesting at various rates/payloads, preferably with an Uno/Nano etc transmitting initially, to avoid any limitations of a Tiny while testing/verifying.

The TX/C1 can be/should be powered off while in sleep to reduce standby consumption (which you may have already planned).

I'm aware that Texas Instruments have put some effort into energy harvesting electronics, it's certain that others have too, further googling in that area may also be productive.

In the automotive world, under-piston telemetry has been a thing to improve over many years, and although as far as I know they use magneto-generators, not piezo, the information in various papers may also be useful in some way.

Out of curiousity, will the telemetry unit be self powered, or powered from the piezo+energy harvesting system it is measuring?
Good luck!

NICKLONG:
In fact, what I want to achieve are as follows:
The first is ultra-low power consumption, because it is ready to be applied to the back end of piezoelectric energy harvesting system. Then, I need to collect the voltage data from a sensor as many as possible and transmit them wirelessly for subsequent analysis. I don't care about the transmission distance now, as long as I can get a lot of data collected accurately.
Is there any other better solution?

Thank you for your suggestion. Now I use atmega328p-pu instead of attiny85. And I use the latest Radiohead library to send and receive data. At present, I can send up to 100 bytes of data at a time. I don't know if there is room for improvement. When sending, the current is about 7.5mA. When in sleep mode, there is 164uA. I measured it with a multimeter. I don't know if it's accurate. During sleep, the current does not reach a few microamperes. Maybe it's because the multimeter can't measure such a small current. Next I will test it with other instruments. Thank you very much for your help.

jremington:
That is not true. The default is 80 bytes maximum per transmission.

VirtualWire is one of the best choices, as it is small and very reliable. To send 400 bytes, send 5x80 byte or 8x50 byte records.

Most of the AT series of microprocessors have similar, ultra low power consumption, if you use them correctly, so there is no point in using anything smaller than the ATmega328. To learn how to do that, study this outstanding tutorial on low power operation: https://www.gammon.com.au/power

Example of micropower (solar) remote sensing Arduino: https://www.gammon.com.au/forum/?id=12821

Thank you very much for your reply. Indeed, virtual wire can transmit up to 80 bytes at a time. Can this be changed? Now I use the latest Radiohead library and manually change the maximum transfer limit in the header file, and now I can send 100 bytes of data at a time. Gammon's tutorial is very well written. I've seen it. Thank you again for your help.

azeo:
That's something you will have to continue to investigate yourself, you have some great leads to follow up.
Here are a few more leads;

The virtual wire library was updated a while ago, and now includes a variety of protocols/packetising methods for various rf modules including ASK (like TX/C1 type) and wire-wire.
RadioHead: RadioHead Packet Radio library for embedded microprocessors
It seems to have a default data rate of 2000bps so you may want to do some spreadsheeting of time vs payload/bps/overhead.

The TX433 type units seem to have a quoted maximun of 100kbps, I don't know whether to believe that but you would need to do some futher benchtesting at various rates/payloads, preferably with an Uno/Nano etc transmitting initially, to avoid any limitations of a Tiny while testing/verifying.

The TX/C1 can be/should be powered off while in sleep to reduce standby consumption (which you may have already planned).

I'm aware that Texas Instruments have put some effort into energy harvesting electronics, it's certain that others have too, further googling in that area may also be productive.

In the automotive world, under-piston telemetry has been a thing to improve over many years, and although as far as I know they use magneto-generators, not piezo, the information in various papers may also be useful in some way.

Out of curiousity, will the telemetry unit be self powered, or powered from the piezo+energy harvesting system it is measuring?
Good luck!

Thank you very much for your help. I'm currently replacing attiny85 with atmega328p-pu. And used your recommended Radiohead library to send and receive data. I changed the RH_ASK_MAX_PAYLOAD_LEN in the RH_ASK.h file to 110. Currently, it can send 100 bytes at a time. But when I change it to a higher value, I can only send 100 bytes as well. Is it because its default data rate is 2000 bps? How can I change this value?

// Maximum message length (including the headers, byte count and FCS) we are willing to support
// This is pretty arbitrary
#define RH_ASK_MAX_PAYLOAD_LEN 110

well, the project I build will be powered by piezo energy harvesting system.

Thank you again!

Nick

But when I change it to a higher value, I can only send 100 bytes as well.

You did something wrong, and forgot to provide the evidence for what you did.

There is undoubtedly more than one change that needs to be made, but there is no reason at all to do so. Break the 400 bytes into 4x100 byte records and send those.

NICKLONG:
Thank you very much for your help. I'm currently replacing attiny85 with atmega328p-pu. And used your recommended Radiohead library to send and receive data. I changed the RH_ASK_MAX_PAYLOAD_LEN in the RH_ASK.h file to 110. Currently, it can send 100 bytes at a time. But when I change it to a higher value, I can only send 100 bytes as well. Is it because its default data rate is 2000 bps? How can I change this value?

well, the project I build will be powered by piezo energy harvesting system.

Thank you again!

Nick

No problem, it looks like you haven't quite understood jremingtons suggestion above, so go back and have another look. You don't have to fiddle with the library files. It's nothing to do with the bit rate. You can send any total number of bytes you want as discrete records/packets, a certain number of bytes at a time, and re-assemble at the receiver. In each packet you could include a byte numbering the record. You would also need some error recognition code at the reciever to decide what to do when/if a packet not received or corrupted. edit > sorry, I missed seeing jremingtons reply when posting this so was referring to the earlier reply

The longer the records/packets you send, the greater the chance of corruption. The default maximum may work fine at short range, but if not, you could try sending a greater number of shorter packets as jr suggested, or even shorter. Even though it would add to the over head, there's less chance of corruption, and if there is, less impact on the the total record of 400 bytes.

There's also some "fine print" about the use of AtTinys with the library on the web page useful to read.

Also found this, which should be useful https://www.electrodragon.com/wp-content/uploads/2012/04/VirtualWire.pdf

It will be interesting to see/hear if a piezo harvests enough energy for telemetry, there's certainly good learning outcomes in the project.

You would also need some error recognition code at the reciever to decide what to do when/if a packet not received or corrupted.

VirtualWire automatically calculates CRCs and rejects packets with CRC errors, but to detect missing packets, a packet numbering system would be required for this project.

Piezoelectric energy harvesters are very interesting and work well, but you are probably going to be limited to short power on periods and short data bursts, which will in turn limit packet size. The smaller the packet, the less error prone, as mentioned above.

VirtualWire expands the data by 50% as part of the error checking protocol, so a 100 byte data packet ends up being about 160 transmitted bytes. At a data rate of 2000 bps, that is a burst of 0.64 seconds.

jremington:
VirtualWire automatically calculates CRCs and rejects packets with CRC errors, but to detect missing packets, a packet numbering system would be required for this project.

Piezoelectric energy harvesters are very interesting and work well, but you are probably going to be limited to short power on periods and short data bursts, which will in turn limit packet size. The smaller the packet, the less error prone, as mentioned above.

I mentioned packet numbering, while also being aware that vw does it's own packet checking so called it "recognition" at the user level :slight_smile:

Good point on the energy cycles.

Nicklong - something to think about once the data transmission is a bit sorted, you will most likely need a powerdown regime, a means of detecting imminent shutdown and saving status to eprom, and a wake-up regime. It may also be prudent/useful to also be continually logging data to some non-volatile memory (such as I2C or SPI flash or maybe even SD card) either for continuation of data sending when interrupted, or manual retrieval if required. More food for thought.

Maybe LoRa is a good option then? Not for its long range but for its low power consumption. Power can probably be tuned all the way down if it's just to cover the range of those 433 MHz modules, and it's much definitely faster than 2kbps.
RadioHead can send 250-odd byte packets on LoRa.