Arduino RF Transmitter / Receiver (315Mhz RF Transmitter )

Hello
Anyone familiar with the popular 315Mhz RF Transmitter and Receiver Modules FS1000A
I am using vitualwire examples to send and receive messages. The examples work fine. But when I added an additional task to display LEDs strip light sequence, the program does not seem to find transmitted data in the buffer most of the time. It is running InOutMiniSequence all the time. The timer calls the getData but it finds data once in a while. From time to time it execute LRDirectionWithStop.

What am i missing???

[code]#include <TimerOne.h>
#include <PololuLedStrip.h>
#define LED_SIGNAL_PIN 12
#include <VirtualWire.h>
PololuLedStrip<LED_SIGNAL_PIN> ledStrip;

#define LED_COUNT 42
rgb_color colors[LED_COUNT];
const int led_pin = 13;
const int receive_pin = 11;
int icount = 0;

void setup()
{
delay(100);
Serial.begin(9600); // Debugging only
// Initialise the IO and ISR
vw_set_rx_pin(receive_pin);
vw_setup(2000); // Bits per sec
vw_rx_start(); // Start the receiver PLL running
pinMode(led_pin, OUTPUT);
Timer1.initialize(150000);
Timer1.attachInterrupt(getData); // blinkLED to run every 0.15 seconds
}

volatile unsigned long iDirection = 0; // use volatile for shared variables
volatile unsigned long iSide = 0; // use volatile for shared variables

void loop()
{
Serial.println(iDirection);
if (iDirection == 71)
{
Serial.println(“Right”);
LRDirectionWithStop(2,0,30) ;
}

else if (iDirection == 83)
{
Serial.println(“STOP”);
StopLight(3,2,2); //Stop
}
else {
InOutMiniSequence (0,0,175,50);
}
delay(100);
}

void getData(void)
{
delay(500);
noInterrupts();
iDirection = 0;
iSide = 0;
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
Serial.print("Getting Data ");
Serial.println(icount);

if (vw_get_message(buf, &buflen)) // Non-blocking
{
    digitalWrite(led_pin, HIGH); // Flash a light to show received good message
char sDirection={buf[6]};
char sSide={buf[5]};
iDirection = sDirection;
iSide = sSide;
Serial.print("direction is ");

Serial.println(sDirection);
digitalWrite(led_pin, LOW);
}
interrupts();
icount =++icount;
}

