/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "delay.h"
#include "bsp_printf.h"
#include "bsp_key.h"
#include "string.h"
#include "usmart.h"
#include "usart.h"
#include "bsp_lcd.h"
//#include "bsp_pcf8574.h"
//#include "bsp_ap3216c.h"
//#include "bsp_adc.h"
//#include "bsp_touchs.h"
//#include "bsp_remote.h"
#include "bsp_flash.h"
#include "bsp_ov5640.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 ---------------------------------------------------------*/
DCMI_HandleTypeDef hdcmi;
DMA_HandleTypeDef hdma_dcmi;
I2C_HandleTypeDef hi2c2;
LTDC_HandleTypeDef hltdc;
SDRAM_HandleTypeDef hsdram1;
/* USER CODE BEGIN PV */
uint16_t FBuffer[LCD_WIDTH*LCD_HEIGHT] __attribute__((at(0xC0000000)));
uint32_t POINT_COLOR; //画笔颜色
uint32_t BACK_COLOR; //背景色
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_FMC_Init(void);
static void MX_DMA_Init(void);
static void MX_DCMI_Init(void);
static void MX_LTDC_Init(void);
static void MX_I2C2_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static void Sdram_SendCommand(uint32_t CommandMode, uint32_t CommandTarget, uint32_t AutoRefreshNumber, uint32_t ModeRegisterDefinition)
{
FMC_SDRAM_CommandTypeDef Command;
Command.AutoRefreshNumber = AutoRefreshNumber;
Command.CommandMode = CommandMode;
Command.CommandTarget = CommandTarget;
Command.ModeRegisterDefinition = ModeRegisterDefinition;
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0);
}
static void Sdram_Init_Sequence(void)
{
uint32_t ModeRegisterDefinition;
// uint16_t Mode_WB;
// uint16_t Mode_Op;
// uint16_t Mode_CasLatency;
// uint16_t Mode_Bt;
// uint16_t Mode_BurstLength;
Sdram_SendCommand(FMC_SDRAM_CMD_CLK_ENABLE, FMC_SDRAM_CMD_TARGET_BANK1, 0, 0);
delay_us(200);
Sdram_SendCommand(FMC_SDRAM_CMD_PALL, FMC_SDRAM_CMD_TARGET_BANK1, 0, 0);
Sdram_SendCommand(FMC_SDRAM_CMD_AUTOREFRESH_MODE, FMC_SDRAM_CMD_TARGET_BANK1, 1, 0);
//SDRAM????2?êy
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
ModeRegisterDefinition=(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
Sdram_SendCommand(FMC_SDRAM_CMD_LOAD_MODE, FMC_SDRAM_CMD_TARGET_BANK1, 1, ModeRegisterDefinition);
HAL_SDRAM_ProgramRefreshRate(&hsdram1, 824);
}
//清空屏幕并在右上角显示"RST"
void Load_Drow_Dialog(void)
{
LTDC_Clear(WHITE);//清屏
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(lcddev.width-24,0,200,16,16,"RST");//显示清屏区域
POINT_COLOR=RED;//设置画笔蓝色
}
//电容触摸屏专有部分
//画水平线
//x0,y0:坐标
//len:线长度
//color:颜色
void gui_draw_hline(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color)
{
if(len==0)return;
LCD_Fill(x0,y0,x0+len-1,y0,color);
}
//画实心圆
//x0,y0:坐标
//r:半径
//color:颜色
void gui_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color)
{
uint32_t i;
uint32_t imax = ((uint32_t)r*707)/1000+1;
uint32_t sqmax = (uint32_t)r*(uint32_t)r+(uint32_t)r/2;
uint32_t x=r;
gui_draw_hline(x0-r,y0,2*r,color);
for (i=1;i<=imax;i++)
{
if ((i*i+x*x)>sqmax)// draw lines from outside
{
if (x>imax)
{
gui_draw_hline (x0-i+1,y0+x,2*(i-1),color);
gui_draw_hline (x0-i+1,y0-x,2*(i-1),color);
}
x--;
}
// draw lines from inside (center)
gui_draw_hline(x0-x,y0+i,2*x,color);
gui_draw_hline(x0-x,y0-i,2*x,color);
}
}
//画一条粗线
//(x1,y1),(x2,y2):线条的起始坐标
//size:线条的粗细程度
//color:线条的颜色
void lcd_draw_bline(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t size, uint16_t color)
{
uint16_t t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol;
if(x1<size|| x2<size||y1<size|| y2<size)return;
delta_x=x2-x1; //计算坐标增量
delta_y=y2-y1;
uRow=x1;
uCol=y1;
if(delta_x>0)incx=1; //设置单步方向
else if(delta_x==0)incx=0;//垂直线
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if(delta_y==0)incy=0;//水平线
else{incy=-1;delta_y=-delta_y;}
if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
else distance=delta_y;
for(t=0;t<=distance+1;t++ )//画线输出
{
gui_fill_circle(uRow,uCol,size,color);//画点
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
//10个触控点的颜色(电容触摸屏用)
const uint16_t POINT_COLOR_TBL[10]={RED,GREEN,BLUE,BROWN,GRED,BRED,GBLUE,LIGHTBLUE,BRRED,GRAY};
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* 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 */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_FMC_Init();
MX_DMA_Init();
MX_DCMI_Init();
MX_LTDC_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
uart_init(115200); //串口初始化
usmart_dev.init(108); //初始化USMART
LCD_Set_Dir(1);
delay_init(216);
delay_ms(5000);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
Sdram_Init_Sequence();
POINT_COLOR=RED;
BACK_COLOR=WHITE;
LTDC_Clear(WHITE);
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7");
LCD_ShowString(30,70,200,16,16,"OV5640 TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2016/7/15");
while(OV5640_Init())//初始化OV5640
{
LCD_ShowString(30,130,240,16,16,"OV5640 ERR");
delay_ms(200);
LCD_Fill(30,130,239,170,WHITE);
delay_ms(200);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
}
LCD_ShowString(30,130,200,16,16,"OV5640 OK");
rgb565_test();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 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};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 432;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 9;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Activate the Over-Drive mode
*/
if (HAL_PWREx_EnableOverDrive() != 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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
{
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC|RCC_PERIPHCLK_I2C2;
PeriphClkInitStruct.PLLSAI.PLLSAIN = 288;
PeriphClkInitStruct.PLLSAI.PLLSAIR = 4;
PeriphClkInitStruct.PLLSAI.PLLSAIQ = 4;
PeriphClkInitStruct.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV2;
PeriphClkInitStruct.PLLSAIDivQ = 1;
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;
PeriphClkInitStruct.I2c2ClockSelection = RCC_I2C2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Enables the Clock Security System
*/
HAL_RCC_EnableCSS();
}
/**
* @brief DCMI Initialization Function
* @param None
* @retval None
*/
static 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_DISABLE;
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 */
__HAL_DCMI_ENABLE_IT(&hdcmi, DCMI_IT_FRAME);
/* USER CODE END DCMI_Init 2 */
}
/**
* @brief I2C2 Initialization Function
* @param None
* @retval None
*/
static void MX_I2C2_Init(void)
{
/* USER CODE BEGIN I2C2_Init 0 */
/* USER CODE END I2C2_Init 0 */
/* USER CODE BEGIN I2C2_Init 1 */
/* USER CODE END I2C2_Init 1 */
hi2c2.Instance = I2C2;
hi2c2.Init.Timing = 0x40D32A31;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c2) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C2_Init 2 */
/* USER CODE END I2C2_Init 2 */
}
/**
* @brief LTDC Initialization Function
* @param None
* @retval None
*/
static void MX_LTDC_Init(void)
{
/* USER CODE BEGIN LTDC_Init 0 */
/* USER CODE END LTDC_Init 0 */
LTDC_LayerCfgTypeDef pLayerCfg = {0};
/* USER CODE BEGIN LTDC_Init 1 */
/* USER CODE END LTDC_Init 1 */
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hltdc.Init.HorizontalSync = 0;
hltdc.Init.VerticalSync = 0;
hltdc.Init.AccumulatedHBP = 40;
hltdc.Init.AccumulatedVBP = 8;
hltdc.Init.AccumulatedActiveW = 520;
hltdc.Init.AccumulatedActiveH = 280;
hltdc.Init.TotalWidth = 525;
hltdc.Init.TotalHeigh = 288;
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 0;
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
{
Error_Handler();
}
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = 480;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = 272;
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
pLayerCfg.FBStartAdress = 0xc0000000;
pLayerCfg.ImageWidth = 480;
pLayerCfg.ImageHeight = 272;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LTDC_Init 2 */
/* USER CODE END LTDC_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
}
/* FMC initialization function */
static void MX_FMC_Init(void)
{
/* USER CODE BEGIN FMC_Init 0 */
/* USER CODE END FMC_Init 0 */
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
/* USER CODE BEGIN FMC_Init 1 */
/* USER CODE END FMC_Init 1 */
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 8;
SdramTiming.SelfRefreshTime = 4;
SdramTiming.RowCycleDelay = 7;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler( );
}
/* USER CODE BEGIN FMC_Init 2 */
/* USER CODE END FMC_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8|GPIO_PIN_3, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3|GPIO_PIN_4
|GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
/*Configure GPIO pin : PI8 */
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PH2 PH3 PH7 */
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
/*Configure GPIO pins : PB0 PB1 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PH6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
/*Configure GPIO pin : PB12 */
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PI3 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
/*Configure GPIO pin : PA15 */
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PB3 PB4 */
GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PB5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* 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 */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
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 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
#include "bsp_dcmi.h"
#include "bsp_ov5640.h"
#include "bsp_lcd.h"
uint16_t dcmi_line_buf[2][2592]; //RGB屏时,摄像头采用一行一行读取,定义行缓存
void BSP_OV5640_M0_RX_Callback(DMA_HandleTypeDef *hdma)
{
uint16_t *pbuf;
uint16_t i;
pbuf=(uint16_t*)dcmi_line_buf[0];
// for(i=0; i<lcddev.width; i++)
// {
// LTDC_Draw_Point(i, curline, pbuf[i]);
// }
LTDC_Color_Fill(0,curline,lcddev.width-1,curline,pbuf);//DM2D填充
if(curline<lcddev.height)curline++;
}
void BSP_OV5640_M1_RX_Callback(DMA_HandleTypeDef *hdma)
{
uint16_t *pbuf;
uint16_t i;
pbuf=(uint16_t*)dcmi_line_buf[1];
// for(i=0; i<lcddev.width; i++)
// {
// LTDC_Draw_Point(i, curline, pbuf[i]);
// }
LTDC_Color_Fill(0,curline,lcddev.width-1,curline,pbuf);//DM2D填充
if(curline<lcddev.height)curline++;
}
/**
* @brief Enables DCMI DMA request and enables DCMI capture
* @param hdcmi pointer to a DCMI_HandleTypeDef structure that contains
* the configuration information for DCMI.
* @param DCMI_Mode DCMI capture mode snapshot or continuous grab.
* @param pData The destination memory Buffer address (LCD Frame buffer).
* @param Length The length of capture to be transferred.
* @retval HAL status
*/
HAL_StatusTypeDef BSP_DCMI_MultiBufferStart_DMA_IT(DCMI_HandleTypeDef *hdcmi, uint32_t DCMI_Mode)
{
/* Check function parameters */
assert_param(IS_DCMI_CAPTURE_MODE(DCMI_Mode));
/* Process Locked */
__HAL_LOCK(hdcmi);
/* Lock the DCMI peripheral state */
hdcmi->State = HAL_DCMI_STATE_BUSY;
/* Enable DCMI by setting DCMIEN bit */
__HAL_DCMI_ENABLE(hdcmi);
/* Configure the DCMI Mode */
hdcmi->Instance->CR &= ~(DCMI_CR_CM);
hdcmi->Instance->CR |= (uint32_t)(DCMI_Mode);
/* Set the DMA memory0 conversion complete callback */
hdcmi->DMA_Handle->XferCpltCallback = NULL;
/* Set the DMA error callback */
hdcmi->DMA_Handle->XferErrorCallback = NULL;
/* Set the dma abort callback */
hdcmi->DMA_Handle->XferAbortCallback = NULL;
/* Reset transfer counters value */
hdcmi->XferCount = 0;
hdcmi->XferTransferNumber = 0;
hdcmi->XferSize = 0;
hdcmi->pBuffPtr = 0;
HAL_DMA_RegisterCallback(&hdma_dcmi, HAL_DMA_XFER_CPLT_CB_ID, BSP_OV5640_M0_RX_Callback);
HAL_DMA_RegisterCallback(&hdma_dcmi, HAL_DMA_XFER_M1CPLT_CB_ID, BSP_OV5640_M1_RX_Callback);
HAL_DMAEx_MultiBufferStart_IT(&hdma_dcmi, (uint32_t)&hdcmi->Instance->DR, (uint32_t)dcmi_line_buf[0], (uint32_t)dcmi_line_buf[1], lcddev.width/2);
/* Enable Capture */
hdcmi->Instance->CR |= DCMI_CR_CAPTURE;
/* Release Lock */
__HAL_UNLOCK(hdcmi);
/* Return function status */
return HAL_OK;
}
/**
* @brief Frame Event callback.
* @param hdcmi pointer to a DCMI_HandleTypeDef structure that contains
* the configuration information for DCMI.
* @retval None
*/
//void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
//{
// curline=yoffset; //行数复位
//}
/**
* @brief VSYNC Event callback.
* @param hdcmi pointer to a DCMI_HandleTypeDef structure that contains
* the configuration information for DCMI.
* @retval None
*/
void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi)
{
curline=yoffset; //行数复位
__HAL_DCMI_ENABLE_IT(hdcmi, DCMI_IT_FRAME);
}
#include "bsp_lcd.h"
#include "bsp_font.h"
//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;
//uint8_t lcd_dir = 0;//0:横屏、1:竖屏
//画点函数
//x,y:坐标
//color:颜色值
void LTDC_Draw_Point(uint16_t x,uint16_t y,uint32_t color)
{
uint16_t dev_x, dev_y;
if(lcddev.dir)//竖屏
{
dev_x = y;
dev_y = LCD_HEIGHT - 1 - x;
}
else//横屏
{
dev_x = x;
dev_y = y;
}
if((dev_y < LCD_HEIGHT) && (dev_x < LCD_WIDTH)) FBuffer[dev_y * LCD_WIDTH + dev_x]=color;
}
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24/32
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode)
{
uint8_t temp,t1,t;
uint16_t y0=y;
uint8_t csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数
num=num-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
for(t=0;t<csize;t++)
{
if(size==12)temp=asc2_1206[num][t]; //调用1206字体
else if(size==16)temp=asc2_1608[num][t]; //调用1608字体
else if(size==24)temp=asc2_2412[num][t]; //调用2412字体
else if(size==32)temp=asc2_3216[num][t]; //调用3216字体
else return; //没有的字库
for(t1=0;t1<8;t1++)
{
if(temp&0x80)LTDC_Draw_Point(x,y,POINT_COLOR);
else if(mode==0)LTDC_Draw_Point(x,y,BACK_COLOR);
temp<<=1;
y++;
if(y>=LCD_HEIGHT)return; //超区域了
if((y-y0)==size)
{
y=y0;
x++;
if(x>=LCD_WIDTH)return; //超区域了
break;
}
}
}
}
//显示字符串
//x,y:起点坐标
//width,height:区域大小
//size:字体大小
//*p:字符串起始地址
void LCD_ShowString(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, uint8_t *p)
{
uint8_t x0=x;
width+=x;
height+=y;
while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
{
if(x>=width){x=x0;y+=size;}
if(y>=height)break;//退出
LCD_ShowChar(x,y,*p,size,0);
x+=size/2;
p++;
}
}
//LCD清屏
//color:颜色值
void LTDC_Clear(uint32_t color)
{
if(lcddev.dir)//竖屏
{
LTDC_Fill(0,0,LCD_HEIGHT-1,LCD_WIDTH-1,color);
}
else//横屏
{
LTDC_Fill(0,0,LCD_WIDTH-1,LCD_HEIGHT-1,color);
}
// HAL_DMA2D_Start(&hdma2d, color, (uint32_t)FBuffer, LCD_WIDTH, LCD_HEIGHT);
// HAL_DMA2D_PollForTransfer(&hdma2d, 0X1FFFFF);
}
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
//color:要填充的颜色
void LTDC_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
{
uint16_t i,j;
for(j = sy; j <= ey; j++)
{
for(i = sx; i <= ex; i++)
{
LTDC_Draw_Point(i, j, color);
}
}
}
//显示数字,高位为0,则不显示
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//color:颜色
//num:数值(0~4294967295);
void LCD_ShowNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t size)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0;t<len;t++)
{
temp=(num/LCD_Pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
LCD_ShowChar(x+(size/2)*t,y,' ',size,0);
continue;
}else enshow=1;
}
LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,0);
}
}
//显示数字,高位为0,还是显示
//x,y:起点坐标
//num:数值(0~999999999);
//len:长度(即要显示的位数)
//size:字体大小
//mode:
//[7]:0,不填充;1,填充0.
//[6:1]:保留
//[0]:0,非叠加显示;1,叠加显示.
void LCD_ShowxNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0;t<len;t++)
{
temp=(num/LCD_Pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
if(mode&0X80)LCD_ShowChar(x+(size/2)*t,y,'0',size,mode&0X01);
else LCD_ShowChar(x+(size/2)*t,y,' ',size,mode&0X01);
continue;
}else enshow=1;
}
LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,mode&0X01);
}
}
//m^n函数
//返回值:m^n次方.
uint32_t LCD_Pow(uint8_t m,uint8_t n)
{
uint32_t result=1;
while(n--)result*=m;
return result;
}
//dir:0-横屏、1-竖屏
void LCD_Set_Dir(uint8_t dir)
{
lcddev.dir = dir;
if(dir == 0)
{
lcddev.width = LCD_WIDTH;
lcddev.height = LCD_HEIGHT;
}
else
{
lcddev.width = LCD_HEIGHT;
lcddev.height = LCD_WIDTH;
}
}
//dir:0-横屏、1-竖屏
uint8_t Get_LCD_Dir(void)
{
return lcddev.dir;
}
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
uint16_t t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol;
delta_x=x2-x1; //计算坐标增量
delta_y=y2-y1;
uRow=x1;
uCol=y1;
if(delta_x>0)incx=1; //设置单步方向
else if(delta_x==0)incx=0;//垂直线
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if(delta_y==0)incy=0;//水平线
else{incy=-1;delta_y=-delta_y;}
if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
else distance=delta_y;
for(t=0;t<=distance+1;t++ )//画线输出
{
LCD_DrawPoint(uRow,uCol);//画点
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(uint16_t x,uint16_t y)
{
LTDC_Draw_Point(x,y,POINT_COLOR);
}
//在指定位置画一个指定大小的圆
//(x,y):中心点
//r :半径
void LCD_Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r)
{
int a,b;
int di;
a=0;b=r;
di=3-(r<<1); //判断下个点位置的标志
while(a<=b)
{
LCD_DrawPoint(x0+a,y0-b); //5
LCD_DrawPoint(x0+b,y0-a); //0
LCD_DrawPoint(x0+b,y0+a); //4
LCD_DrawPoint(x0+a,y0+b); //6
LCD_DrawPoint(x0-a,y0+b); //1
LCD_DrawPoint(x0-b,y0+a);
LCD_DrawPoint(x0-a,y0-b); //2
LCD_DrawPoint(x0-b,y0-a); //7
a++;
//使用Bresenham算法画圆
if(di<0)di +=4*a+6;
else
{
di+=10+4*(a-b);
b--;
}
}
}
//在指定区域内填充单个颜色
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
{
LTDC_Fill(sx,sy,ex,ey,color);
}
//在指定区域内填充指定颜色块,DMA2D填充
//此函数仅支持u16,RGB565格式的颜色数组填充.
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
//color:要填充的颜色数组首地址
void LTDC_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color)
{
uint32_t psx,psy,pex,pey; //以LCD面板为基准的坐标系,不随横竖屏变化而变化
uint32_t timeout=0;
uint16_t offline;
uint32_t addr;
//坐标系转换
if(!lcddev.dir) //横屏
{
psx=sx;psy=sy;
pex=ex;pey=ey;
}else //竖屏
{
psx=sy;psy=LCD_HEIGHT-ex-1;
pex=ey;pey=LCD_HEIGHT-sx-1;
}
offline=LCD_WIDTH-(pex-psx+1);
addr=((uint32_t)FBuffer+2*(LCD_WIDTH*psy+psx));
RCC->AHB1ENR|=1<<23; //使能DM2D时钟
DMA2D->CR=0<<16; //存储器到存储器模式
DMA2D->FGPFCCR=0X02; //设置颜色格式
DMA2D->FGOR=0; //前景层行偏移为0
DMA2D->OOR=offline; //设置行偏移
DMA2D->CR&=~(1<<0); //先停止DMA2D
DMA2D->FGMAR=(uint32_t)color; //源地址
DMA2D->OMAR=addr; //输出存储器地址
DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16); //设定行数寄存器
DMA2D->CR|=1<<0; //启动DMA2D
while((DMA2D->ISR&(1<<1))==0) //等待传输完成
{
timeout++;
if(timeout>0X1FFFFF)break; //超时退出
}
DMA2D->IFCR|=1<<1; //清除传输完成标志
}
#include "bsp_sccb.h"
#include "delay.h"
void SCCB_Delay(void)
{
delay_us(5);
}
//初始化SCCB接口
void SCCB_Init(void)
{
}
//SCCB起始信号
//当时钟为高的时候,数据线的高到低,为SCCB起始信号
//在激活状态下,SDA和SCL均为低电平
void SCCB_Start(void)
{
SCCB_SDA(1); //数据线高电平
SCCB_SCL(1); //在时钟线高的时候数据线由高至低
SCCB_Delay();
SCCB_SDA(0);
SCCB_Delay();
SCCB_SCL(0); //数据线恢复低电平,单操作函数必要
}
//SCCB停止信号
//当时钟为高的时候,数据线的低到高,为SCCB停止信号
//空闲状况下,SDA,SCL均为高电平
void SCCB_Stop(void)
{
SCCB_SDA(0);
SCCB_Delay();
SCCB_SCL(1);
SCCB_Delay();
SCCB_SDA(1);
SCCB_Delay();
}
//产生NA信号
void SCCB_No_Ack(void)
{
SCCB_Delay();
SCCB_SDA(1);
SCCB_SCL(1);
SCCB_Delay();
SCCB_SCL(0);
SCCB_Delay();
SCCB_SDA(0);
SCCB_Delay();
}
//SCCB,写入一个字节
//返回值:0,成功;1,失败.
uint8_t SCCB_WR_Byte(uint8_t dat)
{
uint8_t j,res;
for(j=0;j<8;j++) //循环8次发送数据
{
if(dat&0x80)SCCB_SDA(1);
else SCCB_SDA(0);
dat<<=1;
SCCB_Delay();
SCCB_SCL(1);
SCCB_Delay();
SCCB_SCL(0);
}
SCCB_SDA_IN(); //设置SDA为输入
SCCB_Delay();
SCCB_SCL(1); //接收第九位,以判断是否发送成功
SCCB_Delay();
if(SCCB_READ_SDA)res=1; //SDA=1发送失败,返回1
else res=0; //SDA=0发送成功,返回0
SCCB_SCL(0);
SCCB_SDA_OUT(); //设置SDA为输出
return res;
}
//SCCB 读取一个字节
//在SCL的上升沿,数据锁存
//返回值:读到的数据
uint8_t SCCB_RD_Byte(void)
{
uint8_t temp=0,j;
SCCB_SDA_IN(); //设置SDA为输入
for(j=8;j>0;j--) //循环8次接收数据
{
SCCB_Delay();
SCCB_SCL(1);
temp=temp<<1;
if(SCCB_READ_SDA)temp++;
SCCB_Delay();
SCCB_SCL(0);
}
SCCB_SDA_OUT(); //设置SDA为输出
return temp;
}
#include "bsp_ov5640.h"
#include "bsp_sccb.h"
#include "bsp_pcf8574.h"
#include "delay.h"
#include "usart.h"
#include "bsp_ov5640cfg.h"
#include "bsp_ov5640af.h"
#include "bsp_lcd.h"
#include "bsp_key.h"
#include "bsp_dcmi.h"
//OV5640写寄存器
//返回值:0,成功;1,失败.
uint8_t OV5640_WR_Reg(uint16_t reg,uint8_t data)
{
uint8_t res=0;
SCCB_Start(); //启动SCCB传输
if(SCCB_WR_Byte(OV5640_ADDR))res=1; //写器件ID
if(SCCB_WR_Byte(reg>>8))res=1; //写寄存器高8位地址
if(SCCB_WR_Byte(reg))res=1; //写寄存器低8位地址
if(SCCB_WR_Byte(data))res=1; //写数据
SCCB_Stop();
return res;
}
//OV5640读寄存器
//返回值:读到的寄存器值
uint8_t OV5640_RD_Reg(uint16_t reg)
{
uint8_t val=0;
SCCB_Start(); //启动SCCB传输
SCCB_WR_Byte(OV5640_ADDR); //写器件ID
SCCB_WR_Byte(reg>>8); //写寄存器高8位地址
SCCB_WR_Byte(reg); //写寄存器低8位地址
SCCB_Stop();
//设置寄存器地址后,才是读
SCCB_Start();
SCCB_WR_Byte(OV5640_ADDR|0X01);//发送读命令
val=SCCB_RD_Byte(); //读取数据
SCCB_No_Ack();
SCCB_Stop();
return val;
}
//设置摄像头模块PWDN脚的状态
//sta:0,PWDN=0,上电.
// 1,PWDN=1,掉电
void OV5640_PWDN_Set(uint8_t sta)
{
PCF8574_WriteBit(DCMI_PWDN_IO,sta);
}
//初始化OV5640
//配置完以后,默认输出是1600*1200尺寸的图片!!
//返回值:0,成功
// 其他,错误代码
uint8_t OV5640_Init(void)
{
uint16_t i=0;
uint16_t reg;
PCF8574_Init(); //初始化PCF8574
OV5640_RST(0); //必须先拉低OV5640的RST脚,再上电
delay_ms(20);
OV5640_PWDN_Set(0); //POWER ON
delay_ms(5);
OV5640_RST(1); //结束复位
delay_ms(20);
SCCB_Init(); //初始化SCCB 的IO口
delay_ms(5);
reg=OV5640_RD_Reg(OV5640_CHIPIDH); //读取ID 高八位
reg<<=8;
reg|=OV5640_RD_Reg(OV5640_CHIPIDL); //读取ID 低八位
if(reg!=OV5640_ID)
{
printf("ID:%d\r\n",reg);
return 1;
}
OV5640_WR_Reg(0x3103,0X11); //system clock from pad, bit[1]
OV5640_WR_Reg(0X3008,0X82); //软复位
delay_ms(10);
//初始化 OV5640,采用SXGA分辨率(1600*1200)
for(i=0;i<sizeof(ov5640_uxga_init_reg_tbl)/4;i++)
{
OV5640_WR_Reg(ov5640_uxga_init_reg_tbl[i][0],ov5640_uxga_init_reg_tbl[i][1]);
}
//检查闪光灯是否正常
OV5640_Flash_Ctrl(1);//打开闪光灯
delay_ms(50);
OV5640_Flash_Ctrl(0);//关闭闪光灯
return 0x00; //ok
}
//OV5640切换为JPEG模式
void OV5640_JPEG_Mode(void)
{
uint16_t i=0;
//设置:输出JPEG数据
for(i=0;i<(sizeof(OV5640_jpeg_reg_tbl)/4);i++)
{
OV5640_WR_Reg(OV5640_jpeg_reg_tbl[i][0],OV5640_jpeg_reg_tbl[i][1]);
}
}
//OV5640切换为RGB565模式
void OV5640_RGB565_Mode(void)
{
uint16_t i=0;
//设置:RGB565输出
for(i=0;i<(sizeof(ov5640_rgb565_reg_tbl)/4);i++)
{
OV5640_WR_Reg(ov5640_rgb565_reg_tbl[i][0],ov5640_rgb565_reg_tbl[i][1]);
}
OV5640_WR_Reg(0X3821,0X06);//RGB屏,水平镜像
}
//灯光模式参数表,支持5个模式
const static uint8_t OV5640_LIGHTMODE_TBL[5][7]=
{
0x04,0X00,0X04,0X00,0X04,0X00,0X00,//Auto,自动
0x06,0X1C,0X04,0X00,0X04,0XF3,0X01,//Sunny,日光
0x05,0X48,0X04,0X00,0X07,0XCF,0X01,//Office,办公室
0x06,0X48,0X04,0X00,0X04,0XD3,0X01,//Cloudy,阴天
0x04,0X10,0X04,0X00,0X08,0X40,0X01,//Home,室内
};
//白平衡设置
//0:自动
//1:日光sunny
//2,办公室office
//3,阴天cloudy
//4,家里home
void OV5640_Light_Mode(uint8_t mode)
{
uint8_t i;
OV5640_WR_Reg(0x3212,0x03); //start group 3
for(i=0;i<7;i++)OV5640_WR_Reg(0x3400+i,OV5640_LIGHTMODE_TBL[mode][i]);//设置饱和度
OV5640_WR_Reg(0x3212,0x13); //end group 3
OV5640_WR_Reg(0x3212,0xa3); //launch group 3
}
//色彩饱和度设置参数表,支持7个等级
const static uint8_t OV5640_SATURATION_TBL[7][6]=
{
0X0C,0x30,0X3D,0X3E,0X3D,0X01,//-3
0X10,0x3D,0X4D,0X4E,0X4D,0X01,//-2
0X15,0x52,0X66,0X68,0X66,0X02,//-1
0X1A,0x66,0X80,0X82,0X80,0X02,//+0
0X1F,0x7A,0X9A,0X9C,0X9A,0X02,//+1
0X24,0x8F,0XB3,0XB6,0XB3,0X03,//+2
0X2B,0xAB,0XD6,0XDA,0XD6,0X04,//+3
};
//色度设置
//sat:0~6,代表饱和度-3~3.
void OV5640_Color_Saturation(uint8_t sat)
{
uint8_t i;
OV5640_WR_Reg(0x3212,0x03); //start group 3
OV5640_WR_Reg(0x5381,0x1c);
OV5640_WR_Reg(0x5382,0x5a);
OV5640_WR_Reg(0x5383,0x06);
for(i=0;i<6;i++)OV5640_WR_Reg(0x5384+i,OV5640_SATURATION_TBL[sat][i]);//设置饱和度
OV5640_WR_Reg(0x538b, 0x98);
OV5640_WR_Reg(0x538a, 0x01);
OV5640_WR_Reg(0x3212, 0x13); //end group 3
OV5640_WR_Reg(0x3212, 0xa3); //launch group 3
}
//亮度设置
//bright:0~8,代表亮度-4~4.
void OV5640_Brightness(uint8_t bright)
{
uint8_t brtval;
if(bright<4)brtval=4-bright;
else brtval=bright-4;
OV5640_WR_Reg(0x3212,0x03); //start group 3
OV5640_WR_Reg(0x5587,brtval<<4);
if(bright<4)OV5640_WR_Reg(0x5588,0x09);
else OV5640_WR_Reg(0x5588,0x01);
OV5640_WR_Reg(0x3212,0x13); //end group 3
OV5640_WR_Reg(0x3212,0xa3); //launch group 3
}
//对比度设置
//contrast:0~6,代表亮度-3~3.
void OV5640_Contrast(uint8_t contrast)
{
uint8_t reg0val=0X00;//contrast=3,默认对比度
uint8_t reg1val=0X20;
switch(contrast)
{
case 0://-3
reg1val=reg0val=0X14;
break;
case 1://-2
reg1val=reg0val=0X18;
break;
case 2://-1
reg1val=reg0val=0X1C;
break;
case 4://1
reg0val=0X10;
reg1val=0X24;
break;
case 5://2
reg0val=0X18;
reg1val=0X28;
break;
case 6://3
reg0val=0X1C;
reg1val=0X2C;
break;
}
OV5640_WR_Reg(0x3212,0x03); //start group 3
OV5640_WR_Reg(0x5585,reg0val);
OV5640_WR_Reg(0x5586,reg1val);
OV5640_WR_Reg(0x3212,0x13); //end group 3
OV5640_WR_Reg(0x3212,0xa3); //launch group 3
}
//锐度设置
//sharp:0~33,0,关闭;33,auto;其他值,锐度范围.
void OV5640_Sharpness(uint8_t sharp)
{
if(sharp<33)//设置锐度值
{
OV5640_WR_Reg(0x5308,0x65);
OV5640_WR_Reg(0x5302,sharp);
}else //自动锐度
{
OV5640_WR_Reg(0x5308,0x25);
OV5640_WR_Reg(0x5300,0x08);
OV5640_WR_Reg(0x5301,0x30);
OV5640_WR_Reg(0x5302,0x10);
OV5640_WR_Reg(0x5303,0x00);
OV5640_WR_Reg(0x5309,0x08);
OV5640_WR_Reg(0x530a,0x30);
OV5640_WR_Reg(0x530b,0x04);
OV5640_WR_Reg(0x530c,0x06);
}
}
//特效设置参数表,支持7个特效
const static uint8_t OV5640_EFFECTS_TBL[7][3]=
{
0X06,0x40,0X10,//正常
0X1E,0xA0,0X40,//冷色
0X1E,0x80,0XC0,//暖色
0X1E,0x80,0X80,//黑白
0X1E,0x40,0XA0,//泛黄
0X40,0x40,0X10,//反色
0X1E,0x60,0X60,//偏绿
};
//特效设置
//0:正常
//1,冷色
//2,暖色
//3,黑白
//4,偏黄
//5,反色
//6,偏绿
void OV5640_Special_Effects(uint8_t eft)
{
OV5640_WR_Reg(0x3212,0x03); //start group 3
OV5640_WR_Reg(0x5580,OV5640_EFFECTS_TBL[eft][0]);
OV5640_WR_Reg(0x5583,OV5640_EFFECTS_TBL[eft][1]);// sat U
OV5640_WR_Reg(0x5584,OV5640_EFFECTS_TBL[eft][2]);// sat V
OV5640_WR_Reg(0x5003,0x08);
OV5640_WR_Reg(0x3212,0x13); //end group 3
OV5640_WR_Reg(0x3212,0xa3); //launch group 3
}
//测试序列
//mode:0,关闭
// 1,彩条
// 2,色块
void OV5640_Test_Pattern(uint8_t mode)
{
if(mode==0)OV5640_WR_Reg(0X503D,0X00);
else if(mode==1)OV5640_WR_Reg(0X503D,0X80);
else if(mode==2)OV5640_WR_Reg(0X503D,0X82);
}
//闪光灯控制
//mode:0,关闭
// 1,打开
void OV5640_Flash_Ctrl(uint8_t sw)
{
OV5640_WR_Reg(0x3016,0X02);
OV5640_WR_Reg(0x301C,0X02);
if(sw)OV5640_WR_Reg(0X3019,0X02);
else OV5640_WR_Reg(0X3019,0X00);
}
//设置图像输出大小
//OV5640输出图像的大小(分辨率),完全由该函数确定
//offx,offy,为输出图像在OV5640_ImageWin_Set设定窗口(假设长宽为xsize和ysize)上的偏移
//由于开启了scale功能,用于输出的图像窗口为:xsize-2*offx,ysize-2*offy
//width,height:实际输出图像的宽度和高度
//实际输出(width,height),是在xsize-2*offx,ysize-2*offy的基础上进行缩放处理.
//一般设置offx和offy的值为16和4,更小也是可以,不过默认是16和4
//返回值:0,设置成功
// 其他,设置失败
uint8_t OV5640_OutSize_Set(uint16_t offx,uint16_t offy,uint16_t width,uint16_t height)
{
OV5640_WR_Reg(0X3212,0X03); //开始组3
//以下设置决定实际输出尺寸(带缩放)
OV5640_WR_Reg(0x3808,width>>8); //设置实际输出宽度高字节
OV5640_WR_Reg(0x3809,width&0xff);//设置实际输出宽度低字节
OV5640_WR_Reg(0x380a,height>>8);//设置实际输出高度高字节
OV5640_WR_Reg(0x380b,height&0xff);//设置实际输出高度低字节
//以下设置决定输出尺寸在ISP上面的取图范围
//范围:xsize-2*offx,ysize-2*offy
OV5640_WR_Reg(0x3810,offx>>8); //设置X offset高字节
OV5640_WR_Reg(0x3811,offx&0xff);//设置X offset低字节
OV5640_WR_Reg(0x3812,offy>>8); //设置Y offset高字节
OV5640_WR_Reg(0x3813,offy&0xff);//设置Y offset低字节
OV5640_WR_Reg(0X3212,0X13); //结束组3
OV5640_WR_Reg(0X3212,0Xa3); //启用组3设置
return 0;
}
//设置图像开窗大小(ISP大小),非必要,一般无需调用此函数
//在整个传感器上面开窗(最大2592*1944),用于OV5640_OutSize_Set的输出
//注意:本函数的宽度和高度,必须大于等于OV5640_OutSize_Set函数的宽度和高度
// OV5640_OutSize_Set设置的宽度和高度,根据本函数设置的宽度和高度,由DSP
// 自动计算缩放比例,输出给外部设备.
//width,height:宽度(对应:horizontal)和高度(对应:vertical)
//返回值:0,设置成功
// 其他,设置失败
uint8_t OV5640_ImageWin_Set(uint16_t offx,uint16_t offy,uint16_t width,uint16_t height)
{
uint16_t xst,yst,xend,yend;
xst=offx;
yst=offy;
xend=offx+width-1;
yend=offy+height-1;
OV5640_WR_Reg(0X3212,0X03); //开始组3
OV5640_WR_Reg(0X3800,xst>>8);
OV5640_WR_Reg(0X3801,xst&0XFF);
OV5640_WR_Reg(0X3802,yst>>8);
OV5640_WR_Reg(0X3803,yst&0XFF);
OV5640_WR_Reg(0X3804,xend>>8);
OV5640_WR_Reg(0X3805,xend&0XFF);
OV5640_WR_Reg(0X3806,yend>>8);
OV5640_WR_Reg(0X3807,yend&0XFF);
OV5640_WR_Reg(0X3212,0X13); //结束组3
OV5640_WR_Reg(0X3212,0Xa3); //启用组3设置
return 0;
}
//初始化自动对焦
//返回值:0,成功;1,失败.
uint8_t OV5640_Focus_Init(void)
{
uint16_t i;
uint16_t addr=0x8000;
uint8_t state=0x8F;
OV5640_WR_Reg(0x3000, 0x20); //reset MCU
for(i=0;i<sizeof(OV5640_AF_Config);i++) //发送配置数组
{
OV5640_WR_Reg(addr,OV5640_AF_Config[i]);
addr++;
}
OV5640_WR_Reg(0x3022,0x00);
OV5640_WR_Reg(0x3023,0x00);
OV5640_WR_Reg(0x3024,0x00);
OV5640_WR_Reg(0x3025,0x00);
OV5640_WR_Reg(0x3026,0x00);
OV5640_WR_Reg(0x3027,0x00);
OV5640_WR_Reg(0x3028,0x00);
OV5640_WR_Reg(0x3029,0x7f);
OV5640_WR_Reg(0x3000,0x00);
i=0;
do
{
state=OV5640_RD_Reg(0x3029);
delay_ms(5);
i++;
if(i>1000)return 1;
}while(state!=0x70);
return 0;
}
//执行一次自动对焦
//返回值:0,成功;1,失败.
uint8_t OV5640_Focus_Single(void)
{
uint8_t temp;
uint16_t retry=0;
OV5640_WR_Reg(0x3022,0x03); //触发一次自动对焦
while(1)
{
retry++;
temp=OV5640_RD_Reg(0x3029); //检查对焦完成状态
if(temp==0x10)break; // focus completed
delay_ms(5);
if(retry>1000)return 1;
}
return 0;
}
//持续自动对焦,当失焦后,会自动继续对焦
//返回值:0,成功;其他,失败.
uint8_t OV5640_Focus_Constant(void)
{
uint8_t temp=0;
uint16_t retry=0;
OV5640_WR_Reg(0x3023,0x01);
OV5640_WR_Reg(0x3022,0x08);//发送IDLE指令
do
{
temp=OV5640_RD_Reg(0x3023);
retry++;
if(retry>1000)return 2;
delay_ms(5);
} while(temp!=0x00);
OV5640_WR_Reg(0x3023,0x01);
OV5640_WR_Reg(0x3022,0x04);//发送持续对焦指令
retry=0;
do
{
temp=OV5640_RD_Reg(0x3023);
retry++;
if(retry>1000)return 2;
delay_ms(5);
}while(temp!=0x00);//0,对焦完成;1:正在对焦
return 0;
}
const uint8_t *EFFECTS_TBL[7]={"Normal","Cool","Warm","B&W","Yellowish ","Inverse","Greenish"}; //7种特效
uint16_t curline=0; //摄像头输出数据,当前行编号
uint16_t yoffset=0; //y方向的偏移量
//RGB565测试
//RGB数据直接显示在LCD上面
void rgb565_test(void)
{
uint8_t key;
uint8_t effect=0,contrast=2,fac;
uint8_t scale=1; //默认是全尺寸缩放
uint8_t msgbuf[15]; //消息缓存区
uint16_t outputheight=0;
LTDC_Clear(WHITE);
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7");
LCD_ShowString(30,70,200,16,16,"OV5640 RGB565 Mode");
LCD_ShowString(30,100,200,16,16,"KEY0:Contrast"); //对比度
LCD_ShowString(30,120,200,16,16,"KEY1:Auto Focus"); //执行自动对焦
LCD_ShowString(30,140,200,16,16,"KEY2:Effects"); //特效
LCD_ShowString(30,160,200,16,16,"KEY_UP:FullSize/Scale"); //1:1尺寸(显示真实尺寸)/全尺寸缩放
//自动对焦初始化
OV5640_RGB565_Mode(); //RGB565模式
OV5640_Focus_Init();
OV5640_Light_Mode(0); //自动模式
OV5640_Color_Saturation(3);//色彩饱和度0
OV5640_Brightness(4); //亮度0
OV5640_Contrast(3); //对比度0
OV5640_Sharpness(33); //自动锐度
OV5640_Focus_Constant();//启动持续对焦
if(lcddev.height==1024)
{
yoffset=(lcddev.height-800)/2;
outputheight=800;
OV5640_WR_Reg(0x3035,0X51);//降低输出帧率,否则可能抖动
}else if(lcddev.height==1280)
{
yoffset=(lcddev.height-600)/2;
outputheight=600;
OV5640_WR_Reg(0x3035,0X51);//降低输出帧率,否则可能抖动
}else
{
yoffset=0;
outputheight=lcddev.height;
}
curline=yoffset; //行数复位
OV5640_OutSize_Set(4,0,lcddev.width,outputheight); //满屏缩放显示
BSP_DCMI_MultiBufferStart_DMA_IT(&hdcmi, DCMI_MODE_CONTINUOUS);
LTDC_Clear(BLACK);
while(1)
{
key=KEY_Scan(0);
if(key)
{
if(key!=KEY1_PRES)HAL_DCMI_Stop(&hdcmi); //非KEY1按下,停止显示
switch(key)
{
case KEY0_PRES: //对比度设置
contrast++;
if(contrast>6)contrast=0;
OV5640_Contrast(contrast);
sprintf((char*)msgbuf,"Contrast:%d",(signed char)contrast-3);
break;
case KEY1_PRES: //执行一次自动对焦
OV5640_Focus_Single();
break;
case KEY2_PRES: //特效设置
effect++;
if(effect>6)effect=0;
OV5640_Special_Effects(effect);//设置特效
sprintf((char*)msgbuf,"%s",EFFECTS_TBL[effect]);
break;
case WKUP_PRES: //1:1尺寸(显示真实尺寸)/缩放
scale=!scale;
if(scale==0)
{
fac=800/outputheight; //得到比例因子
OV5640_OutSize_Set((1280-fac*lcddev.width)/2,(800-fac*outputheight)/2,lcddev.width,outputheight);
sprintf((char*)msgbuf,"Full Size 1:1");
}else
{
OV5640_OutSize_Set(4,0,lcddev.width,outputheight);
sprintf((char*)msgbuf,"Scale");
}
break;
}
if(key!=KEY1_PRES) //非KEY1按下
{
LCD_ShowString(30,50,210,16,16,msgbuf);//显示提示内容
delay_ms(800);
//DCMI_Start(); //重新开始传输
BSP_DCMI_MultiBufferStart_DMA_IT(&hdcmi, DCMI_MODE_CONTINUOUS);
}
}
delay_ms(10);
}
}
#include "bsp_pcf8574.h"
#define PCF8574_DEV_ADDR 0x40
//初始化PCF8574
uint8_t PCF8574_Init(void)
{
HAL_StatusTypeDef sta;
uint8_t Data = 0xFF;
sta = HAL_I2C_Master_Transmit(&hi2c2, PCF8574_DEV_ADDR, &Data, 1, HAL_MAX_DELAY);
return (uint8_t)sta;
}
//设置PCF8574某个IO的高低电平
//bit:要设置的IO编号,0~7
//sta:IO的状态;0或1
void PCF8574_WriteBit(uint8_t bit,uint8_t sta)
{
uint8_t data;
HAL_I2C_Master_Receive(&hi2c2, PCF8574_DEV_ADDR, &data, 1, HAL_MAX_DELAY);
if(sta==0)data&=~(1<<bit);
else data|=1<<bit;
HAL_I2C_Master_Transmit(&hi2c2, PCF8574_DEV_ADDR, &data, 1, HAL_MAX_DELAY);
}
//读取PCF8574的某个IO的值
//bit:要读取的IO编号,0~7
//返回值:此IO的值,0或1
uint8_t PCF8574_ReadBit(uint8_t bit)
{
uint8_t data;
HAL_I2C_Master_Receive(&hi2c2, PCF8574_DEV_ADDR, &data, 1, HAL_MAX_DELAY);//先读取这个8位IO的值
if(data&(1<<bit))return 1;
else return 0;
}
总结:
1、
2、
3、
4、
5、
6、
7、
8、
9、
10、
11、
12、
13、
14、