` 本帖最后由 goyuqinghua 于 2014-10-24 16:53 编辑
一、目标 实现用笔在点阵屏上写字。
点阵手写屏主要由三个部分组成:行扫描电路、列扫描电路、光笔检测电路,原理框图如下图所示。这里所使用的光笔里面安装了一个光敏传感器,用来检测点阵上点的状态。 分析如下: 1、 行扫描 依次使译码器的Y0、Y1……有效,而74ls138输出有效时是低电平,而我们用的点阵屏是共阳的,因此需要把它取反,本设计使用PNP三极管取反。每8个列扫描进行一次行扫描。 2、 列扫描 依次使译码器的Y0、Y1……有效,并且在OE1上输入PWM信号,当OE1为高电平时Y0~Y7电平全为高电平,当OE1为低电平时,译码器的输出由ABC三个引脚来决定。当选中某一行时我们依次选中Y0、Y1……,并且每个LED灯的亮度由OE1调节。 3、 光笔 把比较器反相输入端的参考电压设置在某一个值,并且在当光笔接收到光时同相输入端的输入电压会小于这个值,当光笔没有接收到光时同相输入端的输入电压会大于这个值。当光笔没有接收到光时通过R3的电流非常小,因此输入到比较器的同相输入端的电压会接近 电源电压,此时比较器输出高电平,当光笔接收到光时通过R3的电流会增大,则R3两端的电压会增大,因此输入到比较器同相输入端的电压会减小,此时比较器输出低电平,这时 单片机可以捕获这个变化然后做相应的处理。 三、程序分析 要想检测到点阵上的点我们必须点亮点阵上的LED,并且使它处于微亮状态,当光笔触碰到某个点时,就把这个点设置为高亮。那么我们如何知道要点亮的这个点的坐标呢?原理是这样的:让LED逐个点亮,首先第一行第一个,然后第一行第二个,……,到第一行最后一个时再转到第二行第一个,LED这样循环的依次点亮,并且每一个LED设置一个状态值,比如这个值为0时代表微亮,为1时代表高亮。当光笔触碰到某个点时若还没有轮到这个LED点亮,由于光笔没有检测到光因此光笔的输出保持高电平,当轮到点亮这个LED点亮时由于光笔检测到了LED发出的光,因此光笔的输出由高电平变为低电平,当单片机检测到这个电平变化时就进入中断程序,并且获取当前的行、列值,并通过这个行、列值修改这个点的状态值为1,让下一次轮到这个点点亮时就通过判断这个状态值设置为高亮状.态。当把扫描速度加快时我们就看到是整个点阵屏都是亮起来的了,而不是一个一个点亮了。
参考程序如下 #include
#define COL 1 #define ROW 2
int col = 0; //标记当前扫描到的行 int row = 0; //标记当前扫描到的列 int ledState[8][8]; //标记当前LED的状态
/* haveUpdate用于消除光笔输入的抖动,当获取到的光笔信号有下降沿的时候就更新数据,*并且把这个标志设置为1表示已经更新了数据,然后打开定时器定时,在下一次抖动的时 *候由于已经更新了数据从而忽略抖动,当定时时间到的时候重新设置这个标志位的值为0 */ int haveUpdate =0; void setup() { memset(ledState, 0, sizeof(ledState)); //把所有状态值都清零 initPort(); //初始化端口 TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS20); //不分频 OCR2A = 100; OCR2B = 99; //占空比为99% attachInterrupt(0, externInterrupt, FALLING );//设置外部中断为下降沿中断
cli(); //关闭所有中断 TCCR1A=0; //寄存器A是配置PWM的,这里我们只是使用定时功能 TCCR1B=(1< TCNT1=0xFE79; //计数器初值,25ms定时 sei(); //开全局中断 }
ISR(TIMER1_OVF_vect){ //定时器中断服务程序 TIMSK1 = 0; //关闭溢出中断使能 haveUpdate = 0; //重置标志 }
void loop() { scan(); //循环扫描 }
void externInterrupt() //外部中断服务程序 { if(haveUpdate == 0){ ledState[row][col] = 1; //根据行和列标志当前检测到的点的状态 haveUpdate = 1; TCNT1=0xFE79; //计数器初值,25ms定时 TIMSK1 =(1< } }
void initPort() { inti, startPin = 4;
for(i=0; i<10; i++){ pinMode(startPin+i, OUTPUT); } setData(COL, 0x00); setData(ROW, 0x00);//设置行和列都为0
pinMode(3, OUTPUT); }
void setData(int flag, int data) { inti, startPin;
if(COL == flag){ startPin = 4; }else{ startPin = 7; } for(i=0; i<3; i++){ digitalWrite(startPin+i, (data & (1< } }
void scan() { for(row=0; row<8; row++){ setData(ROW, row); for(col=0; col<8; col++){ setData(COL, col); if(ledState[row][col] > 0) OCR2B = 1; else OCR2B = 98; delayMicroseconds(300); OCR2B = 98; } } }
`
|