简介这是一份面向硬件开发与图像传感器应用工程师的线阵CCD驱动电路设计资料围绕数码相机及非接触式工件尺寸测量中的CCD硬件设计问题展开。资料重点介绍采用可编程逻辑器件EPM7032C44动态控制CCD光积分时间的新方法在系统主频不变的前提下根据背景光强自动缩短或延长积分时间从而避免输出信号饱和失真、提高复杂光照环境下的测量精度并配有TCD1206UD型线阵CCD结构与驱动波形说明。所提方案已在带钢纵切机组自动对中系统中验证适合从事CCD驱动、图像采集和嵌入式测控系统设计的工程师参考。压缩包内共1个doc文档大小约120KB文档包含摘要、工作原理、驱动波形设计及应用实例便于直接阅读和复用。该资源已有268人学习/下载可作为相关项目前期选型与电路设计的参考。1. 线阵 CCD 驱动电路为什么要动态控制光积分时间做非接触尺寸测量的工程师大多被 CCD 输出信号的饱和失真和背景分割问题折磨过。环境光一变固定驱动时序下的 CCD 信号要么饱和溢出要么低到把工件淹没在背景里。本文要拆的这套线阵 CCD 驱动电路设计方案核心就一句话在不改系统主频的前提下用可编程逻辑器件动态调整光积分时间让 CCD 输出始终落在正常工作区间。它解决了传统直接数字电路、单片机驱动和计数分频法共有的静态驱动缺陷已经用在带钢纵切机组自动对中系统里。这个思路对做 CCD 硬件设计、数码相机成像前端、各类在线测量系统的从业者都有参考价值尤其是被环境光干扰折腾过的可以直接沿用这套逻辑。2. 三种传统驱动法为什么不够用从静态到动态的选型逻辑2.1 直接数字电路、单片机、计数分频的各自天花板先说结论这三种方法在原理上都是“静态驱动”光积分时间被锁死适应不了光照突变的环境。直接数字电路驱动法用门电路、触发器、计数器硬搭时序。优点是输出波形干净、速率快但元件数量大。一张驱动板几十个芯片排线绕成蜘蛛网调试时拿示波器逐点对波形改一个时序参数就要换电阻电容甚至重新布线。量产时的一致性也差两块板子同样的元件焊出来波形沿的抖动可能就是两回事。单片机驱动法用 I/O 口软件翻转产生驱动脉冲。改动灵活时序想怎么调就怎么调。但瓶颈在 I/O 翻转速率51 内核的单片机跑 12MHz 晶振一条翻转指令好几个周期。TCD1206UD 这类 2000 多像素的线阵 CCDφ1、φ2 需要兆赫兹级别的时钟单片机产生的频率根本喂不饱高速数据采集场景直接淘汰。计数分频法比前两者进了一步通过改变主频或计数器预置值来改变积分时间。但问题是改主频时模拟通道的低通滤波器、相关双采样电路的参数都跟着变频带和信噪比全乱套改计数初值呢直接扰动驱动波形φ1 和 φ2 的相位关系可能错位CCD 输出就花屏。这三种方法共同的问题是光积分时间一固定光照强了就饱和失真光照弱了信号就淹没在噪声里景物和背景的灰度差拉不开。我拆过一个类似的测量项目当时的做法是手动调镜头光圈晴天拧小光圈阴天拧大车间里光照变化快的时候完全跟不上。2.2 动态控制的设计目标主频不动只动空驱动数量这套设计方案的核心思路是引入“空驱动”的概念。TCD1206UD 在一个 φSH 周期内读完 2236 个像素后其实还可以继续打时钟这段多余的时钟就叫空驱动。空驱动期间 CCD 不输出有效像素信号但它延后了下一个转移脉冲 φSH 的到来时间相当于拉长了光积分窗口。积分时间拉长感光单元收集的电荷就多输出电压幅度就高积分时间缩短电荷少幅度低。所以动态控制逻辑就清楚了背景光强时少插空驱动光积分时间短避免饱和背景光弱时多插空驱动光积分时间拉长让信号抬起来。关键操作是保持系统主频 T0 不变只改变空驱动脉冲数量。这样模拟通道的工作条件始终稳定信号处理电路的频带和信噪比不受影响而 CCD 的光积分时间却在一个大范围内可调。最小光积分时间是 2236 个主频脉冲周期最大可以到 22364096 个周期动态范围接近一倍。这套逻辑用 CPLDEPM7032C44实现逻辑规模不大但时序要求严苛接下来看具体的实现方法。3. 基于 EPM7032C44 的动态驱动电路Verilog 实现与参数设置3.1 硬件架构与信号分配先理清这 5 路信号的分工它们是整个驱动电路的基础T0统一主频时钟所有时序从这个时钟派生保证同步φSH转移脉冲高电平期间把感光区的电荷转移到模拟移位寄存器φ1、φ2移位时钟互补驱动把寄存器里的电荷逐级搬向输出端φR复位脉冲每个像素输出前复位一次输出电容从实现角度说φ1 由 T0 二分频得到φ2 是 φ1 的取反频率相同、相位互补。φR 直接由 T0 经过逻辑整形生成保证每个 φ1 周期内完成一次复位和输出。φSH 则不是固定分频得到的它靠计数器组合产生是动态控制的关键节点。整个逻辑的核心是两个计数器基本计数器负责数 2236 个像素周期计满后触发一个信号让预置计数器开始工作预置计数器负责空驱动延时预置初值由微处理器根据 CCD 输出信号幅度反推的光强信息动态设定取值范围 1~4095。预置计数器计满后清除基本计数器同时产生一个 φSH 脉冲开始下一轮积分。这个设计的好处是φSH 的周期被拆成了“固定像素周期 可变空驱动周期”两段改积分时间只动预置值不动像素读出节奏。3.2 核心 Verilog 代码逐段拆解借用原文给出的 Verilog 程序框架补上可读性注释拆一下关键逻辑module Drive(φSH, φ1, φ2, φR, Data, T0); input T0; // 系统主频时钟 input [11:0] Data; // 微处理器写入的空驱动数量预置值 1~4095 output φSH, φ1, φ2, φR; // CCD 四路驱动信号 reg φ1, φ2, φR; reg φSH, Clr, Start_signal, Signal_del; reg [11:0] Data_reg, Base_count; reg [8:0] Sh_count; parameter n 2236; // TCD1206UD 有效像素 暗像素总数 // φ1 二分频φ2 取反形成互补移位时钟 always (posedge T0) begin φ1 ~φ1; φ2 ~φ1; end // φR 直接用主频时钟整形保证与 φ1 同步 always (T0) φR T0; // 基本计数器数到 2236 产生进位信号拉高 Start_signal always (posedge T0) begin if (Base_count n) begin Signal_del 1; Base_count Base_count 1; Start_signal 1; end else if (Base_count n2) Base_count n3; // 防止计数器跑飞 else begin Signal_del 0; Base_count Base_count 1; end if (Clr) begin Base_count 0; Start_signal 0; end end // 预置计数器空驱动延时计数计满 4095 产生清零信号 always (posedge T0) begin if (Signal_del) Data_reg Data; if (Start_signal) begin if (Data_reg 4095) begin Clr 1; end else Data_reg Data_reg 1; end if (Clr) begin if (Sh_count 500) begin Sh_count 0; Clr 0; end else Sh_count Sh_count 1; end end // φSH 在 Clr 期间拉高形成转移脉冲 always (Clr) begin if (Clr) φSH 1; else φSH 0; end endmodule这段代码的关键参数n2236TCD1206UD 的像素总数其中 2160 个有效像元其余是暗像元和虚设单元。这个值跟传感器型号绑定换传感器必须改Data[11:0]12 位预置值取值范围 0~4095对应空驱动脉冲数。这个值的来源是微处理器分析 CCD 输出信号的幅度后做出的判断Sh_count500φSH 高电平持续 500 个 T0 周期这个脉宽要保证电荷完全转移到移位寄存器不能太短从时序角度理解这段逻辑基本计数器数到 2236 后不是马上产生 φSH而是拉起 Start_signal让预置计数器开始数空驱动脉冲。预置计数器从微处理器写入的 Data 值开始往上加加到 4095 时产生 Clr 信号Clr 拉高 φSH同时清零基本计数器。所以 φSH 的周期等于 2236 加上4095 减去 Data个 T0 周期。Data 越大空驱动越少积分时间越短Data 越小空驱动越多积分时间越长。注意这段代码有一个细节信号名用了希腊字母 φ这在某些编译环境中可能不识别实际工程中我一般会改成 SH、P1、P2、PR 这种 ASCII 命名或者用 phiSH、phi1 这样安全的名字避免综合工具报错。这是拿原代码直接跑仿真最容易踩的坑之一。3.3 动态控制的闭环逻辑驱动电路本身不决策它只执行。决策在微处理器那边。系统工作流程是CCD 输出模拟信号经过抗干扰滤波和 A/D 转换后送入微处理器。微处理器分析当前帧的灰度分布如果看到整体电平偏高、接近饱和就增大 Data 值减小空驱动缩短下一帧的积分时间如果看到整体电平偏低、动态范围不够就减小 Data 值增加空驱动延长积分时间。这个反馈回路的基本原理是 CCD 输出电压与光照强度和积分时间的乘积成正比控制积分时间本质上是把曝光量拉回线性区。这套逻辑在工程上跟自动曝光算法是同一套思路只是实现载体换成了 CPLD。做数码相机成像前端的朋友看到这里应该觉得眼熟就是快门优先和光圈优先的硬件版本。注意Data 值的反馈周期不能太短。如果你每个像素都做一次判定CCD 还没读完一行呢预置值就变了好几次画面会出现条带状亮度不均。一般至少要等完整扫完一帧再做一次判定这属于控制周期的工程权衡。4. 系统集成与实测应用带钢纵切机组自动对中系统4.1 系统框图与信号链路应用环境是带钢纵切机组的自动对中系统。现场环境对光电传感器极不友好轧线上有蒸汽、冷却水飞溅、钢粉飘落背景光照随时在变。用固定积分时间的传统方案经常出现板材边缘和背景灰度接近边缘检测算法找不到边界的情况。系统的信号链路这样走CCD 输出端先接抗干扰电路。这级的关键是滤掉电机变频器和周边大功率设备带来的传导干扰否则模拟信号上叠加的毛刺会被 A/D 误判成有效像素。抗干扰电路输出接 A/D 转换器采样率要跟 φ1 时钟匹配才能保证每个像素一个有效采样点。转换结果存入缓冲区微处理器做边缘检测和灰度统计根据统计结果计算新的空驱动预置值写入 CPLD 的 Data 寄存器。微处理器在其中的角色是控制闭环。它每隔固定帧数做一次灰度统计取 CCD 输出有效像素区的最大灰度值和平均灰度值跟预设的上下阈值比较。超过上限就把 Data 往大了调低于下限就往小了调。调整步长要按现场情况设我习惯先用大步长快速逼近再小步长细调避免振荡。4.2 现场参数整定与效果具体参数整定给出一个参考模板表 1 动态驱动电路的现场整定参数参数典型值整定方法系统主频 T01MHz由传感器最高驱动频率决定留 20% 裕量基本计数值 n2236对应 TCD1206UD 像素总数固定φSH 脉宽500 个 T0 周期示波器观测 OS 端输出信号确保电荷转移干净Data 预置值范围500~3000根据现场光照变化区间标定反馈判定周期每帧一次带钢运行速度越快周期要越短整定过程我踩过不少坑。最典型的是把 Data 调到 4095 附近时CCD 输出出现顶部削平。原因不是饱和而是 φSH 脉宽不够——预置计数器计满到 Clr 产生的这段组合逻辑延时导致 φSH 高电平持续时间勉强够用但温度一变CPLD 内部延时漂移时序裕量不够了。后来把 Sh_count 从 500 拉到 700问题消失。另一个实际效果值得说这套动态驱动方案解决了饱和失真和背景分割问题但带钢边缘检测的稳定性还取决于光源布局。现场用的是红外背景光源加 CCD 的透射式方案光源强度波动本来就小动态积分时间主要补偿的是镜头污染和钢粉遮挡带来的缓慢衰减不是光源突变。换句话说这套方法擅长处理慢变的背景光反对快变的光源频闪。系统的检测精度在实验数据上带钢边缘定位误差控制在 0.3mm 以内完全满足纵切机组的对中要求。这套方案能成立的关键是反馈环路有足够的帧率余量——CCD 一帧读出时间在毫秒级微处理器做主控DSP 或 ARM 都跑得动这个闭环。5. 避坑与常见问题排查动态驱动电路的现场实战记录5.1 现象CCD 输出出现周期性条纹现象调试时用示波器看 OS 端信号发现输出波形叠加了低频条纹频率约几百赫兹肉眼可见亮度不均匀。原因Data 预置值的更新时机不对。微处理器在 CCD 正在读出一帧的过程中写入新值CPLD 在 Signal_del 信号到达时锁存数据如果这个时机恰好落在有效像素输出区间就会导致前半帧用旧积分时间、后半帧用新积分时间一帧内部亮度不连续。解决把 Data 更新和帧同步绑定。微处理器只有在检测到 φSH 上升沿之后才写入新预置值给 CPLD 足够的时钟周期完成锁存。代码层面把 Signal_del 的触发条件加一个限定在 Base_count 等于 n 后的第一个 T0 上升沿才锁存数据保证数据写入发生在空驱动区间的起点。5.2 现象高温环境下驱动时序漂移边缘出现毛刺现象车间夏季温度到 40℃ 以上CCD 输出信号边缘出现毛刺A/D 采样偶尔采到错误值边缘检测结果抖动。原因EPM7032C44 作为 CPLD内部走线延时随温度漂移。φR 由组合逻辑产生跟 φ1 的相位差在高温下微小偏移导致 A/D 采样窗口落在信号上升沿上。这不是 CPLD 本身坏了而是时序裕量不够。解决从时序设计上解决不要在关键路径上依赖组合逻辑。把 φR 改成由 T0 直接分频同步产生保证和 φ1 同源同相A/D 采样时钟改成用 φ1 的下降沿触发这样数据稳定时采样再在 PCB 走线上把 φR 信号线加粗做等长。改完以后高温环境下边缘毛刺消失。5.3 现象更换 CCD 后输出全黑现象把 TCD1206UD 换成一个引脚兼容的型号结果输出信号全黑一个有效像素都没有。原因不同型号的线阵 CCD虽然像素数相近但暗像元数量、虚设像元位置、转移脉冲上升沿的要求都不同。基本计数器 n 还停留在 2236实际芯片需要的转移时序不匹配电荷转移不完整。换了传感器直接用旧的配置参数这是硬件工程师最容易犯的经验主义错误。解决换 CCD 后第一件事是查数据手册确认三个参数总像素数决定 n 值、暗像元数量决定有效输出起始位置、φSH 最小脉宽决定 Sh_count。把这三个参数全部改成新传感器对应的值再上示波器看波形。从那以后我形成了习惯任何涉及传感器替换的项目先列一个寄存器参数对照表新旧型号逐项比对参数核对完才上电。5.4 现象微处理器写入的 Data 值不生效现象通过接口向 CPLD 写 Data 值发现写入后 CCD 驱动波形没变化光积分时间一直不变。原因CPLD 里 Data_reg 的锁存逻辑只在 Signal_del 为高时采样一次。如果微处理器的写入时序比 Signal_del 晚就会等到下一帧才生效。如果下一帧 Signal_del 持续窗口太短微处理器接口的时序延迟导致数据没被采到就会一直维持旧值。这是典型的异步接口握手问题。解决在微处理器和 CPLD 之间加一个握手信号。微处理器先拉高写请求CPLD 等到 Signal_del 有效时锁存数据并回一个应答信号微处理器收到应答才撤销写请求。没有硬件握手的话就用查询方式等检测到 φSH 上升沿后再写数据保证时序窗口足够。工程上更省事的办法是让 CPLD 把 Data_reg 做成随时可写、Signal_del 到达时再同步到计数寄存器这样微处理器什么时间写都行只要保证一帧内写完一次就行。5.5 现象A/D 采样率不够像素丢失现象系统跑起来后CCD 像素数对不上每行少了几个像素边缘位置偶发跳动。原因A/D 转换器的采样率和 φ1 频率没匹配。CCD 输出是串行的每个 φ1 周期输出一个像素。如果 A/D 的采样率低于 φ1 频率或者采样时钟抖动大部分像素被漏采。更隐蔽的是采样率高于 φ1 频率好几倍结果同一个像素被采多次虽然总数不变但灰度值被重复平均了边缘精度反而下降。解决A/D 采样率应该等于 φ1 频率并且采样时钟直接由 φ1 分频产生用锁相环保证同相。采样窗口放在像素信号的平台期避开上升沿和下降沿。从效率角度A/D 数据每行存满后直接 DMA 搬运到内存不要在中断服务里逐像素读否则微处理器负载过高反馈控制周期就被拉长动态响应的优势就体现不出来了。6. 进阶调试技巧用一段仿真代码验证驱动时序的正确性在投入硬件调试之前先在仿真环境里把时序跑通能省下大量示波器前折腾的时间。这套驱动电路的核心是计数器和状态机的配合仿真脚本可以直接复用原 Verilog 代码做 testbench重点盯三个时间点最小积分时间、最大积分时间、Data 中途变化时的过渡行为。timescale 1ns/1ps module tb_Drive; reg T0; reg [11:0] Data; wire SH, P1, P2, PR; integer pulse_count; Drive uut( .φSH(SH), .φ1(P1), .φ2(P2), .φR(PR), .Data(Data), .T0(T0) ); // 50MHz 主频时钟 initial begin T0 0; Data 12d2048; // 中等积分时间 forever #10 T0 ~T0; end // 统计 T0 周期数 always (posedge T0) begin if (SH 1) pulse_count 0; else pulse_count pulse_count 1; end initial begin $dumpfile(drive_wave.vcd); $dumpvars; #10000; Data 12d1000; // 模拟光变强缩短积分时间 #10000; Data 12d3500; // 模拟光变弱延长积分时间 #20000; $display(pulse_count at SH low: %0d, pulse_count); $finish; end endmodule跑完仿真重点看两个指标一是 φSH 的周期跟理论值 2236 加上4095 减去 Data是否一致二是 Data 变更后下一帧是否按新值工作有没有出现半帧旧的半帧新的一帧两制现象。这两点过关了硬件调试压力就小得多。仿真通过后还有一个验证细节值得做测量 φSH 低电平期间包含的 T0 脉冲总数检查是否落在理论范围内。用 VCD 波形文件导入查看比直接看波形直观得多。如果计数结果跟理论值差一两个周期多半是组合逻辑的竞争冒险导致计数器多走了一拍可以在敏感列表里补事件或者把计数条件改成严格边沿触发。这套仿真流程是我在某个图像处理 Demo 里的习惯做法从那以后每次调 CCD 驱动时序都强制先在 ModelSim 或 Vivado 里跑一遍全时序仿真然后才是上板。硬件调试一旦烧板CPLD 要重新擦写来回成本比仿真高太多。希望这套流程对你也有帮助——先仿真、后上板、再标定三步走完动态 CCD 驱动电路基本不会跑偏。本文还有配套的精品资源点击获取