Hallo

Trotz Mitmachprojekt finden sich immer noch keine Anwendungen für diese einfache und kostengünstige Kameralösung. Weil ich die Kamera aber für mein RA2-Projekt verwenden möchte und mir gleichzeitig eher zufällig ein zur Kamera passendes sehr grobpixeliges Display in die Hände gefallen ist, habe ich eine Variante für einen 8MHz-ATMega8 geschrieben. Aufgrund der Erkenntnisse aus dem Mitmach-Thread verwende ich als Basis das einfache 24x16 Pixel-Programm. An das Display angepasst werden nur 12 der 16 möglichen x-Pixel angezeigt, die y-Auflösung wurde auf 10 Zeilen reduziert. Der ADC rennt zwar immer noch mit Prescaler /2 im Dauerlauf, aber da nun auf das Ende der AD-Wandlung gewartet wird, ist das Einlesen eines Bildes so entspannt, dass man dazu nicht mal mehr die Interrupts sperren muss:

Code:
uint8_t bild[4][160];

uint8_t Bild_aufnehmen(void)
{
	static uint8_t bildnummer=0;
	uint8_t *bildzeiger;
   uint8_t zeile, sync, c;

   bildnummer = (bildnummer+1) & 3; // Bildnummer von 0 bis 3
   zeile=30; // 30 Zeilen am Bildanfang überlesen
   bildzeiger = &bild[bildnummer][0];

   do{sync=0;while (ADCH > 20);while (ADCH < 30) sync++;}while (sync < 40);
   for(c=0; c<10; c++) // 10 Zeilen einlesen
   {
      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=24; // 24 Zeilen überlesen (30+ 24*10 = 270 Zeilen)
   }
	return(bildnummer);
}
Wie gehabt wird der ADC mit Prescaler /2, rechtsbündig und mit interner 2,56V-Referenz betrieben. Nach der Erkennung des Bildstarts werden 30 Zeilen überlesen, dann werden in einem Rutsch die 16 Pixel einer Zeile eingelesen. Nach jeweils einem Zeilensprung von 24 Zeilen werden dann schließlich die restlichen 9 Zeilen eingelesen. Das alles passiert innerhalb eines Halbbildes und mit freigegebenen Interrupts!

Der Bildspeicher ist 16x10=160 Bytes groß, ich verwende davon vier Stück die ich nacheinander mit den Kameradaten fülle. Die Einlesefunktion verwendet die Bildspeicher als Ringspeicher. Die Auswertefunktion bildet das Mittel aus den einzelnen Bildspeichern und stellt die Pixel auf dem Display dar:

Bild hier  
http://www.youtube.com/watch?v=ngim6DzIcGQ

Mein ungeputzter Arbeitscode:

Code:
// Kamera und acht Helligkeitsstufen                               mic 29.12.2010

#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <inttypes.h>

#define colors 8 // Anzahl der Farbebenen (8 ist Maximum!)

// Variablen ------------------------------------------------------------------
volatile uint8_t ebene=0, col = 0; // Bildaufbau der LED-Matrix mit Timer2-ISR
uint8_t x, y, z, bildspeicher[colors][15];
uint8_t bild[4][160];
uint16_t counter=0;
uint8_t attrib=1;

prog_uint8_t font[5][17]={ // Zeichensatz für 3x5 7-Segmentanzeige 0 bis F und Blank (Speicherplatz im Flash)
{ 0b111, 0b001, 0b111, 0b111, 0b100, 0b111, 0b100, 0b111, 0b111, 0b111, 0b111, 0b100, 0b111, 0b001, 0b111, 0b111, 0b000},\
{ 0b101, 0b001, 0b001, 0b001, 0b101, 0b100, 0b100, 0b001, 0b101, 0b101, 0b101, 0b100, 0b100, 0b001, 0b100, 0b100, 0b000},\
{ 0b101, 0b001, 0b111, 0b111, 0b111, 0b111, 0b111, 0b001, 0b111, 0b111, 0b111, 0b111, 0b100, 0b111, 0b111, 0b111, 0b000},\
{ 0b101, 0b001, 0b100, 0b001, 0b001, 0b001, 0b101, 0b001, 0b101, 0b001, 0b101, 0b101, 0b100, 0b101, 0b100, 0b100, 0b000},\
{ 0b111, 0b001, 0b111, 0b111, 0b001, 0b111, 0b111, 0b001, 0b111, 0b001, 0b101, 0b111, 0b111, 0b111, 0b111, 0b100, 0b000} \
};
prog_uint8_t * fnt = (prog_uint8_t *) font; // Zeiger für den Zugriff auf den Zeichensatz (für plot_byte())

// Funktionen -----------------------------------------------------------------
void init(void);
void cls(void);
void plot_byte(uint8_t x, uint8_t y, uint8_t ziffer); // Ziffer von 0 bis F
void write_byte(uint8_t a, uint8_t z); // z=0 ist oben, z=1 ist unten
uint8_t Bild_aufnehmen(void);
void Bild_darstellen(uint8_t level);
void Bild_Info(void);
// Einen Bildpunkt an x, y setzen. Werte für c: 0 ist aus, 1 ist dunkel, 4 ist hell
void set(uint8_t x, uint8_t y, uint8_t c);
// Potiwert P2 an ADC6 einlesen als Byte! Kanal 7 ist die Cam
uint8_t readADC6(void);

