OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 64|回复: 0

《ESP32-P4开发指南— V1.0》第四十二章 照相机实验

[复制链接]

1255

主题

1269

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5391
金钱
5391
注册时间
2019-5-8
在线时间
1393 小时
发表于 昨天 09:53 | 显示全部楼层 |阅读模式
第四十二章 照相机实验

1)实验平台:正点原子DNESP32P4开发板

2)章节摘自【正点原子】ESP32-P4开发指南— V1.0

3)购买链接:https://detail.tmall.com/item.htm?id=873309579825

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32P4.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子DNESP32S3开发板技术交流群:132780729


2.jpg

3.png

在前面的章节中,我们已经深入学习了MIPI CSI(Mobile Industry Processor Interface Camera Serial Interface)相关的基本原理,了解了MIPI摄像头如何通过CSI接口与处理器进行数据传输,以及图像数据的处理流程。本章节将基于MIPI CSI摄像头实验的基础,进一步实现照相机功能,并将拍摄的图像数据保存到SD卡的BMP文件中。
本章分为如下几个小节:
42.1 BMP编码简介
42.2 硬件设计
42.3 程序设计
42.4 下载验证


42.1 BMP编码简介
在前面的章节中,我们学习了各种图片格式的解码方法,并了解了如何解析图像文件以及如何从中提取图像数据。为进一步掌握图像处理的基本原理,本章将介绍最简单的图片编码方法——BMP(Bitmap)图片编码。BMP格式是一种非常基础且广泛使用的图像格式,它不使用压缩,因此解码和编码都相对简单。通过这个例程,我们将学习如何将图像数据编码为BMP格式,并理解BMP文件的结构。下面的程序是在bmp.c/.h文件下定义的。
BMP文件由以下四个主要部分组成:
1,文件头(File Header): 文件头是BMP格式的第一部分,它包含了文件的基本信息,如文件大小、图像的起始位置等。文件头是BMP文件中固定长度的部分,长度通常为14个字节。如下代码所示。
  1. <font size="3">/* BMP头文件 */</font>
  2. <font size="3">typedef struct</font>
  3. <font size="3">{</font>
  4. <font size="3">    uint16_t  bfType;           /* 文件标志.只对'BM',用来识别BMP位图类型 */</font>
  5. <font size="3">    uint32_t  bfSize;           /* 文件大小,占四个字节 */</font>
  6. <font size="3">    uint16_t  bfReserved1;      /* 保留 */</font>
  7. <font size="3">    uint16_t  bfReserved2;      /* 保留 */</font>
  8. <font size="3">    uint32_t  bfOffBits;        /* 从文件开始到位图数据(bitmap data)开始之间的的偏移量 */</font>
  9. <font size="3">} __attribute__ ((packed)) BITMAPFILEHEADER;</font>
复制代码
2,位图信息头(Bitmap Info Header): 位图信息头紧跟在文件头后面,包含了图像的详细信息,如图像的宽度、高度、颜色深度、压缩类型等。这个部分的长度通常为40个字节(对于Windows BMP格式)。它告诉我们如何解码图像数据,并且包含了关于图像的维度、颜色空间等关键信息,如下代码所示:
  1. <font size="3">/* BMP信息头 */</font>
  2. <font size="3">typedef struct</font>
  3. <font size="3">{</font>
  4. <font size="3">    uint32_t biSize;            /* 说明BITMAPINFOHEADER结构所需要的字数。 */</font>
  5. <font size="3">    long  biWidth;              /* 说明图象的宽度,以象素为单位 */</font>
  6. <font size="3">    long  biHeight;             /* 说明图象的高度,以象素为单位 */</font>
  7. <font size="3">    uint16_t  biPlanes;         /* 为目标设备说明位面数,其值将总是被设为1 */</font>
  8. <font size="3">    uint16_t  biBitCount;       /* 说明比特数/象素,其值为1、4、8、16、24、或32 */</font>
  9. <font size="3">    uint32_t biCompression;     /* 说明图象数据压缩的类型。其值可以是下述值之一</font>
  10. <font size="3">                                 * BI_RGB      :没有压缩</font>
  11. <font size="3">                                 * BI_RLE8     :每个象素8比特的RLE压缩编码 </font>
  12. <font size="3">                                 * BI_RLE4     :每个象素4比特的RLE压缩编码 </font>
  13. <font size="3">                                 * BI_BITFIELDS:每个象素的比特由指定的掩码决定 </font>
  14. <font size="3">                                 */</font>
  15. <font size="3">    uint32_t biSizeImage;                 /* 说明图象的大小,以字节为单位*/</font>
  16. <font size="3">    long  biXPelsPerMeter;      /* 说明水平分辨率,用象素/米表示 */</font>
  17. <font size="3">    long  biYPelsPerMeter;      /* 说明垂直分辨率,用象素/米表示 */</font>
  18. <font size="3">    uint32_t biClrUsed;         /* 说明位图实际使用的彩色表中的颜色索引数 */</font>
  19. <font size="3">    uint32_t biClrImportant;    /* 说明对图象显示有重要影响的颜色索引的数目 */</font>
  20. <font size="3">} __attribute__ ((packed)) BITMAPINFOHEADER;</font>
