32 Kanal Videoempfänger

Status
Nicht offen für weitere Antworten.
#81
Hast du schon aufgeräumt?
Ich würds auch unaufgeräumt nutzen...und aufräumen.
Nein, geräumt hab ich noch nicht ;_)
Wie gesagt, is viel debugging drin was es unübersichtlich macht. Zudem wurden alle statischen arrays und strings ins Flash gelegt um RAM zu sparen, der Framebuffer vom TV-Out frisst 1,5 der verfügbaren 2k RAM....

Code:
/*
 * Based on fs_skyrf_58g-main.c
 * Written by Simon Chambers

The MIT License (MIT)

Copyright (c) 2014 Simon Chambers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <TVout.h>
#include <fontALL.h>
#include <avr/pgmspace.h>

#define spiDataPin 10
#define slaveSelectPin 11
#define spiClockPin 12
#define rssiPin A6
#define buttonSeek 2
#define buttonScan 3

#define RSSIMAX 40

#define STATE_TV 0
#define STATE_SEEK 1
#define STATE_SCAN 2

#define rows 96
#define cols 128

//#define DEBUG

// Channels to sent to the SPI registers
const uint16_t channelTable[] PROGMEM = {
  // Channel 1 - 8
  0x2A05,	0x299B,	0x2991,	0x2987,	0x291D,	0x2913,	0x2909,	0x289F,	// Band A
  0x2903,	0x290C,	0x2916,	0x291F,	0x2989,	0x2992,	0x299C,	0x2A05,	// Band B
  0x2895,	0x288B,	0x2881,	0x2817,	0x2A0F,	0x2A19,	0x2A83,	0x2A8D,	// Band E
  0x2906,	0x2910,	0x291A,	0x2984,	0x298E,	0x2998,	0x2A02,	0x2A0C  // Airwave
};

// Channels with their Mhz Values
const uint16_t channelFreqTable[] PROGMEM = {
  // Channel 1 - 8
  5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725, // Band A
  5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866, // Band B
  5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945, // Band E
  5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880  // Airwave
};

//const char* channelNames[] PROGMEM = {
//"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8",
//"B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8",
//"E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8",
//"W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8"
//};

const uint8_t channelNames[] PROGMEM = {
  0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
  0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
  0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
  0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8
};

// All Channels of the above List ordered by Mhz
const uint8_t channelList[] PROGMEM = {
  19, 18, 17, 16, 7, 8, 24, 6, 9, 25, 5, 10, 26, 4, 11, 27, 3, 12, 28, 2, 13, 29, 1, 14, 30, 0, 15, 31, 20, 21, 22, 23
};

const uint8_t offset = 7;

uint8_t channel = 0;
uint8_t channelIndex = 0;
uint8_t rssi = 0;
uint8_t hight = 0;
uint8_t state = STATE_SCAN;
uint8_t bState = HIGH;
uint8_t writePos = 0;

TVout TV;

// SETUP ----------------------------------------------------------------------------
void setup() {

  // initialize digital pin 13 LED as an output.
  pinMode(13, OUTPUT);

  pinMode(buttonSeek, INPUT);
  digitalWrite(buttonSeek, INPUT_PULLUP);
  pinMode(buttonScan, INPUT);
  digitalWrite(buttonScan, INPUT_PULLUP);


#ifdef DEBUG
  Serial.begin(115200);
  Serial.println(F("START:")); 
#endif

  pinMode (slaveSelectPin, OUTPUT);
  pinMode (spiDataPin, OUTPUT);
  pinMode (spiClockPin, OUTPUT);

#ifdef DEBUG
  Serial.print(F("FREEMEM: ")); Serial.println(freeRam ());
#endif

  char retVal = TV.begin(PAL, cols, rows);
  // 0 if no error.
  // 1 if x is not divisable by 8.
  // 2 if y is to large (NTSC only cannot fill PAL vertical resolution by 8bit limit)
  // 4 if there is not enough memory for the frame buffer.
  if (retVal > 0) {
    // on Error flicker LED
    while (true) {
      digitalWrite(13, !digitalRead(13));
      delay(100);
    }
  }


  TV.select_font(font4x6);

#ifdef DEBUG
  Serial.print(F("FREEMEM: ")); Serial.println(freeRam ());
#endif

  TV.print("5.8GHz Spectrum Analyser");
  TV.print(2, (rows - offset + 2), "5645");
  TV.print(57, (rows - offset + 2), "5800");
  TV.print(111, (rows - offset + 2), "5945");

  // Setup Done - LED ON
  digitalWrite(13, HIGH);
}

// LOOP ----------------------------------------------------------------------------
void loop() {

  if (digitalRead(buttonScan) == LOW) {
    state = STATE_SCAN;
  } else {
    if (state == STATE_SCAN) {
      state = STATE_SEEK;
    }
  }

  // get Channel by Freq. Ascending
  channelIndex = pgm_read_byte_near(channelList + channel);
  //channelIndex = channel;

#ifdef DEBUG
  Serial.print(channel); Serial.print(F(" \t"));
  Serial.print(F("STATE: ")); Serial.print(state); Serial.print(F(" \t"));
  Serial.print(F("CHANNELINDEX: ")); Serial.print(channelIndex); Serial.print(F(" \t"));
#endif

  // if not in TV Mode, tune Module
  if (state != STATE_TV) {
    setChannelModule(channelIndex);
  }


#ifdef DEBUG
  Serial.print(F("FREQ: ")); Serial.print(pgm_read_word_near(channelFreqTable + channelIndex)); Serial.print(F("\t"));
#endif

  // wait for tuning
  delay(100);

  // get rssi and map it to 0-70
  rssi = readRSSI();

#ifdef DEBUG
      Serial.print("RSSIraw: ");Serial.print(rssi); Serial.print(F("\t"));
#endif

  rssi = constrain(rssi, 50, 170);
  rssi = map(rssi, 170, 50, 3, 70);
  
  
#ifdef DEBUG
      Serial.print("RSSI: ");Serial.print(rssi); Serial.print(F("\t"));
#endif

  // if SCAN Mode, print Spectrum
  if (state == STATE_SCAN) {
    // print bar
    hight = (rows - offset - rssi);
    TV.draw_rect((channel * 4), (rows - offset - 74), 3, 70 , BLACK, BLACK);
    TV.draw_rect((channel * 4), hight, 3, rssi , WHITE, WHITE);

    // print channelname
    if (rssi > RSSIMAX) {
      TV.draw_rect(writePos, 7, 20, 6,  BLACK, BLACK);
      TV.print(writePos, 7, pgm_read_byte_near(channelNames + channelIndex), HEX);
      TV.print(writePos+10, 7, pgm_read_word_near(channelFreqTable + channelIndex));
      writePos += 30;
      TV.print((channel * 4) - 3, hight - 5, pgm_read_byte_near(channelNames + channelIndex), HEX);
#ifdef DEBUG
      Serial.print("NAME: ");Serial.print(pgm_read_byte_near(channelNames + channelIndex), HEX); Serial.print(F("\t"));
#endif
    }

    // if SEEK Mode, check RSSI and skip Channel
  } else if (state == STATE_SEEK) {
    if (rssi > RSSIMAX) {
      state = STATE_TV;
    } else {
      delay(200);
    }
  }
  
  if (state == STATE_TV && digitalRead(buttonSeek) == LOW) {
    state = STATE_SEEK;
  }

  // if not in TV Mode, next Channel
  if (state != STATE_TV) {
    // reset Channel channeler
    if (channel < 31) {
      channel++;
    } else {
#ifdef DEBUG
      Serial.println();
#endif
      TV.draw_rect(writePos, 7, cols-writePos-1, 6,  BLACK, BLACK);
      channel = 0;
      writePos = 0;
    }
  }

#ifdef DEBUG
  Serial.println(F(""));
#endif

}

uint16_t readRSSI() {
  uint16_t rssi = 0;
  for (uint8_t i = 0; i <= 10; i++) {
    rssi += analogRead(rssiPin);
  }
  return (rssi / 10);
}

// Private function: from http://arduino.cc/playground/Code/AvailableMemory
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void setChannelModule(uint8_t channel)
{
  uint8_t i;
  uint16_t channelData;

  //channelData = pgm_read_word(&channelTable[channel]);
  //channelData = channelTable[channel];
  channelData = pgm_read_word_near(channelTable + channel);

#ifdef DEBUG
  Serial.print(F("TUNE: ")); Serial.print(channelData, HEX); Serial.print(F("\t"));
#endif

  // bit bash out 25 bits of data
  // Order: A0-3, !R/W, D0-D19
  // A0=0, A1=0, A2=0, A3=1, RW=0, D0-19=0
  SERIAL_ENABLE_HIGH();
  delay(2);
  SERIAL_ENABLE_LOW();

  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT1();

  SERIAL_SENDBIT0();

  // remaining zeros
  for (i = 20; i > 0; i--)
    SERIAL_SENDBIT0();

  // Clock the data in
  SERIAL_ENABLE_HIGH();
  delay(2);
  SERIAL_ENABLE_LOW();

  // Second is the channel data from the lookup table
  // 20 bytes of register data are sent, but the MSB 4 bits are zeros
  // register address = 0x1, write, data0-15=channelData data15-19=0x0
  SERIAL_ENABLE_HIGH();
  SERIAL_ENABLE_LOW();

  // Register 0x1
  SERIAL_SENDBIT1();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();

  // Write to register
  SERIAL_SENDBIT1();

  // D0-D15
  //   note: loop runs backwards as more efficent on AVR
  for (i = 16; i > 0; i--)
  {
    // Is bit high or low?
    if (channelData & 0x1)
    {
      SERIAL_SENDBIT1();
    }
    else
    {
      SERIAL_SENDBIT0();
    }

    // Shift bits along to check the next one
    channelData >>= 1;
  }

  // Remaining D16-D19
  for (i = 4; i > 0; i--)
    SERIAL_SENDBIT0();

  // Finished clocking data in
  SERIAL_ENABLE_HIGH();
  delay(2);

  digitalWrite(slaveSelectPin, LOW);
  digitalWrite(spiClockPin, LOW);
  digitalWrite(spiDataPin, LOW);
}


void SERIAL_SENDBIT1()
{
  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);

  digitalWrite(spiDataPin, HIGH);
  delayMicroseconds(300);
  digitalWrite(spiClockPin, HIGH);
  delayMicroseconds(300);

  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);
}

void SERIAL_SENDBIT0()
{
  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);

  digitalWrite(spiDataPin, LOW);
  delayMicroseconds(300);
  digitalWrite(spiClockPin, HIGH);
  delayMicroseconds(300);

  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);
}

void SERIAL_ENABLE_LOW()
{
  delayMicroseconds(100);
  digitalWrite(slaveSelectPin, LOW);
  delayMicroseconds(100);
}

void SERIAL_ENABLE_HIGH()
{
  delayMicroseconds(100);
  digitalWrite(slaveSelectPin, HIGH);
  delayMicroseconds(100);
}
 

pete1990

Erfahrener Benutzer
#82
Danke, wie hast du denn die Umschaltung zwischen den Videosignalen realisiert? Hat dein Monitor 2 Eingänge, die er selbst auswählt?
 

kl_Haribo

ergebener Benutzer
#84
Ist es möglich, das Modul per SPI in die Fatshark zu implementieren? dann könnte man die Kanalschaltzustände der Fatshark auswerten um einen Knopfdruck zu erhalten, um dann per RSSI ein Autotune des Moduls zu machen.
Sprich man schaltet die Fatshark ein, und der scannt dann bei knopfdruck alle Kanäle durch, bis man einen gefunden hat. Wenns nicht der eigene ist, drückt man einfach nochmal.
Und wenn man garnicht fliegen will, hat man quasi einen "Feldsniffer".

Würde es dazu reichen, alles bis auf nen atmega direkt miteinander verkabeln, oder braucht man noch zusätzliche Bauteile Wie Widerstände Kondensatoren?
 

MarenB

Runter kommen sie immer!
#87
oh, da bin ich auch schon gewesen. konnte das PDF irgendwie nicht öffnen. vielleicht deswegen isses mir nicht aufgefallen.
Klappt es jetzt? Ich hatte gerade das gleiche Problemchen. Erst auf den PDF-Namen klicken, auf der folgenden Seite dann View RAW - damit ging es bei mir.

Ich hab den Thread hier auch schon seit Seite 2 im Abo. Ich nutze einen Foxtech/Boscam D58-2 und sowohl Fertig- als auch DIY-Sender und irgendwie tue ich mich immer wieder schwer, die Kanäle von RX und TX gleich einzustellen. Ich versuche zwar, eine einmal gefundene Einstellung nicht zu verändern, aber gelegentlich muss auch ich mal auf der Wiese im Kreise anderer auf einen
anderen Kanal ausweichen... :/ Und dann hab ich den Salat. Ich hasse diese Dipschalter!

Bis ich dann sicher weiß, ob ich nur auf einem "Streu-Kanal" hänge, oder vielleicht der Empfang aus anderen Gründen schlecht ist, hab ich den Flieger entweder irgendwo unfreiweillig abgesetzt oder mindestens zwei Akkus verflogen (ich bevorzuge die zweite Option ;))

Ein Scanner käme mir also mehr als recht!
Megas und Tinys habe ich in DIL-Form einige hier liegen, da wäre also schnell einer reingefummelt. Aber ich habe mich, wie an anderer Stelle schon mal geschrieben, nie wirklich mit Arduino oder C auseinandergesetzt, sondern halte mich an Bascom.. Das war vielleicht das falsche Pferd damals, aber nun gut...ich komme damit gut zurecht - bloß muss ich meist das Rad neu erfinden, weil ich vorandenen Code z.B. aus diesem Forum nicht übernehmen und für mich anpassen kann.
Muss also mal schauen, ob ich also auch hier mal wieder von vorne anfange und den Scanner selbst programmiere, mich in C einarbeite, oder einfach das nehme, was vorhanden ist :) An dieser Stelle schon mal Danke für Inspiriation und Code, je nachdem :D
Vom Pollin habe ich noch ein sehr flaches und billiges 8x2 LCD, das würde gut dazu und vielleicht noch mit ins Gehäuse passen....
 
Zuletzt bearbeitet:

kl_Haribo

ergebener Benutzer
#88
Ahh, geht. Danke maren :)

Johannes: laut dem Schema ist es genau die Hardware, die er auch in seinem Shop verkauft.
Allerdings kann ich nirgends sehen, dass die RSSI ausgewertet wird,
Augenscheinlich tuned er nur den letzten Kanal/Band wieder ein.
Aber: die hardware ist nun klar, quasi alles direkt verkabelt, dass wollte ich erst einmal wissen.
 
Zuletzt bearbeitet:

kl_Haribo

ergebener Benutzer
#90
Ist denn die RSSI bei den Nachbarkanälen auch so hoch? evtl kann man das einfach über die Pegel quasi anpassen? also nur bei maximaler RSSI?

Edit: evtl auch bei abgeschraubter Antenne?
 
#91
Und zum zweiten ist die Gefahr sehr groß, dass man einen Nachbarkanal erwischt und damit losfliegt. Denn die RSSI-Spannung wird in der HF-Vorstufe generiert und trifft damit einen relativ breiten Frequenzbereich. Man liegt also beim ersten Suchlauftreffer schon mal 10-30MHz daneben, und das rächt sich spätestens nach 100m. Bei Beschränkung auf eins der vier Bänder wäre das evtl. noch grad so machbar, aber ich würd's wegen der Qualitätsstreuung der Module auch dann nicht machen.
Auf den Entschluss bin ich bei meinem Diversity damals auch gekommen. Interessant zu wissen wo die den RSSI abgreifen (hab ich jetzt nie im Datenblatt draufgeguckt) aber das erklärt dann natürlich die Ungenauigkeit.
 
#92
Danke! das wars, :D
der Widerstand mit dem roten Pfeil im obigen Bild ist bei mir def Pin 6, sprich SPILE/CS1
Nach dem abkratzen von PIN7 und wiedereinlöten eines Widerstandes auf Pin6 läuft es jetzt ;-)

Das RX Modul braucht ca 100ms zum Tunen des neuen Kanals bis sinnvolle Werte auf RSSI kommen.

Ich will grad mal prüfen, welchen Widerstand ich auslöten muss. Wie muss ich da jetzt genau messen? PIN7 vom IC zu den einzelnen Widerständen? Und der, der Kontakt hat muss raus?

Auf den Bildern sah die Platine immer so riesig aus, ist schon arg klein das ganze :D Ich löte leider nie smd, hat jemand nen guten Tipp, wie ich den Widerstand am besten rausbekomme?
 

Spacefish

Erfahrener Benutzer
#94
Für das rssi kann man einen peak finder im arduino programmieren. Dann trifft man auch den Kanal korrekt. Man sieht auch ganz gut in meinen oszi Bildern, dass der meanwert sehr verlässlich ist. Man muss das rssi signal nur etwas glätten!
 

pete1990

Erfahrener Benutzer
#96
Danke nochmals an den Frickler für die Bereitstellung des Codes. Ich habe nun den Arduino und das Modul auch noch in das Monitorgehäuse quetschen können.

Die Software habe ich leicht abgeändert, sodass ich nun 3 Modi habe, die durch langes Drücken des Buttons durchgeschaltet werden. Weiterhin habe ich einen Umschalter zwischen TV-Out des Arduino und dem Empfängermodul.

1. Automatischer Suchlauf anhand von RSSI: --> wird ein Kanal gefunden wird Band und Frequenz über das TV-Out des Arduinos angezeigt und der Kanal eingestellt.

2. Manueller Modus: Man kann durch klicken auf den Button durch die Kanäle schalten. Der zweite Schalter dient als Umschalter wenn man durch die Bänder schalten will, sodass man sich nicht zu Tode klickt. auch hier wird wieder Band und Frequenz am TV-Out angezeigt.

3. Spectrum Analyser: wie im Originalcode


Das Video veranschaulicht das Ganze noch etwas:
[video=youtube;CqwSNj1wZtI]http://www.youtube.com/watch?v=CqwSNj1wZtI[/video]

Groß schöner hab ich den Code nicht gemacht, aber vielleicht hat ja noch der ein oder andere Nutzen dafür, daher hier der Code.

Code:
/*
 * Based on fs_skyrf_58g-main.c
 * Written by Simon Chambers

The MIT License (MIT)

Copyright (c) 2014 Simon Chambers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <TVout.h>
#include <fontALL.h>
#include <avr/pgmspace.h>

#define spiDataPin 10
#define slaveSelectPin 11
#define spiClockPin 12
#define rssiPin A6
#define buttonSeek 2
#define buttonScan 3

#define RSSIMAX 60

#define STATE_TV 0
#define STATE_SEEK 1
#define STATE_SCAN 2
#define STATE_MANUAL 3


#define rows 96
#define cols 128

#define DEBUG

// Channels to sent to the SPI registers
const uint16_t channelTable[] PROGMEM = {
  // Channel 1 - 8
  0x2A05,	0x299B,	0x2991,	0x2987,	0x291D,	0x2913,	0x2909,	0x289F,	// Band A
  0x2903,	0x290C,	0x2916,	0x291F,	0x2989,	0x2992,	0x299C,	0x2A05,	// Band B
  0x2895,	0x288B,	0x2881,	0x2817,	0x2A0F,	0x2A19,	0x2A83,	0x2A8D,	// Band E
  0x2906,	0x2910,	0x291A,	0x2984,	0x298E,	0x2998,	0x2A02,	0x2A0C  // Airwave
};

// Channels with their Mhz Values
const uint16_t channelFreqTable[] PROGMEM = {
  // Channel 1 - 8
  5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725, // Band A
  5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866, // Band B
  5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945, // Band E
  5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880  // Airwave
};

//const char* channelNames[] PROGMEM = {
//"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8",
//"B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8",
//"E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8",
//"W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8"
//};

const uint8_t channelNames[] PROGMEM = {
  0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
  0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
  0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
  0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8
};

// All Channels of the above List ordered by Mhz
const uint8_t channelList[] PROGMEM = {
  19, 18, 17, 16, 7, 8, 24, 6, 9, 25, 5, 10, 26, 4, 11, 27, 3, 12, 28, 2, 13, 29, 1, 14, 30, 0, 15, 31, 20, 21, 22, 23
};

const uint8_t offset = 7;

uint8_t channel = 0;
uint8_t channelIndex = 0;
uint8_t rssi = 0;
uint8_t hight = 0;
uint8_t state = STATE_SEEK;
uint8_t bState = HIGH;
uint8_t writePos = 0;
uint8_t switch_count = 0;
uint8_t man_channel = 0;

TVout TV;

// SETUP ----------------------------------------------------------------------------
void setup() {

  // initialize digital pin 13 LED as an output.
  pinMode(13, OUTPUT);

  pinMode(buttonSeek, INPUT);
  digitalWrite(buttonSeek, INPUT_PULLUP);
  pinMode(buttonScan, INPUT);
  digitalWrite(buttonScan, INPUT_PULLUP);


#ifdef DEBUG
  Serial.begin(115200);
  Serial.println(F("START:")); 
#endif

  pinMode (slaveSelectPin, OUTPUT);
  pinMode (spiDataPin, OUTPUT);
  pinMode (spiClockPin, OUTPUT);

#ifdef DEBUG
  Serial.print(F("FREEMEM: ")); Serial.println(freeRam ());
#endif

  char retVal = TV.begin(NTSC, cols, rows);
  // 0 if no error.
  // 1 if x is not divisable by 8.
  // 2 if y is to large (NTSC only cannot fill PAL vertical resolution by 8bit limit)
  // 4 if there is not enough memory for the frame buffer.
  if (retVal > 0) {
    // on Error flicker LED
    while (true) {
      digitalWrite(13, !digitalRead(13));
      delay(100);
    }
  }


  TV.select_font(font4x6);

#ifdef DEBUG
  Serial.print(F("FREEMEM: ")); Serial.println(freeRam ());
#endif





/*
  TV.print("5.8GHz Spectrum Analyser");
  TV.print(2, (rows - offset + 2), "5645");
  TV.print(57, (rows - offset + 2), "5800");
  TV.print(111, (rows - offset + 2), "5945");
*/






  // Setup Done - LED ON
  digitalWrite(13, HIGH);
}

