Hi there!
Build a LCDRadio with SI4703 a16x2LCD via I2C and a rotary enconder.
Platform is a Arduino nano clone 328p.
I used the LCD Radio Sketch as shown down.
System starts up. LCD is working(shows bandFM and menu like Vol or Mute etc.)
Rotary encoder: ONLY the switch is working.
Serial COM works also with commands .
Menu Button goes to A1. Since I dont have a seek Button i keep the code selection to A0.
Si4703 just produce noise. Even when stations are changed.
When i test it with Test4703 it works fine!
Can you please help me with this??
Thanks
Andreas
My Pinout goes like this:
Arduino |
SI4703 sig |
LCD |
KY040 Rotary Encoder |
GND (black) |
GND |
GND |
GND |
3.3V (red) |
VCC |
- |
- |
5V (red) |
- |
VCC |
VCC 5V |
A5 (yellow) |
SCLK |
SCLK |
- |
A4 (blue) |
SDIO |
SDIO |
- |
D2 |
RST |
- |
- |
A3 (white) |
- |
- |
DT |
A2 (yellow) |
- |
- |
CLK |
A1 (green) |
- |
- |
SW |
Code is here!!! :
`///
/// \file LCDRadio.ino
/// \brief Radio implementation including LCD output.
///
/// \author Matthias Hertel, http://www.mathertel.de
/// \copyright Copyright (c) 2014 by Matthias Hertel.\n
/// This work is licensed under a BSD style license.\n
/// See http://www.mathertel.de/License.aspx
///
/// \details
/// This is a full function radio implementation that uses a LCD display to show the current station information.\n
/// It can be used with various chips after adjusting the radio object definition.\n
/// Open the Serial console with 57600 baud to see current radio information and change various settings.
///
/// Wiring
/// ------
/// The necessary wiring of the various chips are described in the Testxxx example sketches.
/// The boards have to be connected by using the following connections:
///
/// Arduino port | SI4703 signal | RDA5807M signal
/// :----------: | :-----------: | :-------------:
/// GND (black) | GND | GND
/// 3.3V (red) | VCC | VCC
/// 5V (red) | - | -
/// A5 (yellow) | SCLK | SCLK
/// A4 (blue) | SDIO | SDIO
/// D2 | RST | -
///
/// More documentation and source code is available at http://www.mathertel.de/Arduino
///
/// History:
/// --------
/// * 05.08.2014 created.
/// * 06.10.2014 working.
#include <Wire.h>
#include <radio.h>
#include <RDA5807M.h>
#include <SI4703.h>
#include <TEA5767.h>
#include <RDSParser.h>
#include <LiquidCrystal_PCF8574.h>
#include <RotaryEncoder.h>
#include <OneButton.h>
// Define some stations available at your locations here:
// 89.40 MHz as 8940
// RADIO_FREQ preset[] = {8850, 8930, 9320,9350, 9450,9570, 9680, 9880, 10030, 10260, 10400, 10500, 10600,10650,10800};
RADIO_FREQ preset[] = {
8770,
8810, // hr1
8820,
8850, // Bayern2
8890, // ???
8930, // * hr3
8980,
9180,
9220, 9350,
9440, // * hr1
9510, // - Antenne Frankfurt
9530,
9560, // Bayern 1
9680, 9880,
10020, // planet
10090, // ffh
10110, // SWR3
10030, 10260, 10380, 10400,
10500 // * FFH
};
// , 10650,10650,10800
int i_sidx=8; // Start at Station with index=19
int i_smax=30; // Max Index of Stations
/// Setup a RoraryEncoder for pins A2 and A3:
RotaryEncoder encoder(A2, A3);
// RotaryEncoder encoder(A9, A8);
int encoderLastPos;
unsigned long encoderLastTime;
// variables for rotator encoder
//unsigned long lastRotatorChange = 0; // last time a change of the rotator was detected.
/// The radio object has to be defined by using the class corresponding to the used chip.
/// by uncommenting the right radio object definition.
// RADIO radio; // Create an instance of a non functional radio.
// RDA5807M radio; // Create an instance of a RDA5807 chip radio
SI4703 radio; // Create an instance of a SI4703 chip radio.
// TEA5767 radio; // Create an instance of a TEA5767 chip radio.
/// The lcd object has to be defined by using a LCD library that supports the standard functions
/// When using a I2C->LCD library ??? the I2C bus can be used to control then radio chip and the lcd.
/// get a LCD instance
LiquidCrystal_PCF8574 lcd(0x27); // set the LCD address to 0x27 for a 16 chars and 2 line display
OneButton menuButton(A1, true);
OneButton seekButton(A0, true);
/// get a RDS parser
RDSParser rds;
/// State definition for this radio implementation.
enum RADIO_STATE {
STATE_NONE = 0,
STATE_PARSECOMMAND, ///< waiting for a new command character.
STATE_PARSEINT, ///< waiting for digits for the parameter.
STATE_EXEC, ///< executing the command.
STATE_FREQ,
STATE_VOL,
STATE_MONO,
STATE_SMUTE
};
RADIO_STATE state; ///< The state variable is used for parsing input characters.
RADIO_STATE rot_state;
// - - - - - - - - - - - - - - - - - - - - - - - - - -
/// Update the Frequency on the LCD display.
void DisplayFrequency(RADIO_FREQ f)
{
char s[12];
radio.formatFrequency(s, sizeof(s));
Serial.print("FREQ:"); Serial.println(s);
lcd.setCursor(0, 0);
lcd.print(s);
} // DisplayFrequency()
/// Update the ServiceName text on the LCD display when in RDS mode.
void DisplayServiceName(char *name)
{
Serial.print("RDS:"); Serial.println(name);
if (rot_state == STATE_FREQ) {
lcd.setCursor(0, 1);
lcd.print(name);
}
} // DisplayServiceName()
void DisplayTime(uint8_t hour, uint8_t minute) {
Serial.print("RDS-Time:");
if (hour < 10) Serial.print('0');
Serial.print(hour);
Serial.print(':');
if (minute < 10) Serial.print('0');
Serial.print(minute);
} // DisplayTime()
/// Display the current volume.
void DisplayVolume(uint8_t v)
{
Serial.print("VOL: "); Serial.println(v);
lcd.setCursor(0, 1);
lcd.print("VOL: "); lcd.print(v);
} // DisplayVolume()
/// Display the current mono switch.
void DisplayMono(uint8_t v)
{
Serial.print("MONO: "); Serial.println(v);
lcd.setCursor(0, 1);
lcd.print("MONO: "); lcd.print(v);
} // DisplayMono()
/// Display the current soft mute switch.
void DisplaySoftMute(uint8_t v)
{
Serial.print("SMUTE: "); Serial.println(v);
lcd.setCursor(0, 1);
lcd.print("SMUTE: "); lcd.print(v);
} // DisplaySoftMute()
// - - - - - - - - - - - - - - - - - - - - - - - - - -
void RDS_process(uint16_t block1, uint16_t block2, uint16_t block3, uint16_t block4) {
rds.processData(block1, block2, block3, block4);
}
// this function will be called when the menuButton was clicked
void doMenuClick() {
unsigned long now = millis();
if (rot_state == STATE_FREQ) {
// jump into volume mode
rot_state = STATE_VOL;
encoderLastPos = radio.getVolume();
encoder.setPosition(encoderLastPos);
DisplayVolume(encoderLastPos);
}
else if (rot_state == STATE_VOL) {
// jump into mono/stereo switch
rot_state = STATE_MONO;
encoderLastPos = radio.getMono();
encoder.setPosition(encoderLastPos);
DisplayMono(encoderLastPos);
}
else if (rot_state == STATE_MONO) {
// jump into soft mute switch
rot_state = STATE_SMUTE;
encoderLastPos = radio.getSoftMute();
encoder.setPosition(encoderLastPos);
DisplaySoftMute(encoderLastPos);
}
else if (rot_state == STATE_SMUTE) {
rot_state = STATE_FREQ;
encoderLastPos = (radio.getFrequency() - radio.getMinFrequency()) / radio.getFrequencyStep();
encoder.setPosition(encoderLastPos);
DisplayServiceName("...");
} // if
encoderLastTime = now;
} // doMenuClick()
// this function will be called when the seekButton was clicked
void doSeekClick() {
Serial.println("SEEK...");
radio.seekUp(true);
} // doSeekClick()
// The Interrupt Service Routine for Pin Change Interrupts
// On Arduino UNO you can use the PCINT1 interrupt vector that covers digital value changes on A2 and A3.
// On Arduino Mega 2560 you can use the PCINT2 interrupt vector that covers digital value changes on A8 and A9.
// Read http://www.atmel.com/Images/doc8468.pdf for more details on external interrupts.
ISR(PCINT2_vect) {
encoder.tick(); // just call tick() to check the state.
} // ISR for PCINT2
/// Setup a FM only radio configuration with I/O for commands and debugging on the Serial port.
void setup() {
// open the Serial port
Serial.begin(57600);
// Initialize the lcd
lcd.begin(16, 2);
lcd.setBacklight(1);
lcd.print("Hallo Du!!!");
delay(1200);
lcd.clear();
// Initialize the Radio
radio.init();
// Enable information to the Serial port
radio.debugEnable();
// radio.setBandFrequency(RADIO_BAND_FM, 8930); // hr3
radio.setBandFrequency(RADIO_BAND_FM, preset[i_sidx]); // 5. preset.
// radio.setFrequency(10140); // Radio BOB // preset[i_sidx]
// Setup rotary encoder
// You may have to modify the next 2 lines if using other pins than A2 and A3
// On Arduino-Uno: rotary encoder in A2(PCINT10) and A3(PCINT11)
// PCICR |= (1 << PCIE1); // This enables Pin Change Interrupt 1 that covers the Analog input pins or Port C.
// PCMSK1 |= (1 << PCINT10) | (1 << PCINT11); // This enables the interrupt for pin 2 and 3 of Port C.
// On Arduino-MEGA2560: A8(PCINT16) and A9(PCINT17) for interrupt vector PCINT2
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT16) | (1 << PCINT17);
encoderLastPos = (radio.getFrequency() - radio.getMinFrequency()) / radio.getFrequencyStep();
Serial.println(encoderLastPos);
encoder.setPosition(encoderLastPos);
// Setup the buttons
// link the doMenuClick function to be called on a click event.
menuButton.attachClick(doMenuClick);
// link the doSeekClick function to be called on a click event.
seekButton.attachClick(doSeekClick);
delay(100);
radio.setMono(false);
radio.setMute(false);
//radio.debugRegisters();
Serial.write('>');
state = STATE_PARSECOMMAND;
rot_state = STATE_NONE;
// setup the information chain for RDS data.
radio.attachReceiveRDS(RDS_process);
rds.attachServicenNameCallback(DisplayServiceName);
rds.attachTimeCallback(DisplayTime);
} // Setup
/// Execute a command identified by a character and an optional number.
/// See the "?" command for available commands.
/// \param cmd The command character.
/// \param value An optional parameter for the command.
void runCommand(char cmd, int16_t value)
{
if (cmd == '?') {
Serial.println();
Serial.println("? Help");
Serial.println("+ increase volume");
Serial.println("- decrease volume");
Serial.println("> next preset");
Serial.println("< previous preset");
Serial.println(". scan up : scan up to next sender");
Serial.println(", scan down ; scan down to next sender");
Serial.println("fnnnnn: direct frequency input");
Serial.println("i station status");
Serial.println("s mono/stereo mode");
Serial.println("b bass boost");
Serial.println("m mute/unmute");
Serial.println("u soft mute/unmute");
}
// ----- control the volume and audio output -----
else if (cmd == '+') {
// increase volume
int v = radio.getVolume();
if (v < 15) radio.setVolume(++v);
}
else if (cmd == '-') {
// decrease volume
int v = radio.getVolume();
if (v > 0) radio.setVolume(--v);
}
else if (cmd == 'm') {
// toggle mute mode
radio.setMute(! radio.getMute());
}
else if (cmd == 'u') {
// toggle soft mute mode
radio.setSoftMute(! radio.getSoftMute());
}
// toggle stereo mode
else if (cmd == 's') { radio.setMono(! radio.getMono()); }
// toggle bass boost
else if (cmd == 'b') { radio.setBassBoost(! radio.getBassBoost()); }
// ----- control the frequency -----
else if (cmd == '>') {
// next preset
if (i_sidx < (sizeof(preset) / sizeof(RADIO_FREQ))-1) {
i_sidx++; radio.setFrequency(preset[i_sidx]);
} // if
}
else if (cmd == '<') {
// previous preset
if (i_sidx > 0) {
i_sidx--;
radio.setFrequency(preset[i_sidx]);
} // if
}
else if (cmd == 'f') { radio.setFrequency(value); }
else if (cmd == '.') { radio.seekUp(false); }
else if (cmd == ':') { radio.seekUp(true); }
else if (cmd == ',') { radio.seekDown(false); }
else if (cmd == ';') { radio.seekDown(true); }
// not in help:
else if (cmd == '!') {
if (value == 0) radio.term();
if (value == 1) radio.init();
}
else if (cmd == 'i') {
char s[12];
radio.formatFrequency(s, sizeof(s));
Serial.print("Station:"); Serial.println(s);
Serial.print("Radio:"); radio.debugRadioInfo();
Serial.print("Audio:"); radio.debugAudioInfo();
// Serial.print(" RSSI: ");
// Serial.print(info.rssi);
//
// for (uint8_t i = 0; i < info.rssi - 15; i+=2) { Serial.write('*'); } // Empfangspegel ab 15. Zeichen
// Serial.println();
} // info
// else if (cmd == 'n') { radio.debugScan(); }
else if (cmd == 'x') { radio.debugStatus(); }
} // runCommand()
/// Constantly check for serial input commands and trigger command execution.
void loop() {
int newPos;
unsigned long now = millis();
static unsigned long nextFreqTime = 0;
static unsigned long nextRadioInfoTime = 0;
// some internal static values for parsing the input
static char command;
static int16_t value;
static RADIO_FREQ lastf = 0;
RADIO_FREQ f = 0;
char c;
// check for the menuButton
menuButton.tick();
if (Serial.available() > 0) {
// read the next char from input.
c = Serial.peek();
if ((state == STATE_PARSECOMMAND) && (c < 0x20)) {
// ignore unprintable chars
Serial.read();
}
else if (state == STATE_PARSECOMMAND) {
// read a command.
command = Serial.read();
state = STATE_PARSEINT;
}
else if (state == STATE_PARSEINT) {
if ((c >= '0') && (c <= '9')) {
// build up the value.
c = Serial.read();
value = (value * 10) + (c - '0');
}
else {
// not a value -> execute
runCommand(command, value);
command = ' ';
state = STATE_PARSECOMMAND;
value = 0;
} // if
} // if
} // if
// check for the rotary encoder
newPos = encoder.getPosition();
if (newPos != encoderLastPos) {
if (rot_state == STATE_FREQ) {
RADIO_FREQ f = radio.getMinFrequency() + (newPos * radio.getFrequencyStep());
radio.setFrequency(f);
encoderLastPos = newPos;
nextFreqTime = now + 10;
}
else if (rot_state == STATE_VOL) {
radio.setVolume(newPos);
encoderLastPos = newPos;
DisplayVolume(newPos);
}
else if (rot_state == STATE_MONO) {
radio.setMono(newPos & 0x01);
encoderLastPos = newPos;
DisplayMono(newPos & 0x01);
}
else if (rot_state == STATE_SMUTE) {
radio.setSoftMute(newPos & 0x01);
encoderLastPos = newPos;
DisplaySoftMute(newPos & 0x01);
} // if
encoderLastTime = now;
}
else if (now > encoderLastTime + 2000) {
// fall into FREQ + RDS mode
rot_state = STATE_FREQ;
encoderLastPos = (radio.getFrequency() - radio.getMinFrequency()) / radio.getFrequencyStep();
encoder.setPosition(encoderLastPos);
} // if
// check for RDS data
radio.checkRDS();
// update the display from time to time
if (now > nextFreqTime) {
f = radio.getFrequency();
if (f != lastf) {
// don't display a Service Name while frequency is no stable.
DisplayServiceName(" ");
DisplayFrequency(f);
lastf = f;
} // if
nextFreqTime = now + 400;
} // if
if (now > nextRadioInfoTime) {
RADIO_INFO info;
radio.getRadioInfo(&info);
lcd.setCursor(14, 0);
lcd.print(info.rssi);
nextRadioInfoTime = now + 1000;
} // update
} // loop
// End.`