复制代码
3,颜色表(Color Table): BMP图像的颜色表用于存储图像中使用的颜色。对于8位或更低位深的BMP图像,颜色表是必需的。颜色表的大小由位深(如8位、16位等)决定,每个颜色由4个字节(包括红、绿、蓝和透明度或alpha值)来表示,如下代码所示:
  1. <font size="3">/* 彩色表  */</font>
  2. <font size="3">typedef struct</font>
  3. <font size="3">{</font>
  4. <font size="3">    uint8_t rgbBlue;           /* 指定蓝色强度 */</font>
  5. <font size="3">    uint8_t rgbGreen;          /* 指定绿色强度 */</font>
  6. <font size="3">    uint8_t rgbRed;            /* 指定红色强度 */</font>
  7. <font size="3">    uint8_t rgbReserved;       /* 保留,设置为0 */</font>
  8. <font size="3">} RGBQUAD;</font>
复制代码
4,图形数据(Pixel Data): 位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=16时,1个像素占2个字节;
当biBitCount=24时,1个像素占3个字节;
当biBitCount=32时,1个像素占4个字节;
biBitCount=1 表示位图最多有两种颜色,缺省情况下是黑色和白色,你也可以自己定义这两种颜色。图像信息头装调色板中将有两个调色板项,称为索引0和索引1。图象数据阵列中的每一位表示一个像素。如果一个位是0,显示时就使用索引0的RGB值,如果位是1,则使用索引1的RGB值。
biBitCount=16 表示位图最多有65536种颜色。每个像素用16位(2个字节)表示。这种格式叫作高彩色,或叫增强型16位色,或64K色。它的情况比较复杂,当biCompression成员的值是BI_RGB时,它没有调色板。16位中,最低的5位表示蓝色分量,中间的5位表示绿色分量,高的5位表示红色分量,一共占用了15位,最高的一位保留,设为0。这种格式也被称作555 16位位图。如果biCompression成员的值是BI_BITFIELDS,那么情况就复杂了,首先是原来调色板的位置被三个DWORD变量占据,称为红、绿、蓝掩码。分别用于描述红、绿、蓝分量在16位中所占的位置。在Windows 95(或98)中,系统可接受两种格式的位域:555和565,在555格式下,红、绿、蓝的掩码分别是:0x7C00、0x03E0、0x001F,而在565格式下,它们则分别为:0xF800、0x07E0、0x001F。你在读取一个像素之后,可以分别用掩码“与”上像素值,从而提取出想要的颜色分量(当然还要再经过适当的左右移操作)。在NT系统中,则没有格式限制,只不过要求掩码之间不能有重叠。(注:这种格式的图像使用起来是比较麻烦的,不过因为它的显示效果接近于真彩,而图像数据又比真彩图像小的多,所以,它更多的被用于游戏软件)。
biBitCount=32 表示位图最多有4294967296(2的32次方)种颜色。这种位图的结构与16位位图结构非常类似,当biCompression成员的值是BI_RGB时,它也没有调色板,32位中有24位用于存放RGB值,顺序是:最高位—保留,红8位、绿8位、蓝8位。这种格式也被成为888 32位图。如果 biCompression成员的值是BI_BITFIELDS时,原来调色板的位置将被三个DWORD变量占据,成为红、绿、蓝掩码,分别用于描述红、绿、蓝分量在32位中所占的位置。在Windows 95(or 98)中,系统只接受888格式,也就是说三个掩码的值将只能是:0xFF0000、0xFF00、0xFF。而NT系统,只要注意使掩码之间不产生重叠就行。(注:这种图像格式比较规整,因为它是DWORD对齐的,所以在内存中进行图像处理时可进行汇编级的代码优化(简单)。
通过以上了解,我们对BMP有了一个比较深入的了解,本章,我们采用16位BMP编码(因为我们的LCD就是16位色的,而且16位BMP编码比24位BMP编码更省空间),故我们需要设置biBitCount的值为16,这样得到新的位图信息(BITMAPINFO)结构体:
  1. <font size="3">/* 位图信息头 */</font>
  2. <font size="3">typedef struct</font>
  3. <font size="3">{ </font>
  4. <font size="3">    BITMAPFILEHEADER bmfHeader;</font>
  5. <font size="3">    BITMAPINFOHEADER bmiHeader;  </font>
  6. <font size="3">    uint32_t RGB_MASK[3];       /* 调色板用于存放RGB掩码 */</font>
  7. <font size="3">    //RGBQUAD bmiColors[256];</font>
  8. <font size="3">} __attribute__ ((packed)) BITMAPINFO;</font>
复制代码
上述的结构体其实就是颜色表由3个RGB掩码代替。最后,我们来看看将LCD的显存保存为BMP格式的图片文件的步骤:
1)创建BMP位图信息,并初始化各个相关信息
这里,我们要设置BMP图片的分辨率为LCD分辨率、BMP图片的大小(整个BMP文件大小)、BMP的像素位数(16位)和掩码等信息。
2)创建新BMP文件,写入BMP位图信息
我们要保存BMP,当然要存放在某个地方(文件),所以需要先创建文件,同时先保存BMP位图信息,之后才开始BMP数据的写入。
3)保存位图数据。
这里就比较简单了,只需要从LCD的GRAM里面读取各点的颜色值,依次写入第二步创建的BMP文件即可。注意:保存顺序(即读GRAM顺序)是从左到右,从下到上。
4)关闭文件。
使用FATFS,在文件创建之后,必须调用f_close,文件才会真正体现在文件系统里面,否则是不会写入的!这个要特别注意,写完之后,一定要调用f_close。
下面是基于之前的四个步骤实现的BMP编码函数。我们将按照文件头、位图信息头、颜色表、像素数据的顺序来编写BMP编码的函数。假设图像数据已经存在并且已知其宽度、高度以及颜色信息:
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief           BMP编码函数</font>
  3. <font size="3"> *   [url=home.php?mod=space&uid=60778]@note[/url]            将图像源保存为16位格式的BMP文件 RGB565格式.</font>
  4. <font size="3"> *                     保存为rgb555格式则需要颜色转换,耗时间比较久,所以保存为565是最快速的办法.</font>
  5. <font size="3"> *</font>
  6. <font size="3"> * [url=home.php?mod=space&uid=271674]@param[/url]              filename    : 包含存储路径的文件名(.bmp)</font>
  7. <font size="3"> * @param              image_addr  : 图像源</font>
  8. <font size="3"> * @param              width,height: 区域大小</font>
  9. <font size="3"> * @param              mode        : 保存模式</font>
  10. <font size="3"> *   @arg                     0, 仅仅创建新文件的方式编码;</font>
  11. <font size="3"> *   @arg                     1, 如果之前存在文件,则覆盖之前的文件。若没有,则创建新文件; </font>
  12. <font size="3"> * @retval            操作结果</font>
  13. <font size="3"> *   @arg              0   , 成功</font>
  14. <font size="3"> *   @arg             其他, 错误码</font>
  15. <font size="3"> */</font>
  16. <font size="3">uint8_t bmp_encode( uint8_t *filename, uint16_t *image_addr, uint16_t width, </font>
  17. <font size="3">uint16_t height, uint8_t mode)</font>
  18. <font size="3">{</font>
  19. <font size="3">#if SHOW_TIME == 1                              </font>
  20. <font size="3">    TickType_t startTick, endTick, diffTick;</font>
  21. <font size="3">    startTick = xTaskGetTickCount();</font>
  22. <font size="3">#endif</font>

  23. <font size="3">    FIL *f_bmp;</font>
  24. <font size="3">    uint32_t bw = 0;</font>
  25. <font size="3">    uint16_t bmpheadsize;       /* bmp头大小 */</font>
  26. <font size="3">    BITMAPINFO hbmp;            /* bmp头 */</font>
  27. <font size="3">    uint8_t res = 0;</font>
  28. <font size="3">    uint16_t *databuf;          /* 数据缓存区地址 */</font>
  29. <font size="3">    uint16_t pixcnt;            /* 像素计数器 */</font>
  30. <font size="3">    uint16_t bi4width;          /* 水平像素字节数 */</font>
  31. <font size="3">    uint16_t row_index = 0;</font>

  32. <font size="3">    uint16_t *img_addr = (uint16_t *)image_addr;</font>

  33. <font size="3">    if (width == 0 || height == 0) return PIC_WINDOW_ERR;   /* 区域错误 */</font>
  34. <font size="3">    </font>
  35. <font size="3">/* 开辟至少bi4width大小的字节的内存区域 ,对240宽的屏,480个字节就够了.</font>
  36. <font size="3">最大支持1024宽度的bmp编码 */</font>
  37. <font size="3">    databuf = (uint16_t *)piclib_mem_malloc(2160);</font>

  38. <font size="3">    if (databuf == NULL) return PIC_MEM_ERR;               /* 内存申请失败. */</font>

  39. <font size="3">    f_bmp = (FIL *)piclib_mem_malloc(sizeof(FIL));                /* 开辟FIL字节的内存区域 */</font>
  40. <font size="3">    if (f_bmp == NULL)                                     /* 内存申请失败 */</font>
  41. <font size="3">    {</font>
  42. <font size="3">        piclib_mem_free(databuf);</font>
  43. <font size="3">        return PIC_MEM_ERR;</font>
  44. <font size="3">    }</font>
  45. <font size="3">    /* BMP头部设置 */</font>
  46. <font size="3">    bmpheadsize = sizeof(hbmp);                                      /* 得到bmp文件头的大小 */</font>
  47. <font size="3">    memset((uint8_t *)&hbmp, 0, sizeof(hbmp));                        /* 置零空申请到的内存 */</font>

  48. <font size="3">    hbmp.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);    /* 信息头大小 */</font>
  49. <font size="3">    hbmp.bmiHeader.biWidth       = width;                       /* bmp的宽度 */</font>
  50. <font size="3">    hbmp.bmiHeader.biHeight      = height;                      /* bmp的高度 */</font>
  51. <font size="3">    hbmp.bmiHeader.biPlanes      = 1;                           /* 恒为1 */</font>
  52. <font size="3">    hbmp.bmiHeader.biBitCount    = 16;                      /* bmp为16位色bmp */</font>
  53. <font size="3">hbmp.bmiHeader.biCompression = BI_BITFIELDS;/* 每个象素的比特由指定的掩码决定 */</font>
  54. <font size="3">/* bmp数据区大小 */</font>
  55. <font size="3">hbmp.bmiHeader.biSizeImage   = hbmp.bmiHeader.biHeight * </font>
  56. <font size="3">hbmp.bmiHeader.biWidth * hbmp.bmiHeader.biBitCount / 8;                  </font>

  57. <font size="3">hbmp.bmfHeader.bfType    = ((uint16_t)'M' << 8) + 'B';      /* BM格式标志 */</font>
  58. <font size="3">/* 整个bmp的大小 */   </font>
  59. <font size="3">    hbmp.bmfHeader.bfSize    = bmpheadsize + hbmp.bmiHeader.biSizeImage; </font>
  60. <font size="3">    hbmp.bmfHeader.bfOffBits = bmpheadsize;           /* 到数据区的偏移 */</font>

  61. <font size="3">    hbmp.RGB_MASK[0] = 0X00F800;        /* 红色掩码 */</font>
  62. <font size="3">    hbmp.RGB_MASK[1] = 0X0007E0;        /* 绿色掩码 */</font>
  63. <font size="3">    hbmp.RGB_MASK[2] = 0X00001F;        /* 蓝色掩码 */</font>

  64. <font size="3">    if (mode == 1)</font>
  65. <font size="3">{</font>
  66. <font size="3">    /* 尝试打开之前的文件 */</font>
  67. <font size="3">        res = f_open(f_bmp, (const TCHAR *)filename, FA_READ | FA_WRITE);       </font>
  68. <font size="3">    }</font>
  69. <font size="3">    </font>
  70. <font size="3">    if (mode == 0 || res == 0x04)</font>
  71. <font size="3">{</font>
  72. <font size="3">    /* 模式0,或者尝试打开失败,则创建新文件 */</font>
  73. <font size="3">        res = f_open(f_bmp, (const TCHAR *)filename, FA_WRITE | FA_CREATE_NEW); </font>
  74. <font size="3">    }</font>

  75. <font size="3">    if ((hbmp.bmiHeader.biWidth * 2) % 4)       /* 水平像素(字节)不为4的倍数 */</font>
  76. <font size="3">{</font>
  77. <font size="3">    /* 实际要写入的宽度像素,必须为4的倍数 */</font>
  78. <font size="3">        bi4width = ((hbmp.bmiHeader.biWidth * 2) / 4 + 1) * 4;  </font>
  79. <font size="3">    }</font>
  80. <font size="3">    else</font>
  81. <font size="3">    {</font>
  82. <font size="3">        bi4width = hbmp.bmiHeader.biWidth * 2;  /* 刚好为4的倍数 */</font>
  83. <font size="3">    }</font>
  84. <font size="3">    /* 写入图像数据 */</font>
  85. <font size="3">    if (res == FR_OK)   /* 创建成功 */</font>
  86. <font size="3">{</font>
  87. <font size="3">    /* 写入BMP首部 */</font>
  88. <font size="3">        res = f_write(f_bmp, (uint8_t *)&hbmp, bmpheadsize, &bw);       </font>
  89. <font size="3">                /* 按一行一行操作 */</font>
  90. <font size="3">        for (uint16_t ty = height - 1; hbmp.bmiHeader.biHeight; ty--)   </font>
  91. <font size="3">        {</font>
  92. <font size="3">            pixcnt = 0;</font>

  93. <font size="3">            for (uint16_t xpix_index = 0; pixcnt != (bi4width / 2);)</font>
  94. <font size="3">            {     </font>
  95. <font size="3">                if (pixcnt < hbmp.bmiHeader.biWidth)</font>
  96. <font size="3">                {</font>
  97. <font size="3">                    databuf[pixcnt] = img_addr[pixcnt + hbmp.bmiHeader.biWidth </font>
  98. <font size="3">* row_index];   </font>
  99. <font size="3">                }</font>
  100. <font size="3">                else</font>
  101. <font size="3">                {</font>
  102. <font size="3">                    databuf[pixcnt] = 0Xffff;   /* 补充白色的像素 */</font>
  103. <font size="3">                }</font>

  104. <font size="3">                pixcnt++;</font>
  105. <font size="3">                xpix_index++;</font>
  106. <font size="3">            }</font>
  107. <font size="3">            hbmp.bmiHeader.biHeight--;</font>
  108. <font size="3">            row_index++;</font>
  109. <font size="3">/* 写入一行数据 */</font>
  110. <font size="3">            res = f_write(f_bmp, (uint8_t *)databuf, bi4width, &bw);</font>
  111. <font size="3">        }</font>
  112. <font size="3">        f_close(f_bmp);</font>
  113. <font size="3">    }</font>


  114. <font size="3">#if SHOW_TIME == 1   </font>
  115. <font size="3">    endTick = xTaskGetTickCount();</font>
  116. <font size="3">    diffTick = endTick - startTick;</font>
  117. <font size="3">    ESP_LOGI(__FUNCTION__, "elapsed time[ms]:%"PRIu32, diffTick * portTICK_PERIOD_MS);</font>
  118. <font size="3">#endif</font>

  119. <font size="3">    piclib_mem_free(databuf);</font>
  120. <font size="3">    piclib_mem_free(f_bmp);</font>

  121. <font size="3">    return res;</font>
  122. <font size="3">}</font>
