Mirko Pavleski
Published © GPL3+

Linear Scale ТЕА5767 FM Radio on ili9341 TFT Display

Simple FM Radio with a beautiful retro look linear scale.

BeginnerFull instructions provided2 hours3,985
Linear Scale ТЕА5767 FM Radio on ili9341 TFT Display

Things used in this project

Hardware components

ESP32
Espressif ESP32
×1
TFT Touchscreen, 320x240
TFT Touchscreen, 320x240
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1
TEA5767 FM Radio Module
×1
Speaker: 0.25W, 8 ohms
Speaker: 0.25W, 8 ohms
×1
PAM8403 D-class Audio Amplifier
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Schematic

Code

Arduino Code

Arduino
#include <Wire.h>
#include <TEA5767.h>
#include <TFT_eSPI.h>
#include <RotaryEncoder.h>
#include <SPI.h>

#define TFT_GREY 0x5AEB
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);

#define PIN_IN1 16
#define PIN_IN2 17

RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

#define color1 0xC638
#define color2  0xC638

int value=980;
int minimal=880;
int maximal=1080;
int strength=0;
String sta[6]={"Ant.5","92.0","Metro","94.8","Super","97.0"};

float freq=0.00;
TEA5767 radio = TEA5767();

bool muted=0;
int deb=0;


uint32_t targetTime = 0;                    // for next 1 second timeout

static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x

uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time

byte omm = 99, oss = 99;
byte xcolon = 0, xsecs = 0;
unsigned int colour = 0;



void setup() {

  tft.begin();
  tft.writecommand(0x11);
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);


  tft.setTextSize(1);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);

  targetTime = millis() + 1000;

  
  pinMode(0, INPUT_PULLUP);

  Wire.begin(21,22);
    
  spr.createSprite(320,170);
  spr.setTextDatum(4);
  spr.setSwapBytes(true);
  spr.setFreeFont(&Orbitron_Light_24);
  spr.setTextColor(color1,TFT_BLACK);

 
  drawSprite();

}

void readEncoder() {

  static int pos = 0;
  encoder.tick();

  if(digitalRead(0)==0){
    if(deb==0){
      deb=1;
      muted=!muted;
      radio.setMuted(muted);
      drawSprite();
      delay(200);
    }
  }else deb=0;
  
  int newPos = encoder.getPosition();
  if (pos != newPos) {
    
    if(newPos>pos)
    value=value-1;
      if(newPos<pos)
      value=value+1;
    
    pos = newPos;
    
    drawSprite();
  } 

}

void drawSprite()
{
freq=value/10.00;
if(muted==false)
radio.setFrequency(freq);

strength=radio.getSignalLevel();
spr.fillSprite(TFT_BLACK);
spr.setTextColor(TFT_WHITE,TFT_BLACK);

spr.drawFloat(freq,1,160,64,7);
spr.setFreeFont(&Orbitron_Light_24);
spr.drawString("FM Radio",160,12);

spr.drawString("STATIONS",38,14,2);
spr.drawRoundRect(1,1,76,110,4,0xAD55);
spr.drawRoundRect(240,20,76,22,4,TFT_WHITE);

spr.drawRect(290,6,20,9,TFT_WHITE);
spr.fillRect(291,7,12,7,0x34CD);
spr.fillRect(310,8,2,5,TFT_WHITE);

spr.setTextFont(0);
spr.setTextColor(0xBEDF,TFT_BLACK);
for(int i=0;i<6;i++){
spr.drawString(sta[i],38,32+(i*12));
spr.fillCircle(16,31+(i*12),2,0xFBAE);
}
spr.setTextColor(TFT_WHITE,TFT_BLACK);

spr.drawString("SIGNAL:",266,54);
spr.drawString("MUTED",260,102,2);
spr.fillRoundRect(288,96,20,20,3,0xCC40);

if(muted==1)
spr.fillCircle(297,105,6,TFT_WHITE);


for(int i=0;i<strength;i++)
spr.fillRect(244+(i*4),80-(i*1),2,4+(i*1),0x3526);



spr.fillTriangle(156,104,160,114,164,104,TFT_RED);

  
 int temp=value-20;
 for(int i=0;i<40;i++)
 {
 if((temp%10)==0){
  spr.drawLine(i*8,170,i*8,140,color1);
  
  spr.drawLine((i*8)+1,170,(i*8)+1,140,color1);
  spr.drawFloat(temp/10.0,1,i*8,130,2);
  }
 else if((temp%5)==0 && (temp%10)!=0)
 {spr.drawLine(i*8,170,i*8,150,color1);
 spr.drawLine((i*8)+1,170,(i*8)+1,150,color1);
 //spr.drawFloat(temp/10.0,1,i*8,144);
 }
 else
  {spr.drawLine(i*8,170,i*8,160,color1);}
 
  temp=temp+1;
 }
spr.drawString("Stereo: "+String(radio.isStereo()),275,31,2);




spr.drawLine(160,114,160,170,TFT_RED);
spr.pushSprite(0,0);

}

