[STM32H7] STM32H7B0 HAL库中关于DMA的注意事项以及DCMI调试遇到的问题及解决方法

[复制链接]
 楼主| 八层楼 发表于 2025-7-10 15:03 | 显示全部楼层 |阅读模式
先总结总结问题
问题1:MX_DCMI_Init();放到  MX_DMA_Init();后

问题2:DMA缓存缓存要放到SRAM中__align(32) uint32_t buffer[65535] __attribute((at(0X24040000)));

问题3:IO复用问题,DCMI数据口可以复用到其他IO口,要注意配置

问题4:摄像头时钟配置,不能过快,也不能过慢,过快采集不过来,过慢JPEG会传一半停止

问题5:上位机字节序,JPG由FF D8开头,FF D9结尾

解决上面5个问题,STM32H7 DCMI就可以轻松使用

由于需要用到摄像头,用IO驱动的话会比较慢,这里使用的STM32H7B0中的DCMI接口,由于DMA用的比较少,在这里卡了3天,期间各种测试,从硬件到软件,接用IO读OV2640,可以读到数据,确定硬件没有问题,DCMI的DMA一直进错误中断Transfer Error Interrupt management

68826686c97cca24d9.png

网上说是内存地址问题,DMA不能访问直接访问DTCM,也改成SRAM了,也会进入错误中断

85237686c97c756f7a.png

DMA1等都不能访问DTCM

91016686c97c252c5d.png

最终发现把    MX_DCMI_Init();放到  MX_DMA_Init();即可正常传输数据

47861686c97be36858.png

Several peripheral DMA handle pointers point to the same DMA handle.
     Be aware that there is only one channel to perform all the requested DMAs.干扰项,删掉就行不用管,我开始还以为这里需要配置什么东西,就保留最上边一行

10110686c97b9848d4.png

删完就像这样就可以

85608686c97b414e1d.png

缓存放到SRAM放到中

__align(32) uint32_t buffer[65535] __attribute((at(0X24040000)));

开启缓存对于DCMI没有影响,开不开都可以正常运行

static void CPU_CACHE_Enable(void)
{
    SCB_EnableICache();//使能I-Cache
  SCB_EnableDCache();//使能D-Cache   
    SCB->CACR|=1<<2;   //强制D-Cache透写,如不开启,实际使用中可能遇到各种问题   
}

启动采集代码

void StartOV2640()
{
                int i =0;
                __HAL_DCMI_ENABLE_IT(&hdcmi, DCMI_IER_FRAME_IE);                                                       //使用帧中断
    memset(buffer, 0, 65535);                                                                                //把接收BUF清空
    HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_SNAPSHOT, (uint32_t)buffer, 65535);         //启动拍照
}


void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
          int i =0;
          HAL_DCMI_Suspend(hdcmi); // 拍照完成,挂起 DCMI
          HAL_DCMI_Stop(hdcmi);    // 拍照完成,停止 DMA传输
    int pictureLength = 65535;
    while (pictureLength > 0)     //循环计算出接收的JPEG的大小
    {
        if (buffer[pictureLength - 1] != 0x00000000)
        {
          break;
        }
        pictureLength--;
    }
                jpeglen = pictureLength * 4;
                getPicture = 1;
}


配置IO也要注意一下D0,D1,D3可以复用到其他IO,一定不要弄错,配置完要对着IO检查一遍,频率使用也很重要,我这里用到的频率如下

单片机主频280M

摄像头主频8M

摄像头分频配置

SCCB_WR_Reg(0XFF,0X00);

SCCB_WR_Reg(0XD3,0XF);

SCCB_WR_Reg(0XFF,0X01);

SCCB_WR_Reg(0X11,0X7);

24540686c97a8447c2.png

45988686c979c73e08.png

开启中断

81242686c9796e3e20.png

DMA配置,不要修改

53764686c978ed6e5e.png

NVIC给个优先级

30767686c97898ff37.png

摄像头时钟,这个可以自由发挥,和摄像头分频配置一起可以有多重组合

28554686c97846ea54.png

样张

59825686c977e5d7cd.png

上位机软件用C#写的,关键部分代码