复制代码
BMP编码过程是将图像数据保存为BMP格式文件的操作。通过设置BMP文件的头部信息(如图像宽度、高度、颜色深度等),并将图像的每一行像素数据逐行写入文件(必须是从左到右,从下到上依次写入)。该过程使用RGB565格式保存图像数据,通过内存分配和文件操作来完成图像的存储,并确保数据按4字节对齐。最终,BMP文件包含图像的元数据和实际像素数据,成功生成BMP图像文件。

42.2 硬件设计

42.2.1 程序功能
该实验通过检测SD卡根目录中的PHOTO文件夹是否存在并创建它,确保拍照功能的正常使用。成功创建文件夹后,系统初始化MIPI摄像头并在LCD屏幕上显示相关信息,按下BOOT按键触发拍照功能。同时,LED0会闪烁,提示程序正常运行。如果SD卡或摄像头初始化失败,系统会显示相应的错误信息。

42.2.2 硬件资源
1)LED灯
        LED        0        - IO51
2)MIPI CSI
3)RGBLCD/MIPILCD(引脚太多,不罗列出来)
4)KEY按键
        BOOT        - IO35

42.2.3 原理图
MIPI CSI原理图已在37.2.3小节中详细阐述,为避免重复,此处不再赘述。

42.3 程序设计

