基于Flir Lepton 3热成像模块的夜视设备

早些时候,我写了一篇有关将热成像机顶盒连接到Flir One Gen 2智能手机的文章。是时候从该机顶盒中卸下轻子模块,并通过组装分辨率为160x120像素的夜视设备将其直接连接到微控制器了。

要构建自己的夜视热成像设备,您需要:

1)带有微控制器的电路板。 我用一个STM32F407VGT6微控制器从一个中国朋友那里拿了一块板子。 如此好的控制器:168 MHz的频率和192 KB的RAM。



2)显示。 我带了一个分辨率为320x240的显示器。 这样的显示器带有各种控制器。 我用hx8347d控制器得到了它。



3)用于在SPI和I2C上连接轻子3的板。



4)轻子本身3.最困难和最昂贵的元素。 为了得到它,我在ebay上买了一个有故障的Flir One Gen 2热像仪,并从中取出了一个轻子。 它的放大倍数如下所示:



您可以从列表中排除第3项,除非您当然可以从故障的热像仪中取出一个婴儿床来安装轻子,然后可以将其拆焊(顺便说一下,她的联络人将从底部开始)。 不幸的是,在轻子上,两腿之间的距离很小,所以这个选择没有提交给我。

要收集所有这些,您只需按以下步骤进行焊接:



您还需要连接电源。 为轻薄板供电,我使用5 V电压,而STM32板为3.3V。要从电池获得5 V,我使用TEL3-0511转换器(输入电压从4.5到9 V),并且已经在常规LP2950CZ-3.3上降低了这5 V(顺便说一句) ,最高可加热70度。在这里,您也需要使用DC / DC转换器,但我尚未购买)。 顺便说一句,Lepton 3吃得很好。 当使用6 V电源供电时,整个设备的电流消耗约为250 mA。 当轻子要点击快门进行校准时,电流上升到500 mA。

放在一起的一切看起来像这样:





要使用轻子,您需要一个程序。 我使用了CubeMX和Keil5。在这种情况下,所有软件绑定都简化为不可能。

与轻子的通信在SPI上进行。 我没有使用过I2C,因为没有特别需要。 根据I2C,您可以控制轻子的状态,其工作模式,启用/禁用自动校准模式,等等。 但是对于夜视仪,这不是特别必要。

为了解密数据,我编写了一个模块:

模组
轻子控制
#ifndef LEPTON_CONTROL_H #define LEPTON_CONTROL_H #include <stdbool.h> #include <stdio.h> //   ( ) #define LEPTON_ORIGINAL_IMAGE_WIDTH 160 #define LEPTON_ORIGINAL_IMAGE_HEIGHT 120 //  VoSPI #define VOSPI_FRAME_HEIGHT 60 //  VoSPI #define VOSPI_FRAME_WIDTH 80 //  VoSPI   (164  RAW14  244  RGB) #define VOSPI_PACKAGE_SIZE 164 //   VoSPI   #define VOSPI_PACKAGE_LINE_SIZE 160 //  VOSPI   #define VOSPI_SEGMENT_LINE_AMOUNT 60 void LEPTONCONTROL_Init(void);// void LEPTONCONTROL_CalculateCRC(unsigned short *crc,unsigned char byte);// crc bool LEPTONCONTROL_PushVoSPI(unsigned char data[VOSPI_PACKAGE_SIZE],bool *first_line);//    VoSPI    unsigned short *LEPTONCONTROL_GetRAW14Ptr(void);//      #endif 

