本人正在使用STM32F103RE驱动0V2640摄像头,原理都是参考https://blog.csdn.net/ZLK1214/article/details/79559466,原理图上有些差异,本人的单片机是PB14(VSYNC)和PB5(=~(HREF & PCLK)),附上我修改后的配置,OV2640初始化配置可以正常配置好,但是无法产生PB14中断,还请大佬看看,哪里有问题!跪谢!
int main(void)
{
RCC->AHBENR |= RCC_AHBENR_CRCEN | RCC_AHBENR_DMA1EN;
RCC->APB1ENR = RCC_APB1ENR_I2C1EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM6EN;
RCC->APB2ENR = RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_USART1EN;
AFIO->MAPR = AFIO_MAPR_TIM3_REMAP_PARTIALREMAP;
GPIOA->CRH = (GPIOA->CRH & 0xfffff00f) | 0x4b0; // 串口发送引脚PA9设为复用推挽输出
GPIOB->CRL = (GPIOB->CRL & 0x00ffffff) | 0xff000000; // PB6~7连接摄像头的I2C接口, 设为复用开漏输出
// PB14(VSYNC)和PB5(=~(HREF & PCLK))为浮空输入
// PC0~7是摄像头的8位数据引脚, 为浮空输入
USART1->BRR = SystemCoreClock / 115200;
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
I2C1->CR2 = 36; // APB1总线频率: 36MHz
I2C1->CCR = 1800; // 速率: 10kHz (不可太高, 否则会导致Ack Failure; 计算公式为PCLK1/nf, 标准模式下n=2)
I2C1->TRISE = 37; // 标准模式下为PCLK+1
I2C1->CR1 = I2C_CR1_PE; // 打开I2C总线
// 每当PB5上出现下降沿时, 就发送一次DMA请求, 采集GPIOC低8位的数据
TIM3->CCMR1 = TIM_CCMR1_CC1S_1; // PB5(TIM3_CH2)映射到TIM3_CH1上
TIM3->CCER = TIM_CCER_CC1P; // 下降沿触发
TIM3->CCER |= TIM_CCER_CC1E; // 打开TIM4_CH3的输入捕获
// 无需让定时器3开始计时, 这里只使用该定时器的一个输入捕获通道
// 配置TIM3_CH1对应的DMA通道
DMA1_Channel6->CMAR = (uint32_t)image_buffer;
DMA1_Channel6->CPAR = (uint32_t)&GPIOC->IDR;
DMA1_Channel6->CNDTR = sizeof(image_buffer); // 超出部分会被自动丢弃!! 所以图像不能大于64480字节
DMA1_Channel6->CCR = DMA_CCR6_PL | DMA_CCR6_MINC | DMA_CCR6_EN;
OV2640_Init(JPEG_800x600);
// 打开PB14外部中断
AFIO->EXTICR[3] = AFIO_EXTICR4_EXTI14_PB;
EXTI->IMR = EXTI_IMR_MR14;
EXTI->RTSR = EXTI_RTSR_TR14; // PB14上的上升沿能触发中断
EXTI->FTSR = EXTI_FTSR_TR14; // PB14上的下降沿也能触发中断
NVIC_EnableIRQ(EXTI15_10_IRQn); // 允许执行中断服务函数
while (1)
{
if (image_state == (STATE_START | STATE_STOP))
{
printf("size=%d\n", image_size);
dump(image_buffer, image_size); // 通过串口发送图像, 然后附上CRC校验值
// 让DMA内部指针回到数组的开头
DMA1_Channel6->CCR &= ~DMA_CCR6_EN;
DMA1_Channel6->CNDTR = sizeof(image_buffer);
DMA1_Channel6->CCR |= DMA_CCR6_EN;
image_state = 0; // 允许采集新图像 (这条语句一次性把START和STOP都清0了)
}
}
}
void EXTI0_IRQHandler(void)
{
EXTI->PR = EXTI_PR_PR14; // 清除中断标志位
if (GPIOB->IDR & GPIO_IDR_IDR14)
{
// PB14上升沿表示图像数据传输开始
if (image_state != 0)
return; // 如果图像已经开始采集了, 就忽略这个开始信号
image_state = STATE_START;
// 打开TIM3_CH1对应的DMA通道, 开始采集数据
TIM3->DIER = TIM_DIER_CC1DE; // 允许PB5上的下降沿触发DMA请求
}
else
{
// PB14下降沿表示图像数据传输结束
if ((image_state & STATE_START) == 0 || (image_state & STATE_STOP))
return; // 忽略没有开始信号的结束信号, 以及重复的结束信号
image_state |= STATE_STOP;
TIM3->DIER &= ~TIM_DIER_CC1DE; // 停止采集
image_size = sizeof(image_buffer) - DMA1_Channel6->CNDTR; // 总量-剩余数据量=图像大小
}
}
|