// LOOP ----------------------------------------------------------------------------
void loop() {

  
  /**************************************************  ********************************
  if (digitalRead(buttonScan) == LOW) {
    state = STATE_SCAN;
  } else {
    if (state == STATE_SCAN) {
      state = STATE_SEEK;
    }
  }
**************************************************  **********************************/

 
  if (digitalRead(buttonSeek) == LOW) {
   
    if (switch_count > 5){      //Button gedrückt
      if (state < 3){
      state = state++;            //switch states
        } else {
           state = 1; 
        }
        
      TV.clear_screen();            
      switch (state) {
//        case 0:
//          TV.print(cols/2, (rows/2), "TV");
//          break;
        case 1:
          TV.print(cols/2, (rows/2), "Auto Search");
          break;
        case 2:
          TV.print(cols/2, (rows/2), "Band Scanner");
         // TV.print("5.8GHz Spectrum Analyser");
          TV.print(2, (rows - offset + 2), "5645");
          TV.print(57, (rows - offset + 2), "5800");
          TV.print(111, (rows - offset + 2), "5945");
          break;
        case 3:
          TV.print(cols/2, (rows/2), "Manual Mode");
          break;
      }
       switch_count = 0;       
       delay(800);
       TV.print(cols/2, (rows/2), "             ");
       
      } else {
        switch_count++; 
        
      }
      
      
    } else {
      
      switch_count = 0;
      
  
    
  }

  // get Channel by Freq. Ascending
  channelIndex = pgm_read_byte_near(channelList + channel);
  //channelIndex = channel;

#ifdef DEBUG
  Serial.print(channel); Serial.print(F(" \t"));
  Serial.print(F("STATE: ")); Serial.print(state); Serial.print(F(" \t"));
  Serial.print(F("CHANNELINDEX: ")); Serial.print(channelIndex); Serial.print(F(" \t"));
#endif





/**************************MANUAL MODE***********************/

if(state == STATE_MANUAL){
  if( digitalRead(buttonSeek) == LOW){
    
    if(digitalRead(buttonScan) == LOW){
      man_channel += 8;      
    } else {
      man_channel++;
    }
      if (man_channel > 31) {  
        man_channel = 0;
      }


  //Serial.print(man_channel); Serial.print(F(" \t"));
   setChannelModule(man_channel);
    
    //Anzeige auf TVout
    TV.clear_screen();     
    TV.print(cols/2, rows/2, pgm_read_byte_near(channelNames + man_channel), HEX);
    TV.print((cols/2)+10, rows/2, pgm_read_word_near(channelFreqTable + man_channel));    
    delay(300);
  }
   
  
  
}









  // if not in TV Mode, tune Module
  if (state != STATE_TV && state != STATE_MANUAL) {
    setChannelModule(channelIndex);
  }


#ifdef DEBUG
  Serial.print(F("FREQ: ")); Serial.print(pgm_read_word_near(channelFreqTable + channelIndex)); Serial.print(F("\t"));
#endif

  // wait for tuning
  delay(100);

  // get rssi and map it to 0-70
  rssi = readRSSI();

#ifdef DEBUG
      Serial.print("RSSIraw: ");Serial.print(rssi); Serial.print(F("\t"));
#endif

  rssi = constrain(rssi, 15, 240);    //original 50---170
  rssi = map(rssi, 15, 240, 3, 70);
  
  
#ifdef DEBUG
      Serial.print("RSSI: ");Serial.print(rssi); Serial.print(F("\t"));
#endif

  // if SCAN Mode, print Spectrum
  if (state == STATE_SCAN) {
    // print bar
    hight = (rows - offset - rssi);
    TV.draw_rect((channel * 4), (rows - offset - 74), 3, 70 , BLACK, BLACK);
    TV.draw_rect((channel * 4), hight, 3, rssi , WHITE, WHITE);

    // print channelname
    if (rssi > RSSIMAX) {
      TV.draw_rect(writePos, 7, 20, 6,  BLACK, BLACK);
      TV.print(writePos, 7, pgm_read_byte_near(channelNames + channelIndex), HEX);
      TV.print(writePos+10, 7, pgm_read_word_near(channelFreqTable + channelIndex));
      writePos += 30;
      TV.print((channel * 4) - 3, hight - 5, pgm_read_byte_near(channelNames + channelIndex), HEX);
#ifdef DEBUG
      Serial.print("NAME: ");Serial.print(pgm_read_byte_near(channelNames + channelIndex), HEX); Serial.print(F("\t"));
#endif
    }

    // if SEEK Mode, check RSSI and skip Channel
  } else if (state == STATE_SEEK) {
    if (rssi > RSSIMAX) {
      state = STATE_TV;            
      TV.clear_screen();     
      TV.print(cols/2, rows/2, pgm_read_byte_near(channelNames + channelIndex), HEX);
      TV.print((cols/2)+10, rows/2, pgm_read_word_near(channelFreqTable + channelIndex));
    } else {
      TV.print(cols/2, rows/2, "Scanning....");
      delay(300);
    }
  }
  
  if (state == STATE_TV && digitalRead(buttonSeek) == LOW) {
    state = STATE_SEEK;
  }

  // if not in TV Mode, next Channel
  if (state != STATE_TV && state != STATE_MANUAL) {
    // reset Channel channeler
    if (channel < 31) {
      channel++;
    } else {
#ifdef DEBUG
      Serial.println();
#endif
      TV.draw_rect(writePos, 7, cols-writePos-1, 6,  BLACK, BLACK);
      channel = 0;
      writePos = 0;
    }
  }

#ifdef DEBUG
  Serial.println(F(""));
#endif

}

