# camera **Repository Path**: dxmcu/camera ## Basic Information - **Project Name**: camera - **Description**: 这个一个可以将三维空间降到二维的装置,任何被他捕捉到的空间,都会被降维到一张小纸条上,人们称他为“二向箔”,哦不,拍立得。 - **Primary Language**: Unknown - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 7 - **Created**: 2024-12-02 - **Last Updated**: 2024-12-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ![IMG_20240605_202913 主图](resource/IMG_20240605_202913 主图.jpg) # 项目说明 这个一个可以将三维空间降到二维的装置,任何被他捕捉到的空间,都会被降维到一张小纸条上,人们称他为“二向箔”,哦不,拍立得。 - 主控使用STM32,并移植LVGL8.2。 - 200万像素摄像头,实现照片拍摄功能。 - 2.8寸TFT液晶显示屏,分辨率240×320。实现照片显示、打印、删除等功能。 - 内置热敏打印单元,可实现拍摄照片打印功能。 - 内置500mAh锂电池,并设计有锂电池充放电管理单。无需外部电源,体积小巧,方便携带。 - 使用波轮按键方便操作,同时提供电源开关键和拍摄按键。 - 支持定时休眠,一键休眠和唤醒,降低功耗。 # 开源协议 GPL3.0 开源网址:[https://gitee.com/liangzili/camera](https://gitee.com/liangzili/camera) # 项目属性 提示:本项目为首次公开,为本人原创项目。项目未曾在别的比赛中获奖。 # 更新计划 - 外壳PCB增加充电完成指示孔。 - 打印纸位置不合理,需要上移。 - 按键增加长按和短按支持。 - TYPC接口集成下载调试。 - 摄像头画面噪点 # 更新日志 master - 固件程序修复摄像头清晰度差的问题。 20240720_V2.1 - 固件程序优化热敏打印速度。 - PCB调整DCMI为等长布线。 - PCB调整热敏打印头和摄像头供电部分线宽。 - PCB修复部分丝印被遮挡的问题。 - PCB修复左下角固定孔位置。 20240521_V2.0 - 新增LVGL8.2适配,实现更好的UI效果。 - 新增摄像头驱动电路,减小因摄像模组带来的空间占用。 - 优化RGB565转灰度算法,实现更合理的灰度值输出。 - 修改电源开关位置,解决因电源开关关闭导致无法充电的问题。 - PCB版型修改,下方开槽,方便打印纸卷放置,减小机身厚度。 - 修复LCD FSMC_D1引脚错误。 - 修复因VDDA、VSSA导致的STM32启动失败问题。 - 修复STM32外围滤波电容接地问题。 20240409_V1.0 - 项目首次发布,基本功能实现,完成验证。 # 硬件设计 ![硬件框图](2.硬件设计/硬件框图.png) **主控:STM32F407ZG** ​ 选用这款微控制器,是因为STM32F4系列提供了出色的计算能力和实时响应能力。可以为项目中摄像头、屏幕、存储卡、热敏打印头、电池管理、按键控制等提供足够的IO支持及资源支持。 **屏幕:2.8寸TFT液晶屏** ​ 这款2.8寸的屏幕采用240*320的分辨率,尺寸小巧的同时也能提供不错的显示效果。通过FSMC连接STM32控制器,简化了电路设计和布线,降低了系统成本和复杂度。 **摄像头:OV2640摄像头模组** ​ 这款200万像素的摄像头,不仅具有极高的性价比,而且完全满足本项目的图像采集需求。通过DCMI连接STM32控制器,提供了高速的数据传输能力。 **热敏打印头:精芯 JX-700-48R** ​ 设计一款拍立得设备,图像的打印是关键,不仅要体积小巧、重量轻,还要功耗低,而热敏打印就是不错的选择。 **电池管理:TP4056** ​ TP4056采用恒定电流/恒定电压(CCCV)充电模式,能够自动完成整个充电过程,包括涓流预充、恒流快速充电和恒压充电阶段,有效保证电池的健康和长寿命。 # 软件设计 **软件界面:** ![PIC0001](resource/PIC0001.png) 受篇幅限制,这里只针对部分关键代码进行讲解。 **热敏打印功能实现:** 当系统检测到`打印键`按下时,将获取当前图片的路径,并调用如下函数,此函数用于从给定路径读取一个BMP图像文件,并将其转换为热敏打印机的数据格式进行打印。 ```c static void PrintFile(char *path) { FRESULT res; FIL file; // 文件对象 UINT br; // 实际读取的字节数 uint16_t line = 0; // 当前打印行号 uint16_t lineDateTemp[384]; // 文件内容缓存,保存一行图片数据 res = f_open(&file, path, FA_READ); if (res != FR_OK) { printe("文件打开失败\n"); } /* 从bmp头 获取图片信息 */ BITMAPINFO hbmp; res = f_read(&file, &hbmp, sizeof(BITMAPINFO), &br); if (res != FR_OK) { printe("文件读取失败\n"); } uint32_t bfOffBits = hbmp.bmfHeader.bfOffBits; // 位图数据偏移量 uint16_t w = hbmp.bmiHeader.biWidth; // 图象的宽度,以象素为单位 uint16_t h = hbmp.bmiHeader.biHeight; // 图象的高度,以象素为单位 printi("位图数据偏移量:%d,宽度:%d,高度:%d。\n",bfOffBits,w,h); f_lseek(&file, bfOffBits); // 移动文件指针跳过bmp文件头 memset(lineDateTemp, 0xFF, sizeof(lineDateTemp)); // 行数据点默认为白色 do{ res = f_read(&file, lineDateTemp, w*2, &br); // 一次读取1行像素,16bit,一个像素2个字节 if(w < 384) // 图片宽度小于打印宽度 { memmove(lineDateTemp + (384 - w)/2, lineDateTemp, w*2); // 数据整体移动,使图像保持居中 memset(lineDateTemp,0xFF, (384 - w)/2); // 填充白色 } if(res != FR_OK) { printf("文件读取失败\n"); break; } uint8_t printLine[48]; // 一行打印数据48字节DotS for(uint16_t i = 0;i < 384;i+=8) // 对当前 DOT点 进行处理,打印宽度 { uint8_t packedByte = 0; // 将8个二值化像素合并为一个字节 for(uint8_t j = 0;j < 8;j++) // 3.将8个二值化后的像素(每个像素1位)合并成一个字节 { uint8_t gray = RGB565ToGray(lineDateTemp[384 - i - j]);// 1.RGB565格式转灰度图,uint16_t => uint8_t packedByte |= GrayToBinary(gray, 127) << (7 - j); // 2.根据灰度值设定阈值进行二值化处理,阈值为128 if(j == 7) { printLine[i/8] = packedByte; // 4.将处理好的数据添加到打印数组,等待打印 } } } printf("打印line%d\n",line); LinePrint(printLine); if (res != FR_OK) { printf("f_lseek err\n"); } line++; }while(br > 0); PrinterStep(80);//打印完成的出纸长度 StopPrint(); f_close(&file); } // RGB565转灰度 uint8_t RGB565ToGray(uint16_t rgb565) { uint32_t gray; uint8_t r = (rgb565 >> 11) & 0x1F; // R 5 bits uint8_t g = (rgb565 >> 5) & 0x3F; // G 6 bits uint8_t b = rgb565 & 0x1F; // B 5 bits gray = (r*30*8 + g*59*4 + b*11*8 + 50) / 100; // 注意,这里使用的是近似的人眼感知权重:R*30%, G*59%, B*11%。加50是为了四舍五入。 return (uint8_t)gray; // 确保结果在0-255范围内,尽管这里计算的结果自然就在该范围内 } // 二值化处理 uint8_t GrayToBinary(uint8_t gray, uint8_t threshold) { return (gray >= threshold) ? 0 : 1; } ``` # 结构设计 ![](resource/拍立得.jpg) ![结构文件截图](resource/结构文件截图.png) # 实物展示 ![IMG_20240608_092451_mini](resource/IMG_20240608_092451_mini.jpg) ![IMG_20240608_092306_mini](resource/IMG_20240608_092306_mini.jpg)