ATTiny85 not reponding

Hi Folks!
I have written a program to receive information via a 433Mhz receiver that works properly with an Arduino Uno. However, when I put this program into an ATTiny85 it will not work properly. The program is supposed to receive a string, confirm the proper information has been received, and light an LED. SOME information must be being received because one LED lights up saying the message has been received. The other LED, which indicates that the message has been decoded, fails to work properly. The LED connected to A4 on the ATTiny85 lights up whenever the power is applied, regardless of messages sent or not.

#include <VirtualWire.h>        // include the file needed for the RX/TX pair

const int branch_th = 3; // ATTiny pin 2
const int main_th = 4; // ATTiny pin 3
char rcvdMessage[15]; 
String finalMessage;

void setup()
{
    pinMode(branch_th, OUTPUT);
    pinMode(main_th, OUTPUT);
    pinMode(2, OUTPUT);
    pinMode(0, INPUT);
    
    //  Serial.begin(9600);          Configure the serial connection to the computer
    vw_set_ptt_inverted(true);  // Required by the RF module
    vw_setup(2000);            // bps connection speed
    vw_set_rx_pin(0);         // ATTiny pin 7 to connect the receiver data pin 
    vw_rx_start();           // Start the receiver
}
 
void loop()
{

  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
  if (vw_get_message(buf, &buflen))      // We check if we have received data
  {
    int i;      // Message with proper check    
    
        digitalWrite(2, HIGH);  // received a message
    
    for (i = 0; i < buflen; i++)
    {
           rcvdMessage[i] = char(buf[i]);
    }
        rcvdMessage[buflen] = '\0';
        finalMessage = rcvdMessage;

 
  }
  

   if (finalMessage.substring(0,4) ==  "bran")  
      {
        digitalWrite(branch_th, LOW);
	digitalWrite(main_th, HIGH);
	delayMicroseconds(10000);
        finalMessage = ("");
      }
    else if (finalMessage.substring(0,4) ==  "main") 
      {
        digitalWrite(main_th, LOW);
        digitalWrite(branch_th, HIGH);
	delayMicroseconds(10000);
        finalMessage = ("");
      }
    else if (finalMessage.substring(0) ==  "") 
       {
	digitalWrite(main_th, LOW);
        digitalWrite(branch_th, LOW);
	delayMicroseconds(10000);
       }

  }

Any help or advice as to how to repair this problem would be greatly appreciated. Thanks.
Brian

kingbf:
The LED connected to A4 on the ATTiny85 lights up whenever the power is applied, regardless of messages sent or not.

    else if (finalMessage.substring(0) ==  "") 

{
digitalWrite(main_th, LOW);
        digitalWrite(branch_th, LOW);
delayMicroseconds(10000);
      }

}

If you haven't received anything yet, what do you expect that finalMessage will look like? Nothing in this bit checks to see if there has been any message, only the content of that String.

There have been several other questions in the past 2-3 weeks wherein a poster has had difficulty making VW work on the tiny85. I would recommend reaching out to those posters and working with them, if they're still trying - maybe you all working together could figure out whether there's a fundamental problem with VW on the tiny85, or if not, what some of you are doing wrong.

Delta_G,
If no message is sent then the finalmessage will be empty and the indicating LED will be off. If a message is received, and decoded, then one of the indicating LED's will turn on, then set finalmessage to blank and then turn off, effectively "pulsing" one of the desired LED's. My problem is that the message received LED lights up, but so does the LED attached to A4 on the ATTIny85. I believe this means the code is not decoding the "bran" or "main" information being sent, but I can't figure out why. This program written to an Arduino Uno works as desired, but not on the ATTiny85.
Brian

kingbf:
Delta_G,
If no message is sent then the finalmessage will be empty and the indicating LED will be off

