完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
最近在搞屏幕,顺便弄了一个字库芯片,刚刚测试完毕。个人认为项目中人机交互是少不了的,而显示是人机交互中的重要一环,所以准备写一篇教程记录一下。 显示原理 首先要知道屏幕显示的原理。屏幕显示的原理其实很简单,其实就是和点阵一样,只不过屏幕集成度高,本质控制输出高或者低,跟点灯一样。 拿0.96寸的oled来举个例子。0.96oled分辨率128*64,也就是说横向128个led,竖向64个led,你想点亮某个led(假设1为亮,0为灭),那么只需要将那个led对应的位置1即可。那如何显示汉字呢。其实原理也是一样的。如下图所示,只需要将对应的点点亮,而这些对应的点可以拼成一个汉字的模样。 再具体一点就是,单片机将想要显示的点的数据通过spi或者iic传给屏幕驱动芯片,屏幕驱动得到命令后就会将对应的点点亮,具体怎么点后面介绍。 字体模型 看到这里可能会有疑问,我不可能每个汉字都去照着样子去点亮led吧?那多费劲! 确实费劲,不过有简单的方法。1.取模 2.用字库(本质还是取模) 1.取模 什么是取模?就上上图看到的一样,将汉字对应的点转换成单片机能识别的二进制数去点亮led,从而显示到屏幕上。只不过这一步可以用软件自动生成,不需要你自己比对这汉字去一个一个点点儿了。下面是三个字取模之后得到的数组,我们只需要将汉字输入到软件中,点击生成字模就行了,是不是很简单。 嵌(0) 入(1) 式(2){0x01,0x80,0x31,0x8C,0x31,0x8C,0x3F,0xFC,0x00,0x30,0x33,0x30,0x33,0x3F,0xFF,0xE3},{0x33,0xDE,0x33,0x18,0x3F,0x18,0x33,0x18,0x33,0x3C,0x3F,0x3C,0x33,0x66,0x00,0xC3},/*"嵌",0*/{0x06,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x03,0xC0,0x03,0xC0,0x03,0xC0},{0x06,0x60,0x06,0x60,0x0C,0x30,0x0C,0x30,0x18,0x18,0x30,0x18,0x60,0x0C,0xC0,0x07},/*"入",1*/{0x00,0x6C,0x00,0x66,0x00,0x66,0x00,0x60,0xFF,0xFF,0x00,0x60,0x00,0x60,0x3F,0x60},{0x0C,0x60,0x0C,0x60,0x0C,0x30,0x0C,0x33,0x0F,0x9B,0x7C,0x0F,0x30,0x07,0x00,0x03},/*"式",2*/ 2.字库 字库其实是个芯片,比如GT21L16S2Y、GT30L32S4W等,它是将取好的字模按照一定标准存放在内存当中,本质还是取模。这个标准遵循GB2312,是个国标。还有别的标准,比如UTF-8、GBK等等。 code +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +FB3A0 场 尝 常 长 偿 肠 厂 敞 畅 唱 倡 超 抄 钞 朝B3B0 嘲 潮 巢 吵 炒 车 扯 撤 掣 彻 澈 郴 臣 辰 尘 晨B3C0 忱 沉 陈 趁 衬 撑 称 城 橙 成 呈 乘 程 惩 澄 诚B3D0 承 逞 骋 秤 吃 痴 持 匙 池 迟 弛 驰 耻 齿 侈 尺B3E0 赤 翅 斥 炽 充 冲 虫 崇 宠 抽 酬 畴 踌 稠 愁 筹B3F0 仇 绸 瞅 丑 臭 初 出 橱 厨 躇 锄 雏 滁 除 楚 比如上面这个表,这是一个遵循GB2312国标的字符排列表。举个栗子,B3A1是16进制数,这个就代表“场”字、什么意思呢?看看下面的代码。 //主函数打印一个“场”字LcdPutString(30,30,"场",FontType24,NORMAL); //LcdPutString函数中解析输入的汉字“场”,汉字是占用两个字节tempint = (((unsigned int)*str)<<8) + (unsigned int)*(str+1); 我在主函数显示一个汉字“场”, LcdPutString 函数中的*str是个形参,指向“场”在单片机中的位置。将指针分解成十进制,并赋值给tempint。也就是说,tempint 的值就是“场”在单片机中仿真的值、下面试仿真结果。 45985转换成十六进制就是B3A1 通过这个实验,我们可以知道,汉字在计算机中是怎么存储的。本质还是0和1,因为计算机只能识别0和1。另外一点就是每个字符在计算机中都有唯一一个二进制与其对应。 显示函数的实现 取完模之后怎么显示呢?以我最近用的一个例子进行讲解。 硬件基础:S08DZ60驱动1.27寸屏幕(驱动SSD1351),汉字模用的字库(GT30L32S4W),基础SPI通信不在讲解,只说下应用函数。代码中有详细注释。 1.首先实现点亮一个点 void Draw_Point(unsigned char x, unsigned char y, int Colour_RGB) { Write_Command(0x15); // 设置列地址 Write_Data(x); Write_Command(0x75); // 设置行地址 Write_Data(y); Set_Write_RAM(); //使能MCU写RAM Write_Data(Colour_RGB >> 8); //写入填充颜色高字节 Write_Data(Colour_RGB); //写入填充颜色低字节 } 2.以汉字12 * 12,字符6 * 12为例写的驱动函数 void PutDotBytes12(unsigned char x,unsigned char y,unsigned char *DataPtr,unsigned char mode) { unsigned char i, j; //定义变量 unsigned char Var_Temp, x_Temp; //定义变量 x_Temp = x; //获取x起始坐标 if(IsAsciiType) //字符 { for(i = 0; i < 9; i++) //6*12 = 9*8;一次只能写入一字节,也就是8位,所以采用8*32的画法 { Var_Temp = DataPtr; //获取汉字在数组的偏移量 for(j = 0; j < 8; j++) { if(Var_Temp & 0x80) //先画最高位的点,为1则画对应的颜色 Draw_Point(x, y, 0x55); //else //Draw_Point(x, y, 0x0000); //为0则黑色(都不亮),可作为背景色 Var_Temp <<= 1; //移位,准备画下一个点 x++; //x坐标加1 if((x - x_Temp) == 6) //画完一列 { x = x_Temp; //x坐标回到起始位置 y++; //y坐标加1 break; //退出当前循环 } } } } else { for(i = 0; i < 24; i++) //12*12 = 32*8;一次只能写入一字节,也就是8位,所以采用8*32的画法 { Var_Temp = DataPtr; //获取汉字在数组的偏移量 for(j = 0; j < 8; j++) { if(Var_Temp & 0x80) //先画最高位的点,为1则画对应的颜色 Draw_Point(x, y, 0x55); //else //Draw_Point(x, y, 0x0000); //为0则黑色(都不亮),可作为背景色 Var_Temp <<= 1; //移位,准备画下一个点 x++; //x坐标加1 if((x - x_Temp) == 12) //画完一列 { x = x_Temp; //x坐标回到起始位置 y++; //y坐标加1 break; //退出当前循环 } } } } } 3.显示函数(集成到一个函数中) void LcdPutString(unsigned char x,unsigned char y,const char *str,unsigned char type,unsigned char mode) { unsigned char *dotptr; unsigned int tempint; while (*str != 0) //判断字符是否为0,不为0,则进入循环中 { if ((unsigned char)*str < 0x80) //根据输入数据的大小判断是字符还是汉字, { IsAsciiType = 1; //字符 tempint = (unsigned int)*str; } else { IsAsciiType = 0; //汉字 tempint = (((unsigned int)*str)<<8) + (unsigned int)*(str+1); } dotptr = (unsigned char *)GetDotAddr(tempint, type); //查找当前字符的点阵字模位置 //PutDotBytes(x+LCD_X_SHR, y, dotptr, mode); //将字模输出至显示设备 //OLED - CT2412864右移2点阵 switch(type) { case FontType08: PutDotBytes08(x+LCD_X_SHR, y, dotptr, mode); //将字模输出至显示设备 //OLED - CT2412864右移2点阵 break; case FontType12: PutDotBytes12(x+LCD_X_SHR, y, dotptr, mode); break; //将字模输出至显示设备 //OLED - CT2412864右移2点阵 case FontType16: PutDotBytes16(x+LCD_X_SHR, y, dotptr, mode); //将字模输出至显示设备 //OLED - CT2412864右移2点阵 break; case FontType24: PutDotBytes24(x+LCD_X_SHR, y, dotptr, mode); //将字模输出至显示设备 //OLED - CT2412864右移2点阵 break; } if (1 == IsAsciiType) //调整指针至下一个将要显示的字符 { str += 1; } else { str += 2; } x += (Xsize+8); //调整显示横坐标 if ((unsigned char)*str < 0x80) { Xsize = Xsize/2; } if ((x + Xsize) > Max_Column) { x = 0; if ((y + Ysize) > Max_Row) { break; } else { y += Ysize; //调整显示纵坐标 } } }//End of while } 总结 这节主要讲了屏幕的驱动函数怎么写的,还有一篇讲解的IIC协议的,以及还有一节51822驱动0.96寸屏幕的,把这三章结合起来理解就能吃透屏幕啦,其他屏幕基本上都是一样的套路。 因为最近一直在搞屏幕驱动,以前都是调用库函数,或者别人写好的驱动函数,这次开发一款新产品,索性直接把底层也搞了一下,并总结下来,希望能帮到你。 |
|
|
|
只有小组成员才能发言,加入小组>>
2549 浏览 0 评论
1152浏览 2评论
750浏览 1评论
503浏览 0评论
269浏览 0评论
433浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 04:46 , Processed in 1.182910 second(s), Total 46, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号