//====== LED runs up and Down
void InOutMiniSequence(int iRed , int iBlue , int iGreen , int idelay)
{
// handleNextPatternButton();
//Run up
for (int g = 0; g < 4; g ++ )
{
colors[ g] = colors[ 6-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[ 7+g] = colors[13-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[14+g] = colors[20-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[21+g] = colors[27-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[28+g] = colors[34-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[35+g] = colors[41-g] =(rgb_color){ iRed, iBlue, iGreen };
ledStrip.write(colors, LED_COUNT);
delay (idelay);
colors[ g] = colors[ 6-g] =(rgb_color){ 0, 0,0 };
colors[ 7+g] = colors[13-g] =(rgb_color){ 0, 0,0 };
colors[14+g] = colors[20-g] =(rgb_color){ 0, 0,0 };
colors[21+g] = colors[27-g] =(rgb_color){ 0, 0,0 };
colors[28+g] = colors[34-g] =(rgb_color){ 0, 0,0 };
colors[35+g] = colors[41-g] =(rgb_color){ 0, 0,0 };
ledStrip.write(colors, LED_COUNT);
delay (10);
}
//Reverse
for (int g = 0; g < 4; g ++ )
{
colors[ 3-g] = colors[ 3+g] =(rgb_color){ iRed, iBlue, iGreen };
colors[10+g] = colors[10-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[17+g] = colors[17-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[24+g] = colors[24-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[31+g] = colors[31-g] =(rgb_color){ iRed, iBlue, iGreen };
colors[38+g] = colors[38-g] =(rgb_color){ iRed, iBlue, iGreen };
ledStrip.write(colors, LED_COUNT);
delay (idelay);
colors[ 3-g] = colors[ 3+g] =(rgb_color){ 0,0,0 };
colors[10+g] = colors[10-g] =(rgb_color){ 0,0,0 };
colors[17+g] = colors[17-g] =(rgb_color){ 0,0,0 };
colors[24+g] = colors[24-g] =(rgb_color){ 0,0,0 };
colors[31+g] = colors[31-g] =(rgb_color){ 0,0,0 };
colors[38+g] = colors[38-g] =(rgb_color){ 0,0,0 };
ledStrip.write(colors, LED_COUNT);
delay (10);
}
}[/code]

I am using Arduino Uno and 32U4

VirtualWire uses Timer1 and requires the interrupts to be active in order to transmit and receive data. You are turning them off in getData.

Hi Jim
I remove them before and the result was the same. I will try again.
Renald

Jim
It was also recommended that before reading the data, you need to stop interrupts and enable after. Timer1 does call getData all the time but it does not find new data. So it skip to the bottom InOutSequence. Which instruction actually pulls data from the receiver? When I manipulate the function by adding delays, it seems to work better.

Renald

In looking more closely at your code (I had only skimmed it before), it is hard to imagine how this could work at all.
VirtualWire already uses the Timer1 interrupt and internally defines a Timer1 ISR, yet you are resetting Timer1 constants and redirecting the Timer1 interrupt to getData.

I think you need to completely rethink the code. I would start with a working VirtualWire example and add to it as necessary, avoiding use of timers 0 and 1. Timer2 is available if you don’t use tone().

Hello.

It sounds like your code worked before you added the PololuLedStrip library and then it stopped working. If that is the case, it might be because the PololuLedStrip library disables interrupts in order to ensure that the colors are written correctly to the LED strip. You could try using the interruptFriendly option of the library which is documented here:

github.com/pololu/pololu-led-strip-arduino

By the way, it looks like getData is called in the ISR and you are delaying for 500 ms inside it. While getData is running, interrupts will be disabled and the board cannot do much else, so it will cause trouble with other libraries that depend on interrupts. You might try making your ISR faster by moving most of the getData features into your loop() function.

–David

Gentlemen
I will try your suggestions and post the results. I know others are interested on getting this to work.
Thank you
Renald

I wasn’t familiar with the LED driver code so looked up the timing requirements. There is this: [quote] However, if you have an interrupt enabled that takes longer than about 5 microseconds for the WS2812B or 8 microseconds for the TM1804, then this interrupt will sometimes cause an extra long low pulse to emitted, which will be interpreted by the LED strip as a reset command. This can cause visible flickering in the LED strip.[/quote]
Given that interrupts are critical to proper operation of VirtualWire and in the receiver case are not short and quick, you will likely have such difficulties.

Jim,
You are correct. I started from scratch using VirtualWire receiver and made changes one at a time. There is indeed an issue with timing. From my test it takes between 26 to 56 loops before it actually finds data in the buffer. When I added my code below InOutMiniSequence (0,0,175,50); it is reduced to 4-5 loops sometimes 7. So, how do I deal with the timing issue? Is there a way to control VirtualWire timing?
void loop()
{
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) // Non-blocking
{
int i;

    digitalWrite(led_pin, HIGH); // Flash a light to show received good message
// Message with a good checksum received, dump it.
Serial.print("Got: ");

for (i = 0; i < buflen; i++)
{
    Serial.print(buf[i], HEX);
    Serial.print(' ');
}
      LRDirectionWithStop(2,0,30) ;  
      Serial.println();
    digitalWrite(led_pin, LOW);
}
else {
Serial.print("Press Button");
Serial.println(iCount);
      InOutMiniSequence (0,0,175,50);
}
    iCount++;

}

The timing for VirtualWire is absolutely critical and would be extremely difficult to change. Are you using the “interrupt friendly” version of the LED library?

I have tried the interrupt friendly and it brought the LED display to a stop. The only really problem is getting the refresh data from the receiver all the time. If I hold the button on the transmitter all the time, which is what I want, the data shows up on the average every 4-6 loops now because the LED stuff slows it down. The response from switching ON or OFF on the transmitter side is not adequate on the receiver end. I am using ARDUINO UNO. Since VirtualWire is using timer1 perhaps another timer should run the LED strips. If so, what would you suggest??
Renald

[quote]I have tried the interrupt friendly and it brought the LED display to a stop.[/quote]There might be a problem with the interrupt friendly version of the LED library, or your use of it.

On the receive end, VirtualWire takes a fair bit of the processor’s time and may not be compatible with the LED library. You could try another approach entirely, and that is a self contained RF system like these keyfob units, perhaps the receiver with the momentary contact output: adafruit.com/product/1095

I am including the version that works but with some delay issues. I also tried to create a toggle switch mode to let it run which ever sequence it is on and only change when it receives a change. Like before the response time is related to timing which is currently the issue.

#include <VirtualWire.h>
#include <PololuLedStrip.h>
#define LED_SIGNAL_PIN 12
PololuLedStrip<LED_SIGNAL_PIN> ledStrip;
#define LED_COUNT 42
rgb_color colors[LED_COUNT];

const int led_pin = 13;
const int receive_pin = 11;
//const int transmit_en_pin = 3;
int iCount=0;
int iState=0;
void setup()
{
    delay(1000);
    Serial.begin(9600);	// Debugging only
    Serial.println("setup");
    // Initialise the IO and ISR
    vw_set_rx_pin(receive_pin);
    vw_setup(4000);	 // Bits per sec
    vw_rx_start();       // Start the receiver PLL running
    pinMode(led_pin, OUTPUT);
 }

void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
	int i;

        digitalWrite(led_pin, HIGH); // Flash a light to show received good message
	// Message with a good checksum received, dump it.
	Serial.print("Got: ");
	
	for (i = 0; i < buflen; i++)
	{
	    Serial.println(buf[i], HEX);
	}
        if (iState==0) {
          iState=1 ;
        }
        else if (iState==1) {
          iState=0 ;
        }
    }
       if (iState==1) LRDirectionWithStop(2,0,30) ;  
       if (iState==0) InOutMiniSequence (0,0,175,50);
        iCount++;
}

//====== LED runs up and Down
void InOutMiniSequence(int iRed , int iBlue , int iGreen , int idelay)
{
//   handleNextPatternButton();
   //Run up
    for (int g = 0; g < 4; g ++ ) 
    {
    colors[   g] = colors[ 6-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[ 7+g] = colors[13-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[14+g] = colors[20-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[21+g] = colors[27-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[28+g] = colors[34-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[35+g] = colors[41-g] =(rgb_color){ iRed, iBlue, iGreen };
    ledStrip.write(colors, LED_COUNT);  
    delay (idelay);
    colors[   g] = colors[ 6-g] =(rgb_color){ 0, 0,0 };
    colors[ 7+g] = colors[13-g] =(rgb_color){ 0, 0,0 };
    colors[14+g] = colors[20-g] =(rgb_color){ 0, 0,0 };
    colors[21+g] = colors[27-g] =(rgb_color){ 0, 0,0 };
    colors[28+g] = colors[34-g] =(rgb_color){ 0, 0,0 };
    colors[35+g] = colors[41-g] =(rgb_color){ 0, 0,0 };
    ledStrip.write(colors, LED_COUNT);  
    delay (10);
    }
    //Reverse
    for (int g = 0; g < 4; g ++ ) 
    {
    colors[ 3-g] = colors[ 3+g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[10+g] = colors[10-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[17+g] = colors[17-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[24+g] = colors[24-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[31+g] = colors[31-g] =(rgb_color){ iRed, iBlue, iGreen };
    colors[38+g] = colors[38-g] =(rgb_color){ iRed, iBlue, iGreen };
    ledStrip.write(colors, LED_COUNT);  
    delay (idelay);
    colors[ 3-g] = colors[ 3+g] =(rgb_color){ 0,0,0 };
    colors[10+g] = colors[10-g] =(rgb_color){ 0,0,0 };
    colors[17+g] = colors[17-g] =(rgb_color){ 0,0,0 };
    colors[24+g] = colors[24-g] =(rgb_color){ 0,0,0 };
    colors[31+g] = colors[31-g] =(rgb_color){ 0,0,0 };
    colors[38+g] = colors[38-g] =(rgb_color){ 0,0,0 };
    ledStrip.write(colors, LED_COUNT);  
    delay (10);
    }
}

Please edit your posts and use code tags.

Jim
I have taken your advice to move to a more self sufficient module to handle the function I was seeking.
I will post results when I get it together.
Thank you

That is undoubtedly for the best. I was curious as to how much CPU time VirtualWire actually consumes, so I ran the standard example receiver program, using a Pro Micro (16 MHz), no receiver and with TIMER1 interrupts on and off. Below is the “sketch”.

With TIMER1 interrupts on, “count” was incremented 155,000 times per second.
With TIMER1 interrupts off, “count” was incremented 199,000 times per second.

So very roughly, 25% of the CPU time is consumed by the VirtualWire interrupt processing.

It is being phased out anyway in favor of smarter RF modules.

[code]// receiver.pde
//
// Simple example of how to use VirtualWire to receive messages
// Implements a simplex (one-way) receiver with an Rx-B1 module
//
// See VirtualWire.h for detailed API docs
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright © 2008 Mike McCauley
// $Id: receiver.pde,v 1.3 2009/03/30 00:07:24 mikem Exp $

#include <VirtualWire.h>
unsigned long count=0;

void setup()
{
Serial.begin(115200); // Debugging only
Serial.println(“setup”);

// Initialise the IO and ISR
vw_set_ptt_inverted(true); // Required for DR3100
vw_setup(2000);	 // Bits per sec

vw_rx_start();       // Start the receiver PLL running

}

void loop()
{
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;

TIMSK1=0;  //<<<< TURN OFF TIMER1 interrupts for testing

unsigned long now = millis();
while (millis()-now < 1000UL) {
count++;
if (vw_get_message(buf, &buflen)) // Non-blocking
{
int i;

    digitalWrite(13, true); // Flash a light to show received good message
// Message with a good checksum received, dump it.
Serial.print("Got: ");

for (i = 0; i < buflen; i++)
{
    Serial.print(buf[i], HEX);
    Serial.print(" ");
}
Serial.println("");
    digitalWrite(13, false);
}

}
Serial.println(count);
count=0;
}
[/code]

When I manipulate the function by adding delays, it seems to work better.