// WatchDog beim Initialisieren ausschalten
// https://www.roboternetz.de/phpBB2/vi...=531597#531597
void kill_WD(void) __attribute__((naked)) __attribute__((section(".init3")));
void kill_WD(void) { MCUSR = 0; wdt_disable(); }

// Hauptschleife --------------------------------------------------------------
int main(void)
{
	init();
	for(x=0; x<12; x++)
	   for(y=0; y<10; y++)
			set(x, y, (colors-((x+y)/3)%colors)); // Helligkeitsstufen anzeigen
   _delay_ms(2000);

 	cls();

	while(Bild_aufnehmen()); 				// Bildspeicher füllen
	// Bild_Info(); // min - max - mitte - durchschnitt
	while(1)
	{
		if(!col)
		{
   		z=readADC6();
   		if(attrib)
			{
				for(y=5; y<10; y++)
   	   		for(x=0; x<12; x++) set(x, y, z/29); // 255/29 ergibt 8,8
			}
			else
			{
	      	while(Bild_aufnehmen());
				Bild_darstellen(z);
			}
   		if(z==0) if(attrib) { attrib=0; Bild_Info(); } // Bit0: Zeile
   		if(z==255) if(!attrib) { attrib=1;};
			if(attrib) write_byte(z, attrib);
		}
      counter++;
	}
	return (0);
}

// Definitionen der Funktionen ------------------------------------------------
uint8_t Bild_aufnehmen(void)
{
	static uint8_t bildnummer=0;
	uint8_t *bildzeiger;
   uint8_t zeile, sync, c;

   bildnummer = (bildnummer+1) & 3; // Bildnummer von 0 bis 3
   zeile=30; // 30 Zeilen am Bildanfang überlesen
   bildzeiger = &bild[bildnummer][0];

   do{sync=0;while (ADCH > 20);while (ADCH < 30) sync++;}while (sync < 40);
   for(c=0; c<10; c++) // 10 Zeilen einlesen
   {
      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=24; // 24 Zeilen überlesen (30+ 24*10 = 270 Zeilen)
   }
	return(bildnummer);
}

void Bild_darstellen(uint8_t level)
{
   uint8_t x, y, temp;
   uint8_t bild_temp[160];
   uint16_t temp16;

   for(x=0; x<160; x++)
   {
      temp16 = bild[0][x] + bild[1][x] + bild[2][x] + bild[3][x];
      bild_temp[x] = temp = temp16/4;
	}

	if(level)
	{
		for(y=0; y<10; y++)
	   	for(x=0; x<12; x++)
			{
		   	temp= bild_temp[16*y+x+2];
	      	if(temp<level) set(x, 9-y, colors); else set(x, 9-y, 0);
			}
	}
	else
		for(y=0; y<10; y++)
	   	for(x=0; x<12; x++)
			{
		   	temp= bild_temp[16*y+x+2];
	      	set(x, 9-y, (temp-20)/8);
			}
}

void Bild_Info(void)
{
   uint8_t min=225, max=0, temp;
   uint16_t durchschnitt=0, temp16;

   for(x=0; x<160; x++)
   {
      temp16 = bild[0][x] + bild[1][x] + bild[2][x] + bild[3][x];
      temp = temp16/4;
      if(temp > max) max=temp;
         else if(temp>20) if(temp < min) min=temp;
		durchschnitt += temp;
	}
	durchschnitt /= 160;

	cls();
	write_byte(min, 1);
	_delay_ms(1000);
	cls();
	write_byte(max, 0);
	_delay_ms(1000);
	cls();
	write_byte((min+max)/2, 1);
	_delay_ms(1000);
	cls();
	write_byte(durchschnitt, 0);
	_delay_ms(1000);
}

