PIC单片机实例八:四种方式24X24点阵显示

单片机   2008-09-24 18:45   阅读359   评论9  
字号:    

    最近终于有空更新了,花了几天时间,弄出个小东西,虽然有很多种实现方式在网上流传了,但我却从没有试过,乘有时间,也弄出了四种方式的显示,各位帮忙看看,哪里还有不好的地方,希不吝指教.

一.原理及仿真图

此种为从右往左显示.

此中为从左往右显示

此种为从下往上显示

此种为从上往下显示

    原理图说明:

1.本实例采用微芯PIC16F877A单片机,此单片机适合初学者

2.点阵采用24X24点,左边为行线,采用U1-U3三个74LS373地址所存芯片,复用单片机RB端口.

右边为列线,采用U4-U6三个74LS373地址所存芯片,复用单片机RD端口.

3.单片机RC端口控制六片373的选通.

4.显示原理:24列列线轮流拉为低电平时,行线输出行玛,通过一定延时,字符即可显示,并通过计算,即可实现上述四种显示方式.

二.程序(已附解释,PICC 8.05 通过)

#include<pic.h>
#define uch unsigned char
int offset;//定义偏置变量,以使字符运动

//以下为需显示的字符数组
const uch zxhn[]=
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x10,0x30,0xE0,0x60,0x00,0x80,0x00,0xF0,0xF0,0x10,0x00,0xF0,0xE0,
 0x20,0x00,0x00,0xF0,0xF0,0x10,0x00,0x00,0x00,0x81,0x83,0x8E,0xCE,0xE0,0x78,0x76,
 0x3D,0x00,0xFF,0x7F,0x04,0x38,0xFF,0xFF,0x00,0x3C,0x38,0xFF,0xFF,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x3F,0x3F,0x20,0x10,0x18,0x0E,0x07,0x00,0x00,0x00,0x1F,0x1F,
 0x00,0x00,0x00,0x3F,0x3F,0x00,0x00,0x00,  //"洲",
 0x00,0x00,0x00,0x30,0x60,0x00,0x80,0x70,0x30,0x90,0x40,0x40,0x40,0x40,0xE0,0xE0,
 0x40,0x40,0x40,0x40,0xE0,0xE0,0x40,0x00,0x00,0x41,0x49,0x49,0x49,0xFF,0xFF,0x49,
 0x6D,0x6D,0x4B,0x9C,0x8C,0x40,0xFF,0xFF,0x01,0x8E,0x8C,0x40,0xFF,0xFF,0x00,0x00,
 0x00,0x40,0x20,0x10,0x0C,0x07,0x01,0x00,0x00,0x03,0x03,0x11,0x10,0x30,0x3F,0x1F,
 0x11,0x11,0x10,0x70,0x3F,0x3F,0x00,0x00,  //"翔"
 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0x80,0x00,0x00,0xE0,0xF8,0x38,
 0x10,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x02,0x04,0x18,0xB0,0xE0,0xFC,
 0x9F,0x23,0x10,0x0C,0x07,0xC3,0xFD,0x3D,0x3D,0xE5,0x19,0x07,0x03,0x03,0x01,0x00,
 0x00,0x10,0x08,0x04,0x03,0x41,0x20,0x21,0x27,0x1F,0x18,0x0C,0x06,0x03,0x01,0x00,
 0x00,0x03,0x0F,0x1C,0x38,0x18,0x10,0x10,  //"欢"
 0x00,0x00,0x00,0x10,0x30,0xE0,0xC0,0x00,0x00,0xC0,0xC0,0x20,0x30,0x38,0x10,0xF0,
 0xC0,0x40,0x40,0x40,0xE0,0xC0,0x40,0x00,0x00,0x00,0x08,0x08,0x08,0xFC,0xFC,0x08,
 0x80,0xFF,0xFF,0x40,0x20,0x20,0x00,0xFF,0xFF,0x40,0x80,0x80,0xFF,0xFF,0x00,0x00,
 0x00,0x00,0x18,0x18,0x0C,0x07,0x07,0x0C,0x08,0x18,0x10,0x10,0x30,0x30,0x30,0x37,
 0x37,0x30,0x30,0x31,0x30,0x30,0x10,0x08,  //"迎"
 0x00,0x00,0x00,0x00,0x80,0xC0,0x70,0x30,0x10,0x00,0x00,0xC0,0x70,0x78,0x50,0x40,
 0x40,0x40,0x40,0xC0,0xE0,0x40,0x40,0x00,0x00,0x08,0x04,0x02,0x03,0xFF,0x7F,0x00,
 0x40,0x22,0x11,0x9C,0x0E,0x44,0xC0,0xFF,0x7F,0x01,0x06,0x09,0x38,0x70,0x00,0x00,
 0x00,0x00,0x10,0x30,0x3C,0x1F,0x00,0x1F,0x3F,0x31,0x30,0x30,0x37,0x37,0x30,0x38,
 0x3E,0x18,0x01,0x02,0x0E,0x1C,0x18,0x00,       //"您"
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};  


