ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 아두이노 Linear CCD project
    LinearImageSensor 2022. 4. 1. 21:27

     

    https://davidallmon.com/projects/adc0820-spectrograph

     

    Arduino Powered Linear CCD Spectrograph Board - ATmega1284, TCD1304AP, ADC0820

    A spectrograph board made with a TCD1304AP or TCD1304DG linear array CCD, an ADC0820 ADC and an ATmega1284 running Arduino code.

    davidallmon.com

    이것은 Arduino Linear CCD 프로젝트에 대한 업데이트입니다. 그것은 더 간단한 회로로 연산 증폭기를 제거하고 그것 때문에 더 선형적입니다. 새로운 회로도인 PCB와 새로운 CAD 패키지가 있습니다. 저는 이제 조금 더 표준이 되기 위해 KiCAD를 사용하고 있습니다.

    Arduino는 내부 아날로그-디지털 변환기를 사용하는 CCD를 따라갈 수 없지만 외부 8비트 하프 플래시 ADC를 사용하면 전혀 문제가 되지 않습니다. ADC는 초당 최대 666k 샘플을 디지털화할 수 있는 TI ADC0820입니다. 여기에서 샘플 속도는 아래 코드를 사용하여 222kSPS 이상의 머리카락으로 작동합니다. 3694픽셀 프레임은 읽고 디지털화하는 데 약 16.66mS가 걸리고 115.2k 보드에서 다운로드하는 데 약 4초가 걸립니다.

    마이크로컨트롤러

    Arduino Uno에는 3694픽셀 버퍼를 위한 충분한 RAM이 없습니다. 이는 Arduino Mega2560에 4kB만 남거나 독립 실행형 ATmega1284에 16kB RAM을 남깁니다. 아두이노 Mega2560을 끼워넣기가 쉽지 않아서 ATmega1284P로 했습니다. "P" 부분은 필요하지 않습니다. 이 프로젝트에는 전원 제어가 없습니다.

    아날로그-디지털 변환기

    이 프로젝트는 여전히 ADC0820을 사용하지만 이번에는 가장 빠른 ADC0820N과 동일하고 선형성이 더 우수하지만 SOIC-20 패키지로 제공되는 ADC0820BCWM(X)입니다. 브레드보드의 경우 여전히 PDIP 패키지를 사용하거나 20핀 Schmartboard 또는 이와 동등한 제품을 사용할 수 있습니다. eBay에서 PDIP 부품을 찾을 수 있지만 더 이상 사용되지 않으므로 가격은 의심할 여지 없이 올라갈 것입니다.

    ADC0820 ADC에는 ADC 범위를 설정하도록 설계된 + 및 - 기준 입력이 있으므로 전체 8비트 분해능을 유지하면서 입력 범위의 흥미로운 부분에 집중할 수 있습니다. ADC0820BCWM/ADC0820BCWMX 부품은 ±1/2 LSB 선형성을 갖습니다. ADC0820CCWM은 ±1 LSB 선형성을 갖습니다.

    선형 배열 CCD

    CCD는 단일 공급 전압만 필요한 Toshiba TCD1304AP 3648 픽셀 선형 CCD 센서입니다. 센서는 마이크로컨트롤러에 의해 직접 구동되며 아날로그 출력은 트랜지스터에 의해 버퍼링됩니다. MCLK 신호는 888.88kHz이고 픽셀은 222.22kHz에서 읽힙니다. 이것이 CCD가 아니라 마이크로컨트롤러의 모든 한계입니다.

    TCD1304AP CCD는 ebay나 aliexpress에서 $4~$40에 구입할 수 있습니다. Mouser는 $25에 새로운 주식(TCD1304DG)을 보유하고 있습니다.

    KiCAD Project Files

    8-bit-spect-1284.zip
    0.09MB

    KiCAD 프로젝트를 사용하려면 라이브러리에서 CCD 및 ADC 데이터를 가져와야 합니다. 라이브러리는 프로젝트 디렉토리에 포함됩니다. 프로젝트에서 그렇게 하려면 기본 설정->심볼 라이브러리 관리...를 클릭한 다음 프로젝트 특정 라이브러리를 클릭하고 하나의 라이브러리를 추가합니다. 닉네임은 "8-bit-spect-1284-rescue"여야 하며 경로는 "8-bit-spect-1284-rescue.lib" 파일의 경로입니다. 그러면 두 부분이 추가됩니다. 라이브러리가 프로젝트에 이미 있는 경우 대화 상자에서 경로 폴더 아이콘을 클릭하고 올바른 경로를 설정합니다.

    Schematic Diagram

    PDF

    8-bit-spect-1284-sch.pdf
    0.04MB

    설명

    ATmega1284의 타이머는 MCLK 신호로 사용할 888.88kHz 구형파를 생성합니다. CCD 및 ADC의 클록을 토글하는 코드는 MCLK 신호에 따라 전환합니다. 클록 에지는 라인을 읽기 전에 타이머를 한 사이클 조정하여 정렬됩니다. MCLK는 지속적으로 실행됩니다. SH, ICG, WR 및 RD는 CCD를 읽을 때만 주장됩니다.

    CCD의 출력은 ADC로 전송되기 전에 PNP 트랜지스터에 의해 버퍼링됩니다. 이전 버전은 OpAmp를 사용하여 ADC의 전체 범위로 CCD 출력을 반전 및 증폭했습니다. 이것은 불필요한 것으로 판명되었고 또 다른 조정이 추가되었습니다. ADC 범위는 구성 가능하며 255에서 픽셀 값을 빼서 반전시키는 것은 간단한 문제입니다.

    원래 펌웨어는 CCD를 지속적으로 읽고 사용자가 요청할 때 버퍼를 덤프했습니다. 이 버전은 그렇게 하지 않습니다. 요청 시 버퍼를 읽습니다. 그로 인해 메인 루프가 다른 일을 할 수 있게 되었습니다. 펌웨어는 CCD를 4번 읽어 노출 전에 지우고 99%이면 충분합니다. 빛이 닿으면서 몇 분 이상 유휴 상태로 있으면 전자가 표면 위로 넘쳐 4 번 읽는 것으로는 충분하지 않습니다. 판독 값에 수직선 외에 아무것도 표시되지 않는다면 아마도 그런 일이 발생한 것입니다. 지우려면 다시 읽으십시오. 그래도 선명하지 않으면 노출 시간을 줄이십시오.

    ICSP 커넥터 및 JP1

    마이크로컨트롤러의 핀 1 끝에는 프로그래밍 커넥터가 있습니다. 핀 3 옆에는 JP1이라고 표시된 점퍼가 있습니다. 프로그래밍 커넥터는 부트로더를 ATmega1284에 굽기 위한 것입니다. 점퍼 JP1이 설치되면 다른 전원 없이 프로그래밍할 수 있도록 프로그래머 전원을 회로에 전달합니다. JP1이 제거되면 프로그래머가 격리됩니다. 이것이 일반적으로 온보드 5V와 프로그래머의 5V 사이에 충돌이 발생하지 않도록 하는 방법입니다.

    직렬 커넥터

    FTDI 핀아웃과 일치하는 직렬 커넥터가 있습니다. 펌웨어 업로드 및 명령 전송 및 비디오 데이터 다운로드에 사용됩니다. 보드는 커넥터의 한쪽 끝에 DTR, 다른 쪽 끝에 GND로 표시되어 있습니다. 뒤로 연결하면 큰 손상을 주지 않습니다. 위험한 핀은 연결되어 있지 않습니다. USB-TTL 변환기에 수 커넥터가 있는 경우 커넥터를 암으로 만드십시오.

    다른 부분

    다이오드 D1은 누군가 실수로 전원을 거꾸로 연결하는 경우 회로를 보호하기 위해 있습니다. 다이오드 D2는 전원을 차단할 때 사용합니다. 레귤레이터가 역 바이어스되는 것을 방지합니다. RST로 표시된 스위치는 ATmega1284의 재설정입니다. 코드 작업을 하고 있는데 문제가 되는 경우를 대비하여. 전원을 껐다가 다시 연결하는 것보다 낫습니다.

    조립 유닛

    집회

    조립은 간단하지만 CCD에는 400mils(10.16mm) 너비의 22핀 소켓이 필요합니다. 내가 한 여성 가공 핀 헤더를 사용할 수 있습니다. PCB를 사용하는 경우 ADC를 먼저 납땜하면 삶이 더 쉬워진다는 것을 알았습니다. 구성 요소 설치를 위한 키로 "8-bit-spect-asy.pdf" 도면을 사용하십시오. PC 보드를 만들려는 경우 Gerber 파일은 거의 모든 PCB 상점에서 사용할 수 있습니다.

    재료 명세서(CSV 파일).

    8-bit-spect-1284-bom.csv
    0.01MB



    프로토 보드에 배선하는 경우 찾을 수 있으면 ADC0820BCN을 사용하십시오. PDIP 부분이 더 좋습니다. 가능한 한 디지털 및 아날로그 배선을 서로 멀리 떨어뜨리도록 주의하십시오. 모든 Vcc 연결에서 0.1µF 바이패스 커패시터를 사용하십시오. 필요한 것보다 더 많이 방사되지 않도록 모든 디지털 전선을 가능한 한 짧게 유지하십시오. 아날로그 영역 근처에서 MCLK 신호를 라우팅할 때 특히 주의하십시오.

    아래 보정 섹션에서 볼 수 있는 약간의 소음이 있었습니다. 회로는 고주파 전원 노이즈에 민감합니다. 이는 작은 스위칭 전원 공급 장치가 아마 나갔음을 의미합니다. 스위처보다 선형 전원 공급 장치를 사용하고 싶을 것입니다. Jameco에서 구할 수 있습니다. 12V가 작동하지만 9V가 완벽합니다. 또는 직렬로 연결된 한 쌍의 리튬 이온 배터리에서 실행할 수 있습니다. 그러나 평균 45mA의 저전력 회로는 아닙니다. 선형 공급 장치에는 100-240V 50-60Hz가 아닌 120V 60Hz의 입력이 있기 때문에 알 수 있습니다. Jameco는 선형 공급 장치에 대한 설명에서 실제로 선형이라고 말하지만 다른 곳에서는 스위처에서도 선형이라고 말합니다. 내가 말하려는 것은 eBay에서 선형 벽 사마귀를 찾지 말라는 것입니다.

    선형 전원으로 전환했을 때 노이즈가 거의 완전히 사라졌고 최소한의 노출을 위해 본질적으로 평평한 선을 얻었습니다. 더 긴 노출에서 어두운 신호는 모든 전원 공급 장치 노이즈를 마스킹합니다.

    소프트웨어

    MCUdude의 MightyCore 보드 관리자 플러그인을 사용합니다. 보드는 ATmega1284가 될 것이고, 당신이 가지고 있는 보드에 따라 1284 또는 1284P가 될 것입니다. 핀아웃은 "표준"이고 주파수는 16MHz입니다. Arduino 환경 설정의 "추가 보드 관리자 URL" 텍스트 상자에 다음 URL을 추가하여 MightyCore 보드를 보드 관리자에 추가할 수 있습니다.

    https://mcudude.github.io/MightyCore/package_MCUdude_MightyCore_index.json

    그런 다음 도구->보드->보드 관리자에서 보드 관리자를 열고 맨 아래로 이동하여 MightyCore 보드를 설치합니다. 보드 선택은 ATmegaxx4 칩, ATmega16/32 및 ATmega8535를 모두 포함하도록 상당히 증가할 것입니다. 추가 프로그래머도 나타날 것이며, MightyCore 부트로더와 함께 그 중 하나를 사용해야 합니다.

    Arduino 부트로더를 ATmega1284로 구우려면 AVR 프로그래머가 필요합니다. 보드는 10핀 ICSP 커넥터를 사용합니다.

    선형 CCD 응용 프로그램의 소스 코드는 모든 CCD 클록 간의 위상 관계를 유지하고 사양에 충실하도록 여러 위치에서 매우 신중하게 제작되었습니다. "readLine()" 함수의 코드 변경 결과를 측정하려면 로직 분석기가 필요합니다.

    #include <util/delay_basic.h>
    
    // ADC RD signal pin 17
    #define RD 0x08
    
    // ADC write signal pin 18
    #define WR 0x10
    
    // CCD Shift Gate pin 19
    #define SH 0x20
    
    // CCD Integration Clear Gate pin 20
    #define ICG 0x40
    
    // CCD Master clock pin 21
    #define MCLK 0x80
    
    // CCD and ADC clocks
    #define CLOCKS PORTD
    #define CLOCKP PIND
    
    // ADC data
    #define ADATA PINC
    
    #define PIXEL_COUNT 3694
    
    uint8_t pixBuf[PIXEL_COUNT];
    char cmdBuffer[16];
    int cmdIndex;
    int cmdRecvd = 0;
    int exposureTime = 10;
    bool looping = false;
    
    void setup() {
      // Initialize the clocks.
      DDRD |= (WR | SH | ICG | MCLK | RD);  // Set the clock lines to outputs
      CLOCKS = (ICG + RD + WR);       // Set the ICG, RD, and WR high.
    
      // Setup the ADC data port as inputs.
    //  DDRC = 0;
      
      // Enable the serial port.
      Serial.begin(115200);
    
      // Setup timer2 to generate an 888.8kHz frequency on pin 21
      TCCR2A =  + (0 << COM2A1) | (1 << COM2A0) | (1 << WGM21) | (0 << WGM20);
      TCCR2B = (0 << WGM22) | (1 << CS20);
      OCR2A = 8;
      TCNT2 = 1;
    }
    
    void readLine() {
      
      // Get a pointer to the buffer.
      uint8_t *buf = pixBuf;
      int x = 0;
      uint8_t scratch = 0;
      
      // Disable interrupts or the timer will get us.
      cli();
      
      // Synchronize with MCLK and
      // set ICG low and SH high.
      scratch = CLOCKS;
      scratch &= ~ICG;
      scratch |= SH;
      while(!(CLOCKP & MCLK));
      while((CLOCKP & MCLK));
      TCNT2 = 0;
      _delay_loop_1(1);
      __asm__("nop");
      __asm__("nop");
      __asm__("nop");
      __asm__("nop");
      __asm__("nop");
      CLOCKS = scratch;
      
      // Wait the remainder of 4.5uS @ 16MHz.
      _delay_loop_1(22);
      __asm__("nop");
      __asm__("nop");
    
      // Set SH low.
      CLOCKS ^= SH;
    
      // Wait the remainder of 4.5uS.
      _delay_loop_1(23);
    
      // Start the readout loop at the first pixel.
      CLOCKS |= (RD + WR + ICG + SH);
      
      do {
        // Wait a minimum of 250nS for acquisition.
        _delay_loop_1(2);
    
        // Start the conversion.
        CLOCKS &= ~WR;
        _delay_loop_1(3);
        CLOCKS |= WR;
    
        // Wait the rest of 2uS for conversion.
        _delay_loop_1(9);
    
        // Read the result.
        CLOCKS &= ~RD;
    
        _delay_loop_1(3);
        __asm__("nop");
        __asm__("nop");
        *buf++ = ADATA;
    
        // Set the clocks back to idle state
        CLOCKS |= RD;
    
        // Toggle SH for the next pixel.
        CLOCKS ^= SH;
    
      } while (++x < PIXEL_COUNT);
      CLOCKS = (ICG + RD + WR);
      sei();
    }
    
    void sendData(void) {
      
      int x;
    
      for (x = 30; x < 3678; ++x) {
        
        Serial.print(x - 30);
        Serial.print(",");
        Serial.print(255-pixBuf[x]);
        Serial.print("\n");
      }
    }
    
    
    void loop() {
      
      int x;
      char ch;
      
      if (cmdRecvd) {
        if (cmdBuffer[0] == 'r') {
          
          // Clear any residual charge.      
          readLine();
          readLine();
          readLine();
          readLine();
          
          // Expose.
          delay(exposureTime);
    
          // Read and send data.
          readLine();
          sendData();
        
        } else if (cmdBuffer[0] == 'e') {
          String tmp = String(&cmdBuffer[1]);
          exposureTime = tmp.toInt();
          Serial.println(exposureTime);
          
        } else if (cmdBuffer[0] == 'l') {
          looping = !looping;
        }
        memset(cmdBuffer, 0, sizeof(cmdBuffer));
        cmdRecvd = 0;
        cmdIndex = 0;
      }
      if (looping) {
          readLine();
          readLine();
          delay(exposureTime);
          readLine();
      }
      while (Serial.available() > 0) {
        
        ch = Serial.read();
        
        if (ch != 0x0a) {
          cmdBuffer[cmdIndex++] = ch;
        } else {
          cmdRecvd = 1;
        }
      }
    }

    타이밍

    시간 0s:0ms:0µs에서 MCLK가 약간 늘어나는 것을 볼 수 있습니다. 즉, ICG, SH, WR 및 RD 라인을 타이머와 동기화하여 888kHz MCLK 신호를 생성합니다. 코드는 전체 읽기 프로세스 동안 이 타이밍 관계를 유지해야 하며 4개의 MCLK 주기마다 한 픽셀을 읽어야 합니다. readLine() 함수는 정확한 타이밍을 유지하기 위해 어셈블리 언어 "NOP" 코드로 가득 차 있습니다. 단일 기계 명령어를 추가하는 경우에도 읽기 타이밍을 리팩토링해야 합니다.

    샘플러 프로그램

    Sampler 프로그램은 Python 3용으로 작성되었습니다. pyserial pip install pyserial도 설치해야 합니다.
    파이썬 코드 끝에서 몇 줄은 다음과 같습니다.

    app = Application(master=root, port="/dev/tty.usbserial-00000000", exposure=50)

    직렬 포트와 일치해야 합니다. Windows를 사용하는 경우 다음과 같이 변경합니다.

    app = Application(master=root, port="COM3", exposure=50)

    다시 한 번, 사용 중인 직렬 포트와 일치하도록 합니다. 프로그램을 실행하면 CCD 출력 그래프를 그리지만 프로그램 디렉토리에 'ccd.csv'라는 파일도 만듭니다. 추가 처리를 위해 해당 파일을 스프레드시트 응용 프로그램으로 가져올 수 있습니다.

    센서의 수평 해상도와 반환된 데이터는 그래프 해상도의 3배입니다. cvs 파일은 전체 해상도로 작성됩니다. 픽셀은 그래프의 3픽셀 너비 버킷으로 비닝됩니다.

    버튼은 다음과 같습니다.

    • 샘플 - CCD를 읽고 화면에 추적을 표시합니다.
      지우기 - 화면에서 모든 흔적을 지웁니다.
      종료 - 프로그램을 종료합니다(종료 시 오류가 발생하지 않도록 하려면 이 작업을 수행해야 함).
      샘플 - 함께 평균화할 스캔 수(약간의 노이즈 제거).
      노출 - 1에서 1000 사이의 정수 값입니다. 노출할 밀리초입니다.
      기준선 - 다른 노출에서 빼기 위해 0초 노출을 만듭니다.

    python app

    TCD1304-Sampler.py.zip
    0.00MB

    샘플을 클릭하면 그래프가 그려집니다. 이전 줄은 지우지 않습니다. 지우기 버튼이 그 역할을 합니다. 예외적인 빌드가 있고 성가신 소음이 없으면 샘플 라디오 버튼이 도움이 되지 않습니다. 기준선은 비디오에서 고정 신호를 제거하는 데 편리합니다. 이 버전에서는 노출이 약간 중복됩니다. 노출 시간을 설정하지만 사용하지 않습니다. 샘플을 클릭하면 텍스트 상자에서 노출 시간을 가져와 읽기를 요청하기 전에 분광기로 보냅니다.

    포화 신호처럼 보이는 경우 노출을 다시 실행하십시오. CCD는 읽든 읽지 않든 빛을 모으기 때문에 30분 동안 그대로 두는 것은 30분 동안 노출되는 것과 같습니다. 코드는 노출되기 전에 프레임을 4번 읽지만 때로는 시스템에서 모든 전자를 꺼내기에 충분하지 않습니다.

    구경 측정
    보정하려면 RV1 포트 "Vref(+)"를 시계 방향으로 끝까지 설정하여 시작합니다. RV2, "Vref(-)"를 시계 반대 방향으로 끝까지 설정하십시오. 이것은 블랙 레벨을 5V로 설정하고 화이트 레벨을 0V로 설정합니다. 각 끝에 ccd + 1/4인치를 덮을 만큼 충분히 긴 검은색 전기 테이프 조각을 가져옵니다. 테이프를 가로질러 슬릿을 자르되, 전체가 아닌 중앙만 자르십시오. X-acto 칼 또는 이와 유사한 것을 사용하십시오. 그런 다음 조명이 어두운 방에서 전기 테이프로 CCD를 덮습니다. 테이프는 CCD를 손상시키지 않고 벗겨집니다. 샘플을 만들 때 스파이크가 표시되어야 합니다. 그렇지 않은 경우 노출 시간을 늘리십시오. 스파이크가 사각 펄스처럼 보이면 노출 시간을 줄이십시오. CCD의 테이프 길이 아래로 손가락을 슬릿에서 시작하여 문지르면 필요한 경우 슬릿이 더 넓게 열립니다. 슬릿 쪽으로 손가락을 문지르면 닫히는 경향이 있습니다.

    스파이크에서 최대 선형 출력을 얻을 때까지 노출 시간을 조정합니다. 스파이크의 높이가 선형적으로 증가하는 것을 멈추면 노출 시간 증가를 중단하십시오. 다음 이미지에서 곡선의 진폭이 선형적으로 높아지다가 마지막 단계에서 비선형이 되는 것을 볼 수 있습니다. 저는 100mS에서 시작하여 250mS까지 단계당 50mS씩 작업했습니다. 200mS는 마지막 선형 개선이었기 때문에 교정 절차를 위한 작업 노출 시간으로 선택했습니다. 비선형성은 센서 포화로 인한 것입니다.

    냄비는 위에서 보았듯이 서로 상호 작용하기 때문에 순서대로 조정해야 합니다. 그것은 디자인에 의한 것입니다. Vref(-)에 가할 수 있는 최대 전압은 Vref(+)에, 최소는 접지이므로 Vref(+)를 변경하면 Vref(-)의 범위와 전류 값이 변경됩니다.

    테이프를 제거할 때 CCD 유리를 알코올로 닦아 잔여물을 제거하십시오.

    이제부터는 노출 시간을 사용하여 신호 범위를 늘리거나 줄입니다. 선이 그래프 상단을 벗어나면 노출 시간을 줄이고, 부족하면 노출 시간을 늘립니다. 1000mS가 충분히 길지 않으면 Python 샘플러와 Arduino IDE(둘 다)에서 원하는 대로 변경할 수 있습니다. 노이즈는 노출 시간에 따라 증가합니다. 더 짧게 해야 하는 경우 마이크로초 타이머로 실험해야 할 수도 있습니다. 연락 양식을 통해 현재 하고 있는 일에 대한 정보를 보내주시면 무엇을 할 수 있는지 알아보겠습니다.

    역학
    여기에서 우리 모두 각자의 길을 갑니다. 라만 분광기를 원하면 레이저, 격자 및 몇 개의 거울을 추가해야 합니다. 바코드 리더기를 원하시면 렌즈를 추가하시면 됩니다. 이것에 대한 나의 특별한 용도는 CCD 천체 사진에 사용되는 이색성 색 분리 필터를 특성화하는 것이었습니다. 그러려면 평행광원, 필터용 스테이지, 슬릿, 투과 격자, 기판이 필요했습니다. 2" x 2" 슬라이드 카드에서 mm Edmund Optics 홀로그램 격자당 1000라인을 사용했습니다.

     

     

     

     

    'LinearImageSensor' 카테고리의 다른 글

    라인센서 감도에 사용되는 색온도 정보  (0) 2022.04.09
    TCD1209DG 정보  (0) 2022.04.01
    TCD1304AP + 아두이노 자료  (0) 2022.04.01
    [비] TCD1201D Code  (0) 2022.04.01
    TCD1201 이미지 센서  (0) 2022.04.01
Designed by Tistory.