That's not what the code says. The piece of code I quoted in my last post doesn't look to see if anything has been received. It only says that if that String is empty (which it will be if you haven't received a message yet) then it should turn on that light.

Delta_G,
If a message is received it should it should actuate one pin high and the other pin low pulsing the output. I have this connected to a self latching relay which drives a bicolor LED. If "bran" is decoded, the LED lights up green. If "main" is decoded, it lights up red. The purpose of the last if statement is to turn off the power to the relay since it is self latching and no longer needs power to maintain its position. You are correct that the last statement outputs nothing effectively because both outputs are low, turning off the relay. My problem goes back to the ATTiny85. When power is applied to it the red LED lights up essentially saying that the message "main" has been received when, if fact, no message has been sent at all. The message received LED (different than the "bran" and "main" LED) is initially off until some message is sent. Once a message is sent, that LED lights up. From powering up condition with the ATTiny86, it does not matter which message is sent, the LED goes from off to on after either message is sent. The red output LED does not change regardless of the message sent. The Arduino with this program works properly. The ATTiny85 with this program does not. I'm baffled.
Brian

OK, I think I had your two LEDS crossed up. I thought LOW was turning them on. SO it looked like that last statement was turning them both on.

void loop()
{

  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;

///////////////////////////////////////////////////////////////////////////////////////////////////////////

// so here you see if there's a message and if there is it will be in buf[]

  if (vw_get_message(buf, &buflen))      // We check if we have received data
  {
    int i;      // Message with proper check    
    
// which is pin 2?
        digitalWrite(2, HIGH);  // received a message
    
// here you copy text from buf[] to rcvdMessage[] and then to String finalMessage.... WHY?

    for (i = 0; i < buflen; i++)
    {
           rcvdMessage[i] = char(buf[i]);
    }
        rcvdMessage[buflen] = '\0';
        finalMessage = rcvdMessage;

// and here is the closing brace for things done IF a message is received 
  }
// and from here on, a message may or may not have been received this time through loop()  

///////////////////////////////////////////////////////////////////////////////////////////////////////////

// so now you process message that might be the last one received, over and over
// simple to say, this block of code belongs inside the if() { } above.

   if (finalMessage.substring(0,4) ==  "bran")  
      {
        digitalWrite(branch_th, LOW);
	digitalWrite(main_th, HIGH);
	delayMicroseconds(10000);
        finalMessage = ("");
      }
    else if (finalMessage.substring(0,4) ==  "main") 
      {
        digitalWrite(main_th, LOW);
        digitalWrite(branch_th, HIGH);
	delayMicroseconds(10000);
        finalMessage = ("");
      }
    else if (finalMessage.substring(0) ==  "") 
       {
	digitalWrite(main_th, LOW);
        digitalWrite(branch_th, LOW);
	delayMicroseconds(10000);
       }

///////////////////////////////////////////////////////////////////////////////////////////////////////////

  }

It works like that on Arduino? Perhaps the timing lets it work. Is the Tiny85 running at 8 MHz or 16?

GoForSmoke,
Thanks for your input. Let me address each of your concerns in turn. The first thing I am looking for is to see if there is a message. If so it goes into rcvdMessage. (pin 2 is physical pin 7 on the ATTiny85) I then add the required delimiter to the end of rcvdMessage. Next I put it into String finalMessage so I can parse the message later.
So you suggest that I put the substring if's right after the original if and then close the original if? I'll try it and see what happens. Thanks.
Brian

kingbf:
GoForSmoke,
Thanks for your input. Let me address each of your concerns in turn. The first thing I am looking for is to see if there is a message. If so it goes into rcvdMessage. (pin 2 is physical pin 7 on the ATTiny85) I then add the required delimiter to the end of rcvdMessage. Next I put it into String finalMessage so I can parse the message later.
So you suggest that I put the substring if's right after the original if and then close the original if? I'll try it and see what happens. Thanks.
Brian

I wondered if pin 2 is your led. Get a message, it turns on. That was my concern.

You can save space on that output message. There is no need to assemble serial output in a single string to send since Arduino can put 1 char at a time extremely faster than they can be sent ... which is 1 at a time.

I suggest that you only need buf as filled by the get function and your stored delimiter. You can print one after the other and the output will be the same as both together. True fact.

C has a full set of text functions in string.h. Substring matching is done with strstr(), for example, and returns a pointer to the substring or NULL if substring not found. The number of chars into the string to the substring is found by subtracting the pointer to the main string from the pointer to the found substring.

The name of every C string array IS a pointer to the string. The name buf is a pointer to the array buf. buf points to buf[0]. buf + 1 points to buf[1]. The text is simply the chars in the array.

So you can get() the message into buf and check for "main" or "bran" in microseconds, send the message received out and then the proper delimiter with anything else you have stored in flash and be done that fast without needing to copy the message even once, though to be truthful the print() will copy all output to the print buffer.

Perhaps if you add leds (and resistors!) to your RX and TX pins you would know if data is streaming?

Whups, forgot to give you a couple of links:

These are references from the base AVR C that Arduino uses. The first one has links to more.

The AVR LibC libraries reference page.

AVR LibC string.h doc.

C++ Strings are not suited to small memory environments. You can get away with using them on Arduinos to some degree but you can do more with C string arrays in the same space. What suits PC's with megabytes of RAM does not fit well with MCU's with a few K RAM or less.
Tiny85 has 512 bytes and for all I know, your crashes happen when a slightly longer message arrives and the String copies itself one time too many. Pow!

as goforsmoke points out, std::strings do a lot of malloc/free afaik.
a char * buffer is fixed but a string even if it is not explicitly doing it, does malloc/free every time you assign to it. it's basically a class that wraps a char* pointer.

ive learned that when i had to debug programs doing segmentation faults while assigning what seemed a constant value to a string.

GoForSmoke and Sonyhome,
Thanks for the advice. Now if I was only more proficient in C I could implement your suggestions. Could you possibly translate your explanation into code I could try on the ATTiny85?
I have an LED connected to pin 2 (physical pin 7) that I am using to indicate reception of a message. This flashes when messages are received. Pins 3 and 4 are the output pins which are used to pulse a self latching relay so do not need to remain on. My objective is to send a message that will select either bran or main and pulse the relay with the correct polarity to set it in the correct position. When no messages are being sent, a null message would cause the relay to have no power, both pins at ground, and remain in its current state until a new message arrives.
The pin 2 LED currently flashes when messages are sent but the if statements do not decode the message. This where I am hung up. Any help is greatly appreciated. Thanks.
Brian
PS At power up pin 4 (physical pin 3 on the ATTiny85) goes high. No idea why.
Brian

This is untested, not even compiled but about right. And I leave it up to you to start figuring out what it’s supposed to do before asking questions so please don’t ask about strncmp() until you’ve looked it up in string.h. Same with memset().

string.h

Does the VW library set VW_MAX_MESSAGE_LEN or are you supposed to do that?

Will it run as is? I don’t know. I started with your code and I don’t have all the hardware to run it.
Looks like I need to get some cheap RF modules for my collection.

#include <VirtualWire.h>        // include the file needed for the RX/TX pair
#include <string.h>

const int branch_th = 3; // ATTiny pin 2
const int main_th = 4; // ATTiny pin 3

char  buf[ VW_MAX_MESSAGE_LEN ];      // and just what is the max message length?
byte  buflen = VW_MAX_MESSAGE_LEN;

word  msg_led_blink_start, msg_led_blink_time; 


void setup()
{
    pinMode(branch_th, OUTPUT);
    pinMode(main_th, OUTPUT);
    pinMode(2, OUTPUT);
    pinMode(0, INPUT);
    
    vw_set_ptt_inverted(true);  // Required by the RF module
    vw_setup(2000);            // bps connection speed
    vw_set_rx_pin(0);         // ATTiny pin 7 to connect the receiver data pin 
    vw_rx_start();           // Start the receiver
}
 
void loop()
{

  if ( msg_led_blink_time )
  {
    if ((word)( millis() & 0xFFFF ) - msg_led_blink_start >= msg_led_blink_time )
    {
      msg_led_blink_time = 0;
      digitalWrite( 2, LOW );  
    }
  }


  if ( vw_have_message() )    // We check if we have received data
  {
    vw_get_message( buf, &buflen );   // then we get it   
    
    digitalWrite( 2, HIGH );  
    msg_led_blink_start = (word) ( millis() & 0xFFFF );
    msg_led_blink_time = 500U;    // pin 2 should stay HIGH 1/2 second from 'now'
    
    
    if ( !strncmp( buf, "bran", 4 )) 
    {
        digitalWrite(branch_th, LOW);
	digitalWrite(main_th, HIGH);
    }
    else if ( !strncmp( buf, "main", 4 )) 
    {
        digitalWrite(main_th, LOW);
        digitalWrite(branch_th, HIGH);
    }
    else 
    {
	digitalWrite(main_th, LOW);
        digitalWrite(branch_th, LOW);
    }

    delayMicroseconds(10000); // is this necessary?

    memset( buf, 0, VW_MAX_MESSAGE_LEN );


  } // end if have message

}

Reception Functions
vw_rx_start()
Activate the receiver process. You must call this function before any reception can occur. An interrupt-based background process is started which monitors the reception of data.

vw_have_message()
Returns true if message has been received. This is similar to the “available” function of most other libraries.

vw_wait_rx()
Wait for a message to be received. This will only return when a message has been received, otherwise it will wait forever.

vw_wait_rx_max(timeout_ms)
Wait for a message, but give up after “timeout_ms”. Returns true if a message was received, or false if the timeout period elapsed.

vw_get_message(buf, &buflen))
Read the last received message. This should be called only when a message is known to be received with any of the 3 functions above. “buf” is an array where the message is copied. “buflen” should have the array’s maximum size upon input, and upon return the number of bytes actually copied is retured. The function itself returns true if the message was verified correct, or false if a message was received but appears to have been corrupted.