轻子控制

 #include "leptoncontrol.h" #include "stm32f4xx_hal.h" static unsigned short RAW14Image[LEPTON_ORIGINAL_IMAGE_HEIGHT*LEPTON_ORIGINAL_IMAGE_WIDTH];//  static unsigned short CRCTable[256];//   CRC16 //     #define RESYNC_TIMEOUT_MS 19 //:   #define NO_SEGMENT -1 //:   #define ERROR_PACKAGE -2 //---------------------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------------------- void LEPTONCONTROL_Init(void) { //    CRC unsigned short code; for(long n=0;n<256;n++) { code=((unsigned short)n)<<8; for(unsigned char m=0;m<8;m++) { if(code&(1<<15)) code=(code<<1)^0x1021; else code=code<<1; } CRCTable[n]=code; } } //---------------------------------------------------------------------------------------------------- // crc //---------------------------------------------------------------------------------------------------- void LEPTONCONTROL_CalculateCRC(unsigned short *crc,unsigned char byte) { *crc=CRCTable[(((*crc)>>8)^byte++)&0xFF]^((*crc)<<8); } //---------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------- long LEPTONCONTROL_ReadSegment(unsigned short *raw14_ptr,unsigned char data[VOSPI_PACKAGE_SIZE],bool *first_line) { static long current_package=-1; static long segment=-1; long n; *first_line=false; if ((data[0]&0x0F)==0x0F) return(NO_SEGMENT);//  unsigned short crc=data[2]; crc<<=8; crc|=data[3]; // CRC unsigned short crc16=0; LEPTONCONTROL_CalculateCRC(&crc16,data[0]&0x0F); LEPTONCONTROL_CalculateCRC(&crc16,data[1]); LEPTONCONTROL_CalculateCRC(&crc16,0); LEPTONCONTROL_CalculateCRC(&crc16,0); for(n=4;n<VOSPI_PACKAGE_SIZE;n++) LEPTONCONTROL_CalculateCRC(&crc16,data[n]); if (crc16!=crc) return(ERROR_PACKAGE);// CRC //   unsigned short package=data[0]&0x0F; package<<=8; package|=data[1]; if (package==0) { *first_line=true; current_package=0; } if (package==20) { unsigned char ttt=(data[0]&0x70)>>4;//     20  segment=ttt; } if (current_package<0) return(NO_SEGMENT); if (current_package!=package) { current_package=-1; return(ERROR_PACKAGE); } unsigned short *raw_ptr=raw14_ptr+current_package*VOSPI_PACKAGE_LINE_SIZE/2; for(n=0;n<VOSPI_PACKAGE_LINE_SIZE/2;n++,raw_ptr++) { //    big-endian: ,  unsigned short value=data[n*sizeof(short)+4]; value<<=8; value|=data[n*sizeof(short)+5]; *raw_ptr=value; } current_package++; if (current_package!=VOSPI_FRAME_HEIGHT) return(NO_SEGMENT); current_package=-1; return(segment); } //---------------------------------------------------------------------------------------------------- //    VoSPI    //---------------------------------------------------------------------------------------------------- bool LEPTONCONTROL_PushVoSPI(unsigned char data[VOSPI_PACKAGE_SIZE],bool *first_line) { *first_line=false; static long waitable_segment=1; long segment=LEPTONCONTROL_ReadSegment(RAW14Image+(waitable_segment-1)*VOSPI_FRAME_WIDTH*VOSPI_SEGMENT_LINE_AMOUNT,data,first_line); if (segment==ERROR_PACKAGE) HAL_Delay(RESYNC_TIMEOUT_MS); if (segment==ERROR_PACKAGE || segment==0) waitable_segment=1; if (segment==ERROR_PACKAGE || segment==NO_SEGMENT || segment==0) return(false); if (segment!=waitable_segment) { waitable_segment=1; if (segment!=1) return(false); } waitable_segment++; if (waitable_segment!=5) return(false); waitable_segment=1; return(true); } //---------------------------------------------------------------------------------------------------- //      //---------------------------------------------------------------------------------------------------- unsigned short *LEPTONCONTROL_GetRAW14Ptr(void) { return(RAW14Image); } 


该模块的所有工作都包括简单提交SPI获得的数据。

使用模块
 while(1) { //   while(1) { HAL_SPI_Receive(&hspi1,buffer,VOSPI_PACKAGE_SIZE,0x1000); bool first_line=false; unsigned char *buffer_ptr=buffer; LEPTONCONTROL_PushVoSPI(buffer_ptr,&first_line); if (first_line==true) break; } //    lepton3 unsigned char *buffer_ptr=buffer; HAL_SPI_Receive(&hspi1,buffer_ptr,VOSPI_PACKAGE_SIZE*SPI_READ_VOSPI_AMOUNT,0x1000); buffer_ptr=buffer; for(long n=0;n<SPI_READ_VOSPI_AMOUNT;n++,buffer_ptr+=VOSPI_PACKAGE_SIZE) { bool first_line=false; bool res=LEPTONCONTROL_PushVoSPI(buffer_ptr,&first_line); if (res==true) CreateImage();//     } } 


组装好框架后,只需将传感器读数归一化,减小到[0..255]范围,并以灰色阴影形式显示在显示屏上。 但是,没有什么可以阻止使用任何调色板为图像着色的。

为了在显示器上显示图像,我以8位数据总线模式使用此控制器内置的FSMC模块。

完整的程序可以在这里下载。

工作录像(很遗憾,我用质量合适的旧相机拍摄了-我现在没有摄像机了)。


PS顺便说一句,您可以直接通过USB将Flir One Gen 2热成像仪连接到STM32F407Discovery调试板。 但是,连接不稳定-热像仪经常丢失。


这样的连接程序在这里 。 也许有人会理解它是什么以及如何使连接稳定。

另外,该lepton 3模块可以轻松,简单地连接到Raspberry Pi。


在这种情况下,我必须从存储库中修改程序,以使我的版本可以使用lepton 3。

Source: https://habr.com/ru/post/zh-CN413021/


All Articles