一. 原理及功能
CCD是一种电荷耦合器件,他可以将接收到的光信号转换为电荷量存储并通过耦合的方式将信号传输给MCU(微处理器)。CCD一般用于摄像头之中,可以在X轴Y轴两个方向同时检测。而像扫描仪,一次智能检测一条线上光强的方式,就称之为线性CCD。
上一段是来自百度对CCD的解释的概述。如果读者读到这里还是不明白线性CCD究竟是一个什么样的东西,没有关系。相信读者看到这篇文章的时候,多少因该接触过一些单片机编程和常用的模块了。CCD的功能和灰度模块很类似,如果读者也没用过灰度模块,没事,下面我将简单讲解原理。灰度模块之中,其实最主要的部分是一个光敏三极管,当基集有光照射时,那么集电极与发射极会导通,产生一个电流,那当电流流过电阻时,就会在电阻两端产生一个电压,电流越大,在电阻上的压降就越大。因此根据此原理,即可通过电压的大小判断当前光亮的大小(检测物体反射回的光亮)。一上设计到数电的一些专业知识,如果读者不懂无需理会,只要知道功能即可即检测物体返回的光亮输出一个对应的电压。根据白色返回光的大部分波段,黑色材质吸收光的大部分波段的物理现象来看,即被检测物体颜色越浅,输出电压值越高,反之电压越小。综上所述就是白色输出高电平,黑色输出低电平。
而线性CCD的线性与之类似但不是同一个检测原理。读者可以将线性CCD理解为一个内部集成了128个灰度模块的传感器,一个灰度模块对应一个检测点,那么线性CCD就是在一条直线上均匀分布了128个检测点而已。
图1.1 线性CCD内部传感部件–TSL1401CL
以上是线性CCD的工作原理,那么接下来就是对其功能和应用场合的一个简要论述。
在生活中,其最主要的应用就是扫描机,用于复印或者将纸质文字图片变成电子文件保存。而在工业中,常将其用于对待加工零件位置的检测。比如说贴片机,为了准确夹取芯片,必须准确的分别正反以及位置,那么通过两个垂直的线性CCD在X轴和Y轴两个方向同时检测,就可以获取准确的位置参数和外轮廓特征即大小。
二. 时序图分析
相信读者因该都接触过电脑,对驱动这个词因该不会太过陌生。那么何为驱动呢?不知到读者在编程的时候,有没有想过一些语句,为什么能实现该功能,这条语句在单片机内部究竟是怎么运行的呢?比如说最简单的引脚初始化语句,在Arduino里是pinMode()语句,51或者32里面是GPIO_Init()之类的语句。可能刚开始学的时候就单纯的记住这句话可以用来初始化引脚,让引脚可以读取或者输出电平。但是细想之后就会发现,无论是单片机还是电脑里的CPU,内部的数据都是在寄存器里,而寄存器只能存储0和1.那么,究竟这条语句是如何将我们熟悉的C语言命令转换为机器可读的单片机指令的呢?这就是底层的驱动程序。
那么相应的,线性CCD也有自己驱动方式,只有为引脚在适当的时刻加上合适的电压才能正确的输出我们想要的检测值出来,这是我们编写线性CCD驱动的基础。
再将之前呢,首先呢笔者要给各位读者灌输一个概念:我们是做项目开发的而不是研发(注意开发和研发的区别),因此我们是使用别人的产品去开发出新的东西出来。因此我们无需太多了解所用产品的内部原理和加工参数细节,就算想知道也没地方找,因为那都是人家公司的核心资料,发布出来公司就倒闭了不是?我们只要根据厂家提供的Datesheet(可以理解为产品说明书吧),知道每个引脚的作用和功能即可,学会如何操作即可。
那下面我们进入正题,分析时序图!
时序图分析是数电中一大重点,其实数电这么课最重要的不是那些编码器、译码器,最重要的就是分析时序图的本领,希望读者可以真的学会如何学习大学里的知识。
图2.1 时序图
图2.1是模块的时序图,TSL1401CL一共有八个引脚,出去两个没用的空引脚外,还有一个VCC和两个GND引脚用于供电,剩下三个引脚就是最关键的控制引脚CLK、SI、AO。这里解释以下CLK引脚的功能,因为几乎所有的地方都会见到这个单词,根据字面意思理解,它是引文时钟Clock的缩写,作用和字面意思一样是为芯片提供一个时钟信号,让其根据这个时间速度工作。可能读者看到这里有点模糊,笔者刚开始学的时候看到这些解释也很不理解,但是没关系,你很幸运,拿到了笔者谢的开发笔记,哈哈。笔者在这里举一个例子。加入你在上课,老师要求你每听到一个英文单词时就记录下来,那么老师讲的英文单词就是CLK的电平的一次上升和下降(假设老师说单词的时候是高电平,那么说完之后安静的那段时间就是低电平),你去记录单词就相当于芯片去执行一条命令或者操作。那老师说单词的速度越快,相应的来说你工作的速度就越快。不知读者读完这句话后是否明白了呢。
下面我们对时序图展开分析。我们看到CLK时钟一直是一条规律的脉冲信号,而SI引脚只出现了一个短暂的脉冲,那么此时读者就需要注意了,因为这个特别的高电平脉冲肯定有着什么特别的作用。我们再看AO引脚,当SI出现了高电平脉冲后,相应的AO引脚就开始不断对外输出电压信号,可以看到,一直连续输出了128个时钟周期,那么对应的就是128个检测点的时钟信号。需要注意的是SI高电平出现的时间,看图发现,SI高电平出现的主要部分都集中在了CLK信号的低电平时间,那么当CLK信号再一次出现高电平并且SI仍为高电平时,AO就开始对外发送信号,所以,掌握时间节点很重要。
单片机或者开发环境下的线性CCD的驱动程序编写。
下面就对代码逐条分析。
首先需要在说一点,线性CCD是根据光照的一个储能元件,他会根据光照强度的不同电容器储存电荷的速度不一样,但是由于电容大小非常小,也就是说不管速度相差多大,在很短的时间内所有的电容器都会被充满,速度可能比我们眨一下眼睛还要快,因此我们在使用时,需要做的第一步就是先把电容器中的电荷全部释放出来,也就是先读取一边当前各个监测点的电压值,但是数据不保存,读取后全部扔掉即可,就是我们所说的丢包,只不过这是我人为的而已。
先看前三条代码:
int exp_time = 5000;
int piexl[129];
int i = 0;
首先定义一个变量exp_time,该变量用来存储曝光的时间,后面会用到。接着我们定义了一个129个元素的数组。可能读到这里读者会有一个疑问,那就是,为什么是129个而不是128个,不是说只有128个检测点吗,多出来的一个是存放什么的呢?多出来的一个肯定不是用来放着好玩的啦,它的作用是存放结束位。为了方便调试,开发者们编写了一个上位机软件,可以将输出的值转化成灰度图显示给读者看。但是计算机如何知道哪里是数据的开头,哪里是结尾呢,就看最后一个结束位,其值为FF。当检测到这个值时上位机就认为一个数组被读取到了。变量i是为for循环工作用的,不必多理会。
再看接下来的四条代码:
digitalWrite(CCD_SI,HIGH); //SI拉高电平
digitalWrite(CCD_CLK,HIGH); //时钟高电平
digitalWrite(CCD_SI,LOW); //SI低电平
digitalWrite(CCD_CLK,LOW); //时钟低电平
这四条代码就很关键,这四条代码模拟的就是时序图中的时钟脉冲和SI信号,具体笔者就不再细讲,读者可以自行参考上文。不过需要注意的是,这四条代码就是让CCD开始输出信号的关键,因此需要读者仔细理解体会其中意思。
下面是将CCD中已经积累的电荷释放掉。
for(i=0;i<128;i++)
{
digitalWrite(CCD_CLK,HIGH);
digitalWrite(CCD_CLK,LOW);
} //从这里完成电压的释放
通过一个for循环,不断模拟CLK时钟信号,让CCD中存储的电压值全部释放出来,以防干扰到后续检测,重新存储电压值。
下面才真正的将检测信号输出并存储到数组之中。
digitalWrite(CCD_SI,HIGH);
digitalWrite(CCD_CLK,HIGH);
digitalWrite(CCD_SI,LOW);
digitalWrite(CCD_CLK,LOW);
for(i=0;i<128;i++)
{
digitalWrite(CCD_CLK,HIGH);
piexl[i]=analogRead(A0);
digitalWrite(CCD_CLK,LOW);
}
同样四条代码开始对外输出数据。
接着下面的for循环是模拟CLK时钟信号。请读者注意和上方for循环的不同,这里的for循环里多了一条数组赋值语句,这里才将输出的值存储到数组之中,用以调用。
代码例程下载:链接:https://pan.baidu.com/s/1QBpWVemWZ2lzCGboJ2ExMw
提取码:6ca5