61阅读

led点阵书写显示屏-led点阵显示屏原理是什么?

发布时间:2017-12-28 所属栏目:led点阵书写显示屏

一 : led点阵显示屏原理是什么?

请差距led点阵显示屏的原理是什么?显示屏要怎么设计才行?目前市场价大概是多少?

led点阵显示屏原理是什么?的参考回复

由16块8x8LED点阵拼合而成,可同时显示4个汉字。8片74HC595完成显示屏的列驱动。两块电路板之间用  40芯的排线连接。在CPU的内部RAM开辟一块显示缓存区.CPU控制板读取flash内部的汉字点阵编码,写入到显示缓存区。然后读取显存中第一行数  据,通过ISP接口驱动74HC595,将串行数据转为并行,然后将接通对应的行,显示1ms后,取下一行的数据,同样显示1ms,直到第16行,完成一  次扫描。再把显存中的数据整体左移一位,再扫描一遍。如此把全部的汉字依次移人显存并显示,便实现了汉字从右向左移,全部汉字移完后对时间、温度和安全天  数的寄存器刷新一次

遥控器用的是成品电视机遥控器,按电源键,显示“调年××××”同时被调  整的位闪烁,按音量“+”相应的位向上加,加到9后,回到0。按频道“+”,则改变被调整的位。

(www.61k.com)

同时对应的位闪烁。

再次按电源键,依次显示“调月××”.“调  日××”,“星期××”,“调  时××”,“调分××”.“调  天××××”,结束。


LED阵列的显示方式是按显示编码的顺序,一行一行地显示。每一行的显示时间大约为4ms,由于人类的视觉暂留现象,将感觉到8行LED是在同时显示的。若显示的时间太短,则亮度不够,若显示的时间太长,将会感觉到闪烁。本文采用低电平逐行扫描,高电平输出显示信号。即轮流给行信号输出低电平,在任意时刻只有一行发光二极管是处于可以被点亮的状态  ,其它行都处于熄灭状态。

为了方便调试本文把4块8*8组成的16*16的点阵屏的行信号扫描输出管脚和列信号显示输出管脚分别引到显示屏的两边。


LED显示的时候是按照编码的不同来进行显示的,一般都是一行一行的显示,原理方面就是通过点阵信号来进行控制。


点阵式汉字LED显示屏电路原理图及单片机程序:

程序清单:

ORG    00H

LOOP:  MOV  A,#0FFH  ;开机初始化,清除画面

MOV  P0,A        ;清除P0口

              ANL  P2,#00      ;清除P2口

MOV  R2,#200

D100MS:  MOV  R3,#250  ;延时100毫秒

              DJNZ  R3,$

              DJNZ  R2,D100MS

              MOV  20H,#00H  ;取码指针的初值

l100:        MOV  R1,#100  ;每个字的停留时间

L16:        MOV  R6,#16  ;每个字16个码

              MOV  R4,#00H  ;扫描指针清零

              MOV  R0,20H  ;取码指针存入R0

L3:        MOV  A,R4      ;扫描指针存入A

              MOV  P1,A      ;扫描输出

              INC  R4            ;扫描指针加1,扫描下一个

              MOV  A,R0      ;  取码指针存入A

              MOV  DPTR,#TABLE  ;取数据表的上半部分的代码

              MOVC  A,@A+DPTR

              MOV  P0,A      ;  输出到P0

              INC  R0            ;取码指针加1,取下一个码。

              MOV  A,R0

              MOV  DPTR,#TABLE  ;取数据表下半部份的代码

              MOVC  A,@A+DPTR

              MOV  P2,A                    ;输出到P2口

              INC  R0

MOV  R3,#02                ;扫描1毫秒

DELAY2:    MOV  R5,#248        ;

              DJNZ  R5,$

              DJNZ  R3,DELAY2

              MOV  A,#00H          ;清除屏幕

              MOV  P0,A

              ANL  P2,#00H

              DJNZ  R6,L3              ;一个字16个码是否完成?

              DJNZ  R1,L16            ;每个字的停留时间是否到了?

              MOV  20H,R0            ;取码指针存入20H

              CJNE  R0,#0FFH,L100  ;8个字256个码是否完成?

              JMP  LOOP  ;反复循环

二 : 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计

第一章概述

LED点阵显示屏是通过PC机将要显示的汉字字模提取出来,并发送给单片机,然后显示在点阵屏上,主要适用于室内外汉字显示。(www.61k.com)

第二章硬件设计

2.1主要器件介绍

LED 点阵显示屏是由20 个8*8 的LED 点阵块组成,形成16*80 矩形点阵,以Atmel 公司的AT89S52单片机为控制核心。显示屏的其他主要硬件有:①带锁存输出的8位移位寄存器74HC595,作为LED的列线驱动输入;②三八译码器74LS138,作为LED行线的译码选择;③三极管C9012,连接两个三八译码器的十六个输出端,作为开关使用,驱动LED 的行线

2.2主要器件详细连接说明

at89s52引脚 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计

Atmel的AT89S52芯片相关器件连接的接脚如下:P00-P03连接3-8译码器的输入口A,B,C,~G2A

at89s52引脚 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计P20-P23连接74HC595的输入口RCK, SI,SCK,SCLR

三八译码器74LS138的16 个输出端连接16 个C9012的三极管的基极B,发射极E 连接16 个行线控制端,集电极C连接到GND。

点阵的80 列数据线驱动由10 片74HC595 级联组成,前一片74HC595 的Q’H 引脚连接

下一片的SI引脚,各片的RCK、SCK、SCLR 分别并联。

2.3 LED点阵块

8*8的LED点阵为单色行共阳模块,单点的工作电压为正向(Vf)=1.8 v ,正向电流(IF)= 8-10 mA 。静态点亮器件时(64 点全亮)总电流为640mA,总电压为1.8 v,总功率为1.15W。动态时取决于扫描频率(1/8或1/16秒),单点瞬间电流可达80-160 mA。16*16点阵静态时16*16*10mA,动态时单点电流80-160mA。

接线方式:

当某一行线打高时,某一列线为低时,其行列交叉的点就被点亮;

某一列线为高时,其行列交叉的点为暗;

当某一行线打低时,无论列线如何,对应这一行的点全部暗。

at89s52引脚 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计

列线:13—20控制点阵的列接低电平

行线:1-4 21-24控制点阵的行接高电平

2.4 AT89S52

at89s52引脚 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计at89s52引脚 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计

(1)P0.0【39 脚】,P0.1【38 脚】,P0.2【37 脚】,P0.3【36 脚】接两片3-8译码器的A,B,C和第一片的~G2A 与第二片的G1,用来选择LED的行线

(2) P2.0【21 脚】:接74HC595的RCK脚。

P2.1【22 脚】:接74HC595的SCK脚。

P2.2【23 脚】:接74HC595的SI脚。

P2.3【24 脚】:接74HC595的SCLR脚。

(3) 其他

VCC 【40 脚】:接电源

EA/VPP【31 脚】:接电源

RST 【9脚】:复位脚。过10K电阻接GND,过10uF的电容C3接VCC;复位按钮接到电容C2两端。

2.5移位寄存器74HC595

74HC595是带锁存输出的8位移位寄存器,其管脚见下图,其中SI是串行数据的输入端;

VCC、GND分别为电源和地;RCK是存储寄存器的输入时钟,SCK是移位寄存器的输入时钟,SCLR是移位寄存器的输入清除,Q’H是串入数据的输出,G是对输入数据的输出使能控制,QA~QH串入数据的并行输出。从SI口输入的数据在移at89s52引脚 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计

位寄存器的SCK脚上升沿的作用下输入到74HC595中,在RCK脚的上升沿作用下将输入的数据锁存在74HC595中,当G为低电平时时,数据并行输出。SCLR为移位寄存器的输入清除端。

