制作出来的DIY书写屏幕实物图如下:
单片机源程序如下:
- #include "dianzhen3_lib.h"
- #define u8 unsigned char
- #define dianzhen_138_location P2
- bit scan_f = 0;//当输入按键按下时138点阵开始扫描
- bit odd_or_even = 0;//修改键按下次数的奇偶标志位
- bit input_or_finish_flag = 0;
- u8 k=0;
- u8 key_value;
- u8 location_num = 0;
- u8 del_location_num = 0;
- u8 xdata t_collect[130]={0xff};
- u8 xdata t_del[30]={ 0xff };
- u8 xdata t_ku[254];
- u8 code t_ku_1[254]={ //0xff被保留,用作采集数据的最后一个.0xfe也被保留,t_ku[]填充
- 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
- …………
- …………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
- 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd};
- extern unsigned char code infro3[208]; //淮工光信秦帅
- void main()
- {
- u8 i, j;
-
- P3M0 = 0; //使P3口与P2口为准双向口,和传统51单片机一样
- P3M1 = 0;
- P2M0 = 0xff; //P2口为推挽输出用来驱动138点阵
- P2M1 = 0;
- P1M0 = 0xff; //用P1口来驱动595点阵屏
- P1M1 = 0;
- P0M0 = 0x07;
- P0M1 = 0;//使P00.P01.P02推挽输出
- EA = 1;//按键中断一直开
- EX1 = 1;
- IT1 = 1;
- P55 = 1; //因为手头上的这块15单片机的P3.5口始终为0,不知为啥,就用了P55来替代,用作按键部分
- P3 = 0xff;
- P01 = 0; ////绿灯,高电平点亮
- P00 = 0; //红灯,高电平点亮
- P02 = 1; //138点阵使能端,低电平有效
-
- for(i=0; i<254; i++ ) //赋值t_ku[]
- {
- t_ku[i] = t_ku_1[i];
- }
- while(scan_f == 0) //当没开始按下的时候一直显示“淮工光信秦帅”
- {
- infro_display( 3 );
- }
- while(1)
- {
- while( scan_f == 1 )
- {
- if( odd_or_even == 0 ) //只有当修改键是偶数次按下的时候才扫描(偶数次包含0次)
- {
- for(k=0; k<254; k++) //开始扫描138点阵
- {
- dianzhen_138_location = t_ku[k];
- Delay(1) ;
- }
- }
- else if( odd_or_even == 1 ) //修改键奇数次按下时,将收集到的数据显示出来
- {
- for( i=0; t_collect[i]!=0xff ; i++ )
- {
- if( t_collect[i] == 0xfe )
- {
- continue;
- }
- dianzhen_138_location = t_collect[i];
- Delay(2);
- }
- }
-
- if( key_value == input )
- {
- key_value = 0 ; //将key_value内容清空
- location_num = 0;
- del_location_num = 0;
- odd_or_even = 0;
- for(i=0; i<254; i++ ) //赋值t_ku[]
- {
- t_ku[i] = t_ku_1[i];
- }
-
- t_collect[0] = 0xff;
- t_del[0] = 0xff;
-
- EX0 = 1; //启动外部中断0(光笔生效)
- IT0 = 1;
- }
-
- if( key_value == modify)
- {
- key_value = 0;
- if( t_collect[0] != 0xff )//没有采集数据则不修改
- {
- odd_or_even = ~odd_or_even;//为1时是奇数次按下,为0时是偶数次按下
- if( odd_or_even == 0 )//如果修改是偶数次按下修改键,则收回被删除的点
- {
- if( t_del[0] != 0xff )
- {
- for( i=0; t_del[i] != 0xff ; i++ )
- {
- for(j=0;t_ku[j] != 0xfe ; j++);
- t_ku[j] = t_del[i];
- }
- t_del[0] = 0xff; //数组的第一个数若为0xff,则说明此数组里面无需执行数据
- del_location_num = 0;
- }
- }
-
- }
- }
-
-
- if( key_value == save )
- {
- key_value = 0;
- EA = 0;
- if (t_collect[ 0 ] == 0xff)//若没有需要保存的数据,则闪一下红灯;返回
- {
- P01 = 1;//如果保存失败则红灯闪烁一下(P01口接红灯)高电平点亮
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- P01 = 0;
- }
- else
- {
- if ( save_data( t_collect ) !=0 )
- {
- P00 = 1;//如果保存成功则绿灯闪烁一下(P01口接绿灯)高电平点亮
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- P00 = 0;
- key_value = input;//若保存成功则开始下个字的输入,若不成功则返回
- }
- else
- {
- P01 = 1;//如果没有保存成功则红灯闪烁一下(P11口接红灯)
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- Delay(255);
- P01 = 0;
- }
-
- }
- EA = 1;
- }
-
- }
- if( key_value == finish )
- {
- key_value = 0;
- EX0 = 0; //关闭外部中断0(光笔生效)
- P02 = 1; //关闭书写屏(P02)为138点阵屏的使能端
- // IT0 = 1;
- P17 = 1;//595点阵屏的使能端,低电平有效(即为高电平是全部输出低电平)
- }
-
- if( key_value == display )
- {
- key_value = 0;
-
- EX0 = 0;
- P02 = 1; //关闭书写屏(P02)为138点阵屏的使能端
- data_display(); //一直显示直到input或者finish按键按下
- // for(k=0; k<254; k++) //用t_ku数组来存显示数据,返回后需重新赋值
- // {
- // dianzhen_138_location = t_ku[k];
- // Delay(1) ;
- // }
- // EX0 = 1;
- }
- }
-
- }
- void key_interput1() interrupt 2
- {
- u8 t;
- t = P3;
- Delay10ms() ;
- if( t != P3 )
- {
- return ;
- }
-
- switch( t & 0Xd0 )
- {
- case 0xc0: key_value = input ; scan_f = 1 ; input_or_finish_flag = 1; P02 =0;break;//P02是138点阵的使能端口
- case 0x90: key_value = save ; input_or_finish_flag = 0; break;
- case 0x50: key_value = finish ; scan_f = 0 ; input_or_finish_flag = 1; break;
- case 0xd0: if( P55 == 0 ) {key_value = modify ;input_or_finish_flag = 0;}
- else if( P33 == 0 ){key_value = display ; scan_f = 0 ;input_or_finish_flag = 0;} break;
- }
-
- for(t=0; t<50; t++)
- {
- while(P33 == 0)
- {
- Delay10ms();
- }
- }
- }
- void Led_3du33_interrput() interrupt 0
- {
- u8 i ;
- //static del_f = 1;
- EX0=0;
- for(i=0; i<location_num; i++) //判断此点是否已经采集过若采集过则不再重新采集
- {
- if( ( t_collect[i] == dianzhen_138_location ) && (dianzhen_138_location != 0xfe))
- {
- if( (odd_or_even == 1) && ( del_location_num<28))//修改键奇数次按下,这里允许删除了28个点坐标,可以改动
- {
- //Delay10ms() ; //如果真要删除点的话,在这里用一下延时,慢一点
- //if (P32 == 0)
- //{
- // del_f=~del_f;
- //if(del_f == 1)
- //{
- if( t_collect[i-1] == dianzhen_138_location ) //这个if是用来防止滞后响应的
- { //比如因为上一个点响应的中断
- t_del[del_location_num++] = t_collect[(i-1)] ;//但是点阵坐标已经跑到下一个了
- t_collect[(i-1)]=0xfe; //消除的数据点需要用0xfe来填充,0xfe将会在存储数据时被消除
- }
- else
- {
- t_del[del_location_num++] = t_collect[i] ;
- t_collect[i]=0xfe; //消除的数据点需要用0xfe来填充,0xfe将会在存储数据时被消除
- }
- t_del[del_location_num] = 0xff ;//用0xff表示结束
- //}
- //}
- }
- EX0 = 1;
- return;
- }
-
- }
- if( location_num <130 )
- {
- t_collect[ location_num++] = dianzhen_138_location;//t_ku[]扫描时选中一个数,则消失一个点
- if(t_ku[(k-1)] == dianzhen_138_location) // 这个if的作用和删除点时的if目的是一样的
- {
- t_ku[(--k)] = 0xfe;//被选中的数,用0xfe来替补 (因为有时候时间有点错开了,比如扫描函数已经执行完了K++,然后才跑到中断的情况)
- }
- else
- {
- t_ku[k] = 0xfe;//被选中的数,用0xfe来替补 (0xfe将会在保存的时候被删除)
- }
- t_collect[ location_num] = 0xff ;//0xff 始终为最后一个数
- }
- EX0 = 1;
- return;
- }
复制代码- #include "intrins.h"
- #include <stc15.h>
- #define ENABLE_IAP 0x82 //if SYSCLK<20MHz
- #define CMD_IDLE 0 //????
- #define CMD_READ 1 //IAP?????
- #define CMD_PROGRAM 2 //IAP??????
- #define CMD_ERASE 3 //IAP??????
- #define data_num_addr 0x0000
- #define data_addr 0x0200
- extern bit input_or_finish_flag; //声明外部变量,用来判断input或者finish键是否按下,0表示无按下,1表示有按下
- extern unsigned char xdata t_ku[300]; //用这个数组来缓存从flash中读取的点阵信息
- void Delay(unsigned char n); //上面对于位变量的外部引用,需要加上变量类型bit
- void IapIdle();
- unsigned char IapReadByte(unsigned int addr);
- void IapProgramByte(unsigned int addr, unsigned char dat);
- void IapEraseSector(unsigned int addr);
- unsigned char code infro1[240]={
- 0x00,0x00,0x10,0x40,0x10,0x20,0x10,0x10,0x10,0x10,0x10,0x28,0x11,0x44,0x16,0x42,
- 0x10,0x41,0x90,0x40,0x50,0x40,0x30,0x40,0x10,0x40,0x00,0x40,0x00,0x40,0x00,0x00,/*"之",0*/
- …………
- …………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/*" ",6*/
- void Delay10ms() //@11.0592MHz
- {
- unsigned char i, j;
- _nop_();
- _nop_();
- i = 108;
- j = 145;
- do
- {
- while (--j);
- } while (--i);
- }
- void Delay(unsigned char i) //@11.0592MHz
- {
- unsigned char j;
- j = 200;//200-215下眼看不怎么闪 220-230,正眼看不怎么闪
- do
- {
- while (--j);
- } while (--i);
- }
- void sendata595(unsigned char i,unsigned char i2)
- {
- unsigned char j;
- P1=P1&0xbf;
- for(j=0;j<8;j++)
- {
- P1&=0Xdf;
- P1=(P1&0Xef)|((i&0x80)>>3);
- P1|=0x20;
- i<<=1;
- }
- for(j=0;j<8;j++)
- {
- P1&=0Xdf;
- P1=(P1&0Xef)|((i2&0x80)>>3);
- P1|=0x20;
- i2<<=1;
- }
- P1=P1|0x40;
- }
- void infro_display( unsigned char i )//当数据存储区达到8个字或者没有存储的信息就用来显示操作信息
- {
- unsigned int j , n, j2=0 ;
- unsigned char i2 ;//用来控制循环显示次数
- unsigned char *table2 ;
- unsigned char c ;//显示一板字时的刷新次数
- switch(i)
- {
- case 1: j2 = 208; table2 = infro1;break;
- case 2: j2 = 416; table2 = infro2;break;
- case 3: j2 = 176; table2 = infro3;break;
- }
- for(i2=0;i2<2;i2++)//循环显示两次
- {
- if( j2==176)//如果是显示“淮工光信秦帅”则一直显示,直到input或者finish
- {
- i2 = 0;
- }
- for(j=0;j<j2;j+=2)
- {
- if( input_or_finish_flag == 1)
- {
- return;//如果输入键(input)按下,或者结束键(finish)按下,则结束此函数
- }
- for(c=0;c<22;c++)//显示一板字时的刷新次数
- {
- n=j;
- P1&=0xf0;
- for(i=0;n<32+j;n=n+2,i++)
- {
- sendata595(table2[n],table2[n+1]);
- P1=( (P1&0xf0)|i );
- P17 = 0;
- Delay(2);
- P17 = 1;
- }
- }
- }
- }
- }
- void pailie(unsigned char*w,unsigned char k)
- {
- unsigned char t=0,i,j;
- for(i=0;i<k-1;i++)
- for(j=0;j<k-1-i;j++)
- {
- if(w[j]>w[j+1])
- {
- t = w[j];
- w[j] = w[j+1];
- w[j+1] = t;
- }
- }
- }
- void convert_to_595( unsigned char *q)
- {
- unsigned char k, i, t, t2, j,a[32]={0x00};
- for(i=0; q[i]!=0xff; i++); //统计出数组内元素的个数
- pailie(q , i) ;
- i=0;
- t=(q[0]&0xf0)>>4;
- j=(q[0]&0x0f);
- t2=t;
- for(;t>0;t--,i=i+2)
- {
- a[i]=0x00 ;
- a[i+1]=0x00 ;
- }
- a[i] |= (0x01<<j );
- for(k=1; q[k]!=0xff; k++)
- {
- t=( q[k]&0xf0 )>>4;
- j=( q[k]&0x0f ) ;
- if( t2 != t )
- {
- i=i+2;
- for( ;i<( t+t ); i=i+2)
- {
- a[i] = 0x00 ;
- a[i+1]=0x00 ;
- }
- t2 = t;
- }
- if( j < 8 )
- {
- a[i] |= ( 0x01<< j ) ;
- }
- else
- {
- a[i+1] |= ( 0x01<<(j-8) );
- }
- }
- for( i=0; i<32;i++)
- {
- q[i] = a[i];
- }
- q[32] = 0xff;
- }
-
- bit save_data( unsigned char *p )
- {
- static unsigned char save_data_num = 0;
- bit y_n_flag =0;//操作成功或失败的标志 1表示成功,0代表失败
- unsigned int i, j = 0;
- while( (j<5) && (y_n_flag == 0) )
- {
- j++;
- IapEraseSector(data_num_addr);//首先擦除第一与第二个扇区的原始数据
- if( save_data_num == 0 )
- IapEraseSector(data_addr);//首先擦除第一与第二个扇区的原始数据
- y_n_flag = 1;
- for(i=0; i<2; i++)
- {
- if (IapReadByte(data_num_addr+i) != 0xff)
- {
- y_n_flag = 0;
- break;
- }
- }
-
- if( save_data_num == 0 )
- {
- for(i=0; i<512; i++)
- {
- if ( IapReadByte(data_addr+i) != 0xff )
- {
- y_n_flag = 0;
- break;
- }
- }
- }
- }
- if( y_n_flag == 0 )
- {
- return 0;//提前结束此函数,因为擦除操作不成功
- }
- Delay(1);
-
- i=0;
- j=0;
- save_data_num ++;
-
- if( save_data_num == 9 )//如果已经保存了8个数,则清除这8个数
- {
- save_data_num = 1;
- IapEraseSector(data_num_addr);
- IapEraseSector(data_addr);
- y_n_flag = 0 ;
- while(( j<5) && ( y_n_flag == 0))
- {
- y_n_flag = 1;
- for(i=0; i<2; i++)
- {
- if ( IapReadByte(data_num_addr+i) != 0xff )
- {
- y_n_flag = 0;
- break;
- }
- }
- if( y_n_flag != 0)
- {
- for( i=0; i<300; i++) //因为最多只是用到了256个
- {
- if ( IapReadByte(data_addr+i) != 0xff )
- {
- y_n_flag = 0;
- break;
- }
- }
- }
- }
- if( y_n_flag == 1 )
- {
- infro_display( 1 );//循环显示两次“之前数据已删”
- }
- else
- {
- infro_display( 2 );//循环显示两次“数据数据删除失败,数据未保存”
- save_data_num = 0;
- return y_n_flag;
- }
-
- }
- for( j=0; p[j] != 0xff; j++ )//将收集数组里面的0xfe删除(0xfe是用来填充的)
- {
- if( p[j] == 0xfe )
- {
- i = j;
- for(;p[i] != 0xff; i++)
- {
- p[i]=p[i+1] ;
- }
- if(j>0) j=j-1;
- }
- }
- convert_to_595(p);//如果前面的块删除操作成功,则开始转化字库
- IapProgramByte(data_num_addr, save_data_num);//在0x0000处写上保存数据的个数
- for( j=(save_data_num-1)*32,i=j; i<j+32; i++ )
- {
- IapProgramByte(data_addr+i, p[(i%32)]);//将点阵数据保存到第二扇区里
- }
-
- return y_n_flag;//若值为0,则说明未保存成功,值为1,则保存成功
- }
- void save_data_display(unsigned char *p3,unsigned int i3)
- {
- unsigned int j = 0,n ;
- unsigned char i,c ;
- while(1) //一直显示直到input或者finish按下
- {
- for(j=0; j<=i3; j+=2)
- {
- if( i3 <33 )//代表只有一个数的时候,j=0,能让其静态显示
- {
- j = 0;
- }
- if( input_or_finish_flag == 1)
- {
- return;//如果输入键(input)按下,或者结束键(finish)按下,则结束此函数
- }
- for(c=0;c<22;c++)//显示一板字时的刷新次数
- {
- n=j;
- P1&=0xf0;
- for(i=0;n<32+j;n=n+2,i++)
- {
- sendata595(p3[n],p3[n+1]);
- P1=( (P1&0xf0)|i );
- P17 = 0;
- Delay(2);
- P17 = 1;
- }
- }
- }
- }
- }
- void data_display()
- {
- unsigned int i,j;
- i = IapReadByte( data_num_addr);
- if ( i == 0xff) //若没有存储的数据,则循环显示“淮工光信秦帅” 可以按input或者finish键退出
- {
- infro_display(3 );
- }
- else if( i >=1)
- {
- i = i*32; //i<256
- for( j=0; j<i ; j++)//若存了不只一个数,则移屏显示这些数 可以按input或者finish键退出
- {
- t_ku[j] = IapReadByte( data_addr+j);
- }
- for(; j<32+i;j++) //为了让其显示更流畅
- {
- t_ku[j] =0x00;
- }
- save_data_display( t_ku,i); //若i>32则说明是移动显示
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
代码.rar
(81.09 KB, 下载次数: 69)
|