void loop() { 
 
 readEncoder();
   if (targetTime < millis()) {
    // Set next update for 1 second later
    targetTime = millis() + 1000;
    tft.setFreeFont(&Orbitron_Light_24);
    tft.drawString("Time :", 17,186);

    tft.drawRoundRect(5,175,310,57,8,TFT_WHITE);
    //tft.drawRoundRect(240,20,76,22,4,TFT_WHITE)
    
    // Adjust the time values by adding 1 second
    ss++;              // Advance second
    if (ss == 60) {    // Check for roll-over
      ss = 0;          // Reset seconds to zero
      omm = mm;        // Save last minute time for display update
      mm++;            // Advance minute
      if (mm > 59) {   // Check for roll-over
        mm = 0;
        hh++;          // Advance hour
        if (hh > 23) { // Check for 24hr roll-over (could roll-over on 13)
          hh = 0;      // 0 for 24 hour clock, set to 1 for 12 hour clock
        }
      }
    }


    // Update digital time
    int xpos = 110;
    int ypos = 183; // Top left corner ot clock text, about half way down
    int ysecs = ypos; // + 24;

    if (omm != mm) { // Redraw hours and minutes time every minute
      omm = mm;
      // Draw hours and minutes
      if (hh < 10) xpos += tft.drawChar('0', xpos, ypos, 6); // Add hours leading zero for 24 hr clock
      xpos += tft.drawNumber(hh, xpos, ypos, 6);             // Draw hours
      xcolon = xpos; // Save colon coord for later to flash on/off later
      xpos += tft.drawChar(':', xpos, ypos - 8, 6);
      if (mm < 10) xpos += tft.drawChar('0', xpos, ypos, 6); // Add minutes leading zero
      xpos += tft.drawNumber(mm, xpos, ypos, 6);             // Draw minutes
      xsecs = xpos; // Sae seconds 'x' position for later display updates
    }
    if (oss != ss) { // Redraw seconds time every second
      oss = ss;
      xpos = xsecs;

      if (ss % 2) { // Flash the colons on/off
        tft.setTextColor(0x39C4, TFT_BLACK);        // Set colour to grey to dim colon
        tft.drawChar(':', xcolon, ypos, 6);     // Hour:minute colon
        xpos += tft.drawChar(':', xsecs, ysecs, 6); // Seconds colon
        tft.setTextColor(TFT_WHITE, TFT_BLACK);    // Set colour back to yellow
      }
      else {
        tft.drawChar(':', xcolon, ypos, 6);     // Hour:minute colon
        xpos += tft.drawChar(':', xsecs, ysecs, 6); // Seconds colon
      }

      //Draw seconds
      if (ss < 10) xpos += tft.drawChar('0', xpos, ysecs, 6); // Add leading zero
      tft.drawNumber(ss, xpos, ysecs, 6);                     // Draw seconds
    }
  }
}


// Function to extract numbers from compile time string
static uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0'; 

 
}

TFTe_spi

C/C++
No preview (download only).

TEA5767

C/C++
No preview (download only).

Credits

Mirko Pavleski

Mirko Pavleski

116 projects • 1164 followers
Thanks to .

Comments