74HC595与AT89S52的连接:SI【14脚】,SCK【11脚】,RCK【12脚】, SCLR【10脚】分别接到AT89S52的P2.2【23脚】,P2.1【22脚】,P2.0【21脚】,P2.3【24脚】上。

其他脚连接:OE【13脚】接地,使其始终输出;

Q’H【9脚】是连接下一片74HC595的SI脚;QA,QB到QH分别连接到LED点阵的1至8列的列线脚上.

2.6 三八译码器74LS138

at89s52引脚 我的第一篇日志-基于AT89S52的单片机的LED点阵显示屏的设计

图所示的是将两片74LS138译码器扩展为4线-16线译码器的连接图。其接线特点为:将四个输入信号~G2A,C,B,A中的低三位C,B,A同时接至两个芯片的地址输入端。输入信号的最高位~G2A接至两个芯片的使能端,使两个芯片不能同时工作。~G2A,C,B,A作为地址输入变量构成二进制代码,Y0~Y7、Y0~Y7作为输入信号,每个输出表示一个二进制代码的含义,即能实现4线-16线译码器的功能。

第三章 软件设计

3.1单片机的程序设计

单片机在LED点阵显示系统中主要负责数据的接收、存储和扫描显示LED点阵屏三大主要功能。

/*************************************************************************************************** * Name: khldragon * Date: 09/12/2009 * Description: This program controls 16*80LED and implements dynamic scan. ****************************************************************************************************/ #include <AT89X52.h> #include <intrins.h> #define CONIO P0 //行选信号 #define NUMOFWORDS	(6) //显示的字数 #define SPEED (30) //扫描周期 SPEED越大,扫描越慢; #define MAXWORDS (5) //屏幕最大固定显示字数 #define BLANK (4) //填充空数 #define MAXROW (16) //最大行数 static sbit OE =	P0^4; //控制74LS138,低电平有效 static sbit RCK	=	P2^0; // 上升沿时数据输出 static sbit SCK	=	P2^1; //上升沿时数据移位 static sbit SI =	P2^2; //74hc595串行输入 static sbit SCLK	=	P2^3; //低电平移位寄存器清零,通常接VCC static void send_in(unsigned char Data); //串行数据输入 static void send_out(void); //并行数据输出 static unsigned int row	=	0; //行选信号 static int j =	0; static int k =	0; static int m =	0; static int s =	0; //与SPEED匹配 static int count	=	0; //当为5时达到最大字数MAX const static unsigned char code zimo[][32]={ {0x20,0x08,0x13,0xFC,0x12,0x08,0x02,0x08,0xFE,0x08,0x0A,0x08,0x12,0x08,0x3B,0xF8,  0x56,0xA8,0x90,0xA0,0x10,0xA0,0x11,0x20,0x11,0x22,0x12,0x22,0x14,0x1E,0x18,0x00},//祝 {0x00,0x80,0x20,0x80,0x20,0x80,0x20,0x80,0x20,0x88,0x24,0x98,0x3E,0xA0,0x20,0xC0, 0x20,0x80,0x20,0x80,0x20,0x80,0x20,0x82,0x26,0x82,0x38,0x82,0x60,0x7E,0x00,0x00},//比 {0x01,0x00,0x7F,0xFE,0x44,0x42,0x9F,0xF4,0x04,0x40,0x1F,0xF0,0x04,0x40,0x7F,0xFC, 0x08,0x20,0x1F,0xF0,0x28,0x2E,0xC9,0x24,0x09,0x20,0x01,0x00,0x06,0xC0,0x18,0x30},//赛 {0x00,0x80,0x00,0xA0,0x00,0x90,0x3F,0xFC,0x20,0x80,0x20,0x80,0x20,0x84,0x3E,0x44, 0x22,0x48,0x22,0x48,0x22,0x30,0x2A,0x20,0x24,0x62,0x40,0x92,0x81,0x0A,0x00,0x06},//成 {0x00,0x80,0x00,0x80,0x08,0x80,0xFC,0x80,0x10,0x84,0x17,0xFE,0x10,0x84,0x10,0x84, 0x10,0x84,0x10,0x84,0x1D,0x04,0xF1,0x04,0x41,0x04,0x02,0x44,0x04,0x28,0x08,0x10},//功 {0x00,0x00,0x01,0x80,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x01,0x80, 0x01,0x80,0x01,0x80,0x00,0x00,0x01,0x80,0x03,0xC0,0x01,0x80,0x00,0x00,0x00,0x00},//! }; void main() { 	//初始化引脚 	CONIO = 0X00; 	P2 = 0X08; /**********************************动态扫描左移显示不限字数***************************************/ 	while(1) 	{  for(k = 0; k < NUMOFWORDS; k++)  {//扫描NUMOFWRODS遍  for(s = 0; s < SPEED; s++)  {  for(row = 0; row < MAXROW; row++)  {  count = 0;  //将要显示的字,送入74HC595的SI端,即单片机的P2^2引脚  for(j = k; j >= 0; j--)  {  count++;  if(count > MAXWORDS)  break;  send_in(zimo[j][2*row+1]);  send_in(zimo[j][2*row]);  }  //填充空白  for(m = BLANK-k; m > 0; m--)  {  send_in(0);  send_in(0);  }  send_out();  CONIO=row;  }  }  } //下面程序逻辑同上,只是换下位置  for(k = 1; k <= MAXWORDS; k++)  {  for(s = 0; s < SPEED; s++)  {  for(row = 0; row < MAXROW; row++)  {  for(m = k; m > 0; m--)  {  send_in(0);  send_in(0);  }  for(j = 1; j <= MAXWORDS - k; j++)  {  send_in(zimo[NUMOFWORDS-j][2*row+1]);  send_in(zimo[NUMOFWORDS-j][2*row]);  }  send_out();  CONIO=row;  }  }  } 	} } /***************************************************************** ** 函数名:void send_in(unsigned char data) ** 输 入:unsigned char data ** 输 出: void ** 功能描述: send data to 74hc595 ** 全局变量: SCK SI ** 调用模块:main() ** 作 者:khldragon ** 日 期:09/12/2009 ** 版本version1.0 ****************************************************************/ void send_in(unsigned char data) { 	unsigned char i;  for(i = 0; i < 8; i++) {	//循环8次,刚好移完8位  SCK = 0; //先将移位寄存器控制引脚置为低  SI = Data & 0x01; //取数据的最低位,form: little endian  Data >>= 1; //将数据的次高位移到最高位  SCK = 1; //再置为高,产生移位时钟上升沿,上升沿时数据寄存器的数据移位  _nop_(); 	} } /***************************************************************** ** 函数名:void send_out(void) ** 输 入:void ** 输 出: void ** 功能描述: send data to led ** 全局变量: RCK ** 调用模块:main() ** 作 者:khldragon ** 日 期:09/12/2009 ** 版本version1.0 ****************************************************************/ void send_out(void) { 	RCK = 0; //先将存储寄存器引脚置为低 	_nop_(); 	_nop_(); 	RCK = 1; //再置为高,产生移位时钟上升沿,上升沿时移位寄存器的数据进入数据存储寄存器,更新显示数据。 	_nop_(); 	_nop_(); 	RCK = 0; //先将存储寄存器引脚置为低 }

第四章总结

在 LED 点阵汉字显示屏的设计过程中,学到了很多东西,基本了解了整个嵌入式开发的流程。

例如,在焊接电路板的时候,应该从最基本的最小系统开始,分模块,逐个进行焊接测试。在对各个硬件模块进行测试时,要保证软件正确的情况下去测试硬件,要不然发生错误时,不知道到底是哪一方出错了。当然,在设计的过程中也存在着失误和不足。例如,在进行搭试点阵块的时候,因为电压过高,导致点阵块损坏。这次设计开发,本人受益非浅,在以后的开发过程中一定吸取教训。

