Dateianhang:
Dateikommentar: Die Verdrahtung. Eine Mischung aus fritzing, Produktfotos und Word.
vietnam-radio-schaltung.jpg [ 149.21 KiB | 10282-mal betrachtet ]
kommen wir nun zur software. Diese ist recht universell. Sie gilt für einen SI4703-Radiobaustein, der von einem Arduino gesteuert wird. Zur Abstimmung wird ein rotary encoder benutzt, ausserdem gibt es 4 fest programmierte Stationstasten. Die Verdrahtung ergibt sich zum Teil aus der Konstellation, zum Teil hab ich Festlegungen getroffen. Die Signalleitungen zum encoder sowie zu den preset-Tasten führe ich zur Entstörung über RC-Glieder. Der I2C-Bus und die RST-Leitung des SI4703 werden von einem level-converter von 5V auf 3,3V umgesetzt.
Nicht änderbar sind die Belegungen D3 und D7 zum encoder, weil diese I/O's interruptfähig sind. Es sei denn man verzichtet auf die Interrupts. Auch nicht änderbar A4=SDIO und A5=SCLK sowie D2=RST für den I2C-Bus. Das gilt jedenfalls für die meisten Arduino-Modelle (Mini, Nano..).
Frei festgelegt sind hingegen D11 für die AFC-LED, D12 für die Stereo-Anzeige und A0 für das preset-Netzwerk.
Dem sketch zugrunde liegt die SI4703_Breakout library von Simon Monk. Bitte hier auf einen aktuellen Stand achten. Die Vorversion hat abweichende Syntax. Ich hatte auch mit anderen Bibliotheken experimentiert, aber favorisiere inzwischen die Monk-Bibliotheken.
Auch bei der LiquidCrystal_I2C library gibt es unterschiedliche Versionen. Bei der einen geschieht die Initialisierung mit lcd.begin(); , bei einer anderen mit lcd.init();. Ansonsten sind beide Varianten einsetzbar.
Der sketch soll mir auch für andere Projekte dienen. Dazu sind immer nur kleinere Änderungen notwendig. Für eine LED-Strip-Ausgabe habe ich D4 vorgesehen, die software dazu allerdings der Übersicht wegen aus dem gezeigten sketch entfernt. Im Labormuster verwendete ich eine Analogausgabe der Frequenz. Dazu wird ein port mit PWM-Fähigkeit benötigt. Bei einem 1mA-Instrument ist ein Vorwiderstand von 4,9K nötig. Auch eine Poti-Abstimmung ist denkbar. Dazu muss das Poti von der internen oder einer externen Referenzspannung versorgt werden. Auch hier ist ein RC-Glied zur Glättung erforderlich sowie geeignete Software-Massnahmen für eine stabile Frequenzausgabe. Das war übrigends eine der schwierigsten Aufgaben auf meinem Weg zum µPC-Radio.
Kommen wir zurück zum Vietnam-Radio. In den Sub-Routinen SI4703_seekUpAuto und SI4703_seekDnAuto gibt es noch einen erwähnenswerten Parameter. Der tune-Wert in der Zeile "if(((SI4703AFC_Tune==false)&&(SI4703RSSI_Tune>15)))" , das ist hier die 15, bestimmt die Schaltschwelle des Suchlaufes. Ja, ich benutze eine Suchlauffunktion zur manuellen Abstimmung. Möglicherweise bin ich der einzige im Netz der sowas macht. Es ist superbequem den Encoder nur eine Raste in eine Richtung zu bewegen und der nächste empfangbare Sender in dieser Richtung wird automatisch eingestellt. Mit dem Wert 15 stoppt der Suchlauf schon bei jeder Störung, und empfängt daher auch schwache Sender. Mit dem Wert 20 sind nur die starken Ortssender zu empfangen. Hier gibt es also Spielraum.
Code:
/// SI4703 Nano Rotary sketch mit der SI4703_Breakout library von Simon Monk. Auf die aktuellere Version achten! Diese
/// hat bei der Objektdefinition 4 Parameter (resetPin, SDIO, SCLK, RDSInterruptPin), die alte Version nur 3.
/// Jupp Haffner 9.11.2017
///
/// Wiring
/// ------
/// The SI4703 board has to be connected by using the following connections:
/// | Arduino UNO pin | Radio chip signal |
/// | -------------------| -------------------|
/// | 3.3V (red) | VCC |
/// | GND (black) | GND |
/// | A5 or SCL (yellow) | SCLK |
/// | A4 or SDA (blue) | SDIO |
/// | D2 (white) | RST |
#include <Arduino.h>
#include <Wire.h>
#include <radio.h>
#include <Si4703_Breakout.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
/*SI4703 - Pins*/
int resetPin = 2;
int SDIO = A4;
int SCLK = A5;
int RDSInterruptPin = 3; // GPIO2 for RDS Interrupt
int AF_LED = 11;
int StereoLED = 12;
/*EEPROM*/
int ChannelEEP=0x01;
//int VolumeEEP=0x02;
int volume = 30;
int rssi; //signal-level
int tune; //AFC
int stereo;
/*Init SI4703 Driver*/
Si4703_Breakout radio(resetPin, SDIO, SCLK, RDSInterruptPin);
//Rotary Encoder http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/keyes-ky-040-arduino-rotary-encoder-user-manual/
int clk = 3; // Connected to CLK on KY-040
int dt = 7; // Connected to DT on KY-040
volatile int channel = 1017; //vorbelegt für den ersten Start
volatile byte INTFLAG1 = 0; //interrupt status flag
volatile byte UP_FLAG = 0; //seekUp
volatile byte DOWN_FLAG = 0; //seekDn
int seek = 0; //Zählvariable für channel
int analogport = A0; //Analogpin für preset-Netzwerk
int analog = 0; //Zählvariable für preset-Netzwerk
LiquidCrystal_I2C lcd(0x3F,16,2);
void setup()
{
//Rotary Encoder KY-040 pull up's built in
pinMode (clk, INPUT);
pinMode (dt, INPUT);
// interrupt 1 digital pin 3 positive edge trigger
attachInterrupt(digitalPinToInterrupt(clk), flag, RISING);
//Read last channel and volume
GetDataFromEEP();
//Initialize and Power up the SI4703
radio.powerOn();
radio.powerOn();
radio.setVolume(volume);
//radio.setChannel(channel);
lcd.begin();
//lcd.init();
lcd.clear();
lcd.setBacklight(1);
}
void loop()
{
if (channel != seek) {
radio.setChannel(channel);
seek = channel;
displayInfo();
SetDataToEEP();
}
//Rotary Encoder
if (INTFLAG1) {
//ISP ausgelöst
if (UP_FLAG) SI4703_seekUpAuto();
if (DOWN_FLAG) SI4703_seekDnAuto();
// clear flags
INTFLAG1 = 0;
UP_FLAG = 0;
DOWN_FLAG = 0;
displayInfo();
delay(40);
}
analog = analogRead(analogport);
switch(analog)
{
case 100 ... 150:
channel = 880;
break;
case 250 ... 300:
channel = 955;
break;
case 380 ... 420:
channel = 1009;
break;
case 500 ... 550:
channel = 1017;
break;
}
}
//ISR for Encoder: http://www.bristolwatch.com/arduino/arduino2.htm
void flag() {
INTFLAG1 = 1;
// CW
if (digitalRead(clk) && digitalRead(dt)) {
UP_FLAG = 1;
}
// CCW
if (digitalRead(clk) && !digitalRead(dt)) {
DOWN_FLAG = 1;
}
}
void displayInfo (void)
{
rssi=radio.getRSSI();
tune=radio.getTune();
stereo=radio.getStereo();
lcd.setCursor(0,0);
lcd.print("Vietnam "); lcd.print(float(seek)/10,1); lcd.print("MHz ");
lcd.setCursor(0,1);
if (stereo) lcd.print("STEREO "); else lcd.print("MONO ");
if(tune==0){lcd.print("RSSI:"); lcd.print(rssi); lcd.print("db");}
if(tune==1){lcd.setCursor(0,1); lcd.print("Tuning.stay.cool.");}
}
void SI4703_seekUpAuto (void)
{
channel+=1;
radio.setVolume(0);
radio.setChannel(channel);
delay(100);
for(seek=channel;; seek++)
{
if(seek>1080)seek=875;
radio.setChannel(seek);
displayInfo();
delay(30);
int SI4703AFC_Tune=radio.getTune();
int SI4703RSSI_Tune=radio.getRSSI();
delay((SI4703RSSI_Tune*4));
if(((SI4703AFC_Tune==false)&&(SI4703RSSI_Tune>15)))
{
radio.setVolume(volume);
channel=seek;
SetDataToEEP();
break;
}
}
}
void SI4703_seekDnAuto (void)
{
channel-=1;
radio.setVolume(0);
radio.setChannel(channel);
delay(100);
for(seek=channel;; seek--)
{
if(seek<=875)seek=1080;
radio.setChannel(seek);
displayInfo();
delay(30);
int SI4703AFC_Tune=radio.getTune();
int SI4703RSSI_Tune=radio.getRSSI();
delay((SI4703RSSI_Tune*4));
if(((SI4703AFC_Tune==false)&&(SI4703RSSI_Tune>15)))
{
radio.setVolume(volume);
channel=seek;
SetDataToEEP();
break;
}
}
}
void GetDataFromEEP (void)
{
channel=EEPROM.read(ChannelEEP)+875;
//volume=EEPROM.read(VolumeEEP);
}
void SetDataToEEP (void)
{ EEPROM.write(ChannelEEP,channel-875);
//EEPROM.write(VolumeEEP,volume);
}