中国领先的单片机及嵌入式资讯、教程、开发工具提供者!
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

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

作者:佚名   来源:本站原创   点击数:  更新时间:2010年05月18日   【字体:

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

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

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

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

LED驱动板PCB:




LED驱动板原理图:



光笔PCB:




光笔 原理图:



主控板PCB:



主控板 原理图:


 

////////////////////////////////////文件 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_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<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///////////////////////////////////////////////////////////////////////////
完了,就是这些,如果我没漏掉的话.....我按照自己的工程文档排列顺序拉过来的,应该没漏了..... 总结写完了
发表评论】【告诉好友】【收藏此文】【关闭窗口

文章评论

相关文章