2

I have recently created a sketch for an ATTiny85.

My project consists of:

  • 1x ATTiny85 IC only
  • 1x 433MHz RF module => using data pin 2
  • 2x input digital pins => using pin 3 and pin 4

Running at 16MHz using the ATTiny85 board core from https://github.com/damellis/attiny

All running on a 5v 1A 7805 only using 24.4mA idle 29.5mA when TXing.

I have optimized my code a bit and the sketch works as intended. However sometimes the RF 433 module just keeps sending data for a few seconds instead of sending a burst then waiting for my 7 second timeout.

I do use the internal pullup resistors on pin 3 and 4.

This happens intermittently.. I would like to know if anyone has had a similar problem and knows how to prevent this "runaway transmission".. Or suggestions code improvements etc.

Strangely enough I can get 450m+- line of sight (farm land) distance accurate pings on my sensitive receiver using this cheap module.

RF 433 Module

I have the one with the SMD coil I have also soldered a 17.3cm LAN wire as antenna.

enter image description here

SDR Waterfall

I expect a constant burst every 7s.

enter image description here

Code

The code starts by looping a switch statement over states when an input is H/L or a timer runs out a state is changed.

When a trigger state is initiated a for loop copies and concatinates a condenses hex string then the next for loop sends these signals over pin 2.

After the signal is sent the state then changes to a timeout to wait before sending a pulse again.

This is where the problem is.

Sometimes the signal keeps sending as if the state is stuck for a few seconds but then the timer starts working as expected...

The longer 15min timer works fine, it's only the 7s and 9s loops that seem to have this issue.


Pictures of testing PCB

enter image description here

enter image description here


Full sketch [updated with suggestions]

#include <stdint.h>
#include <avr/io.h>
#include <util/delay.h>

#define DATA_PIN PB2// digital pin 2
#define ALARM_TRIGGER_PIN PB3// digital pin 3
#define LEARN_PIN PB4// digital pin 4

//15min= 900000 ms
//16min = 960000 ms
//20min= 500000 ms
const unsigned long DELAY_TIME_ZONE_HEARTBEAT = 900000;//15min
const unsigned long DELAY_TIME_CHECKALARM_TIMEOUT = 7000;//7sec
const unsigned long DELAY_TIME_CHECKLEARN_TIMEOUT = 9000;//9sec

unsigned long Delay_Start_Check_Alarm = 0;
unsigned long Delay_Start_Heartbeat = 0;
unsigned long Delay_Start_Learn = 0;

char LEARN[] ="269369a6924d36da6c800";//condensed hexadecimal signal; learnState/tamper same signal
char ALARM[] = "da4da69a4934db69b200";//condensed hexadecimal signal
char HEARTBEAT[] ="1269b4d349269b6d36400";//condensed hexadecimal signal
uint16_t pulse = 1100;//Attiny85 chip needs more of delay time
uint8_t i;

//custom states
enum State 
{
  ALARMTIMEOUT,
  CHECKING,
  HEARTBEATTIMEOUT,
  HEARTBEATSEND,
  LEARNTIMEOUT,
  LEARNSEND,
  ALARMSEND
};

enum State state;

void setup() 
{    
  DDRB |= (1 << DATA_PIN);//replaces pinMode(DATA_PIN, OUTPUT);
  DDRB &= ~(1 << ALARM_TRIGGER_PIN); //replaces pinMode(ALARM_TRIGGER_PIN, INPUT);
  DDRB &= ~(1 << LEARN_PIN); //replaces pinMode(LEARN_PIN, INPUT);

  PORTB |= (1 << ALARM_TRIGGER_PIN);//initiate alarm pin pullup
  PORTB |= (1 << LEARN_PIN);//initiate learn pin pullup

  ADCSRA &= ~(1 << ADEN); //Disable ADC, saves ~230uA

  Delay_Start_Check_Alarm = Delay_Start_Heartbeat = Delay_Start_Learn  = millis();//set to start millis
  state = CHECKING;//initial state
}