三 : 电子设计大赛-LED点阵书写显示屏(总结)

今天终于决定要为这次电赛写点小结了。

遗憾.....

2010/05/14

历经了三个晚上的通宵,白天也逃课了。究竟还是没把电路板做出来...遗憾....QG那边那台刻板机,刻我电路板中的其中一面就需要5、6个小时,而且还刻不成功,最后是因为担心已经轴心磨损的刻板机再这样持续工作下去会坏掉而放弃刻板。那时我的心情很是沉重,因为电路板这一环节的失败就意味着之前的所有努力与成果都是枉然,没有电路板作载体,再好的系统工作方案、再好的程序也得不到体现...眼看这二十多天的努力频临死亡心里真不是滋味。(end)

2010/05/15

已经放弃了采用刻板机来制作电路板,而今天却意外的发现工一某间室可以帮我激光打印热转印纸。之前我跑遍了半个大学城都找不到可以帮我激光打印热转印纸的地方(手工制作电路板的方法其中一种叫热转印法,需要激光打印机把高密度抗腐蚀碳粉打到热转印纸上面去,再热转印到覆铜板上去)。我抱着努力到最后的心态去打印了几张热转印纸。或许是热转印纸的质量问题,每次打印都会受热过度而卷缩(南亭的小赛格真不卖好东西,铜板又贵又不平整、甚至还双面导电!),以致线路不完整,没办法了,总比没有好,线路不完整就用油性笔补呗...

到最后,试验品(小铜板)腐蚀的效果很好,线路很完整。大铜板(20cmX17CM)估计因我只用砂纸打磨了一下,没有用酸性液体预处理过,热转印效果不怎么样,最后断线的地方不少,这样一直补线,(同时,晓光在把另一块从QG那边刻板机做出来的失败品的线路进行抗腐蚀的划线和断线的处理)直到下午五点多,已经超过了作品上交时间...这也意味着我们这次比赛以遗憾告终了....(end)

虽然这次比赛是不成功了,但作品还可以继续做下去,这样可以当做我们的一次项目经验。我是这么认为的:拿不了奖也没关系,以后拿奖的机会还多。最重要的是在比赛中使自己得到锻炼,能力得到提升。不过这下子要得找个更好的手工制作电路板的方法。这热转印法太依赖于特定的机器(激光打印机)了 ,万一以后他不帮我们打了那我们就麻烦了。 (感叹:如果我能早点发现这里可以帮我进行激光打印,那我的电路板或许早就做出来了!不过,人能有多少个“如果”?)

另外,我觉得我自己对这次比赛的时间安排得不太好:大概是4月15号公布题目,直至4月底我才把系统详细的最优工作方案写了下来 (可惜这段时间只有我一个人在做,宇曦老是说没头绪,天天在打PSP和看小说,而晓光也刚学单片机没多久。不然,大家能好好合作的话相信速度会更快!)。大概是4月28号左右吧,我把LED屏驱动板的原理图画好后(即系统工作方案已经定下了、元器件也选好了) ,宇曦也帮忙布线。

这样直到5月1号,宇曦回家了(5月7/8号回来),晓光也回家了(貌似是5月5号回来的吧,忘记了),那惨了,留下我一个寂寞的孩子在孤军作战.....于是我不甘寂寞,5月1号跟女朋友出去玩了......接下来几天,我的主要工作是写程序。在宇曦回来之前,貌似我剩下几个函数还没写:最头大的一个“对象拖移”函数还有其他几个小函数。宇曦回来后,我把对象拖移交给他写了(你是数据结构上的“刷题哥”啊,所以,这种算法难度高的事就拜托你了!没时间了,我弄其他的驱动去)。(感叹:如果早期宇曦能积极点就好!)

接下来在最后的那几天,大家都积极了,我们一起把主控板、光笔的PCB图都设计好。我忘记了自己什么时候把程序调得通过编译了....同时,我在另一块开发板上测试通过了一些诸如延时函数(该单片机是1T单片机,用同样的晶振,速度却是普通51单片机的8~12倍,好东西!)、AD扫描(STC12C5A60S2单片机P1.0~P1.7内置8路10位高精度AD模块)等等的函数。那时候眼看形势发展得还可以,真没想到在最后我们会败在电路板的制作上面....

最后,我说说我们这个作品的设计方案,有兴趣的童鞋们可以看看:

首先,是题目要求:

LED点阵书写显示屏
一、任务

设计并制作一个基于32×32点阵LED模块的书写显示屏,其系统结构如图1所示。在控制器的管理下,LED点阵模块显示屏工作在人眼不易觉察的扫描微亮和人眼可见的显示点亮模式下;当光笔触及LED点阵模块表面时,先由光笔检测触及位置处LED点的扫描微亮以获取其行列坐标,再依据功能需求决定该坐标处的LED是否点亮至人眼可见的显示状态(如图1中光笔接触处的深色LED点已被点亮),从而在屏上实现“点亮、划亮、反显、整屏擦除、笔画擦除、连写多字、对象拖移”等书写显示功能。

控制器

32×32

LED

点阵模块

光笔

led点阵书写显示屏 电子设计大赛-LED点阵书写显示屏(总结)

图1LED点阵书写显示屏系统结构示意图

二、要求

1.基本要求

(1)在“点亮”功能下,当光笔接触屏上某点LED时,能即时点亮该点LED,并在控制器上同步显示该点LED的行列坐标值(左上角定为行列坐标原点)。

(2)在“划亮”功能下,当光笔在屏上快速划过时,能同步点亮划过的各点LED,其速度要求2s内能划过并点亮40点LED。

(3)在“反显”功能下,能对屏上显示的信息实现反相显示(即:字体笔画处不亮,无笔画处高亮)。

(4)在“整屏擦除”功能下,能实现对屏上所显示信息的整屏擦除。

2.发挥部分

(1)在“笔画擦除”功能下,能用光笔擦除屏上所显汉字的笔画。

(2)在“连写多字”功能下,能结合自选的擦除方式,在30s内在屏上以“划亮”方式逐个写出四个汉字(总笔画数不大于30)且存入机内,写完后再将所存四字在屏上逐个轮流显示。

(3)在“对象拖移”功能下,能用光笔将选定显示内容在屏上进行拖移。先用光笔以“划亮”方式在屏上圈定欲拖移显示对象,再用光笔将该对象拖移到屏上另一位置。

(4)当环境光强改变时,能自动连续调节屏上显示亮度。

(5)当光笔连续未接触屏面的时间超过1~5min时(此时间可由控制器设定),能自动关闭屏上显示,并使整个系统进入休眠状态,此时系统工作电流应不大于5mA。

(6)其他。

三、说明

1.设计制作时所用LED点阵模块的发光颜色不限。

2.各种功能的切换方式自定,但应力求操作简便。

3.在各种功能的实际操作过程中,必要时可用按键或其他控制方式进行辅助。例如,“连写多字”时,写完一字后用自定义控制方式存入该字并清屏,然后再写下一字。

4.系统应采用5V单电源供电。

5.设计制作时应在电路板上留有系统耗电参数的测试点。

6.设计报告正文中应包括系统总体框图、核心电路原理图、主要流程图、主要的测试结果。完整的电路原理图、重要的源程序和完整的测试结果用附件给出。

分析:这个系统最核心的两个部分是:光笔扫描、LED屏幕显示。

