在介绍OV7670之前先附上模块链接:
介绍代码前,首先来看之前写的文章:
目前上位机跟开发板是通过串口来通信,命令通信格式是json,摄像头数据是自定义格式,如果你没听过json,那么自行百度,跟OV7670相关的json格式分别如下:
包含:摄像头开启,摄像头关闭,设置亮度模式,设置饱和度,设置对比度,设置亮度,设置摄像头效果。
发送格式示例如下(以摄像头开启为例):
{"FUNC":"HW","OPERATE":"CAMERA_START","PARAM1":null,"PARAM2":null,"PARAM3":null,"PARAM4":null,"PARAM5":null,"PARAM6":null}
上位机用的c# winform,用的json库using Newtonsoft.Json,此库需要Newtonsoft.Json.dll库,发送代码如下:
private void json_construction_send(string func,string operate,string param1,string param2,string param3,string param4,string param5,string param6)
{
json_commmand cmd = new json_commmand();
cmd.FUNC = func;
cmd.OPERATE = operate;
cmd.PARAM1 = param1;
cmd.PARAM2 = param2;
cmd.PARAM3 = param3;
cmd.PARAM4 = param4;
cmd.PARAM5 = param5;
cmd.PARAM6 = param6;
string json_cmd = JsonConvert.SerializeObject(cmd);
#if CONSOLE_DEBUG
Console.WriteLine(json_cmd);
#endif
if (serialPort1.IsOpen)
{
serialPort1.WriteLine(json_cmd);
}
}
其中ov7670的operate字符串包括:
string operate_camera_start = "CAMERA_START";
string operate_camera_stop = "CAMERA_STOP";
string operate_camera_light_mode = "CAMERA_LIGHT";
string operate_camera_saturation = "CAMERA_SATURATION";
string operate_camera_brightness = "CAMERA_BRIGHTNESS";
string operate_camera_contrast = "CAMERA_CONTRAST";
string operate_camera_effect = "CAMERA_EFFECT";
uint8_t uart_receive_parse(uint8_t *shell_string)
{
uint8_t result = HW_ERR_OK;
cJSON* parse_json = cJSON_Parse((const char *)shell_string);
uint8_t* func_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"FUNC"))->valuestring;
uint8_t* operate_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"OPERATE"))->valuestring;
uint8_t* para1 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM1"))->valuestring;
uint8_t* para2 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM2"))->valuestring;
uint8_t* para3 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM3"))->valuestring;
uint8_t* para4 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM4"))->valuestring;
uint8_t* para5 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM5"))->valuestring;
uint8_t* para6 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM6"))->valuestring;
if(hw_strcmp((const char *)func_value,"HW") == 0)
{
if(hw_strcmp((const char *)operate_value,"CAMERA_START") == 0)
{
/* 开启摄像头 */
goto exit;
}
if(hw_strcmp((const char *)operate_value,"CAMERA_STOP") == 0)
{
/* 关闭摄像头 */
goto exit;
}
if(hw_strcmp((const char *)operate_value,"CAMERA_LIGHT") == 0)
{
/* 设置摄像头亮度模式 */
goto exit;
}
if(hw_strcmp((const char *)operate_value,"CAMERA_SATURATION") == 0)
{
/* 设置摄像头饱和度 */
goto exit;
}
if(hw_strcmp((const char *)operate_value,"CAMERA_BRIGHTNESS") == 0)
{
/* 设置摄像头亮度 */
goto exit;
}
if(hw_strcmp((const char *)operate_value,"CAMERA_CONTRAST") == 0)
{
/* 设置摄像头对比度 */
goto exit;
}
if(hw_strcmp((const char *)operate_value,"CAMERA_EFFECT") == 0)
{
/* 设置摄像头效果 */
goto exit;
}
result = HW_ERR_SHELL_NO_CMD;
}
if(hw_strcmp((const char *)shell_string,"shop220811498.taobao.com") == 0)
HW_DEBUG("welcome to use our stm32f1 camera wifi board\n");
else
HW_DEBUG("UART PARSE ERR:HW_ERR_SHELL_NO_CMD\n");
result = HW_ERR_SHELL_NO_CMD;
exit:
cJSON_Delete(parse_json);
return result;
}
整个上位机是硬件测试例程的上位机,包括LED,OLED,SPI FLASH,摄像头,但是本文章只是拿OV7670做说明,整个上位机包括:
①串口配置区->包括串口打开,关闭,包括热插拔的检测
②功能测试区->包括LED,SPI,OLED,摄像头,贴图仅仅是OLED的测试
③串口调试区->包括可以接收开发板打印的log以及发送自定义的字符串给开发板
上位机代码:
private void bcamera_start_Click(object sender, EventArgs e)
{
json_construction_send(hw_func, operate_camera_start, null, null, null, null, null, null);
}
单片机代码:
if(hw_strcmp((const char *)operate_value,"CAMERA_START") == 0)
{
HW_DEBUG("UART PARSE DEBUG:operate CAMERA_START\n");
hw_ov7670_init();
operate_stauts_oled_show(func_value,operate_value,"SUCCESS",0,0,0,0,0,0);
goto exit;
}
上位机代码:
private void bcamera_stop_Click(object sender, EventArgs e)
{
json_construction_send(hw_func, operate_camera_stop, null, null, null, null, null, null);
}
单片机代码:
if(hw_strcmp((const char *)operate_value,"CAMERA_STOP") == 0)
{
HW_DEBUG("UART PARSE DEBUG:operate CAMERA_STOP\n");
hw_ov7670_control(ov7670_ctl_stop);
operate_stauts_oled_show(func_value,operate_value,"SUCCESS",0,0,0,0,0,0);
goto exit;
}
上位机代码:
private void bcamera_light_Click(object sender, EventArgs e)
{
string light = ccamera_light.SelectedIndex.ToString();
json_construction_send(hw_func, operate_camera_light_mode, light, null, null, null, null, null);
}
单片机代码:
if(hw_strcmp((const char *)operate_value,"CAMERA_LIGHT") == 0)
{
uint8_t light = atoi((const char*)para1);
HW_DEBUG("UART PARSE DEBUG:operate CAMERA_LIGHT\n");
hw_ov7670_set_light_mode(light);
operate_stauts_oled_show(func_value,operate_value,"SUCCESS",0,0,0,0,0,0);
goto exit;
}
上位机代码:
private void bcamera_saturation_Click(object sender, EventArgs e)
{
string saturation = ccamera_saturation.SelectedIndex.ToString();
json_construction_send(hw_func, operate_camera_saturation, saturation, null, null, null, null, null);
}
单片机代码:
if(hw_strcmp((const char *)operate_value,"CAMERA_SATURATION") == 0)
{
uint8_t saturation = atoi((const char*)para1);
HW_DEBUG("UART PARSE DEBUG:operate CAMERA_SATURATION\n");
hw_ov7670_set_color_saturation(saturation);
operate_stauts_oled_show(func_value,operate_value,"SUCCESS",0,0,0,0,0,0);
goto exit;
}
上位机代码:
private void bcamera_brightness_Click(object sender, EventArgs e)
{
string brightness = ccamera_brightness.SelectedIndex.ToString();
json_construction_send(hw_func, operate_camera_brightness, brightness, null, null, null, null, null);
}
单片机代码:
if(hw_strcmp((const char *)operate_value,"CAMERA_BRIGHTNESS") == 0)
{
uint8_t brightness = atoi((const char*)para1);
HW_DEBUG("UART PARSE DEBUG:operate CAMERA_BRIGHTNESS\n");
hw_ov7670_set_brightness(brightness);
operate_stauts_oled_show(func_value,operate_value,"SUCCESS",0,0,0,0,0,0);
goto exit;
}
上位机代码:
private void bcamera_contrast_Click(object sender, EventArgs e)
{
string contrast = ccamera_contrast.SelectedIndex.ToString();
json_construction_send(hw_func, operate_camera_contrast, contrast, null, null, null, null, null);
}
单片机代码:
if(hw_strcmp((const char *)operate_value,"CAMERA_CONTRAST") == 0)
{
uint8_t contrast = atoi((const char*)para1);
HW_DEBUG("UART PARSE DEBUG:operate CAMERA_CONTRAST\n");
hw_ov7670_set_contrast(contrast);
operate_stauts_oled_show(func_value,operate_value,"SUCCESS",0,0,0,0,0,0);
goto exit;
}
上位机代码:
private void bcamera_effect_Click(object sender, EventArgs e)
{
string effect = ccamera_effect.SelectedIndex.ToString();
json_construction_send(hw_func, operate_camera_effect, effect, null, null, null, null, null);
}
单片机代码:
if(hw_strcmp((const char *)operate_value,"CAMERA_EFFECT") == 0)
{
HW_DEBUG("UART PARSE DEBUG:operate CAMERA_EFFECT\n");
uint8_t effect = atoi((const char*)para1);
hw_ov7670_set_special_effect(effect);
operate_stauts_oled_show(func_value,operate_value,"SUCCESS",0,0,0,0,0,0);
goto exit;
}
上位机接受摄像头数据
通过串口来判断是否有CAML字符串,如果有后面的数据代表摄像头数据
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (serialPort1.IsOpen)
{
try
{
string recv_data_string;
int recv_data_count = serialPort1.BytesToRead;
while (serialPort1.BytesToRead > 0)
{
recv_data_string = serialPort1.ReadLine();
if (recv_data_string.StartsWith("CAML"))
{
if (recv_data_string.Length >= (320*2*2 4))
{
Color[] colors;
colors = RGBToBitmap(recv_data_string.Substring(4, 1280));
for (int Ycount = 0; Ycount < 320; Ycount )
{
OvImage.SetPixel(Xcount, Ycount, colors[Ycount]);
}
Xcount ;
if (Xcount == 240)
Xcount = 0;
pcamera_box.Image = OvImage;
}
else
Console.WriteLine("camera len error\n" recv_data_string.Length);
}
else
{
t_data_recv.AppendText(recv_data_string '\r' '\n');
}
}
}
catch (Exception ex)
{
return;
}
}
}
单片机发送
void hw_ov7670_get_data_send()
{
uint32_t i, j;
uint8_t color1,color2;
if(ov7670_frame_interrupt)
{
OV7670_RRST_L;
OV7670_RCLK_L;
OV7670_RCLK_H;
OV7670_RCLK_L;
OV7670_RRST_H;
OV7670_RCLK_H;
for(i=0; i<240; i )
{
if(ov7670_start)
{
HW_DEBUG("CAML");
for(j=0; j < 320; j )
{
OV7670_RCLK_L;
color1=GPIOC->IDR&0XFF;
OV7670_RCLK_H;
OV7670_RCLK_L;
color2=GPIOC->IDR&0XFF;
OV7670_RCLK_H;
HW_DEBUG("x",color2);
HW_DEBUG("x",color1);
}
HW_DEBUG("\n");
}
else
break;
}
}
ov7670_frame_interrupt=0;
}