Pause and Resume incrementing

Hello Every body,

Here I am stuck again in another problem. I want to have an FM radio channel search or radio station scan utility with Arduino and a TV tuner plus peripheries (audio etc.). I managed to get the scan function to increment; honestly, I got it accidentally, though, I tried to learn from some posts like this one Adding code to fm sweep - #18
but I couldn't.
I didn't know how get the equivalent of the "radio.setFrequency" in my code, I got errors in the IDE. So I gave up.

// scan 88.00 to 108.00 with increments of 0.1
  for ( uint32_t chanx100 = 8800 ; chanx100 < 10800 ; chanx100 += 10 ) {
    radio.setFrequency( (float)( chanx100 / 100 ) );
    delayMicroseconds( 250 ) ;  // note:the .cpp file has a delay of 100ms anyway per channel change
  }
  digitalWrite(led, LOW);
  delay( 100 ) ;
}

But that's not the issue now as I have a function that increments and stops(forever!).
I need to resume the search upwards incrementing or downwards decrementing by pressing corresponding buttons.
Lots of thanks in advance!

//11.06.2024

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>       
LiquidCrystal_I2C lcd(0x27, 16, 2);  
uint16_t FM = 0;  //2890;//2890*3.2/64-37
int upButton = 8;
int downButton = 7;
uint16_t FM_End = 2915;
uint16_t FM_Start = 2500;

byte ZeroChar[8] = {
  B00000, B00000, B00000, B00000, B00000, B00000, B00000, B11111
};
byte FirstChar[8] = {
  B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111
};
byte SecondChar[8] = {
  B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111
};
byte ThirdChar[8] = {
  B00000, B00000, B00000, B00000, B11111, B11111, B11111, B11111
};
byte FourthChar[8] = {
  B00000, B00000, B00000, B11111, B11111, B11111, B11111, B11111
};
byte FifthChar[8] = {
  B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111
};
byte SixthChar[8] = {
  B00000, B11111, B11111, B11111, B11111, B11111, B11111, B11111
};
byte SeventhChar[8] = {
  B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111
};



void setup() 
{
  Wire.begin();
  Wire.beginTransmission(0x61);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.createChar(0, ZeroChar);
  lcd.createChar(1, FirstChar);
  lcd.createChar(2, SecondChar);
  lcd.createChar(3, ThirdChar);
  lcd.createChar(4, FourthChar);
  lcd.createChar(5, FifthChar);
  lcd.createChar(6, SixthChar);
  lcd.createChar(7, SeventhChar);
  pinMode(upButton, INPUT);
  pinMode(downButton, INPUT);
  pinMode(A0, INPUT);
  delay(200);
  lcd.clear();
}

void loop() 
{
  FM_Band();
  RSSI(); 
}
  
  
  
  
    void FM_Band() 
 {

  
  Wire.beginTransmission(0x61);
  uint16_t fpd = 0;
  fpd = (FM + 107);
  Wire.write(fpd >> 8);    //DB1
  Wire.write(fpd & 0xFF);  //DB2
  Wire.write(0xC0);        //CB
  Wire.write(0x01);        //BB
   
    
     if (FM <= FM_Start)
      {
        FM = (FM_Start);
      }
    else 
  
      if (FM >= FM_End)
      
       {
       
       FM = (FM_Start);
       
      }
    delay(100);
    FM++;
    
    int RSS_IN = analogRead(A0);
    RSS_IN = map(RSS_IN, 0, 1023, 0, 8);
    if (RSS_IN >= 4)
    {
      while(1)
     {

     }
     
    }
    
    lcd.print("RF:          MHz");
    lcd.setCursor(3, 0);
    lcd.print(FM * 3.2 / 64 - 37);  //DB1+DB2x32/640-IF
    
    Wire.endTransmission();
    Wire.requestFrom(0x61, 1);
   if (upButton == 0)
  {
    FM++;
  }
  }
 
 
 
 void RSSI()
  {
  int RSS_IN = analogRead(A0);
  RSS_IN = map(RSS_IN, 0, 1023, 0, 8);
  lcd.setCursor(0, 1);
  if (RSS_IN == 0) 
  {
    lcd.setCursor(0, 1);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
  
  }
  if (RSS_IN == 1) 
  {
    lcd.setCursor(0, 1);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)1);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
  
  }
  if (RSS_IN == 2) 
  {
    lcd.setCursor(0, 3);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)1);
    lcd.write((byte)2);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
  
  }
  if (RSS_IN == 3) 
  {
    lcd.setCursor(0, 3);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)1);
    lcd.write((byte)2);
    lcd.write((byte)3);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
  
  }
  if (RSS_IN == 4) 
  {
    lcd.setCursor(0, 3);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)1);
    lcd.write((byte)2);
    lcd.write((byte)3);
    lcd.write((byte)4);
    lcd.write((byte)0);
    lcd.write((byte)0);
    lcd.write((byte)0);
  
  }
  if (RSS_IN == 5) 
  {
    lcd.setCursor(0, 3);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)1);
    lcd.write((byte)2);
    lcd.write((byte)3);
    lcd.write((byte)4);
    lcd.write((byte)5);
    lcd.write((byte)0);
    lcd.write((byte)0);
  
  }
  if (RSS_IN == 6) 
  {
    lcd.setCursor(0, 3);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)1);
    lcd.write((byte)2);
    lcd.write((byte)3);
    lcd.write((byte)4);
    lcd.write((byte)5);
    lcd.write((byte)6);
    lcd.write((byte)0);
  
  }
  if (RSS_IN == 7) 
  {
    lcd.setCursor(0, 3);
    lcd.print("RSSI: ");
    lcd.write((byte)0);
    lcd.write((byte)1);
    lcd.write((byte)2);
    lcd.write((byte)3);
    lcd.write((byte)4);
    lcd.write((byte)5);
    lcd.write((byte)6);
    lcd.write((byte)7);
  
  }
 }