void cls(void)
{
	uint8_t x, y;
   for(y=0; y<colors; y++)
		for(x=0; x<15; x++)bildspeicher[y][x] = 0;
}
void set(uint8_t x, uint8_t y, uint8_t c)
{
	uint8_t ebene;

	y = 9-y;	// Koordinatennullpunkt unten links
	if(y < 8) // y 9 bis 2
	   for(ebene=0; ebene<colors; ebene++)
	   	if(c>ebene) bildspeicher[ebene][x] |= (1 << y);
	   	   else bildspeicher[ebene][x] &= ~(1 << y);
	else // y 1 und 0
		for(ebene=0; ebene<colors; ebene++)
	   	if(c>ebene) bildspeicher[ebene][12+(x>>2)] |= (1<<((x%4)*2+(y&1)));
	   		else bildspeicher[ebene][12+(x>>2)] &= ~(1<<((x%4)*2+(y&1)));
}
void plot_byte(uint8_t x, uint8_t y, uint8_t ziffer)
{
	uint8_t c, f1=colors, f2=0, fontbyte=0;

	for(c=0; c<5; c++)
	{
		fontbyte = pgm_read_byte_near(fnt+17*c+ziffer); // Zeichensatz ist im Flash
		if(fontbyte & 4) set(x  , y-c, f1); else set(x  , y-c, f2);
		if(fontbyte & 2) set(x+1, y-c, f1); else set(x+1, y-c, f2);
		if(fontbyte & 1) set(x+2, y-c, f1); else set(x+2, y-c, f2);
		if(fontbyte & 0) set(x+3, y-c, f1); else set(x+3, y-c, f2);
	}
}
void write_byte(uint8_t a, uint8_t z) // z=0 ist oben, z=1 ist unten
{
	uint8_t c, temp=1;

	c=0;
	while(a >= 100) {a-=100; c++; }
	if(c) plot_byte(0, 9-5*z, c); else { plot_byte(0, 9-5*z, 16); temp=0; }
	c=0;
	while(a >= 10) {a-=10; c++; }
	if(c || temp) plot_byte(4, 9-5*z, c); else plot_byte(4, 9-5*z, 16);
	c=0;
	while(a >= 1) {a-=1; c++; }
	plot_byte(8, 9-5*z, c);
}
uint8_t readADC6(void)
{
 	uint8_t adc6, dummy;
	ADCSRA = (0 << ADEN);
	dummy=ADCH;
 	
	// A/D Conversion (aus der asuro-Lib)
	ADCSRA = (1 << ADEN) | (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); // clk/32
	ADMUX = (1<<ADLAR) | (1 << REFS0) | (6);// AVCC reference with external capacitor
	ADCSRA |= (1 << ADSC);					// Start conversion
	while (!(ADCSRA & (1 << ADIF)));		// wait for conversion complete
	adc6=ADCH;
	ADCSRA |= (1 << ADIF);					// clear ADCIF
	ADCSRA = (0 << ADEN);
	dummy=ADCH;
	// rechtsbündig, interne 2,56V-Referenz (0:1 5V, 1:1 2,56V) , Kanal 7
	ADMUX = (1<<ADLAR) | (1<<REFS1) | (1<<REFS0) | 7;
	// enable, start conversion, freerunning, prescaler /2
	ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (0<<ADPS2) | (0<<ADPS1) | (1<<ADPS0);

	return(adc6);
}
void init(void)
{
	cli();

	DDRB = 0xff;
	DDRC = 0x0f;
	DDRD = 0xf0;

	TCCR2 = (1<<CS21) | (0<<CS20);		// 8-bit Timer mit 1/8 Vorteiler
	TCCR2 |= (1<<WGM21) | (1<<WGM20); 	// Fast PWM
	TCCR2 |= (0<<COM21) | (0<<COM20); 	// no OC2-Pin
	OCR2 = 100;                         // 0=dunkel, 255=hell
	TIFR = (1<<OCF2) | (1<<TOV2); 		// Clear old flags
	TIMSK |= (1<<TOIE2) | (1<<OCIE2);	// overflow and compare interrupt

	// rechtsbündig, interne 2,56V-Referenz (0:1 5V, 1:1 2,56V) , Kanal 7
	ADMUX = (1<<ADLAR) | (1<<REFS1) | (1<<REFS0) | 7;
	// enable, start conversion, freerunning, prescaler /2
	ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (0<<ADPS2) | (0<<ADPS1) | (1<<ADPS0);

	sei();							    		// Interrupts erlauben
}

// ISR ------------------------------------------------------------------------
SIGNAL (SIG_OUTPUT_COMPARE2)
{
	OCR2 = (1<<ebene)-1;	// hihi
	PORTC &= ~0x0f; 		// Die Pins der Displaymatrix werden wieder auf Low gesetzt
	PORTD &= ~0xf0;
	PORTB &= ~0x03;
}
SIGNAL (SIG_OVERFLOW2)
{
	uint8_t ledval, portb;

// Spalten
	if(col) PORTB |= (1<<4);	/* Danach Einsen hinterherschicken (PB4 = 1) */
		else PORTB &= ~(1<<4);	/* Bei der ersten Spalte eine 0 ausgeben (PB4 = 0) */
	PORTB |= (1 << 3);        	/* PB3 = 1 (cl) */
	PORTB &= ~(1 << 3);        /* PB3 = 0 (!cl) */
	PORTB |= (1 << 2);         /* PB2 = 1 (str) */
	PORTB &= ~(1 << 2);        /* PB2 = 0 (!str) */

// Zeilen
	ledval = bildspeicher[ebene][12+(col>>2)]; // y 1 und 0
	portb = (ledval >> (col%4)*2) & 0x03;
	ledval = bildspeicher[ebene][col]; // y 9 bis 2
	PORTC |= ledval & 0x0f;
	PORTD |= ledval & 0xf0;
	PORTB |= portb;

	col++;
	
	if(col>11)
	{
		col=0;
		ebene++;
		if(ebene == colors) ebene=0;
	}
}
Gruß

mic