mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Arduino Spektroskop mit dem Liniensensor TSL1401


Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Hallo!

Aktuell bastle ich gerade an einem Spektroskop auf Basis des 
Liniensensors TSL1401 (http://www.w-r-e.de/robotik/data/tsl1401.pdf) und 
eines Arduino Mega. Leider besitzt er lediglich 128 Pixel. Dafür kann 
ich bei schwachen Lichtquellen die Belichtungszeit recht hoch wählen 
(derzeit 1 - 255 ms).

Das display hat eine Auflösung von 480x320 Pixel. Der angestrebte 
Wellenlängenbereich geht von 380nm bis 760nm. Als Kollimator kommt ein 
Achromat (2-Linser) mit 39.5mm Brennweite von Astromedia 
(http://astromedia.eu/Material-fuer-Selbermacher/OPTI-Media-Glaslinsen/Achromat-2-Linser-f%3D39-5mm::161.html) 
zum Einsatz. Als Objektiv verwende ich ein 9-22mm Zoom. Für eine 
formatfüllende Abbildung des gewünschten Spektralbereichs bei Verwendung 
eines Beugungsgitters mit 1000 Linien/mm 
(http://astromedia.eu/Material-fuer-Selbermacher/OPTI-Media-Filterfolien/Das-Durchlicht-Beugungsgitter::153.html) 
benötige ich rund f = 17 mm.

Jetzt warte ich nur noch auf das Gehäuse, dann kann ich alles einbauen 
und justieren...

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Habe nun die Halterungen für die Kollimatorlinse, das Gitter und den 
Liniensensor fertiggestellt. Bei Kollimator und Gitter kommen Magnete 
zum Einsatz, damit ich die Justierung betreffend möglichst flexibel bin.

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Hier geht es auch schön langsam weiter. Habe nun einmal die 
Kollimatorlinse positioniert und fixiert. Die Höhe des Zeilensensors 
bzw. die Neigung/Höhe der Abbildungslinse stimmen jetzt auch. Den 
finalen Platz finden sie aber erst, nachdem das neue Gitter (nur 500 
Linien/mm anstelle der derzeitigen 1000 Linien/mm) eingetroffen ist...

Autor: Sven B. (scummos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Cool!

Eine erhebliche Verbesserung der Empfindlichkeit könntest du vermutlich 
erreichen, indem du das Bild mit einer Zylinderlinse auf den Chip 
abbildest, so geht ja doch sehr viel Licht daneben.

Und: da du eine Achsenskala hast, ist das sogar ein Spektrometer, nicht 
bloß ein Spektroskop! ;)

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
4 lesenswert
nicht lesenswert
Das Projekt befindet sich auf der Zielgeraden. Habe gestern die 
Abbildungslinse (f = 26.5 mm) und den Sensor neu ausgerichtet, was gar 
nicht so einfach war. Um den Fokus besser zu treffen, habe ich über die 
Spaltmitte von rechts nach links einen dünnen Streifen schwarzes 
Isolierband geklebt. Dann habe ich ein weißes Papier über den Sensor 
gehalten und alles so positioniert, dass an der Stelle des Sensors das 
dunkle Abbild des Isolierbands zu sehen war...

Jetzt fehlt eigentlich nur noch die Anpassung des am Bildschirm 
dargestellten Spektrums, da die Position der Wellenlängen natürlich noch 
nicht stimmen.

Die Intensität der beiden Laserpointer habe ich mittels 
Neutraldichtefilter auf 10% abschwächen müssen, da sonst der Sensor 
total übersteuert hätte. Ist nun alles sehr lichtempfindlich. Selbst bei 
der weißen LED musste ich auf eine Belichtungszeit von nur 4 ms runter 
gehen (Maximum wäre 255!), damit es zu keiner Übersteuerung kommt.

Sämtliche Schrauben/Muttern habe ich noch mit 2-Komponentenkleber 
fixiert.

Autor: Sven B. (scummos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gutes Projekt, gefällt mir.

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
2 lesenswert
nicht lesenswert
So, das Spektroskop ist soweit fertig. Heute habe ich noch den Sensor 
leicht verrücken müssen, da die Bluray-Linie mit 405nm gerade so am Rand 
zu erkennen war. Jetzt ist sie weiter nach innen gerückt. Dafür habe ich 
im langwelligen Bereich nicht mehr so viel Spielraum. Der erfasste 
Wellenlängenbereich beträgt nun [385,685]nm. Das passt mir recht gut...

Video: Youtube-Video "Arduino spectroscope with TSL1401 line sensor and TFT-display - Arduino Spektroskop"

Arduino-Code:
#include <TFT_HX8357.h> // Hardware-specific library

TFT_HX8357 tft = TFT_HX8357();       // Invoke custom library

#define CENTRE 240
#define clockPin     2       // clock
#define siPin        3       // Start Integration
#define VOUT         A0      // pixel intensity from the sensor in the analog channel A0
#define INTVAL       A1      // integration time adjust in the analog channel A1.

int Faktor = 4;    // Verkleinerungsfaktor zur Darstellung der Helligkeitswerte
long exposure;
int Helligkeiten[128];
int i,j;


// ==========================
// ========  SETUP ==========
// ==========================

void setup()
{
  Serial.begin(38400);
  
  pinMode(siPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  
  // Setup the LCD
  tft.init();
  tft.setRotation(1);
  
  tft.fillScreen(TFT_BLACK);
  tft.fillRect(0, 0, 480, 14, tft.color565(210, 210, 210));

  

  tft.setTextColor(tft.color565(255, 255, 255),tft.color565(0, 0, 0));
  tft.drawCentreString("400", 10 + 19, 310, 1);
  tft.drawCentreString("440", 10 + 19 + 1 * 50.6, 310, 1);
  tft.drawCentreString("480", 10 + 19 + 2 * 50.6, 310, 1);
  tft.drawCentreString("520", 10 + 19 + 3 * 50.6, 310, 1);
  tft.drawCentreString("560", 10 + 19 + 4 * 50.6, 310, 1);
  tft.drawCentreString("600", 10 + 19 + 5 * 50.6, 310, 1);
  tft.drawCentreString("640", 10 + 19 + 6 * 50.6, 310, 1);
  tft.drawCentreString("680", 10 + 19 + 7 * 50.6, 310, 1);
  tft.drawCentreString("[nm]", 420, 310, 1);


  tft.drawCentreString("exposure =", 438, 140, 1);
  tft.drawCentreString("msec", 438, 180, 1);
  
  
 }



// ==================================
// ========  HAUPTSCHLEIFE ==========
// ==================================

void loop()
   {
    tft.drawLine(10, 300, 10 + 380, 300, tft.color565(255, 255, 255));
   
    tft.drawLine(10 + 19 + 0 * 50.6, 300, 10 + 19 + 0 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 0.5 * 50.6, 300, 10 + 19 + 0.5 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 1.0 * 50.6, 300, 10 + 19 + 1.0 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 1.5 * 50.6, 300, 10 + 19 + 1.5 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 2.0 * 50.6, 300, 10 + 19 + 2.0 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 2.5 * 50.6, 300, 10 + 19 + 2.5 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 3.0 * 50.6, 300, 10 + 19 + 3.0 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 3.5 * 50.6, 300, 10 + 19 + 3.5 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 4.0 * 50.6, 300, 10 + 19 + 4.0 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 4.5 * 50.6, 300, 10 + 19 + 4.5 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 5.0 * 50.6, 300, 10 + 19 + 5.0 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 5.5 * 50.6, 300, 10 + 19 + 5.5 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 6.0 * 50.6, 300, 10 + 19 + 6.0 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 6.5 * 50.6, 300, 10 + 19 + 6.5 * 50.6, 305, tft.color565(255, 255, 255));
    tft.drawLine(10 + 19 + 7.0 * 50.6, 300, 10 + 19 + 7.0 * 50.6, 305, tft.color565(255, 255, 255));

    tft.fillRect(10,15,382,285,TFT_BLACK);

    exposure = analogRead(INTVAL);  // read integration time from potentiometer.
    exposure = exposure / 4;        // Integrations-Intervall [0,255] ms

    Serial.print("Belichtung = ");
    Serial.println(exposure);
    
    getCamera();

    /*
    for (int j = 0; j < 128; j++)
       {
        Serial.println(Helligkeiten[j]);
       }
    */
 
     
    tft.fillRect(410,160,70,10,TFT_BLACK);
    tft.setTextColor(tft.color565(255, 255, 255),tft.color565(0, 0, 0));
    tft.drawNumber(exposure, 428, 160,1);
    
    /*
    for(i = 0; i < 128; i++)
       {
        Helligkeiten[i] = random(255);      
       }
    */


    
    for(i = 0; i < 128; i++)
       {
        if(i >= 0 && i < 32)
           {       
            tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0 + int((255.0/32.0) * i), 255, 0));
        
            tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/32.0) * (i + 1.0/3.0)), 255, 0));

            tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/32.0) * (i + 2.0/3.0)), 255, 0));
            
            /*
            Serial.print(int((255.0/18.0) * i));
            Serial.print("  ");
            Serial.print(int((255.0/18.0) * (i + 1.0/3.0)));
            Serial.print("  ");
            Serial.println(int((255.0/18.0) * (i + 2.0/3.0)));
            delay(100);
            */
           }

        if(i >= 32 && i < 48)
           {       
            tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(255, 255 - int((255.0/16.0) * (i - 32)),0));
        
            tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 255 - int((255.0/16.0) * (i - 32 + 1.0/3.0)), 0));

            tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 255 - int((255.0/16.0) * (i - 32 + 2.0/3.0)), 0));
           }

        if(i >= 48 && i < 61)
           {       
            tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(255, 0, 0 + int((255.0/13.0) * (i - 48))));
        
            tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 0, 0 + int((255.0/13.0) * (i - 48 + 1.0/3.0))));

            tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255, 0, 0 + int((255.0/13.0) * (i - 48 + 2.0/3.0))));
           }

         if(i >= 61 && i < 82)
           {       
            tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(255 - int((255.0/21.0) * (i - 61)), 0, 255));
        
            tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255 - int((255.0/21.0) * (i - 61 + 1.0/3.0)), 0, 255));

            tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(255 - int((255.0/21.0) * (i - 61 + 2.0/3.0)), 0, 255));
           }  
        
        if(i >= 82 && i < 107)
           {       
            tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0, 0 + int((255.0/25.0) * (i - 82)), 255));
        
            tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0, 0 + int((255.0/25.0) * (i - 82 + 1.0/3.0)), 255));

            tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0, 0 + int((255.0/25.0) * (i - 82 + 2.0/3.0)), 255));
           } 
        
        if(i >= 107 && i < 127)
           {       
            tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0 + int((255.0/34.0) * (i - 107)), 255, 255));
        
            tft.drawLine(10 + 3*i + 1, 299, 10 + 3*i + 1, 299 - (Helligkeiten[i] + (1.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/34.0) * (i - 107 + 1.0/3.0)), 255, 255));

            tft.drawLine(10 + 3*i + 2, 299, 10 + 3*i + 2, 299 - (Helligkeiten[i] + (2.0/3.0) * (Helligkeiten[i+1] - Helligkeiten[i])), tft.color565(0 + int((255.0/34.0) * (i - 107 + 2.0/3.0)), 255, 255));
           }

        if(i == 127)
           {
            tft.drawLine(10 + 3*i, 299, 10 + 3*i, 299 - Helligkeiten[i], tft.color565(0 + int((255.0/34.0) * (i - 107)), 255, 255));
           }
       }
     
    tft.setTextColor(tft.color565(20, 20, 255),tft.color565(210, 210, 210));
    tft.drawCentreString("Spektroskop - stoppi", CENTRE, 3, 1); 
         
    delay(900);
       
   }