uint16_t readRSSI() {
  uint16_t rssi = 0;
  for (uint8_t i = 0; i < 10; i++) {
    rssi += analogRead(rssiPin);
  }
  return (rssi / 10);
}

// Private function: from http://arduino.cc/playground/Code/AvailableMemory
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void setChannelModule(uint8_t channel)
{
  uint8_t i;
  uint16_t channelData;

  //channelData = pgm_read_word(&channelTable[channel]);
  //channelData = channelTable[channel];
  channelData = pgm_read_word_near(channelTable + channel);

#ifdef DEBUG
  Serial.print(F("TUNE: ")); Serial.print(channelData, HEX); Serial.print(F("\t"));
#endif

  // bit bash out 25 bits of data
  // Order: A0-3, !R/W, D0-D19
  // A0=0, A1=0, A2=0, A3=1, RW=0, D0-19=0
  SERIAL_ENABLE_HIGH();
  delay(2);
  SERIAL_ENABLE_LOW();

  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT1();

  SERIAL_SENDBIT0();

  // remaining zeros
  for (i = 20; i > 0; i--)
    SERIAL_SENDBIT0();

  // Clock the data in
  SERIAL_ENABLE_HIGH();
  delay(2);
  SERIAL_ENABLE_LOW();

  // Second is the channel data from the lookup table
  // 20 bytes of register data are sent, but the MSB 4 bits are zeros
  // register address = 0x1, write, data0-15=channelData data15-19=0x0
  SERIAL_ENABLE_HIGH();
  SERIAL_ENABLE_LOW();

  // Register 0x1
  SERIAL_SENDBIT1();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();
  SERIAL_SENDBIT0();

  // Write to register
  SERIAL_SENDBIT1();

  // D0-D15
  //   note: loop runs backwards as more efficent on AVR
  for (i = 16; i > 0; i--)
  {
    // Is bit high or low?
    if (channelData & 0x1)
    {
      SERIAL_SENDBIT1();
    }
    else
    {
      SERIAL_SENDBIT0();
    }

    // Shift bits along to check the next one
    channelData >>= 1;
  }

  // Remaining D16-D19
  for (i = 4; i > 0; i--)
    SERIAL_SENDBIT0();

  // Finished clocking data in
  SERIAL_ENABLE_HIGH();
  delay(2);

  digitalWrite(slaveSelectPin, LOW);
  digitalWrite(spiClockPin, LOW);
  digitalWrite(spiDataPin, LOW);
}


