OV7670摄像头出现垂直条纹的原因排查及解决方法咨询
问题分析
从你描述的现象(垂直条纹)和提供的寄存器配置、采集代码来看,大概率是同步信号错位或者数据采样时机不匹配导致的——垂直条纹通常是每行采样数据偏移、行对齐错误的典型表现。下面从几个核心方向逐一排查:
1. PCLK采样沿寄存器与代码逻辑不匹配
这是最可能的根因!
- 你设置的
COM10(0x15)=0x30,二进制为00110000。查OV7670 datasheet可知,COM10的BIT3是PCLK采样极性位:0=上升沿采样数据,1=下降沿采样。当前BIT3=0,摄像头会在PCLK上升沿锁存数据。 - 但你的采集代码里,是先
wait_for_low(PCLK_PIN)(等待PCLK变低)再读像素,这相当于在PCLK低电平阶段采样,和摄像头的锁存时机完全错位,导致每次读的都是不稳定的旧数据,每行采样数偏移,最终出现垂直条纹。
修复建议:
两种方案二选一:
- 方案一:修改寄存器配置,将PCLK采样沿改为下降沿,和代码逻辑对齐:
{0x15, 0x38}, // COM10: 00111000,BIT3设为1,PCLK下降沿采样 - 方案二:修改代码采样时机,在PCLK上升沿读数据:
wait_for_high(PCLK_PIN, true); // 等待PCLK上升沿(摄像头锁存数据的时机) if(get_value(VSYNC_PIN)) break; uint8_t pixel = !!(NRF_P0->IN & PIXEL_PIN_7_MASK); // ... 后续逻辑不变 wait_for_low(PCLK_PIN);
2. 水平行同步寄存器设置可能偏移
你的HSTART(0x17)=0x16、HSTOP(0x18)=0x04,OV7670的HSTART和HSTOP是10位的水平起止值(HSTART为0x17高5位+低3位0,HSTOP为0x18高5位+低3位0),如果起止值计算错误,会导致HREF有效宽度与实际采样行像素数不匹配,每行多采/少采几个像素,累积后出现垂直条纹。
修复建议:
参考成熟的OV7670 320x240 YUYV初始化配置,调整行同步寄存器:
{0x17, 0x16}, // HSTART: 水平起始(对应320像素行的常用起始值) {0x18, 0x04}, // HSTOP: 水平结束 {0x19, 0x02}, // VSTART: 垂直起始 {0x1A, 0x7A}, // VSTOP: 垂直结束
若行同步仍错位,可尝试将HREF(0x32)从0x80改为0x00测试。
3. 采集代码的行采样数验证
垂直条纹也可能因每行实际采样像素数与后续reshape的image_x不匹配导致。比如预期每行320像素(40字节),但实际采了321像素(41字节),下一行起始就会偏移1位,累积后出现条纹。
修复建议:
在采集代码中添加每行字节数统计:在wait_for_vsync()后重置行计数器,每次HREF变高时统计当前行的byte_counter增量,打印验证所有行的字节数是否一致,且等于image_x/8。若不一致,说明行同步逻辑存在问题。
4. 数据处理的位顺序反转问题
你的received_bytes_to_pixels函数从字节最低位到最高位取像素:
for i in range(8): self._pixels.append((x >> i) & 1)
但采集代码中,第一个采样的像素被放到字节的最高位:
byte = (byte << 1) | (pixel); // 第一个pixel是bit7,最后一个是bit0
这会导致每个字节内的8个像素顺序完全反转,虽不会直接导致垂直条纹,但会让图像水平反转,若image_x不是8的倍数,还可能间接影响行对齐。
修复建议:
修正数据处理的位顺序,从最高位到最低位取:
for i in reversed(range(8)): # 从bit7到bit0取像素 self._pixels.append((x >> i) & 1)
5. 其他潜在小问题
- 检查VSYNC极性:OV7670默认VSYNC低电平表示有效帧,你的代码逻辑
while(!get_value(VSYNC_PIN))是正确的,但如果引脚接反,会采样到消隐期数据。 - 尝试开启自动曝光:修改
COM8(0x13)为0x80,排除因曝光不均导致的伪条纹。
建议先从PCLK采样沿的问题入手修改,这是最常见的同步错误原因,大概率能解决垂直条纹问题。若仍有问题,再逐步排查行同步和采样数的问题。
内容来源于stack exchange

