mathertel / Radio

An Arduino library to control FM radio chips like SI4703, SI4705, RDA5807M, TEA5767.
http://mathertel.github.io/Radio
BSD 3-Clause "New" or "Revised" License
297 stars 89 forks source link

Just noise LCDRadio SI7403 #47

Closed Beppi4U closed 1 year ago

Beppi4U commented 3 years ago

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

include

include

include

include

include

include

include

include

// 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.`

Beppi4U commented 3 years ago

Ok! After some experimenting with this and that i found out :

  1. I have to set up the "interrupt service routine" correctly. Means line 257 change this "ISR(PCINT2_vect" to ---> that "ISR(PCINT1_vect" Now the rotary encoder works! But directions are reversed -- turn left and values are increasing turning right values are decreasing. Hope someone can tell me to change that!
  2. Uncommenting lines 290-291 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 ...so rotary encoder setup seems to be complete! Comment out the lines for Mega2560 few lines down.

    BUT!! Still no sound just noise!!!!
    Setting Volume workes but on the LCD the displayed values are going nuts when you reach 255 --> backwards 0. Would somebody please help me with that!?? Thanks a lot! Andreas

mathertel commented 1 year ago

Please use the TESTxxx examples first to make sure the chip and setup works.

The interrupt code was changed in version 3.0.x