42.3.1 程序流程图

第四十二章 照相机实验9531.png
图42.3.1 照相机实验程序流程图

42.3.2 程序解析
在33_photograph例程中,基于28_mipicamera例程进行了修改,主要是在33_photograph\components\Middlewares文件夹下添加了MYFATFS、PICTURE和TEXT这三个组件。这些组件的具体功能和作用,笔者已经在前面的章节中详细讲解过,因此在此不再重复描述。
1,图像存储代码
在main/APP/MIPI_CAM/mipi_cam.c文件下的lcd_cam_task摄像头任务函数中,首先通过PPA(Pixel Processing Accelerator)将摄像头模块采集到的原始图像数据转换为适合显示的格式和大小,然后将转换后的图像数据展示在LCD屏幕上。当按下BOOT按键时,系统会触发拍照功能,将当前显示的图像数据传递给bmp_encode函数进行BMP格式编码,最终将编码后的图片保存到SD卡的PHOTO文件夹中:
  1. <font size="3">if (key_scan(0) == BOOT_PRES)       /* 按下BOOT按键进行拍照 */</font>
  2. <font size="3">{</font>
  3. <font size="3">    camera_new_pathname(pname, 0);  /* 得到文件名 */  </font>
  4. <font size="3">    res=bmp_encode(pname,(uint16_t *)draw_buffer,lcddev.width,lcddev.height, 1);</font>

  5. <font size="3">    text_show_string(30, 130, 240, 16, "请耐心等待,正在进行文件写入!", 16, 0, RED);</font>
  6. <font size="3">    if (res)</font>
  7. <font size="3">    {</font>
  8. <font size="3">        text_show_string(30, 130, 240, 16, "写入文件错误!", 16, 0, RED);</font>
  9. <font size="3">    }</font>
  10. <font size="3">    else</font>
  11. <font size="3">    {</font>
  12. <font size="3">        text_show_string(30, 130, 240, 16, "拍照成功!", 16, 0, RED);</font>
  13. <font size="3">        text_show_string(30, 150, 240, 16, "保存为:", 16, 0, RED);</font>
  14. <font size="3">        text_show_string(30 + 56, 150, 240, 16, (char *)pname, 16, 0, RED);</font>
  15. <font size="3">        vTaskDelay(pdMS_TO_TICKS(500));</font>
  16. <font size="3">    }</font>
  17. <font size="3">}</font>
