本来这一节打算开始讲调用液晶屏内部字库时的反显程序,但是我担心跳跃太大,恐怕很多初学者跟不上,所以多插入这一节讲讲后面菜单程序中经常用到的基本功能,在调用内部字库的情况下,如何把一个任意数值的变量显示在液晶屏上。这一节的功能需求跟前面第76节是一模一样的,只不过前面的不是用自带字库,现在的是用自带字库而已。我们还是需要做一个变量转换成ASCII码的函数,以后只要调用这个转换函数就可以了。这一节就要把这个转换函数和框架思路教给大家。
具体内容,请看源代码讲解。
(1)硬件平台:
基于朱兆祺51单片机学习板。
(2)实现功能:我们定义一个char型的全局变量,把它默认初始化为218,开机上电后,能看到正中间恰好显示这个全局变量的数值218。大家也可以试着更改它的默认初始值,只要不超过char型最大数值255范围,我们就会看到它上电后显示的就是这个初始值。
- #include "REG52.H"
- sbit LCDCS_dr = P1^6; //片选线
- sbit LCDSID_dr = P1^7; //串行数据线
- sbit LCDCLK_dr = P3^2; //串行时钟线
- sbit LCDRST_dr = P3^4; //复位线
- sbit beep_dr=P2^7; //蜂鸣器的驱动IO口
- void initial_myself(void);
- void initial_peripheral(void);
- void delay_long(unsigned int uiDelaylong);
- unsigned char *number_to_ASCII(unsigned char ucBitNumber);
- void display_service(void); //显示服务程序,在main函数里
- void SendByteToLcd(unsigned char ucData); //发送一个字节数据到液晶模块
- void SPIWrite(unsigned char ucWData, unsigned char ucWRS); //模拟SPI发送一个字节的命令或者数据给液晶模块的底层驱动
- void WriteCommand(unsigned char ucCommand); //发送一个字节的命令给液晶模块
- void LCDWriteData(unsigned char ucData); //发送一个字节的数据给液晶模块
- void LCDInit(void); //初始化 函数内部包括液晶模块的复位
- void display_clear(void); // 清屏。4行8列的坐标点全部显示2个空字符相当于清屏了。
- void display_double_code(unsigned int x,unsigned int y,const unsigned char ucArray1,const unsigned char ucArray2); //在一个坐标点显示1个汉字或者2个字符的函数
- void delay_short(unsigned int uiDelayshort); //延时
- code unsigned char ucAddrTable[]= //调用内部字库时,液晶屏的坐标体系,位置编码,是驱动内容,读者可以不用深究它的含义。
- {
- 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
- 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
- 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
- 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
- };
- code unsigned char ASCII816_0[]="0"; //0 对于数组内的字符,编译会自动翻译成 ASCII码(1字节)
- code unsigned char ASCII816_1[]="1"; //1
- code unsigned char ASCII816_2[]="2"; //2
- code unsigned char ASCII816_3[]="3"; //3
- code unsigned char ASCII816_4[]="4"; //4
- code unsigned char ASCII816_5[]="5"; //5
- code unsigned char ASCII816_6[]="6"; //6
- code unsigned char ASCII816_7[]="7"; //7
- code unsigned char ASCII816_8[]="8"; //8
- code unsigned char ASCII816_9[]="9"; //9
- code unsigned char ASCII816_nc[]=" "; //空格
- /* 注释一:
- * 以下变量就是本程序的任意变量,网友可以自己更改它的大小来测试本程序,不要超过255.
- */
- unsigned char ucAnyNumber=218; //任意变量默认初始化为218。
- unsigned char ucWd1Part1Update=1; //窗口1的第1个局部更新显示变量 1代表更新显示,响应函数内部会清零
- void main()
- {
- initial_myself();
- delay_long(100);
- initial_peripheral();
- while(1)
- {
- display_service(); //显示服务程序
- }
- }
- /* 注释二:在一个坐标点显示1个汉字或者2个字符的函数
- * 第1,2个参数x,y是坐标体系。x的范围是0至8,y的范围是0至3.
- * 第3个参数ucArray1是第1个汉字机内码或者ASCII码。
- * 第4个参数ucArray2是第2个汉字机内码或者ASCII码。
- */
- void display_double_code(unsigned int x,unsigned int y,const unsigned char ucArray1,const unsigned char ucArray2)
- {
- WriteCommand(0x30); //基本指令集
- WriteCommand(ucAddrTable[8*y+x]); //起始位置
- LCDWriteData(ucArray1);
- LCDWriteData(ucArray2);
- }
- void display_clear(void) // 清屏。4行8列的坐标点全部显示2个空字符相当于清屏了。
- {
- unsigned int i,j;
- for(i=0;i<4;i++)
- {
- for(j=0;j<8;j++)
- {
- display_double_code(j,i,0x20,0x20); //0x20是空格的ASCII码
- }
- }
- }
- void SendByteToLcd(unsigned char ucData) //发送一个字节数据到液晶模块
- {
- unsigned char i;
- for ( i = 0; i < 8; i++ )
- {
- if ( (ucData << i) & 0x80 )
- {
- LCDSID_dr = 1;
- }
- else
- {
- LCDSID_dr = 0;
- }
- LCDCLK_dr = 0;
- LCDCLK_dr = 1;
- }
- }
- void SPIWrite(unsigned char ucWData, unsigned char ucWRS) //模拟SPI发送一个字节的命令或者数据给液晶模块的底层驱动
- {
- SendByteToLcd( 0xf8 + (ucWRS << 1) );
- SendByteToLcd( ucWData & 0xf0 );
- SendByteToLcd( (ucWData << 4) & 0xf0);
- }
- void WriteCommand(unsigned char ucCommand) //发送一个字节的命令给液晶模块
- {
- LCDCS_dr = 0;
- LCDCS_dr = 1;
- SPIWrite(ucCommand, 0);
- delay_short(90);
- }
- void LCDWriteData(unsigned char ucData) //发送一个字节的数据给液晶模块
- {
- LCDCS_dr = 0;
- LCDCS_dr = 1;
- SPIWrite(ucData, 1);
- }
- void LCDInit(void) //初始化 函数内部包括液晶模块的复位
- {
- LCDRST_dr = 1; //复位
- LCDRST_dr = 0;
- LCDRST_dr = 1;
- }
- /* 注释三:
- * 本程序的核心转换函数。
- * 是可以把一位任意数字变量的函数转换成对应的ASCII码,由于ASCII码放在数组里,所以返回的是指针,代表数组的首地址。
- */
- unsigned char *number_to_ASCII(unsigned char ucBitNumber)
- {
- unsigned char *p_ucAnyNumber; //此指针根据ucBitNumber数值的大小,分别调用不同的ASCII码。
- switch(ucBitNumber) //根据ucBitNumber数值的大小,分别调用不同的ASCII码。
- {
- case 0:
- p_ucAnyNumber=ASCII816_0;
- break;
- case 1:
- p_ucAnyNumber=ASCII816_1;
- break;
- case 2:
- p_ucAnyNumber=ASCII816_2;
- break;
- case 3:
- p_ucAnyNumber=ASCII816_3;
- break;
- case 4:
- p_ucAnyNumber=ASCII816_4;
- break;
- case 5:
- p_ucAnyNumber=ASCII816_5;
- break;
- case 6:
- p_ucAnyNumber=ASCII816_6;
- break;
- case 7:
- p_ucAnyNumber=ASCII816_7;
- break;
- case 8:
- p_ucAnyNumber=ASCII816_8;
- break;
- case 9:
- p_ucAnyNumber=ASCII816_9;
- break;
- case 10:
- p_ucAnyNumber=ASCII816_nc;
- break;
- default: //如果上面的条件都不符合,那么默认指向空格ASCII码
- p_ucAnyNumber=ASCII816_nc;
- break;
- }
- return p_ucAnyNumber; //返回转换结束后的指针
- }
- void display_service(void) //显示服务程序,在main函数里
- {
- /* 注释四:
- * 这里的局部变量用static关键词修饰,是因为这个函数一直在主函数while(1)里循环扫描,我不希望它每次进来这个函数
- * 都多花几条指令去初始化这些局部变量,这样会多耗掉几个指令,所以我就用static关键字避免了这种情况,让这些局部变量
- * 只在上电那一刻就初始化了,以后每次进来这个函数不用再初始化这些变量。
- */
- static unsigned char ucAnyNumber_1; //分解变量的个位
- static unsigned char ucAnyNumber_10; //分解变量的十位
- static unsigned char ucAnyNumber_100; //分解变量的百位
- static unsigned char *p_ucAnyNumber_1; //经过数字转换成字模后,分解变量的个位字模首地址
- static unsigned char *p_ucAnyNumber_10; //经过数字转换成字模后,分解变量的十位字模首地址
- static unsigned char *p_ucAnyNumber_100; //经过数字转换成字模后,分解变量的百位字模首地址
- if(ucWd1Part1Update==1) //窗口1的第1个局部更新显示变量,里面放一些经常需要刷新显示的内容
- {
- ucWd1Part1Update=0; //及时清零,避免一直更新
- if(ucAnyNumber>=100) //有3位数以上
- {
- ucAnyNumber_100=ucAnyNumber/100; //百位
- }
- else //否则显示空
- {
- ucAnyNumber_100=10; //在下面的转换函数中,代码10表示空字模
- }
- if(ucAnyNumber>=10) //有2位数以上
- {
- ucAnyNumber_10=ucAnyNumber%100/10; //十位
- }
- else //否则显示空
- {
- ucAnyNumber_10=10; //在下面的转换函数中,代码10表示空字模
- }
- ucAnyNumber_1=ucAnyNumber%10/1; //个位
- p_ucAnyNumber_100=number_to_ASCII(ucAnyNumber_100); //把数字转换成字符ASCII码
- p_ucAnyNumber_10=number_to_ASCII(ucAnyNumber_10); //把数字转换成字符ASCII码
- p_ucAnyNumber_1=number_to_ASCII(ucAnyNumber_1); //把数字转换成字符ASCII码
- display_double_code(2,1,ASCII816_nc[0],p_ucAnyNumber_100[0]);//液晶屏的显示驱动函数 这里的ASCII816_nc[0]代表填充显示一个空格字符
- display_double_code(3,1,p_ucAnyNumber_10[0],p_ucAnyNumber_1[0]);//液晶屏的显示驱动函数
- }
- }
- void delay_short(unsigned int uiDelayShort)
- {
- unsigned int i;
- for(i=0;i<uiDelayShort;i++)
- {
- ;
- }
- }
- void delay_long(unsigned int uiDelayLong)
- {
- unsigned int i;
- unsigned int j;
- for(i=0;i<uiDelayLong;i++)
- {
- for(j=0;j<500;j++) //内嵌循环的空指令数量
- {
- ; //一个分号相当于执行一条空语句
- }
- }
- }
- void initial_myself(void) //第一区 初始化单片机
- {
- beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。
- }
- void initial_peripheral(void) //第二区 初始化外围
- {
- LCDInit(); //初始化12864 内部包含液晶模块的复位
- WriteCommand(0x0C); //命令字0x0c表示用内部字库模式。命令字0x36表示用自构字库模式。
- display_clear(); // 清屏。4行8列的坐标点全部显示2个空字符相当于清屏了。
- }
总结陈词:
在液晶屏程序里,经常要用到反显的功能来表示选中某一项菜单。在调用内部字库时,这样的驱动程序又该怎么写?欲知详情,请听下回分解-----如何在调用液晶屏内部字库时让某行内容反显。
(未完待续,下节更精彩,不要走开哦)