// ================================
// ===== Helligkeiten einlesen ====
// ================================

void getCamera()
   {
    digitalWrite(clockPin, LOW);
    digitalWrite(siPin, HIGH);
    digitalWrite(clockPin, HIGH);
    digitalWrite(siPin, LOW);
    digitalWrite(clockPin, LOW);
 
    for (int j = 0; j < 128; j++)
       {
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
       }
 
    //delayMicroseconds(exposure);
    
    delay(exposure);    // Belichtungszeit = Verzögerung in ms
 
    digitalWrite(siPin, HIGH);
    digitalWrite(clockPin, HIGH);
    digitalWrite(siPin, LOW);
    digitalWrite(clockPin, LOW);
    
    for (int j = 0; j < 128; j++)   
       {
        delayMicroseconds(20);
        
        Helligkeiten[j] = analogRead(VOUT) / Faktor;    // Wertebereich [0,255]
        
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
       }
 
    delayMicroseconds(20);
   }

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
4 lesenswert
nicht lesenswert
Anbei noch zwei Messungen mit dem Spektroskop.

Einmal eine Kerze. Wie man anhand der Planckschen Strahlungskurve sieht, 
ist bei einer Temperatur von 1400 K das Spektrum noch weitestgehend im 
IR-Bereich (Maximum bei rund 2.1 µm). Aber die Kurve wächst den 
sichtbaren Spektralbereich betrachtend in Richtung größerer Wellenlänge 
stark an. Dieser Anstieg ist auch in meinem Spektrum zu erkennen.

Zum zweiten eine Energiesparlampe. Auch hier erkennt man deutlich die 5 
peaks. Praxistest also bestanden... :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.