一、选摄像头
1、海康 TB-4117-3/S 像素较高,无奈鄙人囊中羞涩。
2、MLX90640-BAA 视场角度110*75度,角度大,适合近距离测量。
3、MLX90640-BAB 视场角度55*35度,角度小,适合远距离测量。
二、选芯片
1、STM32F103C8T6 这颗芯片无需多言,男女老少都爱用。
2、GD32F470ZGT6 这颗芯片整体性能提高了一个档次,且学生可免费申请。
三、选屏幕
1、屏幕没有太多的忌口,选择自己喜欢的就行。我选择的是1.47寸 LCD SPI通信 显示屏,驱动芯片为ST7789V3,以上两款的引脚扇出方式略有差异,可自行选择。
四、接线
1、方案搭配:MLX90640-BAB + GD32F470ZGT6 + ST7789V3。
2、如下是摄像头与开发板的引脚对应:
摄像头 | 开发板 |
VIN | 3V3 |
GND | GND |
时钟引脚 SCL | PB6 |
数据引脚 SDA | PB7 |
3、如下是屏幕与开发板的引脚对应:
屏幕 | 开发板 |
VCC | 3V3 |
GND | GND |
时钟引脚 CLK(SCL) | PB13 |
数据引脚 DIN(SDA) | PB15 |
片选引脚 CS | PB12 |
数据/命令控制引脚 DC | PC6 |
复位引脚 RST(RES) | 低有效,可悬空 |
背光控制引脚 BL(BLK) | 默认打开,可悬空 |
4、使用导电率 ≥ 61.0% IACS 的物体连接上述对应引脚。
五、炫代码
1、驱动下载:
-
摄像头官方驱动:MLX90640官方驱动链接
-
屏幕驱动资料:百度网盘下载链接
-
驱动移植过程较死板且网上教程很多,此处不再赘述。
2、软件 Keil uVision5 开!
主函数:
int main(void)
{
uint16_t state; // 摄像头采集准备就绪-->状态位
LCD_Init(); // 屏幕初始化
mlx90640_init(); // 摄像头初始化
while (1)
{
MLX90640_I2CRead(MLX90640_ADDR, 0x8000, 1, &state); //读取状态位
if (state & 0x0008) //如果就绪
{
Temp2RGB(); // 1、将温度数据转化为RGB数据
LCD_ShowPicture(0, 0, 224, 168, rgb8); // 2、设置图片显示位置、大小
Serial_SendPacket(); // 3、发送给屏幕
//显示数据
LCD_ShowString(230, 0, "Max:", RED, BLACK, 16, 0);
LCD_ShowFloatNum1(270, 0, max_temp, 4, RED, BLACK, 16);//显示最大温度值
LCD_ShowString(230, 50, "Min:", BLUE, BLACK, 16, 0);
LCD_ShowFloatNum1(270, 50, min_temp, 4, BLUE, BLACK, 16);//显示最小温度值
LCD_ShowString(230, 100, "Ta:", GREEN, BLACK, 16, 0);
LCD_ShowFloatNum1(270, 100, Ta, 4, GREEN, BLACK, 16);//显示环境温度
LCD_ShowString(230, 150, "VDD:", YELLOW, BLACK, 16, 0);
LCD_ShowFloatNum1(270, 150, VDD, 4, YELLOW, BLACK, 16);//显示供电电压
}
}
}
数据转化函数:
// 将温度数据转化成RGB数据
void Temp2RGB(void)
{
// 1、调用官方提供的函数计算温度
int status = MLX90640_GetFrameData(MLX90640_ADDR, Frame); // 从摄像头获取一帧数据
VDD = MLX90640_GetVdd(Frame, &MLXPars); // 读供电电压
Ta = MLX90640_GetTa(Frame, &MLXPars); // 读环境温度
MLX90640_CalculateTo(Frame, &MLXPars, 0.95, Ta - 8, Temp); // 计算温度
// 2、找出最小和最大温度及其位置
max_temp = -40;
min_temp = 300;
for (uint16_t x = 0; x < 768; x++)
{
if (Temp[x] > max_temp)
{
max_temp = Temp[x];
max_temp_pos = x;
}
if (Temp[x] < min_temp)
{
min_temp = Temp[x];
min_temp_pos = x;
}
}
// 3、温度值-->灰度值
float k = 255 / (max_temp - min_temp); // 线性映射系数
for (uint16_t i = 0; i < 768; i++)
{
gray[i] = (Temp[i] - min_temp) * k;
}
// 4、对24*32灰度图像进行"双线性插值"放大7倍到168*224
int srcWidth = 32;
int srcHeight = 24;
int targetWidth = 224;
int targetHeight = 168;
for (int i = 0; i < targetHeight; i++)
{
for (int j = 0; j < targetWidth; j++)
{
float x = (float)j / targetWidth * srcWidth;
float y = (float)i / targetHeight * srcHeight;
int x1 = (int)x;
int y1 = (int)y;
int x2 = x1 < srcWidth - 1 ? x1 + 1 : x1;
int y2 = y1 < srcHeight - 1 ? y1 + 1 : y1;
float dx = x - x1;
float dy = y - y1;
unsigned char q11 = gray[y1 * srcWidth + x1];
unsigned char q21 = gray[y1 * srcWidth + x2];
unsigned char q12 = gray[y2 * srcWidth + x1];
unsigned char q22 = gray[y2 * srcWidth + x2];
gray_bi[i * targetWidth + j] = (unsigned char)(q11 * (1 - dx) * (1 - dy) + q21 * dx * (1 - dy) + q12 * (1 - dx) * dy + q22 * dx * dy);
}
}
// 5、双插灰度值-->8位RGB伪彩色-->16位RGB565
for (uint32_t i = 0; i < 37632; i++)
{
float R, G, B;
if( ((float)gray_bi[i]>=0) && (gray_bi[i]<=63) )
{
R=0;
G=round(((float)gray_bi[i]-0)/64*255);
B=255;
}
else if( (gray_bi[i]>=64) && (gray_bi[i]<=95) )
{
R=0;
G=255;
B=round((95-(float)gray_bi[i])/32*255);
}
else if( (gray_bi[i]>=96) && (gray_bi[i]<=127) )
{
R=round(((float)gray_bi[i]-96)/32*255);
G=255;
B=0;
}
else if( (gray_bi[i]>=128) && (gray_bi[i]<=191) )
{
R=255;
G=round((191-(float)gray_bi[i])/64*255);
B=0;
}
else if( (gray_bi[i]>=192) && (gray_bi[i]<=255) )
{
R=255;
G=round(((float)gray_bi[i]-192)/64*255);
B=round(((float)gray_bi[i]-192)/64*255);
}
uint16_t rbits = (R * 0.125f);
uint16_t gbits = (G * 0.250f);
uint16_t bbits = (B * 0.125f);
gray_bi[i] = (rbits << 11) | (gbits << 5) | bbits;
}
// 6、将16位RGB565分为2个字节存储,方便传输
for (uint32_t i = 0; i < 37632; i++)
{
rgb8[i * 2] = gray_bi[i] & 0x00FF;
rgb8[i * 2 + 1] = gray_bi[i] >> 8;
}
}
六、成品实测
1、RGB伪彩色从左到右,温度越高,最高为白色。
2、继电器工作发热主触点温度实测如下:
七、结束语
若家人们感兴趣,点赞收藏较多,后期将编写Python用串口连接到电脑上直接显示图像。