wenns nach mir geht brauchen wir nur schwarz , weis und grau
Druckbare Version
wenns nach mir geht brauchen wir nur schwarz , weis und grau
so habe jetzt den test für die dritte phase gemacht und bei mir kommen ergebnisse die schon mal ganz gut aussehen nur einen abweichung von 0,002 das sollte doch ausreichen oder ??
lg
martin
@Martin:
Das sieht sehr gut aus! Die Zeilenfrequenz beträgt 15625 Hz, d.h. alle 64 µs (Zeilenlänge) kommt ein HSync-Impuls (1 / 0,000064 s = 15625 Hz).Zitat:
... bei mir kommen ergebnisse die schon mal ganz gut aussehen nur einen abweichung von 0,002 das sollte doch ausreichen oder ??
Gruß Dirk
habe jetzt mal im wiki die rätsels lösung eingetragen also das man den jumper neun verücken mus um das vsync signal im test messsen zu können
@dirk
ist es okay wenn ich im wiki (rp6 mitmachprojekt) auch etwas ergänze oder möchtest du das nicht ???
lg
martin
@martin:
Das ist ok! Sicher gibt es noch an vielen Stellen "Lücken", besonders auch im Software-Teil!Zitat:
ist es okay wenn ich im wiki (rp6 mitmachprojekt) auch etwas ergänze
Gruß Dirk
Hallo
"Mehr als 16 Werte hintereinander kann der ADC auch bei 4MHZ-Takt nicht digitalisieren"!
Das wußten wir eigentlich schon immer, nur wirklich wahrhaben wollten wir es bisher noch nicht. Nach einem erneuten Anstoß habe ich das nun endlich mal aufgegriffen und das Einlesen einer Bildschirmzeile daraufhin "optimiert". Anstelle von "lies Werte so schnell du kannst" verwende ich nun einen regelkonformeren Ansatz:
Der ADC wandelt weiterhin im Dauerlauf, Erkennung von Bildstart und Anfang der gewünschten Zeile funktionieren wie gehabt.
Neu ist nun der Abschnitt nach dem Start der gewünschten Zeile: Bei gefundener Zeile steht nach while(ADC<30) schon der Wert des ersten Zeilenpixel in ADCH. Dieser wird abgespeichert und das ADIF-Flag wird gelöscht. Dann werden die nächsten 15 Werte eingelesen, nachdem der ADC jeweils die Fertigmeldung der Wandlung über ADIF signalisiert hat.
Nach dem Zeilensprung zur nächsten gesuchten Zeile wird das dann bis zum Bildende wiederholt. Ich verwende im Demo unten einen Zeilensprung von 10, das ergibt bei 24 Zeilen und 30 übersprungenen Zeilen eine Bildlänge von 270 Pixel (ungefähr;)
Hier nun ein paar Bilder dazu. Links der Versuchsaufbau (im Bild vom Blitz der Kamera extrem ausgeleuchtet, im Versuch war es deutlich dunkler), das TV-Kontrollbild und schließlich die Terminalausgabe:
Bild hier Bild hier Bild hier
Terminal ist ZOC das ich hier vorgestellt habe. Der Code unten funktioniert aber mit dem RP6Loader (Infos zur Anpassung im Quelltext):
Das Bild wird einmal in der Sekunde neu dargestellt, mit ZOC steht dabei das Bild still und wird nicht hochgescrollt.Code:// Ein 24*16 Ascii-Bild 3.5.10 mic
// Mit neuen Erkenntnissen ein Versuch, diese umzusetzen. Ziel war möglichst
// schnell einen Überblick über den Bildinhalt einzulesen und ohne zu Scrollen
// im Terminal darzustellen. Dazu verwende ich anstelle des Loaders ein anderes
// Terminalprogramm: https://www.roboternetz.de/phpBB2/viewtopic.php?t=54087
// Es funktioniert aber in dieser Version auch mit dem RP6Loader!
// Es werden in einem Halbbild(!) von 24 Linien jeweils die 16 Zeilenwerte am Stück
// eingelesen. Das ergibt zwar ein extrem verzerrtes Bild, aber mit 90°-Drehung
// und mit Ausgabe der Werte im Hexformat hat man so durchaus ein Bildgefühl ;)
#include "RP6RobotBaseLib.h"
#define vt100_Black 0 // VT100 Farbdefinitionen
#define vt100_Red 1
#define vt100_Green 2
#define vt100_Yellow 3
#define vt100_Blue 4
#define vt100_Magenta 5
#define vt100_Cyan 6
#define vt100_White 7
#define vt100_Reset 0
#define vt100_Bright 1
#define vt100_Dim 2
#define vt100_Underscore 4
#define vt100_Blink 5
#define vt100_Reverse 7
#define vt100_Hidden 8
uint8_t c; // freies Char
uint16_t x, y;
uint8_t std, min, sec;
void init(void);
void setMotorPWM(uint8_t power_links, uint8_t power_rechts);
void vt100_cls(void);
void vt100_set_cursor(uint8_t line, uint8_t column);
void vt100_set_color(uint8_t foreground, uint8_t background);
void vt100_set_attrib(uint8_t attrib);
void vt100_writeGrafic(uint8_t *string);
void vt100_writeGraficAt(uint8_t line, uint8_t column, uint8_t *string);
void Bild_aufnehmen(void)
{
// Variablen dürfen NICHT global sein!
uint8_t bildspeicher[24][16], *bildzeiger;
uint8_t zeile, sync, c;
zeile=30; // 30 Zeilen am Bildanfang überlesen
// Warten auf langen Syncbereich = Bildstart
cli();
do{sync=0;while (ADCH > 20);while (ADCH < 30) sync++;}while (sync < 40);
for(c=0; c<24; c++) // 24 Zeilen einlesen
{
bildzeiger=&bildspeicher[c][0];
sync=15; // 15 Werte sollen am Stück gelesen werden
while(zeile--){while (ADCH > 20);while (ADCH < 30);} // auf Zeile warten
*bildzeiger++=ADCH; // erster Wert!
ADCSRA |= (1<<ADIF);
while(sync--) // Werte 2-16 einlesen
{
while(!(ADCSRA & (1<<ADIF)));
*bildzeiger++=ADCH;
ADCSRA |= (1<<ADIF);
}
zeile=10; // 10 Zeilen überlesen (30+ 24*10 = 270 Zeilen) Sind auch 11 möglich?
}
sei();
// Hier kann man die Darstellung mit dem VT100-Terminal verbessern
writeChar('\n'); // extra Vorschub für RP6Loader
writeChar('\n');
// vt100_set_cursor(3,1); // Bildstart bei VT100-Terminal, beim RP6Loader störend
for(c=0; c<16; c++)
{
for(zeile=0; zeile<24; zeile++)
{
writeChar(' ');
//writeIntegerLength(bildspeicher[23-zeile][c], HEX, 2); // Hexwerte
writeChar((bildspeicher[zeile][c]-30)/10+'0');
}
writeChar('\n');
}
}
int main(void)
{
init();
vt100_cls();
writeString_P(" Ein 24*16 Ascii-Bild per VT100 3.5.10 mic");
setStopwatch1(0);
startStopwatch1();
while(1)
{
if(getStopwatch1() >999) // Uhr
{
setStopwatch1(0);
sec++;
if(sec>59) {sec=0; min++;}
if(min>59) {min=0; std++;}
if(std>23) std=0;
vt100_set_cursor(26,72);
writeIntegerLength(std,10,2);
writeChar(':');
writeIntegerLength(min,10,2);
writeChar(':');
writeIntegerLength(sec,10,2);
Bild_aufnehmen(); // Bildrefresh nach einer Sekunde
}
}
return(0);
}
void init(void)
{
initRobotBase();
//DDRC |= (SCL | SDA); // Servopins auf Ausgang setzen
//TIMSK |= (1 << TOIE1); // Die Timer1 Overflow-ISR zur Servoansteuerung
extIntOFF(); // schaltet den E_INT1-Port auf Eingang für den ADC
// ADC interne Referenz 2,56V, Ergebniss linksbündig, Kanal ADC4 (E_INT1)
ADMUX = (1<<REFS1) | (1<<REFS0) | (1<<ADLAR) | 4;
// setzte free running triggern
SFIOR = (0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
// kein interupt, Wandler einschalten, prescaller /2
ADCSRA = (0<<ADIE) | (1<<ADEN) | (0<<ADPS2) | (0<<ADPS1) | (1<<ADPS0);
// Autotriggern bedeutet jetzt free running aktivieren, altes Flag löschen
ADCSRA |= (1<<ADATE) | (1<<ADIF);
// Initialisierung starten
ADCSRA |= (1<<ADSC);
// und noch die wohl eher unnötige Initiallesung
while (!(ADCSRA & (1<<ADIF)));
ADCSRA |= (1<<ADIF);
//powerON();
}
// Achtung! Die PWM-Werte werden hier OHNE Rampe verändert!
void setMotorPWM(uint8_t power_links, uint8_t power_rechts)
{
extern uint8_t mleft_ptmp, mright_ptmp;
if(power_links > 210) power_links = 210;
if(power_rechts > 210) power_rechts = 210;
mleft_power=mleft_ptmp=power_links;
mright_power=mright_ptmp=power_rechts;
OCR1BL = power_links;
OCR1AL = power_rechts;
if(power_links || power_rechts)
TCCR1A = (1 << WGM11) | (1 << COM1A1) | (1 << COM1B1);
else
TCCR1A = 0;
}
void vt100_cls(void)
{
writeString_P("\x1B[2J"); // clear screen ESC [ 2 J
writeString_P("\x1B[H"); // cursor home ESC [ H
}
void vt100_set_cursor(uint8_t line, uint8_t column)
{
writeString_P("\x1B["); // set cursor position ESC [ Pl ; Pc H
writeInteger(line, 10);
writeString_P(";");
writeInteger(column, 10);
writeString_P("H");
}
void vt100_set_color(uint8_t foreground, uint8_t background)
{
writeString_P("\x1b[");
writeInteger(30+foreground, 10);
writeString_P(";");
writeInteger(40+background, 10);
writeString_P("m");
}
void vt100_set_attrib(uint8_t attrib)
{
writeString_P("\x1b[");
writeInteger(0, 10);
writeString_P(";");
writeInteger(attrib, 10);
writeString_P("m");
}
void vt100_writeGrafic(uint8_t *string)
{
while(*string)
writeChar(128|*string++); // Grafikzeichen mit gesetztem Bit7 senden
}
void vt100_writeGraficAt(uint8_t line, uint8_t column, uint8_t *string)
{
vt100_set_cursor(line, column); // Cursor postionieren
while(*string)
writeChar(128|*string++); // Grafikzeichen mit gesetztem Bit7 senden
}
Gruß
mic
PS:
Bei der Ausgabe der Werte dreht sich alles um diese Zeile:
writeChar((bildspeicher[zeile][c]-30)/10+'0');
Vom Helligkeitswert von Bildpunkt x, y wird der Grundwert 30 abgezogen, der Rest durch 10 geteilt. Das ergab bei meinem Demo Werte bis 4. Um die Ausgabe z.B. auf einstellige Werte oder begrenzte Graustufen zu optimieren müßte man an dieser Formel schrauben. Die '0' sollte wohl klar sein ;)
Auf diese Bildbasis könnte man schon einfache Bildanalysen wie hellster/dunkelster Punkt/Zeile/Spalte aufsetzen oder Faltungen anwenden um Kanten zu finden ;)
Erst klassig werd ich bald mal ausprobieren
@mic:
Wieder mal ein tolles Stück! Muss ich gleich probieren!
Ich denke: Nein.Zitat:
(30+ 24*10 = 270 Zeilen) Sind auch 11 möglich?
Mein erstes "Zählprogramm", das die wirklich vorhandenen TV Zeilen der CMOS Kamera ermittelt, gibt aus: 288.
Das hat mich auch gewundert, ich war nach Datenblatt von 260 TV Zeilen ausgegangen, obwohl das Bildelement mit 288 angegeben wird.
Gruß Dirk
hi Leute,
ich hätte da ein kleines Problem ich habe nämlich heute mdie kamera platine fertig nun ist die kammera ja festgelötet und ich weiß nicht mehr welcher Pin was ist könnte jemand ein bild von der rückseite seiner Kammera machen
Danke
Leider etwas unscharf:
Bild hier
Von oben links nach unten:
Video out
GND
Vcc
Gamma
Gain
Die Kamera sollte man steckbar einbauen ;)
Gruß
mic