题目所说的“微亮扫描”中的微亮意为:高速、短时间地点亮、熄灭每一个LED灯,利用人眼的“视觉停留效应”(貌似是这么个叫法),让人眼察觉不出LED灯的闪烁,人眼只会觉得它是在微亮。而题目中要求每秒光笔能至少划过并点亮20个点,那也意味着扫描一次光笔所在位置并让屏幕更新显示并延时的操作必须<=50ms,而且光笔位置的扫描所占的时间比必须远远<LED显示所占的时间比。这样,由于扫描过程中,光笔所在点的的LED灯亮的时间是非常短暂的,所以对光敏器件有两个要求:响应速度快、灵敏。于是我选用了3DU33光电三极管。tr、tf(电平的上升、下降变化所需最小时间)均小于5微秒,而且3DU33是对波长为880nm的近红外光反应最灵敏(LED屏上的LED灯也是红光灯),再加上3DU33在基极产生的光电流经过自身的放大能达到3ma左右,这电流足以让外接的8050(NPN三极管)进入深饱和,这样一来,光笔对光的反应时很稳定了。(结果我们做出来的电路板只有光笔,这光笔的外形挺像一架潜艇的,哈哈,我那笨拙的手工总是被宇曦笑,不过这光笔对光的反应还真的想预期那样非常稳定,而且对自然光没反应(抗自然光干扰))

另外,在光笔上,我安装了一个小按键(为了人性化而设计的),因为假如我把光笔对着LED屏却不想写字、或者写字过程中轻轻拖过LED屏的表面,在普通情况下都默认为写字。这样就不好了,我把按键装在人手大拇指最常按到的地方,这样,我真要写字时便自然而然的按下去了。这按键接到外部中断口(平时关掉外部中断用来作普通IO口用),这样,程序里面可以判断按键是否被按下而决定是否进行光笔扫描和数据更新了。另外,这按键还有一个好处,就是可以在空闲模式(待机)时按下唤醒整个系统,即我想写字时,随手用拇指按一下便可以写了,很人性化吧?呵呵~(至于这个按键的按键抖动,我接了个旁路电容去抖,再说,因为按键抖动时间比扫描一次并更新显示的50ms要小得多,所以可以忽略其带来的负面影响,负面影响几乎为0)。

关于这个光笔,最后我说说这个扫描方案,这几乎是这个系统的核心(以后的所有操作都有依赖于它):我最初的笨方案是一个一个点的扫描,没扫描一次就是1024个点,算法/操作时间复杂度为O(1024)。这是最笨最没效率的方法。后来改进了,把光笔接到普通IO口上去,每次选通一行LED,给该行中32列LED同步输出(用74HC573的输出使能控制可以做到)这32列的地址编码(0~31可以用5位二进制数表示,所以32列LED的地址编码都是5位数据),每次截取32列编码中的一位送出去,再读回光笔端口数据,共5位。这样马上就可以判断光笔所在列。可是,这样当光笔在第31列就分辨不出来了,因为扫描不在光笔当前所在行的话,数据与扫描在光笔所在行,而光笔在31列的效果一样,同样是11111(b)。而且这种方案的算法/操作时间复杂度为O(32*5)=O(160)。为了解决这个问题,我再加以改进了一下,把光笔接到定时器/计数器端口,并让计数器赋初值:65535-N,(N>=1)并把该定时器/计数器工作方式选为16位计数器。在每次的行扫描时同步给32列以N次高低脉冲(电平持续时间>=5微秒)。这样当行扫描切换到光笔当前所在行时,光笔电平从高到低跳变N次就可以触发计数器中断。N取指为2就可以有效地抗干扰了。进入计数器中断服务程序后,保持当前行选通并保存行数据,同步给32列以5次编码脉冲(电平的高低变化)。这样读回的5位数据就是光笔当前所在列坐标,保存,OK!这种改进的方案不仅解决了上述问题,而且提高了抗干扰性,还有一个更重要的是它的算法/操作时间复杂度仅为:O'(32*N+5),如果N取指为2,则时间复杂度为:O'(69),而且比起第二个方案,O(1)'<O(1)。因为采用计数器中断,所以比起第二个方案节省了很多CPU时间。

最后,我说说整个系统的构架。我是首先按照题目要求把实现的功能划分为两种性质:功能、和对功能的操作。

功能:必须时刻运行(不时刻运行也要间断运行,即在次数--时间坐标系上的表现是线性的)。

操作:不能预知什么时候运行,由使用者决定,即在次数--时间坐标系上的表现是离散的。

功能有如下:1、点亮与画亮 (即写字功能、开机默认)
2、多字连写
3、自动调光功能
4、超时待机功能

对功能的操作有如下:

1、反显(可对于功能1和功能2模块操作)
2、整屏擦除(可对于功能1和功能2模块操作)
3、光笔擦除(可对于功能1和功能2模块操作)
4、对象拖移(可对于功能1和功能2模块操作)
5、写字存储(可对于功能1和功能2模块操作)PS:由于时间问题,
而且这个功能题目没要求,暂先搁置
6、自动调光参数设置,即调整使用者喜好的屏幕亮度级别,

而同时,系统会在这个级别内对LED屏根据环境光强的变化而自动调光
7、超时待机时间设定

然后接下来就是程序了.........程序很长呢,不知道各位童鞋们看不看得下(因为我们一起干的宇曦、晓光说看不下,估计宇曦这家伙是懒得不愿意看),由于篇幅有限完整的程序和电路图请点这里:,完全测试通过,如有问题可与我联系.

四 : LED点阵书写显示屏的程序和电路图

最后补充一些总结性的东西:

失败:这次比赛看起来我们是败在那台刻板机上面。但实际这只是一方面而已,我们更多败在时间的分配不合理、早期合作的积极性不足以及功底不够之上。

所得:这次比赛,算是一次很好的锻炼了。我们从接手一个项目开始到设计方案到元器件的选用到程序的设计再到硬件和软件的调试(未能全部调试,因为板子都没做出来,只在另一个开发板上调试了部分程序),这都是很好的项目经验啊!我在这二十几天里也给自己补充了不少的模电数电知识....我认为得奖并不是我们最需要的,我们最需要的是使自己的水平得到提高。

展望:我们这个小组从原来的1个人变成两个人,再变成4个人,现在又多了3个(可惜原来的两个:周勋、永庆好像学不下去了)。剩下的童鞋们还有:宇曦、晓光、文迪、志安、当然还有我也是...志安是最新加入的。希望大家能好好发展!以后有什么项目什么比赛都能好好配合! 光有程序,没有硬件连接的示意难以看懂呢:先上图

LED驱动板PCB:

led点阵书写显示屏 LED点阵书写显示屏的程序和电路图


LED驱动板原理图:

led点阵书写显示屏 LED点阵书写显示屏的程序和电路图

光笔PCB:

led点阵书写显示屏 LED点阵书写显示屏的程序和电路图

光笔 原理图:

led点阵书写显示屏 LED点阵书写显示屏的程序和电路图

主控板PCB:

led点阵书写显示屏 LED点阵书写显示屏的程序和电路图

主控板 原理图:

led点阵书写显示屏 LED点阵书写显示屏的程序和电路图