复制代码
lcd_cam_task摄像头任务函数实现已在第三十七章节中介绍过了,因此在此不再重复描述。
2,CMakeLists.txt文件
CMakeLists.txt文件跟摄像头实验一致,代码如下:
  1. <font size="3">idf_component_register(</font>
  2. <font size="3">                        SRC_DIRS </font>
  3. <font size="3">                            "."</font>
  4. <font size="3">                            "APP/MIPI_CAM" </font>
  5. <font size="3">                        INCLUDE_DIRS </font>
  6. <font size="3">                            "."</font>
  7. <font size="3">                            "APP/MIPI_CAM" </font>
  8. <font size="3">                        )</font>
复制代码
3,main.c驱动代码
在main.c里面编写如下代码。
  1. <font size="3">void app_main(void)</font>
  2. <font size="3">{</font>
  3. <font size="3">    esp_err_t ret;</font>
  4. <font size="3">    uint8_t key = 0;</font>

  5. <font size="3">    ret = nvs_flash_init();           /* 初始化NVS */</font>
  6. <font size="3">    if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)</font>
  7. <font size="3">    {</font>
  8. <font size="3">        ESP_ERROR_CHECK(nvs_flash_erase());</font>
  9. <font size="3">        ESP_ERROR_CHECK(nvs_flash_init());</font>
  10. <font size="3">    }</font>

  11. <font size="3">    led_init();                             /* LED初始化 */</font>
  12. <font size="3">    key_init();                             /* KEY初始化 */</font>
  13. <font size="3">    myiic_init();                           /* MYIIC初始化 */</font>
  14. <font size="3">    lcd_init();                             /* LCD屏初始化 */</font>

  15. <font size="3">    while (sdmmc_init())            /* 检测不到SD卡 */</font>
  16. <font size="3">    {</font>
  17. <font size="3">        lcd_show_string(30, 110, 200, 16, 16, "SD Card Error!", RED);</font>
  18. <font size="3">        vTaskDelay(pdMS_TO_TICKS(200));</font>
  19. <font size="3">        lcd_fill(30, 110, 239, 126, WHITE);</font>
  20. <font size="3">        vTaskDelay(pdMS_TO_TICKS(200));</font>
  21. <font size="3">    }</font>

  22. <font size="3">    ret = exfuns_init();            /* 为fatfs相关变量申请内存 */</font>

  23. <font size="3">    while (fonts_init())            /* 检查字库 */</font>
  24. <font size="3">    {</font>
  25. <font size="3">        lcd_clear(WHITE);</font>
  26. <font size="3">        lcd_show_string(30, 30, 200, 16, 16, "ESP32-P4", RED);</font>
  27. <font size="3">        </font>
  28. <font size="3">        key = fonts_update_font(30, 50, 16, (uint8_t *)"0:", RED);  /* 更新字库 */</font>

  29. <font size="3">        while (key)                 /* 更新失败 */</font>
  30. <font size="3">        {</font>
  31. <font size="3">            lcd_show_string(30, 50, 200, 16, 16, "Font Update Failed!", RED);</font>
  32. <font size="3">            vTaskDelay(pdMS_TO_TICKS(200));</font>
  33. <font size="3">            lcd_fill(20, 50, 200 + 20, 90 + 16, WHITE);</font>
  34. <font size="3">            vTaskDelay(pdMS_TO_TICKS(200));</font>
  35. <font size="3">        }</font>

  36. <font size="3">        lcd_show_string(30, 50, 200, 16, 16, "Font Update Success!   ", RED);</font>
  37. <font size="3">        vTaskDelay(pdMS_TO_TICKS(1000));</font>
  38. <font size="3">        lcd_clear(WHITE); </font>
  39. <font size="3">    }</font>

  40. <font size="3">    text_show_string(30, 50,  200, 16, "正点原子ESP32-P4开发板", 16, 0, RED);</font>
  41. <font size="3">    text_show_string(30, 70,  200, 16, "照相机 实验", 16, 0, RED);</font>
  42. <font size="3">    text_show_string(30, 90,  200, 16, "正点原子@ALIENTEK", 16, 0, RED);</font>
  43. <font size="3">    text_show_string(30, 110, 200, 16, "BOOT:TAKE PHOTO", 16, 0, RED);</font>

  44. <font size="3">    vTaskDelay(pdMS_TO_TICKS(1000));</font>
  45. <font size="3">    lcd_clear(WHITE);</font>
  46. <font size="3">    </font>
  47. <font size="3">    mipi_cam_init();    /* 摄像头初始化 */</font>

  48. <font size="3">    while (1)</font>
  49. <font size="3">    {</font>
  50. <font size="3">        LED0_TOGGLE();</font>
  51. <font size="3">        vTaskDelay(pdMS_TO_TICKS(500));</font>
  52. <font size="3">    }</font>
  53. <font size="3">}</font>
复制代码
上述函数主要实现了硬件初始化、SD卡检测、字库更新、LCD显示和摄像头初始化等功能。程序首先初始化了NVS、LED、按键、I2C总线和LCD屏,随后检测SD卡是否存在并可用,如果未检测到SD卡则提示错误信息并反复重试。接着,程序检查并更新字库,确保显示文字的正确性。字库更新成功后,屏幕会显示开发板和实验相关的信息。在完成硬件和系统初始化后,摄像头被初始化准备拍照,同时LED灯每500毫秒闪烁,提示程序正常运行。

42.4 下载验证
将程序下载到开发板后,可以看到LCD首先显示一些实验相关的信息,如下图所示:

第四十二章 照相机实验13097.png
图42.4.1 显示实验相关信息

显示了上图的信息后,自动进入监控界面。可以看到LED0不停的闪烁,提示程序已经在运行了。此时,我们可以按下BOOT,即可进行bmp拍照。拍照得到的照片效果如下图所示:

第四十二章 照相机实验13200.png
图42.4.2 拍照样图
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-2-7 07:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表