原创 (原创)基于FPGA的线阵CCD驱动

2009-4-21 01:39 4525 9 10 分类: FPGA/CPLD

  最近还是干点实事。。。。
 
  线阵CCD是什么东西....
http://baike.baidu.com/view/1544931.html?fromTaglist

 线阵CCD驱动的原理:
这个可以去看一下《
光电传感器及其应用》这本书或者类似的,里面对CCD的内部原理介绍的很清楚
这里有2篇文章作参考:
CCD原理简介:点击下载

CCD与CMOS的区别点击下载

如果你看懂了这个原理其实就知道了CCD怎么驱动以及如何去驱动
下面就我只用的TCD1703来说一下驱动的时序:
我使用的Cyclone II 系列的EP2C8T144C8来实现驱动时序的
TCD1703 的信号管脚如下;






















点击看大图
光敏单元产生的7500个光积分电荷信号在转移栅(在这里就是信号E1\E2)的作用下并行地转移到奇、偶数列(OS1\OS2)的模拟移位寄存器中,模拟移位寄存器在驱动脉冲

















驱动下经奇、偶输出电路输出。输出电路有复位脉冲RS和一个钳位脉冲CP,钳位脉冲使输出信号钳位在0信号电平上,使输出信号更稳定。驱动的时序':
点击看大图
清晰的驱动图片可以参考文档:pdf





基本可以说只要值按照这个时序写出来就可以驱动CCD来(这是我以为师兄的话,感谢他,的确是这样,你完全可以不用去理解CCD是怎么工作的,只要时序正确、电压正确就可以了)。

需要注意的2点:
1.
正常工作时从OS1OS2首先输出64 * 2个哑元,然后输出3570个像元,最后在输出8 * 2个哑元和一个检测单元。由于其为2列并行奇、偶输出,故在一个SH周期内至少要有3822个驱动脉冲。
2.时序中的信号间隔问题:
点击看大图
这个关系很重要,在写时序的时候要打到这个要求
点击看大图



(别人的,请原谅使用)
下面是我的代码的原理图:
点击看大图
第一个模块是时钟 。里面我使用了PLL来产生适合的时钟。。。
第二个模块就是产生需要的信号:
代码就不给了,思路供大家来参考:
首先第一个模块产生20M的时钟
在第二个模块中,对20M的时钟进行分频产生2M 的时钟来实现SH E1 E2这三个信号的时序,我在同一个模块里面实现这三个信号(可以很简单的实现SH 与E1之间的时序问题,就是在)
6f993bfb-0e15-4d3f-b3a7-ce64d63e22b9.jpg
这个时序是通过状态机来实现的
           case(sh_counter)
             0:                            //time 0ns
               begin
                   e1 <= 1'b1;
                   sh <= 1'b0;
                   sh_counter <= sh_counter + 12'h001;
               end
//////////////////////////////////////////////////////////////////////////////////////
             1:                            //time 2t ns (refer to clk frequence)
               begin
                   e1 <= 1'b1;
                   sh <= 1'b1;
                   sh_counter <= sh_counter + 12'h001;
               end
             2:                            //time 3t ns
               begin
                   e1 <= 1'b1;
                   sh <= 1'b1;
                   sh_counter <= sh_counter + 12'h001;
               end
///////////////////////////////////////////////////////////////////////////////////////
             3:                       //time 3500ns
               begin
                   e1 <= 1'b1;
                   sh <= 1'b0;
                   sh_counter <= sh_counter +12'h001;
               end
             4:                       //time 4000ns
               begin
                   e1 <= 1'b0;
                   sh <= 1'b0;
                   sh_counter <= sh_counter + 12'h001;
               end
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
             default:
               begin
                   e1 <= ~e1;
                   sh <= 1'b0;
                   sh_counter <= sh_counter + 12'h001;
               end
           endcase

       end

end

