当前位置:主页 > 光电电路 > LED电路 > 正文

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

时间:2015-02-02 13:10 来源:电路图之家 作者:编辑部


LED驱动板PCB:

LED驱动板原理图:

光笔PCB:

光笔 原理图:

主控板PCB:

主控板 原理图:


////////////////////////////////////文件 myself.h///////////////////////////////////////////////////////////////
#include
#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
#include

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
#include
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_lig4) 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
#include
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_result0x99)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_result0x99)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
#include


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(sleepmin1)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
#include
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
#include
void dis_play(uchar show_obj[32][4])
{
uchar row,line,temp_row,templine;

for(row=0;row
#include

void fourwords()
{
uchar count;

for(count=0;count=key_words_modle&&KEYS
#include
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
#include
#define CLICK P3^3
#define X LED_ROW
#define Y LED_LINE
void 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^d
void 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=start.x&&X=start.y&&Yc^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///////////////////////////////////////////////////////////////////////////