////////////////////////////////////文件 myself.h///////////////////////////////////////////////////////////////#include<reg52.h>#define writting 0x01 //写字#define erasure 0x00 //擦除#define key_enter 1 //确定#define key_esc 2 //退出/取消#define key_words_modle 3 //多字连写#define key_light_level 4 //屏幕亮度级别#define key_sleep_time 5 //超时待机时间设定#define key_fanxian 6 //反显操作#define key_cachu 7 //擦除操作#define key_tuoyi 8 //对象拖移#define key_all_screen_del 9 //整屏擦除#define key_tuoyi_quxiao 10 //对象拖移内容选定后取消#define key_crease 11 //数据加一(待机时间、亮度级别)#define key_decrease 12 //数据减一//24M晶振#define _TH0_TL0_ (65536 - 50000) #define HI (_TH0_TL0_ / 256) //给高8位赋值#define LO (_TH0_TL0_ % 256) //给低8位赋值#define M 40 //(2000/50)1秒要50个中断的累计 typedef char (*size)[4]; //把size定义为一个指向32X4的二维数组首地址的类型typedef unsigned char uchar;extern size point[4]; extern uchar LED_CODE[5][4];extern uchar LED_ROW,LED_LINE;extern uchar ROW_TEMP; extern uchar KEYS; extern uchar li_level;extern uchar N;extern uchar men_lig;extern uchar sleepmin;extern uchar min,sec;extern uchar xdata LEDDATA0[32][4],LEDDATA1[32][4],LEDDATA2[32][4],LEDDATA3[32][4],LEDDATA4[32][4];void LED_GAI(uchar obj_mem[32][4],uchar opera,uchar LED_ROW,uchar LED_LINE );void one_word(uchar dat_addr[32][4],uchar caozuo);void sys_init(); void one_word(uchar dat_addr[32][4],uchar caozuo);uchar getkey();void lightlev(uchar showing[32][4]);void sleeptim(uchar showing[32][4]);void fanxian(uchar LEDDATA[32][4]);void delay_us(int us); void LEDcachu(uchar LEDDATA[32][4]);void obj_move(uchar led_data[32][4]);void fourwords();void fou_show();void dis_play(uchar show_obj[32][4]);void del_all(uchar obj[32][4]);void shu_ma_g(); //void daiji();void digital_show(uchar row,uchar line);void output();void input(uchar word);void saomiao();void light();//void input(uchar word);;////////////////////////////////////END/////////////////////////////////////////////////////////////// ////////////////////////////////////文件 main.c/////////////////////////////////////////////////////////////////*************************************************************************//作品:LED书写点阵显示屏//作者:陈宇曦 黄晓光 唐敏健//时间:2010/04~2010/05//主控器:IAP12C5A62S2(STC12系列)//晶振:24MHZ//功能模块分析:// 系统共有4个功能模块:// 1、点亮与画亮 (即写字功能、开机默认)// 2、多字连写// 3、自动调光功能// 4、超时待机功能// 而对上述功能的 操作 有:// 1、反显(可对于功能1和功能2模块操作)// 2、整屏擦除(可对于功能1和功能2模块操作)// 3、光笔擦除(可对于功能1和功能2模块操作)// 4、对象拖移(可对于功能1和功能2模块操作)// 5、写字存储(可对于功能1和功能2模块操作)PS:由于时间问题,// 而且这个功能题目没要求,暂先搁置// 6、自动调光参数设置,即调整使用者喜好的屏幕亮度级别,// 而同时,系统会在这个级别内对LED屏根据环境光强的变化而自动调光// 7、超时待机时间设定////联系人:唐敏健(15014225360/380467850@qq.com)////****************************************************************************#include"myself.h"#include<reg52.h>#include<intrins.h>uchar LED_CODE[5][4]= /*LED灯的列编码,每个LED灯的编码为5位数据(0到2^5),每次要给32列LED灯同步输出1位数据,共5次。*/ { /*这些数据由于操作频率高,故把它们定义在内部RAM中*/ 0X00,0X00,0XFF,0XFF, 0X00,0XFF,0X00,0XFF, 0X0F,0X0F,0X0F,0X0F, 0X33,0X33,0X33,0X33, 0X55,0X55,0X55,0X55 };uchar LED_ROW,LED_LINE,N; //存放当前光笔坐标的全局变量,系统初始化时把它设为99(任意一个大于32的数)uchar ROW_TEMP; //扫描时行坐标的”临时变量“(全局变量),以便进入中断后,LED_ROW=ROW_TEMP,保存起来uchar KEYS=0; //存储按下的按键编号,初始化为0,uchar li_level=10;uchar men_lig=10;uchar min=0,sec=0;uchar sleepmin=5; //默认超时5分钟待机//sbit pen_key=P3^3; //光笔按键P3^3是INT0,所以要在初始化阶段关闭外部中断0//sbit OUT_EN =P1^7;uchar xdata LEDDATA0[32][4],LEDDATA1[32][4],LEDDATA2[32][4],LEDDATA3[32][4],LEDDATA4[32][4]; //存放整屏数据的数组,屏幕数据量为32/8*32字节size point[4]; //二维数组的指针数组void delay_us( int us){ while(us>0) { _nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();//24条空操作指令为1US,现在为20条 us--; }}void main(){ uchar light_T; N=3; light_T=0; relay=0; point[0]=LEDDATA1;point[1]=LEDDATA2; point[2]=LEDDATA3;point[3]=LEDDATA4; //********************** //定时器1初始化 TL0 = _TH0_TL0_ % 256; TH0 = _TH0_TL0_ / 256 + (char)CY; TR0 = 1; //***************** //sys_init(); //系统初始化,把4个数组首地址放进point[4]中去 while(1) { one_word(LEDDATA0,writting); //扫描一个点并予以显示 KEYS=getkey(); //AD扫描按键,其实按键扫描1秒钟内进行10次足矣,不必跟随这个dis_play()做至少20次的扫描, //因为人的手不可能一秒内按键超过10次。 //调试时如果发现LED屏对光笔的反应比较慢,则需要修改getkey()在一秒内的时间占用比例, //即也意味着getkey()在一秒内的执行次数。可以这样:设定一个计数器,每dis_play()一次就+1,初值 //为0,到了1就清零,并且调用get_key(),否则不执行get_key().if(KEYS) //getkey()检测到按键按下就返回按键的值,没按键按下就返回0 { switch(KEYS) { case key_enter : break; //”确定“在这里没意义 case key_esc : break; //没得退出,已经是最底的一层了 case key_words_modle : fourwords();break; //进入多字连写功能 case key_light_level : lightlev(LEDDATA0);break; //调整屏幕亮度级别的参数 case key_sleep_time : sleeptim(LEDDATA0);break; //调整超时待机的超时时间 case key_fanxian : fanxian(LEDDATA0);break; //反显操作 case key_cachu : LEDcachu(LEDDATA0);break; //擦除操作 case key_tuoyi : obj_move(LEDDATA0);break; //对象拖移 case key_all_screen_del : del_all(LEDDATA0);break; // case key_tuoyi_quxiao : break; //”对象选定确认后取消“在这里没意义 case key_crease : break; //”数据+1“在这里没意义 case key_decrease : break; //”数据-1“在这里没意义 default : break; //没按键匹配的,直接退出。虽然在这里不发生,但安全起见加上去 } } KEYS=0; light_T++; if(light_T>5){light_T=0;light();} //一秒内自动调光4次左右 }} void one_word(uchar dat_addr[32][4],uchar caozuo) //一秒钟的一部分,大概是1/20秒。进行一个点的扫描并显示在LED屏上显示, //以及更新数码管的显示{ if(!pen_key) { saomiao(); //光笔上的按键被按下就扫描,光笔这里占时间笔也算是一个大块头,3DU33的 //响应时间保险点来计算大约需要延时5uS。这样,每次扫描按最坏打算则需要时 //长为:T=(5+5)*32*N+(5+5)*N=330N(uS).N为给32列LED的高->低变换次数,同时也为 //计数器计满溢出的次数。 LED_GAI(dat_addr,caozuo,LED_ROW,LED_LINE); //修改当前屏幕数据内容以便下面更新显示,writting意味着LED_GAI()函数 // 对LEDDATA1[LED_ROW][LED_LINE/8]中的第LED_LINE%8位数据作”与0“操作。 //因为给74HC595的输出端口低电平对应选通该列。 //而相反,假如参数为erasure,则对同样一位数据作”或1“运算 //另外,如果pen_key没被按下,那数据没更新就不用改了。 } else {LED_ROW=99;LED_LINE=99;} //当光笔上的按键没被按下,即使用者没打算写字时,把光笔当前坐标值显示为99,99. shu_ma_g(); //数码管更新静态显示 dis_play(dat_addr); //LED更新显示,不管扫描是否执行,LED屏肯定要显示,占用着时间,而且是占CPU的大部分时间 //以使人眼察觉不到闪烁,如果显示时长比例不>>扫描时长比例,那人眼将觉得LED在闪烁或微亮扫描 //(”不亮点“)太亮而显示内容(”亮点“)不够亮 //主要是这个函数分配好时间,以达到1秒钟至少扫描20次的效果} void LED_GAI(uchar obj_mem[32][4],uchar opera,uchar LED_ROW,uchar LED_LINE ){uchar temp,byteline,bitline; byteline=(LED_LINE-1)/8,bitline=(LED_LINE-1)%8; if(opera) //写,即对应位作“与0”运算 { temp=0X80; temp=_cror_(temp,bitline); obj_mem[LED_ROW][byteline]=obj_mem[LED_ROW][byteline]|temp; } else{ temp=0x7F; temp=_cror_(temp,bitline); obj_mem[LED_ROW][byteline]=obj_mem[LED_ROW][byteline]&temp; }} void Timer1() interrupt 3 { static unsigned char count = 0; //定义静态变量count TR0 = 0; //以下调整出栈入栈的时间误差 TL0 += (_TH0_TL0_ + 9) % 256; TH0 += (_TH0_TL0_ + 9) / 256 + (char)CY; TR0 = 1; count++; if(pen_key) if(KEYS==0) { sec=0; min=0;} //光笔不被使用,而且任何按键没被按下 else{ if(count>= 20)//1秒种时间到 { count = 0; sec++; if(sec == 60)//1分钟时间到 { min++; sec = 0; } } if(min>=sleepmin) relay=1;//关屏 }} ////////////////////////////////////END/////////////////////////////////////////////////////////////////////////// ////////////////////////////////////文件 自动调光.c///////////////////////////////////////////////////////////////#include"myself.h"#include<reg52.h>#include<intrins.h>void light(){ uchar finish,adc_result; //********************* //ADC_POWER_ON ADC_CONTER|=0X80; delay_us(1000); //1ms左右的延时 //********************* //********************* //选择模拟口(P1.2),即断开上拉电阻形成模拟口 P1ASF=0x04; //********************* //********************* //选择P1.2作为ADC转换通道 ADC_CONTER&=0XF0; //低三位清零 _nop_();_nop_();_nop_();_nop_();//让ADC_CONTER的数据稳定 ADC_CONTER|=0X03; //切换通道 delay_us(20); //延时20us使电压稳定 //********************* //********************* //取AD转换结果,ADRJ上电复位默认为0,即取高8位数据 ADC_RES=0XFF; //初始化为0XFF; ADC_CONTER|=0X08; //ADC_START _nop_();_nop_();_nop_();_nop_(); do{ finish=0X10; //0001 0000(b) finish|=ADC_CONTER; }while(finish); //等待AD转换完成 ADC_CONTER&=0XE7; //11100111,清ADC_FLAG和ADC_START,停止AD转换 adc_result=ADC_RES; //********************* if(adc_result>0x80)li_level=10; //R5549阻值在100K以上 else if(adc_result>0X71)li_level=9; //R5549阻值在80K~100K区间 else if(adc_result>0x60)li_level=8; //R5549阻值在60K~80K区间 else if(adc_result>0X49)li_level=7; //R5549阻值在40K~60K区间 else if(adc_result>0X2A)li_level=6; //R5549阻值在20K~40K区间 else if(adc_result>0X17)li_level=5; //R5549阻值在10K~20K区间 else li_level=4; //降到4级就好}void lightlev(uchar showing[32][4]){uchar key;uchar save_row=LED_ROW,save_line=LED_LINE; //用来保存数码管数据while(1) { key=getkey(); switch(key) { case key_esc : return;break; //退出 case key_crease : if(men_lig<10)men_lig++;break; //”数据+1“ 最大值为10 case key_decrease : if(men_lig>4) men_lig--;break; //”数据-1“最少值为4 default : break; //没按键匹配的,直接退出。虽然在这里不发生,但安全起见加上去 } LED_ROW=0x00;LED_LINE=men_lig; shu_ma_g(); dis_play(showing); LED_ROW=save_row;LED_LINE=save_line; }}////////////////////////////////////END///////////////////////////////////////////////////////////////////////////////////////////////////////////////文件按键扫描.c//////////////////////////////////////////////////////////#include"myself.h"#include<reg52.h>#include<intrins.h>uchar getkey(){ uchar key,finish,adc_result; //********************* //ADC_POWER_ON ADC_CONTER|=0X80; delay_us(1000); //1ms左右的延时 //********************* //********************* //选择模拟口(P1.0、P1.1),即断开上拉电阻形成开漏输出 P1ASF=0x03; //********************* //********************* //选择P1.0作为ADC转换通道 ADC_CONTER&=0XF8; //低三位置零,同时即选择P1.0 _nop_();_nop_();_nop_();_nop_();//让ADC_CONTER的数据稳定 delay_us(20); //延时20us使电压稳定 //********************* //********************* //取AD转换结果,ADRJ上电复位默认为0,即取高8位数据 ADC_RES=0XFF; //初始化为0XFF; ADC_CONTER|=0X08; //ADC_START _nop_();_nop_();_nop_();_nop_(); do{ finish=0X10; //0001 0000(b) finish=ADC_CONTER&finish; }while(!finish); ADC_CONTER&=0XE7; //11100111,请AD转换完成标志位,停止AD转换 adc_result=ADC_RES; //********************* if (adc_result<0xB3)//0xb3即3.5V,0XB3/0XFF*5=3.5 { if(adc_result>0x99)key=7; //>3v else if(adc_result>0X80)key=6; //>2.5v else if(adc_result>0X66)key=5; //>2V else if(adc_result>0X4C)key=4; //>1.5V else if(adc_result>0X33)key=3; //>1V else if(adc_result>0X19)key=2; //>0.5V else key=1; }else{ //********************* //ADC_POWER_ON ADC_CONTER|=0X80; delay_us(1000); //1ms左右的延时 //********************* //********************* //选择模拟口(P1.0、P1.1),即断开上拉电阻形成开漏输出 P1ASF=0x03; //********************* //********************* //选择P1.0作为ADC转换通道 ADC_CONTER&=0XF8; //低三位清零 _nop_();_nop_();_nop_();_nop_();//让ADC_CONTER的数据稳定 ADC_CONTER|=0X01; delay_us(20); //切换通道,延时20us使电压稳定 //********************* //********************* //取AD转换结果,ADRJ上电复位默认为0,即取高8位数据 ADC_RES=0XFF; //初始化为0XFF; ADC_CONTER|=0X08; //ADC_START _nop_();_nop_();_nop_();_nop_(); do{ finish=0X10; //0001 0000(b) finish|=ADC_CONTER; }while(finish); //等待AD转换完成 ADC_CONTER&=0XE7; //11100111,请AD转换完成标志位,停止AD转换 adc_result=ADC_RES; //********************* if (adc_result<0xB3)//0xb3即3.5V,0XB3/0XFF*5=3.5 { if(adc_result>0x99)key=14; //>3v else if(adc_result>0X80)key=13; //>2.5v else if(adc_result>0X66)key=12; //>2V else if(adc_result>0X4C)key=11; //>1.5V else if(adc_result>0X33)key=10; //>1V else if(adc_result>0X19)key=9; //>0.5V else key=8; } } return key;}////////////////////////////////////END/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////文件超时待机.c//////////////////////////////////////////////////////////#include"myself.h"#include<reg52.h>#include<intrins.h>void sleeptim(size showing){ uchar key; uchar save_row=LED_ROW,save_line=LED_LINE; //用来保存数码管数据 while(1) { key=getkey(); switch(key) { case key_esc : return;break; //退出 case key_crease : if(sleepmin<20)sleepmin++;break; //”数据+1“ case key_decrease : if(sleepmin>1)sleepmin--;break; //”数据-1“最小值为1 default : break; //没按键匹配的,直接退出。虽然在这里不发生,但安全起见加上去 } LED_ROW=0x00;LED_LINE=sleepmin; shu_ma_g(); dis_play(showing); LED_ROW=save_row;LED_LINE=save_line; }}////////////////////////////////////END/////////////////////////////////////////////////////////////////////////// ////////////////////////////////////文件 数码管显示.c//////////////////////////////////////////////////////////////////#include "myself.h"#include <intrins.h>#include <reg52.h>sbit RCLK_595=P2^5;sbit SRCLK_595=P2^6;sbit SER_595=P2^7; void shu_ma_g(){ digital_show(LED_ROW,LED_LINE);}void digital_show(uchar row,uchar line){ uchar one; one=line%10; input(one); _nop_();_nop_(); one=(line-one)/10; input(one); _nop_();_nop_(); one=row%10; input(one); _nop_();_nop_(); one=(row-one)/10; input(one); _nop_();_nop_(); output();}//将移位寄存器内的数据锁存到输出寄存器并显示void output(){ RCLK_595=0; _nop_();_nop_(); RCLK_595=1; _nop_();_nop_(); RCLK_595=0;}//;*****移位寄存器接收一个字节(如3FH)数据子程序 void input(uchar word){ uchar i; word=~word; //共阳,先取反 for(i=0;i<8;i++) { word=_cror_(word,1); SER_595=CY; SRCLK_595=0; _nop_();_nop_(); SRCLK_595=1; } SER_595=word;}////////////////////////////////////END///////////////////////////////////////////////////////////////////////////////////////////////////////////////文件 display.c/////////////////////////////////////////////////////////////////////////#include"myself.h"#include<reg52.h>#include<intrins.h>void dis_play(uchar show_obj[32][4]){ uchar row,line,temp_row,templine; for(row=0;row<32;row++) {OUT_EN=1; //锁止输出 temp_row=P2&0XE0; //保存P2高三位数据,低五位置零 P2=temp_row|row; //P2口低五位输出行选数据,高三位保持不变 for(line=0;line<4;line++) { templine=0X08; //p1.3=1,p1.4,p1.5,p1.6=0 只打开第一个锁存器的锁存使能,P1.3接第一个锁存器 //0X08=0000 1000B P1=P1&0X87; //P1&10000111 P1=P1|_crol_(templine,line); //保存了P1的0、1、2、7位,对3/4/5/6进行移位。 P0=show_obj[row][line]; //输出八位数据并锁存 _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_(); //延时500ns,让数据能顺利进入74HC573 } OUT_EN=0; //输出使能 delay_us(10*men_lig*li_level); //1MS左右的延时,row循环执行32次,即整个显示函数占时 OUT_EN=1; //30MS左右,而题目要求每秒钟至少扫描20次即平均分下来 delay_us(10*men_lig*(10-li_level)); //每扫描显示一次最多用时50MS } //**************************************延时,level调节占空比,即屏幕亮度 OUT_EN=0; //锁止输出}////////////////////////////////////END/////////////////////////////////////////////////////////////////////////// ////////////////////////////////////多字连写.c///////////////////////////////////////////////////////////#include"myself.h"#include<reg52.h>#include<intrins.h>void fourwords(){ uchar count; for(count=0;count<4;count++) { do{ //要是“确定”-----写下一个字、“esc”----退出多字连写模式,这两个没按下, //则把程序指针拖回这里来,不然FOR循环执行完了count就+1,即写下一个字了 //不要了 LCD_SHOW(); //1602的第一行显示当前模块,第二行进行操作提示,参数为提示内容的字符串首地址 one_word(point[count],writting); //扫描一个点并予以显示,在LEDDATA[count]内存区 KEYS=0; KEYS=getkey(); //AD扫描按键,其实按键扫描1秒钟内进行10次足矣,不必跟随这个dis_play()做至少20次的扫描, //因为人的手不可能一秒内按键超过10次。 //调试时如果发现LED屏对光笔的反应比较慢,则需要修改getkey()在一秒内的时间占用比例, //即也意味着getkey()在一秒内的执行次数。可以这样:设定一个计数器,每dis_play()一次就+1,初值 //为0,到了1就清零,并且调用get_key(),否则不执行get_key(). if(KEYS) //getkey()检测到按键按下就返回按键的值,没按键按下就返回0 { switch(KEYS) { case key_enter : break; //进入下一个数据区,即些下一个字,break退出后count+1 case key_esc : return; break; //返回最底层的点亮与画亮功能模式下 // case key_words_modle : break; //没反应,因为已经在多字连写功能下了 case key_light_level : lightlev(point[count]);break; //调整屏幕亮度级别的参数,这个功能可在任意模式下进入,同时返回也为进入前的当前模式 case key_sleep_time : sleeptim(point[count]);break; //调整超时待机的超时时间 ,同上 case key_fanxian : fanxian(point[count]);break; //反显操作 case key_cachu : LEDcachu(point[count]);break; //擦除操作 case key_tuoyi : obj_move(point[count]);break; //对象拖移 // case key_tuoyi_xuanding : break; //”对象选定确认“在这里没意义 // case key_tuoyi_quxiao : break; //”对象选定确认后取消“在这里没意义 // case key_crease : break; //”数据+1“在这里没意义 // case key_decrease : break; //”数据-1“在这里没意义 default : break; //没按键匹配的,直接退出。虽然在这里不发生,但安全起见加上去 } } }while(KEYS>=key_words_modle&&KEYS<=key_decrease); } fou_show(); //四个字写完了,重新显示出来。完了后退出返回点亮与画亮模式}void fou_show()//多字连写模式中的连续轮流显示4个字的函数,每个字显示1秒。4个字显示完之后便自动退出{ uchar words, times; //words为显示的第几个字,times为dis_play的执行次数,执行25次大约为1秒 for(words=0;words<4;words++) { for(times=0;times<25;times++) { dis_play(point[words]); } }}////////////////////////////////////文件 光笔扫描.c//////////////////////////////////////////////////////////////////////#include"myself.h"#include<reg52.h>#include<intrins.h>void saomiao(){ uchar tempsave,mod_save; uchar N_times; TR1=0;//关闭定时器1 OUT_EN=1; //先让锁止LED点阵显示 mod_save&=0XF0; TMOD|=0X06; //TMOD=XXXX 0110,计数器,八位自动重载 TH0=0XFF-N; TL0=0XFF-N; TR0=1; //开始对外负跳变脉冲进行计算,此时OUT_EN还是锁止输出 for(ROW_TEMP=0;ROW_TEMP<32;ROW_TEMP++) {tempsave=P2&0XE0; //保存P2高三位数据,低五位置零 P2=tempsave|ROW_TEMP; //P2口低五位输出行选数据,高三位保持不变 P0=0X00; //全亮 P1|=0X78; //P1|=0111 1000,573锁存全部打开 _nop_();_nop_(); for(N_times=0;N_times<N;N_times++) { OUT_EN=0; //亮 delay_us(5); //亮5us的延时 P1&=0X87; //P1&=1000 0111关闭锁存允许 OUT_EN=1; //灭 delay_us(5); //5us的延时 } } TR0=0; OUT_EN=1; TR1=1; //开启定时器1} void Timer0() interrupt 1 //定时器0中断服务程序{uchar templine,line,i,data_sav,result=0x00; LED_ROW=ROW_TEMP; //保存光笔行坐标 for(i=0;i<5;i++) { OUT_EN=1; for(line=0;line<4;line++) { templine=0X08; //0000 1000 p1.3=1,p1.4,p1.5,p1.6=0 只打开第一个锁存器的锁存使能,P1.3接第一个锁存器 //0X08=0000 1000B P1=P1&0X87; //P1&10000111 P1=P1|_crol_(templine,line); //保存了P1的0、1、2、7位,对3/4/5/6进行左移位。 P0=LED_CODE[i][line]; //输出八位数据并锁存 _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_(); //延时500ns,让数据能顺利进入74HC573 } OUT_EN=0; //573输出数据 delay_us(5); //延时5us,让光笔数据稳定 data_sav=P3&0X10; //0001 0000保存P3.4数据,准备移位 result|=_cror_(data_sav,5-i); //顺序得出5位数据,刚好当光笔所在列为0时(列选通),光笔数据为0;所在列为1时,光笔数据为1 } LED_LINE=result;}////////////////////////////////////END/////////////////////////////////////////////////////////////////////////// ////////////////////////////////////文件 对象拖移.c///////////////////////////////////////////////////////////////////#include "myself.h"#include <intrins.h>#include<reg52.h>#define CLICK P3^3#define X LED_ROW#define Y LED_LINEvoid enkey(uchar led_data[32][4],uchar x,uchar y); //将第x行第y列反显void mov(uchar a,uchar b,uchar c,uchar d);//a^b->c^dvoid obj_move(uchar led_data[32][4]){ struct zuobiao { uchar x,y; }start,end,go,pref; uchar temp,i,j,chang,kuan; uchar xdata save[32][4]; uchar xdata tempscr[32][4]; while(CLICK);//等待按下 saomiao(); start.x=X;start.y=Y;//起点 while(!CLICK);//等待弹起 saomiao(); end.x=X;end.y=Y;//终点 if(start.x>=end.x){temp=start.x;start.x=end.x;end.x=temp;} //将start定位到矩形左上角, if(start.y>=end.y){temp=start.y;start.y=end.y;end.y=temp;} //end至右下角 for(i=start.x;i<end.x;i++){enkey(led_data,i,start.y);enkey(led_data,i,end.y);}//反显方框 for(j=start.y;j<end.y;j++){enkey(led_data,start.x,j);enkey(led_data,end.x,j);} dis_play(led_data); chang=end.x-start.x+1;kuan=end.y-start.y+1;//记录方框长宽 while(CLICK); saomiao(); if( !( (X>=start.x&&X<=end.x) && (Y>=start.y&&Y<=end.y) ) ) return ;// //开始拖动 for(i=start.x;i<end.x;i++){enkey(led_data,i,start.y);enkey(led_data,i,end.y);} //恢复方框的反显 for(j=start.y;j<end.y;j++){enkey(led_data,start.x,j);enkey(led_data,end.x,j);} dis_play(led_data); go.x=X;go.y=Y; //记录基准点 for(i=start.x;i<end.x;i++) //将选定区域“挖出” for(j=start.y;j<end.y;j++) { mov(led_data[i][j/8],j%8,save[i-start.x][(j-start.y)/8],(j-start.y)%8); mov(led_data[i][j/8],j%8,0xff,0); } for(i=0;i<32;i++) //将挖出选定区域后的屏幕交给tempscr处理 for(j=0;j<4;j++) { tempscr[i][j]=led_data[i][j]; } pref.x=99;pref.y=99; while(!CLICK)//未松开 { saomiao(); //取鼠标位置 if(X!=pref.x||Y!=pref.y) { for(i=0;i<32;i++) //将挖出选定区域后的屏幕交给tempscr处理 for(j=0;j<4;j++) { tempscr[i][j]=led_data[i][j]; } for(i=X-go.x;i<X-go.x+chang;i++) //以鼠标位置为基准点,放置选定 for(j=Y-go.y;j<Y-go.y+kuan;j++) { mov(save[i-X+go.x][(j-Y+go.y)/8],(j-Y+go.y)%8,tempscr[i][j/8],j%8); } pref.x=X;pref.y=Y; } dis_play(tempscr); } for(i=0;i<32;i++) //将临时屏幕“转正” for(j=0;j<4;j++) { led_data[i][j]=tempscr[i][j]; }}void enkey(uchar led_data[32][4],uchar x,uchar y) //将第x行第y列反显{ uchar a,b; uchar temp; a=y/8;b=y%8; temp=0x80; temp=_cror_(temp,b); led_data[x][a]=temp^led_data[x][a];}void mov(uchar a,uchar b,uchar c,uchar d)//a^b->c^d{ uchar ta,tb; ta=0x80;tb=0x7f; ta=_cror_(ta,b);tb=_cror_(tb,d); ta=a&ta;tb=b&tb; if(b>d)ta=_crol_(ta,b-d); else ta=_cror_(ta,d-b); c=ta|tb;}///////////////////////////////////文件 operating.c//////////////////////////////////////////////////////// #include"myself.h"#include<reg52.h>#include<intrins.h>void fanxian(uchar LEDDATA[32][4]){ uchar row; for(row=0;row<32;row++) { LEDDATA[row][0]=~LEDDATA[row][0]; LEDDATA[row][1]=~LEDDATA[row][1]; LEDDATA[row][2]=~LEDDATA[row][2]; LEDDATA[row][3]=~LEDDATA[row][3]; }} void LEDcachu(uchar LEDDATA[32][4]){ do { one_word(LEDDATA,erasure); //扫描一个点并予以显示 KEYS=getkey(); //AD扫描按键,其实按键扫描1秒钟内进行10次足矣,不必跟随这个dis_play()做至少20次的扫描, //因为人的手不可能一秒内按键超过10次。 //调试时如果发现LED屏对光笔的反应比较慢,则需要修改getkey()在一秒内的时间占用比例, //即也意味着getkey()在一秒内的执行次数。可以这样:设定一个计数器,每dis_play()一次就+1,初值 //为0,到了1就清零,并且调用get_key(),否则不执行get_key()./*if(KEYS) //getkey()检测到按键按下就返回按键的值,没按键按下就返回0 { switch(KEYS) { //为了不让使用者觉得混乱,这里就不允许多级嵌套了,因此 //下面很多都不允许 case key_enter : break; //”确定“在这里没意义 case key_esc : return;break; //退出,返回点亮与画亮模式 case key_words_modle : break; //这里模式下不允许进入多字连写功能 case key_light_level : break; //不允许调整屏幕亮度级别的参数 case key_sleep_time : break; //不允许调整超时待机的超时时间 case key_fanxian : break; //不允许反显操作 case key_cachu : break; //不允许擦除操作 case key_tuoyi : break; //不允许对象拖移 case key_tuoyi_xuanding : break; //”对象选定确认“在这里没意义 case key_tuoyi_quxiao : break; //”对象选定确认后取消“在这里没意义 case key_crease : break; //”数据+1“在这里没意义 case key_decrease : break; //”数据-1“在这里没意义 default : break; //没按键匹配的,直接退出。虽然在这里不发生,但安全起见加上去 } } */ //这一段可以不需要了 }while(KEYS!=key_esc);}void del_all(uchar obj[32][4]){ uchar row; for(row=0;row<32;row++) { obj[row][0]=0X00; obj[row][1]=0X00; obj[row][2]=0X00; obj[row][3]=0X00; }}////////////////////////////////////END///////////////////////////////////////////////////////////////////////////

扩展:led点阵书写显示屏 / 8x8led点阵电路图 / led点阵电路图

完了,就是这些,如果我没漏掉的话.....我按照自己的工程文档排列顺序拉过来的,应该没漏了..... 总结写完了

扩展:led点阵书写显示屏 / 8x8led点阵电路图 / led点阵电路图

本文标题:led点阵书写显示屏-led点阵显示屏原理是什么?
本文地址: http://www.61k.com/1135769.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1