void Check_Alarm_And_Heartbeat() 
{
  unsigned long Mill = millis();//set to current time

  uint8_t alarmState = PINB&8;//read alarm pin 3
  uint8_t learnState = PINB&16;//read learn pin 4

  //main switch loop
    switch (state) 
    {
    case CHECKING:
         //constant checking here
         if((alarmState) && (!learnState))
          {
           state = ALARMSEND;//set state
           Delay_Start_Check_Alarm = Mill;//keep time
          }
         //learn loop
         if((learnState) && (!alarmState))
         {
           state = LEARNSEND;//set state
           Delay_Start_Learn = Mill;//keep time
         }
         //continue heartbeat
         if((!alarmState) && (!learnState))
         {
           state = HEARTBEATTIMEOUT;//set state
         }
         //if both are high prioratize learnState/tamper signal
         if((alarmState) && (learnState))
         {
           state = LEARNSEND;//set state; learnState/tamper same signal
           Delay_Start_Learn = Mill;//keep time
         }
        break;
    case LEARNSEND:
         {
           state = LEARNTIMEOUT;//set state
           char LEARNFINAL[168];//make LEARNFINAL var and define length
           strcpy(LEARNFINAL, LEARN);//copy LEARN to new LEARNFINAL var
           for (uint8_t i = 0; i < 7; i++) 
           {
             strcat(LEARNFINAL, LEARN);// append/concatenate LEARN 7 times to LEARNFINAL
           }
             for (i = 0; i < sizeof(LEARNFINAL); i++)
             {  
               Send_Hex_Digit(DATA_PIN, LEARNFINAL[i], pulse);//send finished LEARNFINAL var
             }
             //PORTB &= ~(1 << DATA_PIN);//write low
         }
        break;
    case ALARMSEND:
         {
           state = ALARMTIMEOUT;//set state
           char ALARMFINAL[168];//make ALARMFINAL var and define length
           strcpy(ALARMFINAL, ALARM);//copy ALARM to new ALARMFINAL var
            for (uint8_t i = 0; i < 7; i++) 
            {
               strcat(ALARMFINAL, ALARM);// append/concatenate ALARM 7 times to ALARMFINAL
            }
             for (i = 0; i < sizeof(ALARMFINAL); i++)
             {
               Send_Hex_Digit(DATA_PIN, ALARMFINAL[i], pulse);//send finished ALARMFINAL var
             }
             //PORTB &= ~(1 << DATA_PIN);//write low
         }
        break;
    case HEARTBEATSEND:
         {
             state = CHECKING;//change state
             char HEARTBEATPREFINAL[160];//make HEARTBEATPREFINAL var and define length
             strcpy(HEARTBEATPREFINAL, HEARTBEAT);//copy HEARTBEAT to new HEARTBEATPREFINAL var
              for (uint8_t i = 0; i < 7; i++)
              {
                 strcat(HEARTBEATPREFINAL, HEARTBEAT);// append/concatenate HEARTBEAT 7 times to HEARTBEATPREFINAL
              }
             for (i = 0; i < sizeof(HEARTBEATPREFINAL); i++)
             {
               Send_Hex_Digit(DATA_PIN, HEARTBEATPREFINAL[i], pulse);//send finished HEARTBEATPREFINAL var
             }
         }
        break;
    case HEARTBEATTIMEOUT:
             state = CHECKING;//change state
             if ((Mill - Delay_Start_Heartbeat) >= DELAY_TIME_ZONE_HEARTBEAT)
             {
                 Delay_Start_Heartbeat += DELAY_TIME_ZONE_HEARTBEAT;//prevents drift
                 state = HEARTBEATSEND;//change state when time ends
             }
        break;
    case ALARMTIMEOUT:
             state = ALARMTIMEOUT;//change state
             if ((Mill - Delay_Start_Check_Alarm) >= DELAY_TIME_CHECKALARM_TIMEOUT)
             {
                 state = CHECKING;//change state when time ends
             } 
        break;
    case LEARNTIMEOUT:
             state = LEARNTIMEOUT;//change state
             if ((Mill - Delay_Start_Learn) >= DELAY_TIME_CHECKLEARN_TIMEOUT)
             {
                 state = CHECKING;//change state when time ends
             } 
        break;
    default:
        //do nothing
        break;
    }
}

void Send_Hex_Digit(uint8_t pin, char c, uint16_t pulse) 
{
  byte bc = c - 48 ; // convert c to number 0 to 15
  for (int i = 3; i >= 0; i--)
  {
    bitWrite(PORTB, pin, bitRead(bc, i));
    delayMicroseconds(pulse);
  }
}

void loop() 
{
  Check_Alarm_And_Heartbeat();
}
15
  • So after the alarm trigger you want 7s timeout, before the code checks the trigger again? In that case I would expect, that you set Delay_Start_Check_Alarm if the alarm was triggered, but I cannot see such a line. You are setting it in setup and then only incrementing it in the timeout. It is never actually set to the alarm trigger timestamp.
    – chrisl
    Sep 30, 2023 at 23:54
  • Have you got compiler warnings switched on? You are declaring a variable within a case unsigned char HEARTBEATPREFINAL[160] without wrapping the case code in { } to make a block.
    – 6v6gt
    Oct 1, 2023 at 7:00
  • In case CHECKING: you have not considered the combination if((alarmState) && (learnState)) . Even if that should never happen maybe it should be handled?
    – 6v6gt
    Oct 1, 2023 at 7:31
  • @chrisl Thanks for the suggestion! I should only need it to be set in the timeout as the ALARMTIMEOUT switch will loop over itself until the 7s are up, but I'll take a closer look when neatening up
    – Jonas
    Oct 1, 2023 at 11:06
  • @6v6gt Yes compiler warnings were off. I knew something was amiss there. I have implementing your suggestions but sadly the occasional runaway burst is still happening. I may have to just use a blocking delay() but would rather not. Will continue to think about it...
    – Jonas
    Oct 1, 2023 at 11:18

1 Answer 1

1

After implementing the suggestions I was able to make the sketch smaller and also solve the unwanted transmitting for the 2 timeouts (pin3, pin4).

The main issue was a 7s timeout before the sketch checks the High/Low.

This was solved by setting Delay_Start_Check_Alarm and Delay_Start_Learn in my switch statement, if the alarm was triggered.

    Delay_Start_Check_Alarm = Mill;//Setting this solved the issue

The heartbeat did not need this change since it gets set every time HEARTBEATTIMEOUT is called so it works ok.

The code in the question is also updated.

Big thanks to @chrisl, @6v6gt and @timemage.

4
  • void Send_Hex_Digit() could be even smaller with a for loop but the law of diminishing returns soon cuts in.
    – 6v6gt
    Oct 4, 2023 at 17:56
  • @6v6gt Added the for loop made it 1% smaller but still looks good and the ATiny412 sketch will also be happy
    – Jonas
    Oct 5, 2023 at 2:23
  • for (uint8_t i = 4; i > 0; i--) check that loop carefully. I thought i had values from 3 down to 0. But be very careful of using an an unsigned integer as a decrementing loop index. For example for (uint8_t i = 3; i >= 0; i--) gives an infinite loop.
    – 6v6gt
    Oct 5, 2023 at 4:34
  • @6v6gt changed back to int so it should work correctly. for (int i = 3; i >= 0; i--)Will do some more tests as well
    – Jonas
    Oct 5, 2023 at 11:54

Your Answer

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

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