对于如rs和cp这2个信号,脉冲比较小,而且要达到时序的要求,而且实在E1 E2的后面,所以我使用20m的时钟进行控制,在SH为高的是时候,着个信号是低电平,通过检测E1 E2的状态来完成控制,其实这里还是一个状态机
  else if(sh)
            begin
                rs <= 1'b0;
                cp <= 1'b0; 
                rs_cp_counter <= 3'b000; 
            end
          else if(!e1 && inter_clk) //////////???  not  good
                begin
                    case(rs_cp_counter)
                    0:
                    begin
                       rs <= 1'b1;
                       cp <= 1'b0; 
                       rs_cp_counter <= rs_cp_counter + 3'b001; 
                    end
                    1:
                    begin
                       rs <= 1'b1;
                       cp <= 1'b0; 
                       rs_cp_counter <= rs_cp_counter + 3'b001; 
                    end
                    2:
                    begin
                       rs <= 1'b0;
                       cp <= 1'b1; 
                       rs_cp_counter <= rs_cp_counter + 3'b001; 
                    end
                    3:
                    begin
                       rs <= 1'b0;
                       cp <= 1'b1; 
                       rs_cp_counter <= rs_cp_counter + 3'b001; 
                    end
                    default:
                    begin
                       rs <= 1'b0;
                       cp <= 1'b0; 
                       rs_cp_counter <= 3'b000; 
                    end              
                    endcase
                end

最后说一个最要命的一点 就是复位的问题;
开始我写的时候是这样复位的:
always@(negedge reset or posedge clkin or posedge sh)
begin
if(~reset)
  begin
     cp  <= 1'b0;
     rs  <= 1'b0;
     rs_cp_counter <= 4'b0000;
  end
end
也就是说是通过检测复位信号的边沿来实现复位的,但是这种要求在外部有时候是很难打到要求的。
后来参考师兄的写法改为;
always@(posedge clkin )
begin
     if(!reset)
       begin
          rs <= 1'b0;
          cp <= 1'b0; 
          rs_cp_counter <= 3'b000;       
       end
end

这样做 是通过电平 来实现的。。。。原来的不稳定因素就少了很多



PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户1312638 2009-4-23 10:02

最近小兄弟做了不少事情啊,呵呵。 对了,你在QQ上闪我一下,我把徐博士email给你。你直接给他去email就可以了,我已经和他说过了。
相关推荐阅读
zhangshaobing517_935512703 2011-03-21 01:28
KC24RT-300调试笔记
项目中需要使用LED驱动器,主要是为了让一串LED发出的光照一致,所以在试验中采用LED串联的方式比较好点,LED并联容易导致LED发光的 不均匀以及寿命减少。我在项目中采用金升阳公司的KC24RT-...
zhangshaobing517_935512703 2010-11-19 14:53
线程中CreateEvent和SetEvent及WaitForSingleObj
首先介绍CreateEvent是创建windows事件的意思,作用主要用在判断线程退出,程锁定方面.CreateEvent 函功能描述:创建或打开一个命名的或无名的事件对象.EVENT有两种状态:发信...
zhangshaobing517_935512703 2010-11-15 13:29
VS2008 BEGIN
Visual Studio 2008环境与VC6.0的环境存在着比较大的区别,下面就一些小小的区别在这里做一些探讨,欢迎指教!1、如果是调试控制台程序,很多时候点击“启动调试”后是一闪而过,此时可有两...
zhangshaobing517_935512703 2010-11-01 20:38
使用MFC的数组类
 MFC的数组类支持的数组类似于C++中的常规数组,可以存放任何数据类型。C++的常规数组在使用前必须将其定义成能够容纳所有可能需要的元素,而MFC数组类创建的对象可以根据需要动态地增大或减小,数组的...
zhangshaobing517_935512703 2010-09-07 13:14
循环
 循环设计的注意的事情:(1)双重循环的跳出问题,break只挑出所在的循环,如果使用双层FOR循环,单个BREAK就不可能跳出所有的双层(2)在迭代的时候,注意起始和终止的条件,尤其是终止问题(3)...
zhangshaobing517_935512703 2010-09-02 01:09
图像处理改进
1.特征点提取的算法  标志点的提取算法对结果的影响虽然没有经过试验或者计算的推算,每1个pix的偏差对结果的影响有多大,但是不可避免的,要想获得高精度的  测量结果,高精度的提取对结果的影响还是很大...
我要评论
1
9
关闭 站长推荐上一条 /3 下一条