that's called an infinite loop - if you arrive there, you are stuck forever.

why would you do that?

How do you know the radio is locked on a good frequency ? is that this analogRead(A0)?

you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

1 Like

Thanks a lot! Well, to stop the incrementing once there's a station or a strong signal. I connect the radio signal to A0 to respond to the if (stronger than 4 bars) or if (there's a station stronger than 4 bars) stop(at that frequency) and stay tuned there, here I can't express it in Arduino it's not my mother tongue :slightly_smiling_face:. But I also need a way to get out of the While(1), custom search strong stations and stop at any, but if it's not what I want, I need to skip it and resume the search! Do you see what I mean. I'll study your suggestion.

Here is an example with a state machine

To summarise the requirements.

  • You have a given frequency between 87.50 MHz (or 88.00) and 108.00 MHz
  • frequencies can be changed through scanning with a 0.1 MHz step
  • a strong signal is detected by the analog read on A0 being > half the value (512)

Your system has a button and when you press on the button it scans up (and circle) until a strong signal is detected in which case it stops the scanning process. Pressing on the button whilst scanning will also stop the scanning process.

try this simulation :

the button will start or stop the scanning process and you can "fake" the RSSI level by moving the potentiometer.

click to see the code
/* ============================================
  code is placed under the MIT license
  Copyright (c) 2024 J-M-L
  For the Arduino Forum : https://forum.arduino.cc/u/j-m-l

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/


#include <Wire.h>
#include <hd44780.h>                        // main hd44780 header https://www.arduino.cc/reference/en/libraries/hd44780
#include <hd44780ioClass/hd44780_I2Cexp.h>  // i2c expander i/o class header
#include <Toggle.h>                         // https://www.arduino.cc/reference/en/libraries/toggle


const uint8_t nbCols = 16;
const uint8_t nbRows = 2;
hd44780_I2Cexp lcd;

const byte scanPin = 2;
Toggle scanButton;

const uint16_t minFrequency = 8750;
const uint16_t maxFrequency = 10800;
const uint16_t frequencyStep = 10;
const unsigned long pauseDuration = 25; // ms in between 2 scans

uint16_t currentFrequency = minFrequency;
byte currentRssi;
const byte rssiThreshold = 4;

enum : byte {AT_REST, SCANNING} scanState = AT_REST;

const byte customChars[][8] PROGMEM = {
  {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00100},
  {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b01110, 0b00100},
  {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b01110, 0b01110, 0b00100},
  {0b00000, 0b00000, 0b00000, 0b00000, 0b01110, 0b01110, 0b01110, 0b00100},
  {0b00000, 0b00000, 0b00000, 0b11111, 0b01110, 0b01110, 0b01110, 0b00100},
  {0b00000, 0b00000, 0b11111, 0b11111, 0b01110, 0b01110, 0b01110, 0b00100},
  {0b00000, 0b11111, 0b11111, 0b11111, 0b01110, 0b01110, 0b01110, 0b00100},
  {0b11111, 0b11111, 0b11111, 0b11111, 0b01110, 0b01110, 0b01110, 0b00100},
};
const byte customCharsCnt = sizeof customChars / sizeof * customChars;

void showRssi() {
  static byte rssiOnLCD = 100;
  if (rssiOnLCD != currentRssi) {
    lcd.setCursor(nbCols - 1, 0);
    lcd.write(currentRssi);
    rssiOnLCD = currentRssi;
  }
}

byte updateRSSI() {
  currentRssi = map(analogRead(A0), 0, 1024, 0, customCharsCnt);
  showRssi();
  return currentRssi;
}

void showFrequency() { // freq x 100 => minFrequency to maxFrequency
  static uint16_t freqOnLcd = 0;
  if (freqOnLcd != currentFrequency) {
    char freqString[10];
    if (currentFrequency < minFrequency || currentFrequency > maxFrequency) freqString[0] = '\0';
    else dtostrf(currentFrequency / 100.0, 6, 2, freqString);
    lcd.setCursor(0, 0);
    lcd.print(freqString);
    freqOnLcd = currentFrequency;
  }
}

void handleScan() {
  static unsigned long chrono;

  updateRSSI();

  switch (scanState) {
    case AT_REST:
      scanButton.poll();
      if (scanButton.onPress()) {
        chrono = millis() - pauseDuration;
        scanState = SCANNING;
      }
      break;

    case SCANNING:
      scanButton.poll();
      if (scanButton.onPress()) {
        // pressing the button will stop the scan
        scanState = AT_REST; // we have a signal top there
      }
      else if (millis() - chrono >= pauseDuration) {
        // go to next frequency
        currentFrequency += frequencyStep;
        if (currentFrequency > maxFrequency) currentFrequency = minFrequency;
        showFrequency();
        chrono = millis();
      } else {
        if (currentRssi >= rssiThreshold) {
          scanState = AT_REST; // we have a signal top there
        }
      }
      break;
  }
}

void setup() {
  scanButton.begin(scanPin);
  Serial.begin(115200);

  int result = lcd.begin(nbCols, nbRows);
  if (result) {
    Serial.print("LCD initialization failed: ");
    Serial.println(result);
    hd44780::fatalError(result);
  }
  for (byte c = 0; c < customCharsCnt; c++) lcd.createChar(c, customChars[c]);
  showFrequency();
  lcd.print(F(" MHz"));
}

void loop() {
  handleScan();
}

PS: I'm using the Toggle library for the button and the hd44780 library for the LCD.

1 Like

Wow! You've done me a great favor! I'm really very grateful.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.