private const int count = 200 * 1024;
private byte[] buffer = new byte[count];
private int offset = 0;
private int length = 0;
private bool isData = false;
public void DataCallBack(Object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        if (isData==false)
        {
            var data = _serialPort.ReadLine();
            if (!string.IsNullOrEmpty(data) && data.Length > 0)
            {
                if(data.IndexOf("jpeg data size:")>=0)
                {
                    var lengthStr = data.Split(':');
                    if(lengthStr != null && lengthStr.Length>1)
                    {
                        length = int.Parse(lengthStr[1]);
                        if (length > count)
                        {

                        }
                        else
                        {
                            isData = true;
                        }
                    }
                    Console.WriteLine(data);
                }
                else
                {
                    Console.WriteLine(data);
                }
            }
        }
        else
        {
            int thisLength = _serialPort.Read(buffer, offset, length - offset);
            offset = offset + thisLength;
            if(offset >= length)
            {
                Console.WriteLine($"接收完一张图片,offset:{offset},length:{length}");
                string path = Directory.GetCurrentDirectory();
                DirectoryCheak(path + "\\out\\");
                bool ispictrue = false;
                if (false)//bmp
                {
                    //bmp
                    if (false)
                    {
                        //RGB888
                        System.Drawing.Bitmap formBitmap = new System.Drawing.Bitmap(96, 96);
                        for (int i = 0; i < 96; i++)
                        {
                            for (int j = 0; j < 96; j++)
                            {
                                formBitmap.SetPixel(i, j, System.Drawing.Color.FromArgb(buffer[i * j + j], buffer[i * j + j + 1], buffer[i * j + j + 2]));
                            }
                        }
                        formBitmap.Save(path + "\\out\\" + DateTime.Now.ToString("yyyyMMdd-HHmmss.fff") + ".bmp");
                    }
                    else
                    {
                        //RGB565
                        List<UInt16> data = new List<UInt16>();
                        for (int i = 0; i < length; i += 2)
                        {
                            UInt16 thisData = (UInt16)((buffer << 8) | buffer[i + 1]); ;
                            data.Add(thisData);
                        }
                        System.Drawing.Bitmap formBitmap = new System.Drawing.Bitmap(96, 96);
                        for (int i = 0; i < 96; i++)
                        {
                            for (int j = 0; j < 96; j++)
                            {
                                byte red = (byte)((data[i * j + j] >> 11) << 3); //5位 移动3位
                                byte green = (byte)(((data[i * j + j] << 5) >> 10) << 2); //6位 移动2位
                                byte blue = (byte)(((data[i * j + j] << 11) >> 11) << 3); //5位 移动3位
                                formBitmap.SetPixel(i, j, System.Drawing.Color.FromArgb(red, green, blue));
                            }
                        }
                        formBitmap.Save(path + "\\out\\" + DateTime.Now.ToString("yyyyMMdd-HHmmss.fff") + ".bmp");
                    }
                }
                else
                {
                    List<byte> data = new List<byte>();
                    for (int i = 1; i < length; i++)
                    {
                        //Console.WriteLine($"i:{i},length:{length}");
                        if (ispictrue == true)
                        {
                            data.Add(buffer);
                        }
                        else if ((buffer[i - 1] == 0xFF) && (buffer == 0xd8))
                        {
                            ispictrue = true;
                            data.Add(buffer[i - 1]);
                            data.Add(buffer);
                        }
                        //if((buffer[i - 1] == 0xFF) && (buffer == 0xd9))
                        //{
                        //    data.Add(buffer[i - 1]);
                        //    data.Add(buffer);
                        //    ispictrue = false;
                        //    break;
                        //}
                    }
                    WriteFileUsingBinaryWriter(path + "\\out\\", DateTime.Now.ToString("yyyyMMdd-HHmmss.fff") + ".jpg", data.ToArray(), data.Count());
                }
                offset = 0;
                length = 0;
                isData = false;

            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("串口解析出错" + ex.ToString());
    }
}

public void WriteFileUsingBinaryWriter(string path,string fileName,byte[] data,int length)
{
    var outputStream = File.Create(path + fileName);
    using (var writer = new BinaryWriter(outputStream))
    {
        writer.Write(data, 0, length);
    }
}

/// <summary>
/// 效验文件夹,没有就创建
/// </summary>
private void DirectoryCheak(string path)
{
    if (false == System.IO.Directory.Exists(path))
    {
        System.IO.Directory.CreateDirectory(path);
    }
}

private void OpenSerialPort_Click(object sender, RoutedEventArgs e)
{
    try
    {
        _serialPort = new SerialPort();

        _serialPort.PortName = SerialPort.Text;
        _serialPort.BaudRate = int.Parse(SerialBaudRate.Text);
        _serialPort.Parity = Parity.None;
        _serialPort.DataBits = 8;
        _serialPort.StopBits = StopBits.One;
        _serialPort.ReadTimeout = 10000;//单位毫秒
        _serialPort.WriteTimeout = 10000;//单位毫秒

        //设置串口字节接收缓冲值,通常为1
        //获得接收后,触发事件处理
        _serialPort.ReceivedBytesThreshold = 1;
        _serialPort.DataReceived += new SerialDataReceivedEventHandler(DataCallBack);


        _serialPort.Open();//Console.WriteLine(serialPort.IsOpen.ToString());
        OpenSerialPort.IsEnabled = false;
        CloseSerialPort.IsEnabled = true;
    }
    catch (Exception ex)
    {
        MessageBox.Show("串口打开失败" + ex.ToString());
        //System.Environment.Exit(0);//退出应用程序
    }
}

private void CloseSerialPort_Click(object sender, RoutedEventArgs e)
{
    try
    {
        if (_serialPort.IsOpen == true)
        {
            _serialPort.Close();
            OpenSerialPort.IsEnabled = true;
            CloseSerialPort.IsEnabled = false;
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("串口关闭失败" + ex.ToString());
        System.Environment.Exit(0);//退出应用程序
    }
}



单片机关键部分代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    dcmi.c
  * @brief   This file provides code for the configuration
  *          of the DCMI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "dcmi.h"

/* USER CODE BEGIN 0 */
#include <string.h>
#include <stdio.h>

__align(32) uint32_t buffer[65535] __attribute((at(0X24040000)));

unsigned char getPicture = 0;
unsigned int jpeglen = 0;
//unsigned int recvOk = 0;

/* USER CODE END 0 */

DCMI_HandleTypeDef hdcmi;
DMA_HandleTypeDef hdma_dcmi_pssi;

/* DCMI init function */
void MX_DCMI_Init(void)
{

  /* USER CODE BEGIN DCMI_Init 0 */

  /* USER CODE END DCMI_Init 0 */

  /* USER CODE BEGIN DCMI_Init 1 */

  /* USER CODE END DCMI_Init 1 */
  hdcmi.Instance = DCMI;
  hdcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
  hdcmi.Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
  hdcmi.Init.VSPolarity = DCMI_VSPOLARITY_LOW;
  hdcmi.Init.HSPolarity = DCMI_HSPOLARITY_LOW;
  hdcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
  hdcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
  hdcmi.Init.JPEGMode = DCMI_JPEG_ENABLE;
  hdcmi.Init.ByteSelectMode = DCMI_BSM_ALL;
  hdcmi.Init.ByteSelectStart = DCMI_OEBS_ODD;
  hdcmi.Init.LineSelectMode = DCMI_LSM_ALL;
  hdcmi.Init.LineSelectStart = DCMI_OELS_ODD;
  if (HAL_DCMI_Init(&hdcmi) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN DCMI_Init 2 */
        //printf("MX_DCMI_Init ok\r\n");
  /* USER CODE END DCMI_Init 2 */

}

void HAL_DCMI_MspInit(DCMI_HandleTypeDef* dcmiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(dcmiHandle->Instance==DCMI)
  {
  /* USER CODE BEGIN DCMI_MspInit 0 */
         //printf("if(dcmiHandle->Instance==DCMI)\r\n");
  /* USER CODE END DCMI_MspInit 0 */
    /* DCMI clock enable */
    __HAL_RCC_DCMI_CLK_ENABLE();

    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**DCMI GPIO Configuration
    PE4     ------> DCMI_D4
    PE5     ------> DCMI_D6
    PE6     ------> DCMI_D7
    PA4     ------> DCMI_HSYNC
    PA6     ------> DCMI_PIXCLK
    PB13     ------> DCMI_D2
    PA9     ------> DCMI_D0
    PA10     ------> DCMI_D1
    PD3     ------> DCMI_D5
    PB7     ------> DCMI_VSYNC
    PE1     ------> DCMI_D3
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* DCMI DMA Init */
    /* DCMI_PSSI Init */
    hdma_dcmi_pssi.Instance = DMA1_Stream0;
    hdma_dcmi_pssi.Init.Request = DMA_REQUEST_DCMI_PSSI;
    hdma_dcmi_pssi.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_dcmi_pssi.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_dcmi_pssi.Init.MemInc = DMA_MINC_ENABLE;
    hdma_dcmi_pssi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_dcmi_pssi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_dcmi_pssi.Init.Mode = DMA_NORMAL;
    hdma_dcmi_pssi.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_dcmi_pssi.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_dcmi_pssi.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_dcmi_pssi.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_dcmi_pssi.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_dcmi_pssi) != HAL_OK)
    {
      Error_Handler();
    }

    /* Several peripheral DMA handle pointers point to the same DMA handle.
     Be aware that there is only one channel to perform all the requested DMAs. */
    __HAL_LINKDMA(dcmiHandle,DMA_Handle,hdma_dcmi_pssi);

    /* DCMI interrupt Init */
    HAL_NVIC_SetPriority(DCMI_PSSI_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(DCMI_PSSI_IRQn);
  /* USER CODE BEGIN DCMI_MspInit 1 */
               
                HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
                HAL_Delay(100);
                HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);
                //printf("HAL_DCMI_MspInit ok\r\n");
  /* USER CODE END DCMI_MspInit 1 */
  }
}

void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef* dcmiHandle)
{

  if(dcmiHandle->Instance==DCMI)
  {
  /* USER CODE BEGIN DCMI_MspDeInit 0 */

  /* USER CODE END DCMI_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_DCMI_CLK_DISABLE();

    /**DCMI GPIO Configuration
    PE4     ------> DCMI_D4
    PE5     ------> DCMI_D6
    PE6     ------> DCMI_D7
    PA4     ------> DCMI_HSYNC
    PA6     ------> DCMI_PIXCLK
    PB13     ------> DCMI_D2
    PA9     ------> DCMI_D0
    PA10     ------> DCMI_D1
    PD3     ------> DCMI_D5
    PB7     ------> DCMI_VSYNC
    PE1     ------> DCMI_D3
    */
    HAL_GPIO_DeInit(GPIOE, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_1);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10);

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_7);

    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_3);

    /* DCMI DMA DeInit */
    HAL_DMA_DeInit(dcmiHandle->DMA_Handle);

    /* DCMI interrupt Deinit */
    HAL_NVIC_DisableIRQ(DCMI_PSSI_IRQn);
  /* USER CODE BEGIN DCMI_MspDeInit 1 */
                HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
                HAL_Delay(100);
                HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);
          printf("HAL_DCMI_MspDeInit ok\r\n");
  /* USER CODE END DCMI_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */


void StartOV2640()
{
                int i =0;
                __HAL_DCMI_ENABLE_IT(&hdcmi, DCMI_IER_FRAME_IE);                                                       //使用帧中断
    memset(buffer, 0, 65535);                                                                                //把接收BUF清空
    HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_SNAPSHOT, (uint32_t)buffer, 65535);         //启动拍照
}


void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
          int i =0;
          HAL_DCMI_Suspend(hdcmi); // 拍照完成,挂起 DCMI
          HAL_DCMI_Stop(hdcmi);    // 拍照完成,停止 DMA传输
    int pictureLength = 65535;
    while (pictureLength > 0)     //循环计算出接收的JPEG的大小
    {
        if (buffer[pictureLength - 1] != 0x00000000)
        {
          break;
        }
        pictureLength--;
    }
                jpeglen = pictureLength * 4;
                getPicture = 1;
}
/* USER CODE END 1 */


单片机代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dcmi.h"
#include "dma.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "ov2640.h"
#include "ov5640.h"
#include <string.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

#define OV2640_JPEG_WIDTH         1600        //JPEG拍照的宽度       
#define OV2640_JPEG_HEIGHT 1200                //JPEG拍照的高度

#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
PUTCHAR_PROTOTYPE
{
                USART1->TDR = ch;
                while(!(USART1->ISR& USART_ISR_TXE_TXFNF_Msk))
                {;}
                 return ch;
}

