Dirk
07.05.2010, 18:07
Hallo Leute,
für die Experimentierplatine, die wir hier beschrieben haben:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=53424
... und die hier:
http://www.rn-wissen.de/index.php/RP6_Kamera_-_Mitmach-Projekt
... gebaut wurde, hier ein zweites Programm für die M32. Es funktioniert ab der Phase 3 des Aufbaus.
Auf dem LCD wird die Zahl der CSync-Flanken bis zur 1. TV Zeile, die Anzahl der TV Zeilen und der Video Pegel der Austastlücke und einer TV Zeile angezeigt.
/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 TESTS
* ************************************************** **************************
* Beispiel: Zählt die Video (TV) Zeilen einer CMOS Kamera
* Autor(en): Dirk
* ************************************************** **************************
* Beschreibung:
*
* Mit diesem Programm kann die Zeilenzahl einer CMOS Kamera (CONRAD 150001)
* und die Zahl der CSync Flanken von VSync bis zur ersten TV Zeile auf dem
* LCD angezeigt werden. Der Video Pegel der Austastlücke und einer TV Zeile
* wird auch angezeigt.
* Die Kamera ist an dieses Hardware Projekt (Phase 3 und höher) angeschlossen:
* http://www.rn-wissen.de/index.php/RP6_Kamera_-_Mitmach-Projekt
* Die BAS Video Information (PG3) ist angeschlossen an ADC4 (M32 ADC Stecker,
* Pin 3).
* Die Synchronisationssignale sind wie folgt verbunden:
*
* Signal RP6 Name Port Funktion
* VSync EINT2 PD3 INT1
* HSync IO_PD6 PD6 ICP1
* Odd/Even EINT3 PB2 INT2
*
* ################################################## ##########################
* Der Roboter bewegt sich NICHT in diesem Beispiel! Du kannst ihn einfach auf
* einen Tisch neben deinen PC stellen und solltest ihn mit dem PC über das
* USB-Interface verbinden!
* ################################################## ##########################
* ************************************************** **************************
*/
/************************************************** ***************************/
// Einzufügende Dateien:
#include "RP6ControlLib.h" // Die RP6 Control Bibliothek.
// Muss immer eingefügt werden!
/************************************************** ***************************/
// Definitionen:
#define FALLING 0 // Fallende Flanken
#define RISING 1 // Steigende Flanken
//-------------------------------
#define EDGE FALLING //<== Wähle FALLENDE oder
// STEIGENDE Flanken!
//-------------------------------
#define ODD (1<<EINT3) // Feld 1
#define EVEN 0 // Feld 2
//-------------------------------
#define FIELD ODD //<== Wähle Feld 1 oder Feld 2!
//-------------------------------
#define VIDEO_BLANK 108 //<== Passe den Video Pegel der
// Austastlücke an!
#define HSYNC (PIND & IO_PD6)
#define VSYNC (PIND & EINT2)
#define ODD_EVEN (PINB & EINT3)
#define IRon() (PORTC &= ~IO_PC6)
#define IRoff() (PORTC |= IO_PC6)
/************************************************** ***************************/
// Variablen:
volatile uint16_t edgecnt;
volatile uint16_t video;
volatile uint8_t tvlevelflag;
uint8_t field;
uint16_t blankedges;
uint16_t tvlines;
uint16_t videolevel_1;
uint16_t videolevel_2;
/************************************************** ***************************/
// Funktionen:
/**
* TIMER1 Capture ISR
*
* In dieser ISR werden die fallenden/steigenden Flanken des CSync Signals
* ab VSync gezählt, und der Video Pegel wird einmal pro Zeile mit ADC4
* gemessen. Im Hauptprogramm muss edgecnt direkt nach der fallenden
* Flanke von VSync auf Null zurückgesetzt werden!
* Die komplette Zeit der Messung vom Zeitpunkt des "Sample and Hold" bis
* zum Ergebnis in ADC liegt in der ersten Hälfte der TV Zeile, weil
* einige Impulse in der Austastlücke einen Abstand von ca. 32 µs (eine
* halbe TV Zeile) haben. Daher darf die ISR nicht länger als eine halbe
* TV Zeile dauern!
* Der Video Pegel wird NICHT nach den ersten 10 CSync Flanken nach VSync
* gemessen.
*
* Ausgabe: edgecnt -> CSync Flankenzähler
* video -> 10 Bit ADC Wert (Video Pegel)
* tvlevelflag -> true: TV Zeile mit Video Inhalt
* false: Austastlücke
*
* ACHTUNG: Die Konstante VIDEO_BLANK muss auf einen Video Pegel
* zwischen dem Pegel der Austastlücke und dem einer TV
* Zeile in einem völlig dunklen Raum angepaßt werden!
*
*/
ISR (TIMER1_CAPT_vect)
{uint8_t h_delay;
edgecnt++;
tvlevelflag = false;
if (edgecnt > 10) {
h_delay=15; while (h_delay--) {nop();};
ADMUX = (1<<REFS0) | (1<<REFS1) | (ADC_4<<MUX0);
ADCSRA = (0<<ADIE) | (1<<ADSC) | (1<<ADEN)
| (1<<ADPS2) | (1<<ADPS1) | (1<<ADIF);
while(ADCSRA & (1<<ADIF));
ADCSRA |= (1<<ADIF);
video = ADC;
if (video > VIDEO_BLANK) tvlevelflag = true;
}
}
/************************************************** ***************************/
// Haupt Funktion - Das Programm beginnt hier:
int main(void)
{
initRP6Control();
initLCD();
showScreenLCD("################", "################");
mSleep(1500);
showScreenLCD("<<RP6 Control>>", "<<LC - DISPLAY>>");
mSleep(2500);
showScreenLCD(" Video Lines Cnt", " Version 1.00 ");
mSleep(2500);
clearLCD();
setLEDs(0b0000);
// Initialisiere den M32 ICP Pin (PD6) als Eingang:
DDRD &= ~IO_PD6; // ==> HSync
PORTD |= IO_PD6; // Pullup an
// Initialisiere den M32 INT1 Pin (PD3) als Eingang:
DDRD &= ~EINT2; // ==> VSync
PORTD |= EINT2; // Pullup an
// Initialisiere den M32 INT2 Pin (PB2) als Eingang:
DDRB &= ~EINT3; // ==> Odd/Even
PORTB |= EINT3; // Pullup an
// Initialisiere den M32 TOSC1 Pin (PC6) als Ausgang:
DDRC |= IO_PC6; // ==> IR
IRoff(); // IR LEDs aus
// Initialisiere die M32 Timer1 Input Capture Funktion:
TCCR1B = (1<<CS10) // Trigger: Kein Vorteiler
| (1<<ICNC1); // und Noise Canceler
#if EDGE
TCCR1B |= (1<<ICES1); // Steigende Flanke
#else
TCCR1B &= ~(1<<ICES1); // Fallende Flanke
#endif
/*
// Zeige die ADC Werte der Austastlücke und einer TV Zeile:
// Wenn man VIDEO_BLANK (für eine andere Kamera) anpassen will,
// muss man diese Konstante auf einen Wert setzen, der zwischen
// den beiden hier angezeigten Werten liegt. Das muss in einem
// dunklen Raum gemacht werden, um einen sehr niedrigen TV
// Video Pegel zu erreichen!
TIMSK = (1<<TICIE1); // Aktiviere Capture ISR
while(true)
{
while(VSYNC); // Warte auf Seitenanfang
TIFR = (1<<ICF1); // Lösche aktiven Interrupt
edgecnt = 0; // Flankenzähler zurücksetzen
while(edgecnt < 18); // Austastlücke!
videolevel_2 = video; // Speichere Pegel der Austastlücke
while(edgecnt < 120); // TV Zeilen Bereich!
videolevel_1 = video; // Speichere TV Video Pegel
setCursorPosLCD(0, 0);
writeStringLCD("Video Blank ");
writeIntegerLengthLCD(videolevel_2, DEC, 3);
setCursorPosLCD(1, 0);
writeStringLCD("Video TV ");
writeIntegerLengthLCD(videolevel_1, DEC, 3);
while(!VSYNC); // Warte auf VSync Highpegel
}
*/
// Zeige die Anzahl der CSync Flanken bis zur ersten TV Zeile,
// die Zahl der TV Zeilen, den Video Pegel der Austastlücke und
// einer TV Zeile an:
// Wenn hier keine realistischen Werte angezeigt werden, muss
// die Konstante VIDEO_BLANK (siehe oben!) angepaßt werden.
while(true)
{
while(VSYNC); // Warte auf Seitenanfang
nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
TIFR = (1<<ICF1); // Lösche aktiven Interrupt
edgecnt = 0; // Flankenzähler zurücksetzen
TIMSK = (1<<TICIE1); // Aktiviere Capture ISR
field = ODD_EVEN; // Feld Nummer?
if ((field && FIELD)
|| ((!field) && (!FIELD))) { // Gewähltes Feld?
tvlevelflag = false;
while(!tvlevelflag); // Zähle bis zur ersten TV Zeile
blankedges = edgecnt;
videolevel_1 = video; // Speichere den TV Video Pegel
blankedges--; // HSync der ersten TV Zeile!
while(tvlevelflag); // Zähle bis zum Ende der TV Zeilen
tvlines = edgecnt - blankedges;
videolevel_2 = video; // Speichere Pegel der Austastlücke
tvlines--; // Anzahl TV Zeilen!
TIMSK &= ~(1<<TICIE1); // Inaktiviere Capture ISR
setCursorPosLCD(0, 0);
writeStringLCD("Ebn");
writeIntegerLengthLCD(blankedges, DEC, 3);
setCursorPosLCD(0, 7);
writeStringLCD("Ltv");
writeIntegerLengthLCD(tvlines, DEC, 3);
if (field) writeStringLCD(" :O"); // Zeige Odd/Even Feld
else writeStringLCD(" :E");
setCursorPosLCD(1, 0);
writeStringLCD("Vbn");
writeIntegerLengthLCD(videolevel_2, DEC, 3);
setCursorPosLCD(1, 7);
writeStringLCD("Vtv");
writeIntegerLengthLCD(videolevel_1, DEC, 3);
#if (EDGE == FALLING)
writeStringLCD(" :F"); // Zeige Falling/Rising Flanke
#else
writeStringLCD(" :R");
#endif
while(!VSYNC); // Warte auf VSync Highpegel
}
}
return 0;
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 07.05.2010 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
Viel Spaß!
Gruß Dirk
für die Experimentierplatine, die wir hier beschrieben haben:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=53424
... und die hier:
http://www.rn-wissen.de/index.php/RP6_Kamera_-_Mitmach-Projekt
... gebaut wurde, hier ein zweites Programm für die M32. Es funktioniert ab der Phase 3 des Aufbaus.
Auf dem LCD wird die Zahl der CSync-Flanken bis zur 1. TV Zeile, die Anzahl der TV Zeilen und der Video Pegel der Austastlücke und einer TV Zeile angezeigt.
/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 TESTS
* ************************************************** **************************
* Beispiel: Zählt die Video (TV) Zeilen einer CMOS Kamera
* Autor(en): Dirk
* ************************************************** **************************
* Beschreibung:
*
* Mit diesem Programm kann die Zeilenzahl einer CMOS Kamera (CONRAD 150001)
* und die Zahl der CSync Flanken von VSync bis zur ersten TV Zeile auf dem
* LCD angezeigt werden. Der Video Pegel der Austastlücke und einer TV Zeile
* wird auch angezeigt.
* Die Kamera ist an dieses Hardware Projekt (Phase 3 und höher) angeschlossen:
* http://www.rn-wissen.de/index.php/RP6_Kamera_-_Mitmach-Projekt
* Die BAS Video Information (PG3) ist angeschlossen an ADC4 (M32 ADC Stecker,
* Pin 3).
* Die Synchronisationssignale sind wie folgt verbunden:
*
* Signal RP6 Name Port Funktion
* VSync EINT2 PD3 INT1
* HSync IO_PD6 PD6 ICP1
* Odd/Even EINT3 PB2 INT2
*
* ################################################## ##########################
* Der Roboter bewegt sich NICHT in diesem Beispiel! Du kannst ihn einfach auf
* einen Tisch neben deinen PC stellen und solltest ihn mit dem PC über das
* USB-Interface verbinden!
* ################################################## ##########################
* ************************************************** **************************
*/
/************************************************** ***************************/
// Einzufügende Dateien:
#include "RP6ControlLib.h" // Die RP6 Control Bibliothek.
// Muss immer eingefügt werden!
/************************************************** ***************************/
// Definitionen:
#define FALLING 0 // Fallende Flanken
#define RISING 1 // Steigende Flanken
//-------------------------------
#define EDGE FALLING //<== Wähle FALLENDE oder
// STEIGENDE Flanken!
//-------------------------------
#define ODD (1<<EINT3) // Feld 1
#define EVEN 0 // Feld 2
//-------------------------------
#define FIELD ODD //<== Wähle Feld 1 oder Feld 2!
//-------------------------------
#define VIDEO_BLANK 108 //<== Passe den Video Pegel der
// Austastlücke an!
#define HSYNC (PIND & IO_PD6)
#define VSYNC (PIND & EINT2)
#define ODD_EVEN (PINB & EINT3)
#define IRon() (PORTC &= ~IO_PC6)
#define IRoff() (PORTC |= IO_PC6)
/************************************************** ***************************/
// Variablen:
volatile uint16_t edgecnt;
volatile uint16_t video;
volatile uint8_t tvlevelflag;
uint8_t field;
uint16_t blankedges;
uint16_t tvlines;
uint16_t videolevel_1;
uint16_t videolevel_2;
/************************************************** ***************************/
// Funktionen:
/**
* TIMER1 Capture ISR
*
* In dieser ISR werden die fallenden/steigenden Flanken des CSync Signals
* ab VSync gezählt, und der Video Pegel wird einmal pro Zeile mit ADC4
* gemessen. Im Hauptprogramm muss edgecnt direkt nach der fallenden
* Flanke von VSync auf Null zurückgesetzt werden!
* Die komplette Zeit der Messung vom Zeitpunkt des "Sample and Hold" bis
* zum Ergebnis in ADC liegt in der ersten Hälfte der TV Zeile, weil
* einige Impulse in der Austastlücke einen Abstand von ca. 32 µs (eine
* halbe TV Zeile) haben. Daher darf die ISR nicht länger als eine halbe
* TV Zeile dauern!
* Der Video Pegel wird NICHT nach den ersten 10 CSync Flanken nach VSync
* gemessen.
*
* Ausgabe: edgecnt -> CSync Flankenzähler
* video -> 10 Bit ADC Wert (Video Pegel)
* tvlevelflag -> true: TV Zeile mit Video Inhalt
* false: Austastlücke
*
* ACHTUNG: Die Konstante VIDEO_BLANK muss auf einen Video Pegel
* zwischen dem Pegel der Austastlücke und dem einer TV
* Zeile in einem völlig dunklen Raum angepaßt werden!
*
*/
ISR (TIMER1_CAPT_vect)
{uint8_t h_delay;
edgecnt++;
tvlevelflag = false;
if (edgecnt > 10) {
h_delay=15; while (h_delay--) {nop();};
ADMUX = (1<<REFS0) | (1<<REFS1) | (ADC_4<<MUX0);
ADCSRA = (0<<ADIE) | (1<<ADSC) | (1<<ADEN)
| (1<<ADPS2) | (1<<ADPS1) | (1<<ADIF);
while(ADCSRA & (1<<ADIF));
ADCSRA |= (1<<ADIF);
video = ADC;
if (video > VIDEO_BLANK) tvlevelflag = true;
}
}
/************************************************** ***************************/
// Haupt Funktion - Das Programm beginnt hier:
int main(void)
{
initRP6Control();
initLCD();
showScreenLCD("################", "################");
mSleep(1500);
showScreenLCD("<<RP6 Control>>", "<<LC - DISPLAY>>");
mSleep(2500);
showScreenLCD(" Video Lines Cnt", " Version 1.00 ");
mSleep(2500);
clearLCD();
setLEDs(0b0000);
// Initialisiere den M32 ICP Pin (PD6) als Eingang:
DDRD &= ~IO_PD6; // ==> HSync
PORTD |= IO_PD6; // Pullup an
// Initialisiere den M32 INT1 Pin (PD3) als Eingang:
DDRD &= ~EINT2; // ==> VSync
PORTD |= EINT2; // Pullup an
// Initialisiere den M32 INT2 Pin (PB2) als Eingang:
DDRB &= ~EINT3; // ==> Odd/Even
PORTB |= EINT3; // Pullup an
// Initialisiere den M32 TOSC1 Pin (PC6) als Ausgang:
DDRC |= IO_PC6; // ==> IR
IRoff(); // IR LEDs aus
// Initialisiere die M32 Timer1 Input Capture Funktion:
TCCR1B = (1<<CS10) // Trigger: Kein Vorteiler
| (1<<ICNC1); // und Noise Canceler
#if EDGE
TCCR1B |= (1<<ICES1); // Steigende Flanke
#else
TCCR1B &= ~(1<<ICES1); // Fallende Flanke
#endif
/*
// Zeige die ADC Werte der Austastlücke und einer TV Zeile:
// Wenn man VIDEO_BLANK (für eine andere Kamera) anpassen will,
// muss man diese Konstante auf einen Wert setzen, der zwischen
// den beiden hier angezeigten Werten liegt. Das muss in einem
// dunklen Raum gemacht werden, um einen sehr niedrigen TV
// Video Pegel zu erreichen!
TIMSK = (1<<TICIE1); // Aktiviere Capture ISR
while(true)
{
while(VSYNC); // Warte auf Seitenanfang
TIFR = (1<<ICF1); // Lösche aktiven Interrupt
edgecnt = 0; // Flankenzähler zurücksetzen
while(edgecnt < 18); // Austastlücke!
videolevel_2 = video; // Speichere Pegel der Austastlücke
while(edgecnt < 120); // TV Zeilen Bereich!
videolevel_1 = video; // Speichere TV Video Pegel
setCursorPosLCD(0, 0);
writeStringLCD("Video Blank ");
writeIntegerLengthLCD(videolevel_2, DEC, 3);
setCursorPosLCD(1, 0);
writeStringLCD("Video TV ");
writeIntegerLengthLCD(videolevel_1, DEC, 3);
while(!VSYNC); // Warte auf VSync Highpegel
}
*/
// Zeige die Anzahl der CSync Flanken bis zur ersten TV Zeile,
// die Zahl der TV Zeilen, den Video Pegel der Austastlücke und
// einer TV Zeile an:
// Wenn hier keine realistischen Werte angezeigt werden, muss
// die Konstante VIDEO_BLANK (siehe oben!) angepaßt werden.
while(true)
{
while(VSYNC); // Warte auf Seitenanfang
nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
TIFR = (1<<ICF1); // Lösche aktiven Interrupt
edgecnt = 0; // Flankenzähler zurücksetzen
TIMSK = (1<<TICIE1); // Aktiviere Capture ISR
field = ODD_EVEN; // Feld Nummer?
if ((field && FIELD)
|| ((!field) && (!FIELD))) { // Gewähltes Feld?
tvlevelflag = false;
while(!tvlevelflag); // Zähle bis zur ersten TV Zeile
blankedges = edgecnt;
videolevel_1 = video; // Speichere den TV Video Pegel
blankedges--; // HSync der ersten TV Zeile!
while(tvlevelflag); // Zähle bis zum Ende der TV Zeilen
tvlines = edgecnt - blankedges;
videolevel_2 = video; // Speichere Pegel der Austastlücke
tvlines--; // Anzahl TV Zeilen!
TIMSK &= ~(1<<TICIE1); // Inaktiviere Capture ISR
setCursorPosLCD(0, 0);
writeStringLCD("Ebn");
writeIntegerLengthLCD(blankedges, DEC, 3);
setCursorPosLCD(0, 7);
writeStringLCD("Ltv");
writeIntegerLengthLCD(tvlines, DEC, 3);
if (field) writeStringLCD(" :O"); // Zeige Odd/Even Feld
else writeStringLCD(" :E");
setCursorPosLCD(1, 0);
writeStringLCD("Vbn");
writeIntegerLengthLCD(videolevel_2, DEC, 3);
setCursorPosLCD(1, 7);
writeStringLCD("Vtv");
writeIntegerLengthLCD(videolevel_1, DEC, 3);
#if (EDGE == FALLING)
writeStringLCD(" :F"); // Zeige Falling/Rising Flanke
#else
writeStringLCD(" :R");
#endif
while(!VSYNC); // Warte auf VSync Highpegel
}
}
return 0;
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 07.05.2010 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
Viel Spaß!
Gruß Dirk