const uch col[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//列码

//初始化子程序
void init()
{
 ADCON1=0x06;//初始化RA口为普通数字端口
 TRISA=0X20;
 PORTA=0;
 TRISB=0;
 PORTB=0;
 TRISC=0;
 PORTC=0;
 TRISD=0;
 PORTD=0;
}

//延时子程序
void delay1ms()
{
 uch i;

 for(i=0;i<150;i++)
 { NOP();
 }
}

//从右往左显示
void display1()
{
 uch i,j,k,t,n;
 int m=0;//字符定位变量
 for(n=0;n<6;n++)
 {
  for(offset=0;offset<24;offset++)//偏置最多24位
  {
  for(t=0;t<4;t++)//每个位置显示4次
  {
  for(i=0;i<24;i++)//取数,每行24列,故取24个数
  {
   PORTD=0xff;//一开始先把列置高电平,关显示
   PORTC=0x70;
   NOP();
   PORTC=0;
   
   PORTB=zxhn[i+offset+m];//取行码
   if((i+offset)>23)PORTB=zxhn[i+offset+48+m];
   RC0=1;
   NOP();
   RC0=0;


   PORTB=zxhn[i+24+offset+m];
   if((i+offset)>23)PORTB=zxhn[i+offset+72+m];
   RC1=1;
   NOP();
   RC1=0;


   PORTB=zxhn[i+48+offset+m];
   if((i+offset)>23)PORTB=zxhn[i+offset+96+m];
   RC2=1;
   NOP();
   RC2=0;

   j=i/8;//求需要选通的行线

   k=i%8;//求需要选通的列线

   PORTD=col[k];
   switch(j)
   {
    case 0:  RC4=1; NOP(); RC4=0; break;
    case 1:  RC5=1; NOP(); RC5=0; break;
    case 2:  RC6=1; NOP(); RC6=0; break;
   }
   delay1ms(); //视觉暂留 
  }
  }
  }
 m=m+72;//定位下一个初始字符
 }
}

//从左往右显示
void display2()
{
 uch i,j,k,t,n,tt1,tt2,tt3;
 int m=0;//字符定位变量
 for(n=0;n<6;n++)
 {
  for(offset=24;offset>0;offset--)//偏置最多24位
  {
  for(t=0;t<4;t++)//每个位置显示4次
  {
  for(i=24;i>0;i--)//取数,每行24列,故取24个数
  {
   if((i+offset)>23)
   {
    tt1=zxhn[i+offset-24+m];
    tt2=zxhn[i+offset+m];
    tt3=zxhn[i+offset+24+m];
   }
   else
   {
    tt1=zxhn[i+offset+m+72];
    tt2=zxhn[i+offset+m+96];
    tt3=zxhn[i+120+offset+m];
   }
   
   PORTD=0xff;//一开始先把列置高电平,关显示
   PORTC=0x70;
   NOP();
   PORTC=0;
   
   PORTB=tt1;  //取行码
   RC0=1;
   NOP();
   RC0=0;
   PORTB=tt2;
   RC1=1;
   NOP();
   RC1=0;
   PORTB=tt3;
   RC2=1;
   NOP();
   RC2=0;

   j=(i-1)/8;//求需要选通的373
   k=(i-1)%8;//求需要选通的列线

   PORTD=col[k];
   switch(j)
   {
    case 0:  RC4=1; NOP(); RC4=0; break;
    case 1:  RC5=1; NOP(); RC5=0; break;
    case 2:  RC6=1; NOP(); RC6=0; break;
   }
   delay1ms(); //视觉暂留 
  }
  }
  }
 m=m+72;
 }
}

//从下往上显示
void display3()
{
 uch i,j,k,t,n,tt1,tt2,tt3,l;
 int m=0;//字符定位变量
 for(n=0;n<18;n++)
 {
  for(l=0;l<7;l++)//滚动8位
  {
  for(t=0;t<3;t++)//每个位置显示4次
  {
  for(i=0;i<24;i++)//取数,每行24列,故取24个数
  {
   tt1=(zxhn[i+m]>>l)|(zxhn[i+24+m]<<(8-l));
   tt2=(zxhn[i+24+m]>>l)|(zxhn[i+48+m]<<(8-l));
   tt3=(zxhn[i+48+m]>>l)|(zxhn[i+72+m]<<(8-l));
   
   PORTD=0xff;//一开始先把列置高电平,关显示
   PORTC=0x70;
   NOP();
   PORTC=0;
   
   PORTB=tt1;  //取行码
   RC0=1;
   NOP();
   RC0=0;
   PORTB=tt2;
   RC1=1;
   NOP();
   RC1=0;
   PORTB=tt3;
   RC2=1;
   NOP();
   RC2=0;

   j=i/8;//求需要选通的373
   k=i%8;//求需要选通的列线

   PORTD=col[k];
   switch(j)
   {
    case 0:  RC4=1; NOP(); RC4=0; break;
    case 1:  RC5=1; NOP(); RC5=0; break;
    case 2:  RC6=1; NOP(); RC6=0; break;
   }
   delay1ms(); //视觉暂留 
  }
  }
  }
 m=m+24;
 }
}

//从上往下显示
void display4()
{
 uch i,j,k,t,n,tt1,tt2,tt3,l,a,b;
 int m=0;//字符定位变量
 for(n=0;n<6;n++)
 {
  for(l=0;l<24;l++)
  {
  for(t=0;t<3;t++)//每个位置显示4次
  {
  for(i=0;i<24;i++)//取数,每行24列,故取24个数
  {
   a=l/8;
   b=l%8;
   if(a==0)
   {
   tt1=(zxhn[i+m]<<b)|(zxhn[i+120+m]>>(8-b));
   tt2=(zxhn[i+24+m]<<b)|(zxhn[i+m]>>(8-b));
   tt3=(zxhn[i+48+m]<<b)|(zxhn[i+24+m]>>(8-b));
   }
   if(a==1)
   {
   tt1=(zxhn[i+m+120]<<b)|(zxhn[i+96+m]>>(8-b));
   tt2=(zxhn[i+m]<<b)|(zxhn[i+m+120]>>(8-b));
   tt3=(zxhn[i+24+m]<<b)|(zxhn[i+m]>>(8-b));
   }
   if(a==2)
   {
   tt1=(zxhn[i+m+96]<<b)|(zxhn[i+72+m]>>(8-b));
   tt2=(zxhn[i+m+120]<<b)|(zxhn[i+96+m]>>(8-b));
   tt3=(zxhn[i+m]<<b)|(zxhn[i+m+120]>>(8-b));
   }
   
   PORTD=0xff;//一开始先把列置高电平,关显示
   PORTC=0x70;
   NOP();
   PORTC=0;
   
   PORTB=tt1;  //取行码
   RC0=1;
   NOP();
   RC0=0;
   PORTB=tt2;
   RC1=1;
   NOP();
   RC1=0;
   PORTB=tt3;
   RC2=1;
   NOP();
   RC2=0;

   j=i/8;//求需要选通的行线
   k=i%8;//求需要选通的列线

   PORTD=col[k];
   switch(j)
   {
    case 0:  RC4=1; NOP(); RC4=0; break;
    case 1:  RC5=1; NOP(); RC5=0; break;
    case 2:  RC6=1; NOP(); RC6=0; break;
   }
   delay1ms(); //视觉暂留 
  }
  }
  }
 m=m+72;
 }
}

void main()
{
 uch mo;
 init();
 while(1)
 {
  display1();
  display2();
  display3();
  display4();
 }
}

三.总结

虽然已有四种方式显示了,但我觉得可以尝试更多的方式,例如,可以象滚轮子一样,旋转着从左滚到右显示,只是数据处理的量可能大了些,已经有两个自由度了,而我的四种只有一个自由度.由于本人水平有限,没有想到什么好的思路,不过希望抛砖引玉,写出这种显示方式.

评论(?)
阅读(?)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
网易公司版权所有 ©1997-2009