利用STM32控制ov2640软件二值化采集数据,进行图像识别,可以操作机械臂
本实验将实现如下功能:开机后,初始化摄像头模块(OV2640),如果初始化成功,则提示选择模式:RGB565模式,或者JPEG模式。KEY0用于选择RGB565模式,KEY1用于选择JPEG模式。
当使用RGB565时,输出图像(固定为:UXGA)将经过缩放处理(完全由OV2640的DSP控制),显示在LCD上面。我们可以通过KEY_UP按键选择:1:1显示,即不缩放,图片不变形,但是显示区域小(液晶分辨率大小),或者缩放显示,即将1600*1200的图像压缩到液晶分辨率尺寸显示,图片变形,但是显示了整个图片内容。通过KE0Y按键,可以设置对比度;KEY1按键,可以设置饱和度;KEY2按键,可以设置特效。
当使用JPEG模式时,图像可以设置任意尺寸(QQVGA~UXGA),采集到的JPEG数据将先存放到STM32F4的内存里面,每当采集到一帧数据,就会关闭DMA传输,然后将采集到的数据发送到串口2(此时可以通过上位机软件(串口摄像头.exe)接收,并显示图片),之后再重新启动DMA传输。我们可以通过KEY_UP设置输出图片的尺寸(QQVGA~UXGA)。通过KEY0按键,可以设置对比度;KEY1按键,可以设置饱和度;KEY2按键,可以设置特效。
注意:本实验需要有ALIENTEK OV2640摄像头模块才可以做!!
单片机源程序如下:
- #include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "led.h"
- #include "key.h"
- #include "fing.h"
- #include "lcd.h"
- #include "usmart.h"
- #include "usart2.h"
- #include "timer.h"
- #include "ov2640.h"
- #include "dcmi.h"
- u8 ov2640_mode=0; //工作模式:0,RGB565模式;1,JPEG模式
- u8 x=174,wide=51,mode=0,stop=1;
- u8 tempdrum[4][201];
- u8 delaytime=50,time=0;
- #define jpeg_buf_size 31*1024 //定义JPEG数据缓存jpeg_buf的大小(*4字节)
- __align(4) u32 jpeg_buf[jpeg_buf_size]; //JPEG数据缓存buf
- volatile u32 jpeg_data_len=0; //buf中的JPEG有效数据长度
- volatile u8 jpeg_data_ok=0; //JPEG数据采集完成标志
- //0,数据没有采集完;
- //1,数据采集完了,但是还没处理;
- //2,数据已经处理完成了,可以开始下一帧接收
- void jpeg_data_process(void)
- {
- if(ov2640_mode)//只有在JPEG格式下,才需要做处理.
- {
- if(jpeg_data_ok==0) //jpeg数据还未采集完?
- {
- DMA_Cmd(DMA2_Stream1, DISABLE);//停止当前传输
- while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}//等待DMA2_Stream1可配置
- jpeg_data_len=jpeg_buf_size-DMA_GetCurrDataCounter(DMA2_Stream1);//得到此次数据传输的长度
- jpeg_data_ok=1; //标记JPEG数据采集完按成,等待其他函数处理
- }
- if(jpeg_data_ok==2) //上一次的jpeg数据已经被处理了
- {
- DMA2_Stream1->NDTR=jpeg_buf_size;
- DMA_SetCurrDataCounter(DMA2_Stream1,jpeg_buf_size);//传输长度为jpeg_buf_size*4字节
- DMA_Cmd(DMA2_Stream1, ENABLE); //重新传输
- jpeg_data_ok=0; //标记数据未采集
- }
- }
- }
- void KeyMode()
- {
- u8 msgbuf2[20];
- DCMI_Stop(); //停止显示
- if(WK_UP==1)
- {
- mode+=1;
- if(mode==3)
- {
- mode=0;
- sprintf((char*)msgbuf2,"x=%d w=%d",x,wide);//g
- LCD_ShowString(200,200,100,16,16,msgbuf2);//显示提示内容
- }
- sprintf((char*)msgbuf2,"mode=%d",mode);//g
- LCD_ShowString(200,220,100,16,16,msgbuf2);//显示提示内容
- while(WK_UP==1);
- }
- if(mode==1)
- {
- if(KEY0==0)
- {
- x+=1;
- sprintf((char*)msgbuf2," x=%d ",x);//g
- LCD_ShowString(200,200,100,16,16,msgbuf2);//显示提示内容
- while(KEY0==0);
- }
- if(KEY2==0)
- {
- x-=1;
- sprintf((char*)msgbuf2," x=%d ",x);//g
- LCD_ShowString(200,200,100,16,16,msgbuf2);//显示提示内容
- while(KEY2==0);
- }
- }
- if(mode==2)
- {
- if(KEY0==0)
- {
- wide+=1;
- sprintf((char*)msgbuf2," w=%d ",wide);//g
- LCD_ShowString(200,200,100,16,16,msgbuf2);//显示提示内容
- while(KEY0==0);
- }
- if(KEY2==0)
- {
- wide-=1;
- sprintf((char*)msgbuf2," w=%d ",wide);//g
- LCD_ShowString(200,200,100,16,16,msgbuf2);//显示提示内容
- while(KEY0==0);
- }
- }
- if(mode==0)
- {
- if(KEY0==0)
- {
- delaytime+=1;
- sprintf((char*)msgbuf2," w=%d ",delaytime);//g
- LCD_ShowString(200,220,100,16,16,msgbuf2);//显示提示内容
- while(KEY0==0);
- }
- if(KEY2==0)
- {
- delaytime-=1;
- sprintf((char*)msgbuf2," w=%d ",delaytime);//g
- LCD_ShowString(200,220,100,16,16,msgbuf2);//显示提示内容
- while(KEY0==0);
- }
- }
- DCMI_Start();
- }
- void getcolor(tx,ty,num)
- {
- u8 msgbuf1[15]; //消息缓存区
- u16 tempcolor;
- DCMI_Stop(); //停止显示
- tempcolor=LCD_ReadPoint(tx,ty);
- sprintf((char*)msgbuf1,"%d",(int) ((tempcolor>>5&0x3f) * 255.0 / 63.0 + 0.5));//g
- LCD_ShowString(tx-8,ty+24,210,16,16,msgbuf1);//显示提示内容
- if((int) ((tempcolor>>5&0x3f) * 255.0 / 63.0 + 0.5)>30) //软件二值化
- {
- LCD_Fill((num-1)*120+1,150-20,num*120-1,150+20,WHITE);
- tempdrum[num-1][time]=1;
- }
- else
- {
- LCD_Fill((num-1)*120+1,150-20,num*120-1,150+20,BLACK);
- tempdrum[num-1][time]=0;
- }
- LCD_DrawRectangle(tx-1,ty-1, tx+1, ty+1);
- LCD_DrawLine(tx, ty-2, tx, ty-7);
- LCD_DrawLine(tx-2, ty, tx-7, ty);
- LCD_DrawLine(tx+2, ty, tx+7, ty);
- //
- // while(KEY_Scan(0))
- // KeyMode();
- DCMI_Start();
- //低字节的前5位用来表示B(BLUE)
- //低字节的后三位+高字节的前三位用来表示G(Green)
- //高字节的后5位用来表示R(RED)
- // R8 = (int) floor( R5 * 255.0 / 31.0 + 0.5);
- // G8 = (int) floor( G6 * 255.0 / 63.0 + 0.5);
- // B8 = (int) floor( R5 * 255.0 / 31.0 + 0.5);
- // R8 = (int) floor( (tempcolor>>11) * 255.0 / 31.0 + 0.5);
- // G8 = (int) floor((tempcolor>>5&0x3f) * 255.0 / 63.0 + 0.5);
- // B8 = (int) floor( (tempcolor&0x1f) * 255.0 / 31.0 + 0.5);
- // delay_ms(1);
- }
- //RGB565测试
- //RGB数据直接显示在LCD上面
- void fing()
- {
- u16 temptime;
- if (time else temptime=time-delaytime;
- if(tempdrum[0][temptime]==1)GPIO_SetBits(GPIOG,GPIO_Pin_2);
- else GPIO_ResetBits(GPIOG,GPIO_Pin_2);
- if(tempdrum[1][temptime]==1)GPIO_SetBits(GPIOG,GPIO_Pin_4);
- else GPIO_ResetBits(GPIOG,GPIO_Pin_4);
- if(tempdrum[2][temptime]==1)GPIO_SetBits(GPIOG,GPIO_Pin_6);
- else GPIO_ResetBits(GPIOG,GPIO_Pin_6);
- if(tempdrum[3][temptime]==1)GPIO_SetBits(GPIOG,GPIO_Pin_8);
- else GPIO_ResetBits(GPIOG,GPIO_Pin_8);
- }
- void rgb565_test()
- {
- u8 effect=0,saturation=2,contrast=2;
- u8 scale=1; //默认是全尺寸缩放
- u8 msgbuf[15]; //消息缓存区
- // u8 msgbuf2[15]; //消息缓存区
- u16 tempx;
- LCD_Clear(BLACK);
- POINT_COLOR=RED;
- OV2640_RGB565_Mode(); //RGB565模式
- My_DCMI_Init(); //DCMI配置
- //OV2640_Window_Set(0,0,lcddev.width,lcddev.height/4);
- DCMI_DMA_Init((u32)&LCD->LCD_RAM,1,DMA_MemoryDataSize_HalfWord,DMA_MemoryInc_Disable);//DCMI DMA配置
- OV2640_ImageWin_Set((800-lcddev.width)/2,(800-lcddev.height/4)/2,lcddev.width,lcddev.height/8);//1:1真实尺寸
- OV2640_OutSize_Set(480,lcddev.height/8);
- delay_ms(800);
- DCMI_Start(); //启动传输
- while(1)
- {
- tempx=x;
- getcolor(tempx,20,1);
- tempx+=wide;
- getcolor(tempx,20,2);
- tempx+=wide;
- getcolor(tempx,20,3);
- tempx+=wide;
- getcolor(tempx,20,4);
- fing();
- time++;
- if(time>200)time=0;
- if(KEY_Scan(0))
- KeyMode();
- }
- }
- int main(void)
- {
- u8 key;
- u8 t;
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
- delay_init(168); //初始化延时函数
- uart_init(115200); //初始化串口波特率为115200
- usart2_init(42,115200); //初始化串口2波特率为115200
- LED_Init(); //初始化LED
- LCD_Init(); //LCD初始化
- KEY_Init(); //按键初始化
- FINE_Init();
- TIM3_Int_Init(10000-1,8400-1);//10Khz计数,1秒钟中断一次
- usmart_dev.init(84); //初始化USMART
- POINT_COLOR=RED;//设置字体为红色
- while(OV2640_Init())//初始化OV2640
- {
- LCD_ShowString(30,130,240,16,16,"OV2640 ERR");
- delay_ms(200);
- LCD_Fill(30,130,239,170,WHITE);
- delay_ms(200);
- }
- LCD_ShowString(30,130,200,16,16,"OV2640 OK");
- while(1)
- {
- rgb565_test();
- }
- }
所有资料51hei提供下载:
摄像头采集程序.rar
|