void SERIAL_SENDBIT1()
{
  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);

  digitalWrite(spiDataPin, HIGH);
  delayMicroseconds(300);
  digitalWrite(spiClockPin, HIGH);
  delayMicroseconds(300);

  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);
}

void SERIAL_SENDBIT0()
{
  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);

  digitalWrite(spiDataPin, LOW);
  delayMicroseconds(300);
  digitalWrite(spiClockPin, HIGH);
  delayMicroseconds(300);

  digitalWrite(spiClockPin, LOW);
  delayMicroseconds(300);
}

void SERIAL_ENABLE_LOW()
{
  delayMicroseconds(100);
  digitalWrite(slaveSelectPin, LOW);
  delayMicroseconds(100);
}

void SERIAL_ENABLE_HIGH()
{
  delayMicroseconds(100);
  digitalWrite(slaveSelectPin, HIGH);
  delayMicroseconds(100);
}
grüße,
Peter
 

Anhänge

Butcher

Bill the Butcher
#98
Ich sag auch an der Stelle mal danke, ich hab aus des durch pete umgefrickelten codes des Fricklers mal ne ganz einfache 2 button lösung zum durchswitchen der 32 kanäle gefrickelt, einfach, schlank und simpel!

hier mal der code, ein Diagramm zur Verkablung folgt:

http://fpv-kassel.de/ul/32ch/sketch_dec07b.ino

have fun, dabei werden wie zu sehen ist an pin 2 und 3 2 buttons angeschlossen, das SPI interface liegt an 10, 11, 12, Der code verarbeitet dann zwar kein RSSI, ist aber finde ich zum einsatz auf dem Feld, wo man einfach alle Kanäle durchzappen will die sinnvollste Lösung, man sieht auch ganz gut ob man nun den Kanal genau getroffen hat oder nicht, da bei den "angrenzenden" Kanälen das Bild doch stark verstört wirkt :)

frickel On :)
 
#99
Hi,

bin gerade dabei diese cooole Kollektiveleistung noch einen Schritt weiter zu treiben.

Was ich gemacht habe:

1. Code Refakturiert (= Struktur, Formatierung, Entwicklerreliktre raus, Kommentare...)
2. Bedienung weiter optimiert
3. Optimiert auf Performance (Ein Scan dauert dann nur ~2-3 Sekunden ;-) )
4. Schöne Screens bei Ausnutzung der tollen Funktion von der TV lib...
5. mal sehen...

Videos wirds dann wohl heute geben.

Was ich noch machen will:

Das ganze z.B. auf Google als Opensource Projekt einstellen (Ist eh alles MIT Lizenz).
Da kann es einfach gepflegt werden...

Daher brauche ich noch Infos von Euch, wer was dazu begetragen hat.
Es sollte doch immer ein "Change Log" mit den Beiträgen der Leute (für den Ruhm und Verbesserungen :))

Was ich bisher auf dem Schirm habe:

1. SPI Treiber (Simon Chambers)
2. TV Lib (Myles Metzer)
3. Spektrum Scanner (Frickler)
4. Bedienkonzept (pete1990)
5. Code optimierung, Grafische Bedienung (Marko Höpken)

Ich habe Frickler ud Pete1990 direkt angeschrieben...

Fehlt noch wer?

Marko
 
Prima das das Ding weiter geführt wird! Dann muss ich meines demnächst mal updaten...

Jepp, genau, die Idee mit TV Lib sowie Scanner am TV stammen von mir, danach haben die anderen Jungs fleißig dran gearbeitet.
 
Status
Nicht offen für weitere Antworten.
FPV1

Banggood

Oben Unten