static void CPU_CACHE_Enable(void)
{
        SCB_EnableICache();//使能I-Cache
  SCB_EnableDCache();//使能D-Cache   
        SCB->CACR|=1<<2;   //强制D-Cache透写,如不开启,实际使用中可能遇到各种问题       
}

void Send(uint8_t *pData)
{
        uint32_t i = 0;
        printf("jpeg data size:%d\r\n",jpeglen);//串口打印JPEG文件大小       
        HAL_Delay(1000);               
        for(i = 0;i < jpeglen;i++)
        {
                //printf("%02x\t",pData);
                printf("%c",pData);
        }
        HAL_Delay(1000);               
        printf("\r\n");
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
        uint32_t i = 0;
        uint32_t index = 1;
        //CPU_CACHE_Enable();
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
        HAL_Delay(5000);
        //__enable_irq();
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */
        HAL_Delay(100);
        MX_DCMI_Init();
               
        HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
       
        HAL_Delay(1000);
       
       
//        HAL_DCMI_DeInit(&hdcmi);
//  PY_DCMI_Full_Init();
       
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
                printf("OV2640 初始化!cam:%d\r\n",index);
                while(OV2640_Init(index))                       
                {
                        printf("OV2640 错误!cam:%d\r\n",index);
                }
                printf("OV2640 成功!cam:%d\r\n",index);
                HAL_Delay(1000);
                if(1)
                {
                        OV2640_JPEG_Mode();        //切换为JPEG模式
                        printf("切换为JPEG模式 !\r\n");
                        OV2640_OutSize_Set(OV2640_JPEG_WIDTH,OV2640_JPEG_HEIGHT);
                        printf("设置图像大小 !\r\n");
                        SCCB_WR_Reg(0XFF,0X00);
                        SCCB_WR_Reg(0XD3,0X10);
                        SCCB_WR_Reg(0XFF,0X01);
                        SCCB_WR_Reg(0X11,0X8);
                }
                if(0)
                {
                        OV2640_RGB565_Mode();                        //RGB565模式
                        printf("RGB565模式 !\r\n");
                        OV2640_OutSize_Set(OV2640_JPEG_WIDTH,OV2640_JPEG_HEIGHT);
                        printf("设置图像大小 !\r\n");
                        SCCB_WR_Reg(0XFF,0X00);               
                        SCCB_WR_Reg(0XD3,0X12);        //设置PCLK分频
                        SCCB_WR_Reg(0XFF,0X01);
                        SCCB_WR_Reg(0X11,0X1);        //设置CLK分频       
                }
                printf("开始工作\r\n");
                HAL_Delay(100);
                //Get_Photo();
                //DCMI_Start();
                StartOV2640();
                HAL_Delay(1000);               
                while(1)
                {
                        if(getPicture==1)
                        {
                                Send((uint8_t *)buffer);
                                break;
                        }
                        else
                        {
                                //printf("adc start\r\n");
                                //GetValue();
                                //printf("adc end\r\n");
                                HAL_Delay(10);
                                HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
                                HAL_Delay(10);
                                HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);
                        }       
                        //printf("jpeg haven't finished\r\n");               
                }       
                if(index>3)
                {
                        index = 1;
                }
                else
                {
                        index++;
                }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Macro to configure the PLL clock source
  */
  __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSI);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 35;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_8);
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
        printf("Error_Handler\r\n");
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
        HAL_Delay(1000);               
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/g313105910/article/details/126894008

小小蚂蚁举千斤 发表于 2025-7-28 22:56 | 显示全部楼层
非常不错的解决方法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

113

主题

4338

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部

113

主题

4338

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部