历史上的今天
返回首页

历史上的今天

今天是:2024年09月20日(星期五)

正在发生

2018年09月20日 | STM32F4xx 取得摄像头数据并进行处理

2018-09-20 来源:eefocus

  最近做的一个项目需要对摄像头采集到的数据进行简单的处理,我们用的MCU是Cortex-M4 F407系列的。关于STM32F4xx的视频处理,ST的官方给的例程是在显示屏上直接显示摄像头采集到的数据。经过了一番探索……根据官方的英文手册、网友们的无私分享和对各个例程的研究。今天终于搞定了将数据采集下来。


   官方给的例程中,是通过DMA将数据直接输入到屏幕中的。DMA简单地说就是各个设备间自动倒腾内存的东西,转移数据的时候并不需要CPU干涉,减少了CPU的负担。由于所有的数据都不经过CPU进行干涉,如何获取其中的数据也是倒腾了一阵子。下面讲讲主要代码的配置:

  在摄像头DCMI的配置中首先根据摄像头将各个管脚设置成需要的,这个例程里都有,不贴了。

  要一帧一帧处理数据完了再获取数据,摄像头配置中DCMI_CaptureMode要配置成快照模式:DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_SnapShot,这样每完成一帧图像的获取,摄像头就停止捕获数据了,要想它再次捕获数据只需要执行DCMI_CaptureCmd(ENABLE)就可以了。

  然后是摄像头的中断配置(DCMI_ITConfig),在中断配置中,官方的例程是配置的垂直同步DCMI_ITConfig(DCMI_IT_VSYNC, ENABLE),通过垂直同步进行的中断中,获得的数据是整帧画面的数据,我们的板子的RAM就只有192k,呵呵,一帧图像放不进去,所以没有使用垂直同步中断,用的是列数据中断DCMI_ITConfig(DCMI_IT_LINE, ENABLE)。列数据中断,也就是说摄像头每采集到一列数据,就在它的列中断位(DCMI_IT_LINE位)上置1。我们这个摄像头采集的数据是240*320像素的16位色图像。也就是说每次摄像头产生列中断的时候都会采集到320个16位的数据。在每次列中断发生时都在列中断的中断服务中对数据进行处理就ok啦。

  在官方给的例程文件中stm32f4xx_it.c是用来放各个中断服务的文件。摄像头的中断服务在void DCMI_IRQHandler(void)函数里面,我们这用到的列中断,所以对其中的if (DCMI_GetITStatus(DCMI_IT_LINE) != RESET) 进行添加代码即可,最后不要忘了清除摄像头的列中断标志DCMI_ClearITPendingBit(DCMI_IT_LINE)。

  为了能够更有效的利用CPU的资源,当然不要丢了DMA这神器。下面进行DMA的配置。官方例程中需要改的的地方是DMA_InitStructure.DMA_Memory0BaseAddr = FSMC_LCD_ADDRESS这个地方,FSMC_LCD_ADDRESS是LCD屏幕的地址,我们这里要把数据取下来,得弄个数组存放数据。这里我弄了个全局的数组变量uint16_t fps[320],每个像素16位数据RGB--5:6:5,每列320个数据。所以DMA_Memory0BaseAddr参数就是这么配置DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)fps。DMA_MemoryInc要设置成DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable。这是目的地址写入后自增指针的配置。这样数据才能往fps数组里排着写入。

  设置的理论基本说完了。下面上代码


DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_SnapShot;//快照模式

DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware;//硬件时钟

DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Falling;//下降沿

DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High;//垂直极性

DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_High;//水平极性

DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame;//捕获率

DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;//8位数据模式

DCMI_Init(&DCMI_InitStructure);//初始化上面的摄像头配置


DCMI_ITConfig(DCMI_IT_LINE, ENABLE);//列中断

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//中断抢占组1

NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn;//摄像头中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//先占优先级

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//从优先级

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//开启中断控制通道

NVIC_Init(&NVIC_InitStructure);//初始化上面的中断配置


RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);//使能DMA2时钟

DMA_DeInit(DMA2_Stream1);//复位DMA2_Stream1数据流的配置

DMA_InitStructure.DMA_Channel = DMA_Channel_1;//DMA流通道

DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS;//外设内存地址

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)fps;//内存地址

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//数据方向从外设到内存

DMA_InitStructure.DMA_BufferSize = 320;//每次转移320数据,每个数据的位数根据目的地设置定

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不改变

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址在每次写入后自增

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设每单位长度_Word是32位

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//内存每单位长度_HalfWord是16位

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//运行模式,循环

DMA_InitStructure.DMA_Priority = DMA_Priority_High;//优先模式,高

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;//开启先入先出模式

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//FIFO水平阈值

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//内存单通道

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设单通道

DMA_Init(DMA2_Stream1, &DMA_InitStructure);//初始化上面的DMA配置


void DCMI_IRQHandler(void)//摄像头的中断服务

{      

if (DCMI_GetITStatus(DCMI_IT_VSYNC) != RESET)//垂直中断的配置 需要DCMI_ITConfig(DCMI_IT_VSYNC, ENABLE);

{  

DCMI_ClearITPendingBit(DCMI_IT_VSYNC);  

}

if (DCMI_GetITStatus(DCMI_IT_LINE) != RESET)//列中断的配置 需要DCMI_ITConfig(DCMI_IT_LINE, ENABLE);

{

DCMI_ClearITPendingBit(DCMI_IT_LINE);

}

if (DCMI_GetITStatus(DCMI_IT_FRAME) != RESET)//帧中断的配置 需要DCMI_ITConfig(DCMI_IT_FRAME, ENABLE);

{

DCMI_ClearITPendingBit(DCMI_IT_FRAME);

}

if (DCMI_GetITStatus(DCMI_IT_ERR) != RESET)//错误中断的配置 需要DCMI_ITConfig(DCMI_IT_ERR, ENABLE);

{

DCMI_ClearITPendingBit(DCMI_IT_ERR);

}

}


推荐阅读

史海拾趣

Herga公司的发展小趣事

进入21世纪后,Herga公司意识到全球化市场的重要性,开始实施积极的国际化战略。公司首先在欧洲市场建立了稳固的根据地,随后通过并购和合资等方式,逐步进入北美、亚洲等新兴市场。在这个过程中,Herga公司不仅提供了符合当地市场需求的产品和服务,还积极融入当地文化,建立了良好的品牌形象。这些努力使得Herga公司的全球市场份额逐年上升,成为国际电子行业中不可忽视的力量。

Highland Electronics Co Ltd公司的发展小趣事

面对全球半导体市场的周期性波动和贸易环境的不确定性,High Tech Chips Inc展现出了强大的应变能力和灵活性。在市场需求下滑时,公司迅速调整产品结构,加大在物联网、5G通信等新兴领域的研发投入。同时,通过优化供应链管理、提高生产效率等方式降低成本,保持了良好的盈利能力。这种灵活应对市场挑战的策略使得公司在行业低谷期依然能够稳健发展。

Cableform Inc公司的发展小趣事

Cableform Inc公司起源于一位名叫约翰·卡贝尔的电气工程师的创意。在20世纪中期,约翰看到了电子工业的巨大潜力,特别是在电磁控制领域。于是,在1945年,他创立了Cableform Inc,专注于研发和生产电磁控制设备。起初,公司只有几名员工,面临着资金短缺和技术挑战。然而,约翰凭借着对技术的执着和对市场的敏锐洞察,成功设计出了一款具有竞争力的磁铁控制器,为公司的发展奠定了基石。

Future Designs, Inc. (FDI)公司的发展小趣事