vw_rx_stop()
Disable the receiver process.

GoForSmoke,
Thanks very much. I’ll give it a whirl and let you know how things work out. At least this is a different approach to decoding the message. Again, thanks.
Brian

Brian, that's event driven code.

1st event is a check to see if the message received led is on and if it is, checks if it's time to turn it off and if it is, it turns the led off.

2nd event is a check to see if a new message has been received and if it has, .....

and so it goes round and round in loop().

AVR at 16 MHz without an operating system to drag it down is insanely fast. That code won't tap 1% of the power of the chip. You could clock it down to 1 MHz and it would still be loafing.

Learn this and you can work with state machines next.

I don't have time to figure out your code, but my 2 cents would be to get rid of finammessage, and just do a
if (strstr(rcvdMessage,"bran") != NULL) {...}

And also I'd use Serial.println() to debug the program to see what the program is manipulating...

Pretty much similar approach to goforsmoke.

Cheers.

GoForSmoke and sonyhome,
Thanks for all the advice. I tried GoForSmoke's solution and got numerous compiling errors. As I said, I am far from proficient at C. So, I tried sonyhome's idea and, voila, it works. Now I have to learn more about the string functions that are available and I can get to work so I can parse sections from a string and use them. Thanks for help folks.
Brian

C string library is standard, so google "man strcmp C".

std::string is a c++ class, it's not a char* C string.