點陣的移位一般有上、下、左、右的移動,這里我們重點講上移和左移,其它同理。
1. 點陣的上移:
點陣的上移相對來說很簡單,看效果圖如下:
源代碼:(該程序?qū)崿F(xiàn)了循環(huán)上移顯示“邢臺”)
/************16*16LED點陣屏顯示*****************/
#include<reg52.h>
sbit R="P2"^0; //數(shù)據(jù)輸入端口
sbit CLK="P2"^1; // 時鐘信號
sbit STB="P2"^2; // 鎖存端
char code table[]={
/*-- 文字: 邢 --*/
/*-- 宋體12; 此字體下對應的點陣為:寬x高=16x16 --*/
0x00,0x00,0xFE,0x3E,0x48,0x22,0x48,0x22,
0x48,0x12,0x48,0x12,0x48,0x0A,0xFF,0x13,
0x48,0x22,0x48,0x42,0x48,0x42,0x48,0x46,
0x44,0x2A,0x44,0x12,0x42,0x02,0x40,0x02,
/*-- 文字: 臺 --*/
/*-- 宋體12; 此字體下對應的點陣為:寬x高=16x16 --*/
0x40,0x00,0x40,0x00,0x20,0x00,0x10,0x04,
0x08,0x08,0x04,0x10,0xFE,0x3F,0x00,0x20,
0x00,0x08,0xF8,0x1F,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0xF8,0x0F,0x08,0x08,
};
void delay(int z)
{
int x,y;
for(x=0;x<z;x++)
for(y=0;y<110;y++);
}
void WriteByte(char dat) //寫一個字節(jié)的數(shù)據(jù)
{
char i;
for(i=0;i<8;i++) //循環(huán)8次把編碼傳給鎖存器
{
dat=dat>>1; //右移一位,取出該字節(jié)的最低位
R=CY; //將該字節(jié)的最低位傳給R
CLK=0; //將數(shù)據(jù)送出,上升沿
CLK=1;
}
}
void main()
{
int num,move,speed;
while(1)
{
if(++speed>8) //移動速度控制
{
speed=0;
move++; //移位
if(move>16) //是否完成移位一個漢字
move=0; //從頭開始
}
for(num=0;num<16;num++)
{
WriteByte(table[2*num+move*2]); //送出一個字節(jié)
WriteByte(table[2*num+1+move*2]);
P1=num; //行選
STB=1; //輸出鎖存器中的數(shù)據(jù),下降沿
STB=0;
delay(2);
}
}
}
可以看到這個程序和靜態(tài)顯示的程序沒有太大的差距,主要就是加入了一個move變量來控制移動,WriteByte(table[2*num+move*2])中當move變量變化的時候更改了寫入595中的數(shù)據(jù),正好實現(xiàn)了移動顯示的效果。而speed變量的if判斷語句能夠控制移動速度的大小。下面重點講左移。
2. 點陣的左移:
因為點陣的數(shù)據(jù)最終是一個一個字節(jié)的并行送出的,所以要實現(xiàn)點陣的左移,我們就需要考慮如何才能夠動態(tài)的更改每一個發(fā)送字節(jié)的數(shù)據(jù),而漢字的每一個字節(jié)的編碼是固定的,這里我們可以使用一個數(shù)據(jù)緩沖區(qū)來完成點陣的左移。重點說一下點陣左移中關鍵的一步操作temp=(BUFF>>tempyid) | (BUFF[s+1]<<(8-tempyid))。這里temp作為要發(fā)送的一個字節(jié)數(shù)據(jù),它由數(shù)據(jù)緩沖區(qū)中的數(shù)據(jù)組合而成,并且動態(tài)的變化,大致來說就是首先第一個字節(jié)的數(shù)據(jù)右移tempyid位,第二個字節(jié)的數(shù)據(jù)左移8-tempyid位,兩者相或后組成一個字節(jié)新的數(shù)據(jù),只要我們一直不斷地移位、相或、發(fā)送,就能實現(xiàn)左移的效果。不太好理解,先來看實例(循環(huán)左移顯示“邢臺學院”),效果圖如下:
見源代碼:
#include <AT89x51.H>
#define uchar unsigned char
#define uint unsigned int
uchar yid,h; //YID為移動計數(shù)器,H為行段計數(shù)器
uint zimuo; //字模計數(shù)器
uchar code hanzi[]; //漢字字模
uchar BUFF[4]; //緩存
void in_data(void); //調(diào)整數(shù)據(jù)
void rxd_data(void); //發(fā)送數(shù)據(jù)
void sbuf_out(); //16段掃描
uchar code table[]={//篇幅有限,省略編碼};
void main(void)
{
uchar i,d=10;
yid=0;
zimuo=0;
while(1)
{
while(yid<16) //數(shù)據(jù)移位。
{
for(i=0;i<d;i++) //移動速度
{
sbuf_out();
}
yid++; //移動一步
}
yid=0;
zimuo=zimuo+32; //后移一個字,
if(zimuo>=96) //到最后從頭開始,有字數(shù)決定
zimuo=0;
}
}
/********************************/
void sbuf_out()
{
for(h=0;h<16;h++) //16行掃描
{
in_data(); //調(diào)整數(shù)據(jù)
rxd_data(); //串口發(fā)送數(shù)據(jù)
P1=0x7f; //關閉顯示。
P1_7=1; //鎖存為高,595鎖存信號
P1=h; //送行選
}
}
/******************************************************/
void in_data(void)
{
char s;
for(s=1;s>=0;s--) //h為向后先擇字節(jié)計數(shù)器,zimuoo為向后選字計數(shù)器
{
BUFF[2*s+1]=table[zimuo+1+32*s+2*h]; //把第一個字模的第一個字節(jié)放入BUFF0
//中,第二個字模的第一個字節(jié)放入BUFF2中
BUFF[2*s]=table[zimuo+32*s+2*h]; // 把第一個字模的第二個字節(jié)放入BUFF1中,
//第二個字模的第二個字節(jié)放入BUFF3中
}
}
/*******************************************************/
void rxd_data(void) //串行發(fā)送數(shù)據(jù)
{
char s;
uchar inc,tempyid,temp;
if(yid<8)
inc=0;
else
inc=1;
for(s=0+inc;s<2+inc;s++) //發(fā)送2字節(jié)數(shù)據(jù)
{
if(yid<8)
tempyid=yid;
else
tempyid=yid-8;
temp=(BUFF>>tempyid)|(BUFF[s+1]<<(8-tempyid));//h1左移tempyid位后和h2右移8-tempyid相或,取出移位后的數(shù)據(jù)
SBUF=temp;//把BUFF中的字節(jié)從大到小移位相或后發(fā)送輸出。
while(!TI); //注:這里使用了串口,串口數(shù)據(jù)的發(fā)送為最低位在前。
TI=0; //等待發(fā)送中斷
}
}
首先來看定義的數(shù)據(jù)緩沖區(qū)BUFF[ ],這里一開始將會存儲第一個漢字與第二個漢字的第一行的編碼,該緩沖區(qū)動態(tài)的存儲點陣屏每一行要發(fā)送的數(shù)據(jù),注意這里BUFF的大小為4個字節(jié),比16*16點陣屏要顯示的漢字多了一個漢字行的大小,這一點是必要的,這樣我們才能實現(xiàn)利用該緩沖區(qū)進行左移控制,接著來看in_data(void)函數(shù),利用該函數(shù),我們實現(xiàn)了動態(tài)的修改緩沖區(qū)中的數(shù)據(jù),這里不再詳述過程,重點看程序的注釋即可。然后看rxd_data(void)函數(shù),該函數(shù)的作用正是利用串口串行發(fā)送數(shù)據(jù),也就是上面提到的移位、相或然后發(fā)送,關于在移位過程中的具體實現(xiàn)細節(jié)以及如何協(xié)調(diào)的進行數(shù)據(jù)發(fā)送,首先來看inc變量,該變量決定了從BUFF緩沖區(qū)中的第一個還是第二個數(shù)據(jù)開始讀取,當移位開始后,在移完一個字節(jié)的數(shù)據(jù)之前我們都從BUFF數(shù)據(jù)緩沖區(qū)中的第一個字節(jié)開始讀取,當移完一個字節(jié)后,inc變成1,這時我們從BUFF數(shù)據(jù)緩沖區(qū)中的第二個字節(jié)開始讀取,于此同時后一個字節(jié)總是在和前一個字節(jié)的數(shù)據(jù)進行移位相或,達到慢慢向前推進的效果,這里有一個臨界點,就是當移位滿16位后,即一個漢字移出點陣屏后,這時候我們就需要將數(shù)據(jù)緩沖區(qū)中的數(shù)據(jù)進行更新,即后移一個字,這時數(shù)據(jù)緩沖區(qū)中的數(shù)據(jù)就變成了第二個漢字和第三個漢字的第一行漢字的編碼,以此類推。下面來看sbuf_out()函數(shù),該函數(shù)實現(xiàn)了16行的掃描,最后來看while循環(huán)內(nèi),這時主函數(shù)內(nèi)已經(jīng)很簡單了,首先在while(yid<16)內(nèi),有控制移動速度的for循環(huán),即顯示幾次靜態(tài)的畫面移動一步,而zimuo變量為移位過程中漢字的選擇變量,它每32位的變化,正好是一個16*16漢字的編碼個數(shù)。這樣就完成了整個點陣左移的控制(這里使用了串口實現(xiàn)點陣的左移,當然我們也可以不用串口,關于非串口實現(xiàn)的左移后面介紹),它的過程比較復雜,需反復思考。