Future Designs, Inc.(FDI)成立于几十年前,最初由一群在电子设计领域拥有丰富经验的工程师创立。他们看到市场上对于高质量、快速响应的触摸屏LCD图形用户界面(GUI)解决方案的需求日益增长,于是决定成立一家公司,专注于提供此类产品和服务。初创时期,FDI面临诸多挑战,包括资金短缺、市场认可度低以及技术难关等。然而,凭借团队成员的坚持不懈和专业技术,他们逐步攻克难关,开发出了ELI™和罗德里格斯™GUI家族产品,为公司赢得了初步的市场地位。

中科芯(CKS)公司的发展小趣事

作为电子行业的领军企业,中科芯承担着众多国家重点科研任务。多年来,公司积极参与国家重大科研项目,涉及通信、计算机、航空航天等多个领域。通过不断的技术攻关和创新,中科芯成功完成了500多项国家重点科研任务,获得了国家奖18项、省部级奖近200项。这些成果的取得不仅提升了公司的技术实力,也为中国电子行业的发展做出了巨大贡献。

Box Enclosures公司的发展小趣事

Box Enclosures公司自创立之初,就明确了自己的定位——专注于为电子行业提供高品质的机箱和外壳产品。公司始终坚持严格的质量控制标准,从原材料采购到生产工艺,每一个环节都力求精益求精。这种对品质的执着追求,使得Box Enclosures的产品在市场上赢得了良好的口碑,逐渐在电子行业中占据了一席之地。

问答坊 | AI 解惑

优秀设计的十条戒律

钱又不够了,再上新内容…

查看全部问答>

关于LM3S8962评估板的OLED驱动芯片的中文手册

目前翻译了一些,通过翻译深入理解OLED现实原理,有助于后续项目的升入开发,共享给坛友,不对之处,请指正!…

查看全部问答>

请教一个移植boa的问题

请教一个boa的问题 cgi串口程序在arm上单独运行可以,但是用boa服务器调用该串口程序时,程序报错:不能打开串口。 还有一个问题就是我怎么不能使用post传递数据,user已经改为root 谢谢 …

查看全部问答>

keil MDK启动文件分析---基于LPC2100系列(其实都是相通的)

转用MDK有一段时间了,越来越觉得MDK的强大,因为我之前都是用ADS1.2开发产品,所以更能体会到MDK的强大与易用性。MDK编译出来的代码与ADS1.2相比,代码量减少了很多,我的一个工程用ADS1.2编译为25.4KB(都是bin格式),但用MDK编译出来仅有19.5KB( ...…

查看全部问答>

关于MC9S12XS128 单片机之间 SPI通信的一些问题

最近在做一个东西,上面用到了两篇XS128之间的主从机通信一片主机一片从机。下面用A(主机)  B(从机)代替单功形式,A通过直接写数据寄存器吧数据发送到B,B生成中断响应 接收数据。完全好用在尝试A接收B的数据时。首先B写数据寄存器,进入死 ...…

查看全部问答>

TI官网的ADC资料

本帖最后由 dontium 于 2015-1-23 13:13 编辑 大家参考一下 …

查看全部问答>

实现记录

数码管动态扫描实现了秒表、开始、暂停功能。开始/暂停公用一个键,还有一个键用来记录之前暂停的数(之前有多个暂停),要求至少能记录4个以上。求实现记录功能。 开始/暂停函数如下: void key_1 ()  // k1函数{    & ...…

查看全部问答>

在CCS4中编译BIOS项目时出错

我在CCS4中创建了一个“swi_example”的项目(其实是CCS4自带的示例)。再将NewTargetConfiguration.ccxml文件添加,以及 .cmd 文件(复制以前在非dsp/bios项目用过的cmd文件)。 这样,编译时,CCS显示:   .......... --preproc_with_co ...…

查看全部问答>

大家是否知道这个芯片

本帖最后由 dontium 于 2015-1-23 11:40 编辑 我在一个电路上看到一个芯片,应该是TI的,贴片封装,10个引脚,上面第一行写着72 TI,第二行写着JAAQ,大家是否知道啊,还有就是我不太明白这个贴片上写的JAAQ代表什么意思,72是不是就是人们常说的器 ...…

查看全部问答>