Vorbereitend für ein Radioprojekt stelle ich hier schon mal die Platine vor. Ein Arduino Nano steuert einen SI4703 Baustein. Die Abstimmung erfolgt über Rotary Encoder und die Frequenzanzeige über ein LED-Strip.
LED-Strip:
Diese LED-Streifen gibt es als gerade Stücke, als Kreis oder Teilkreis, oder als Band als Meterware. Man schneidet sich ein passendes Stück des Bandes einfach ab (wie hier im Beispiel). Jede LED-Einheit setzt sich zusammen aus einem Miniprozessor und mehrfarbigen LED's. Der Hammer aber ist das es nur eine einzige Steuerleitung gibt und damit auch nur ein Digitalpin des Arduino benötigt wird. Die Steuerleitung und die Betriebsspannung von 5V wird von einer LED-Einheit zur nächsten weitergereicht. Es existieren libraries für alle möglichen bunten Effekte. Ich benutze hier eine wheel Funktion und lösche alle LED bevor ich die nächste LED setze. Dadurch entsteht ein wandernder Punkt. Farbe und Helligkeit sind parametrisierbar. Die Grundlagen hab ich mir hier angeeignet.
Rotary Encoder:
Die Funktionsweise ist hier sehr gut beschrieben. Im Prinzip keine große Sache. Trotzdem hat es mich tagelang beschäftigt bis die Abstimmung sauber funktionierte. Der Grund ist das Kontaktprellen der Schaltkontakte. Die Effekte waren Sprünge bei der Frequenzeinstellung, willkürliches Ändern der Drehrichtung, Verschlucken von Impulsen. Etwas Erfolge hatte ich mit dem Abfragen der Kontakte per Interruptfunktion, wobei die ansteigende bzw. abfallende Flanke ausgewertet wird. Ein zusätzliche Verbesserung brachte eine Zeitverzögerung, die in der Interruptfunktion per millis() einbaut wird. Zufriedenstellend war es immer noch nicht, und ich wollte schon von dem Encoder weg. Dann fand ich einen Hinweis auf eine hardware-Entprellung mit einem einfachen RC-Glied. Das war dann der Durchbruch. Die millis() konnte ich wieder rausnehmen, die Interrupts mussten bleiben. Der Encoder arbeitet jetzt ganz präzise und die Abstimmung ist endlich brauchbar. In die Leitungen der 2 Encodersignale kommen 10K Widerstände und 100n gegen Masse. Bei einer Auflösung von 100kHz pro Raster und 20 Rasterungen pro Umdrehung muss man natürlich schon etwas kurbeln um den Bereich durchzustimmen. Deshalb benutze ich noch zusätzlich den switch des Encoders um festeingestellte Empfangsfrequenzen zu toogeln.
Dann gab es ein weiteres großes Problem. Nach kurzem intensiven Durchstimmen der Frequenz gab es auf einmal reproduzierbar einen Frequenzversatz, so das die eingestellte Frequenz nicht mehr zur Frequenz passte den der SI4703 Baustein ausgab. Möglicherweise änderte der Baustein das Regionalband. Das Problem verschwand erst als ich die library austauschte. Das Programm basierte bis dahin auf der <SparkFunSi4703.h> library, nun arbeitet es stabil mit der Hertel-library <si4703.h>.
Auf dem Video steckt der library-Fehler noch drin, deshalb musste ich zwischendurch den Prozessor resetten:
der aktuelle Programmcode. Wie üblich ein Zusammensetzen von code-Schnitzeln für die eigenen Bedürfnisse. Quellangaben sind soweit wie möglich eingebaut.
//bis jetzt fehlerfreie Funktion!
//Hertel-Library si4703.h
//learning about NeoPixel:
//https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library
//
/// 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 |
//http://www.bristolwatch.com/arduino/arduino2.htm
#include <Arduino.h>
#include <Wire.h>
#include <radio.h>
#include <si4703.h>
#include <Adafruit_NeoPixel.h>
#define Din 4
int anz_led = 26; // Anzahl der LED's
Adafruit_NeoPixel strip = Adafruit_NeoPixel(anz_led, Din, NEO_GRB + NEO_KHZ800);
int wc = 0;
int led = 0;
// Input buttons on radio
#define preset 8
#define volDown 9
#define volUp 10
//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
// Si4703 radio chip
#define FIX_BAND RADIO_BAND_FM ///< The band that will be tuned by this sketch is FM.
SI4703 radio; // Create an instance of Class for Si4703 Chip
// Variables definition
volatile int channel = 8800; // universal count
volatile byte INTFLAG1 = 0; // interrupt status flag
int volume = 10;
void setup()
{
// Set internal pull up resistors on inputs
pinMode(preset, INPUT_PULLUP);
pinMode(volDown, INPUT_PULLUP);
pinMode(volUp, INPUT_PULLUP);
//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);
Serial.begin(9600);
Serial.println(channel);
// Set all radio setting to the fixed values.
radio.init();
radio.setBandFrequency(FIX_BAND, channel);
radio.setVolume(volume);
radio.setMono(false);
radio.setMute(false);
Serial.println("fixed values");
//Initialize LED-Stripes
strip.begin();
strip.show(); // Initialize all pixels to 'off'
strip.setBrightness(64); //range 0 (off) to 255 (max brightness)
UpdateLed();
Serial.println("LED-Stripes");
}
void loop()
{
// Volume down
if (digitalRead(volDown) == LOW)
{
if (volume > 0) volume--;
radio.setVolume(volume);
delay(100);
}
// Volume up
if (digitalRead(volUp) == LOW)
{
if (volume < 15) volume++;
radio.setVolume(volume);
delay(100);
}
//Rotary Encoder
if (INTFLAG1) {
INTFLAG1 = 0; // clear flag
Serial.println(channel);
Serial.println("ISP ausgelöst");
radio.setFrequency(channel);
UpdateLed();
delay(40);
} // end if
// Preset-Stationen http://www.w3ii.com/de/arduino/arduino_switch_case_statement.html
if (digitalRead(preset) == LOW)
{
switch (channel){
case 8800: channel = 9550; break;
case 9550: channel = 10090; break;
case 10090: channel = 10170; break;
case 10170: channel = 10370; break;
case 10370: channel = 8800; break;
default: channel = 8800;
}
Serial.print("Preset: ");
Serial.println(channel);
radio.setFrequency(channel);
UpdateLed();
delay(100);
}
delay(50);
}//end loop
//ISR for Encoder: http://www.bristolwatch.com/arduino/arduino2.htm
void flag() {
INTFLAG1 = 1;
// add 1 to count for CW
if (digitalRead(clk) && digitalRead(dt)) {
channel+=10 ;
if (channel > 10800) channel = 8700;
}
// subtract 1 from count for CCW
if (digitalRead(clk) && !digitalRead(dt)) {
channel-=10 ;
if (channel < 8700) channel = 10800;
}
}
void UpdateLed()
{
strip.setPixelColor(led, strip.Color( 0, 0, 0));
led = map(channel, 8700, 10800, 0, (anz_led - 1));
strip.setPixelColor(led, Wheel(wc));
strip.show();
delay(20);
}
uint32_t Wheel(byte WheelPos) {
if (WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
Die kleine hochkantstehende Platine ist ein NF-Verstärker mir LM386. Der genügt völlig um ein mittelgroßes Radio zu betreiben. Die Anordnung der Bauteile ist von der Platine weitgehend vorgegeben, da es sich um eine Steckbrett-Ersatz-Lochrasterplatine handelt. Das spart sehr viele Lötverbindungen.
Keine Kommentare:
Kommentar veröffentlichen