`
本帖最后由 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;
}
}
}
`
回帖(7)
2014-10-31 13:51:33
挺 好玩的,我在哪可以买到模块试一下啊?
挺 好玩的,我在哪可以买到模块试一下啊?
举报
2016-4-25 23:23:39
请问一下_BV()语句是什么意思啊?
请问一下_BV()语句是什么意思啊?
举报
2016-7-23 15:51:03
楼主做的好高端呀,我看到点阵完全没想到居然还可以作为手写屏。厉害,厉害,厉害!!!

楼主做的好高端呀,我看到点阵完全没想到居然还可以作为手写屏。厉害,厉害,厉害!!!

举报
2016-8-1 16:05:37
可不可以进一步把笔去掉啊?这样太高端啦!!
可不可以进一步把笔去掉啊?这样太高端啦!!
举报
更多回帖