打点思路
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于ST7920控制的12864液晶用于字符显示很方便的,但网友说用它显示图形并不合适,原因就是它绘图时先要关闭显示,绘完后又要打开,速度会较慢。
我没有用过别的液晶,手中只有这一款,摆弄了几天,掌握了一点东西,写出来共享。
首先,我们知道,图形都是由像素点组成的,绘图的基础其实就是画点。
只要我们能点亮液晶的任意一个像素点,那么绘图就不是什么难事了。
万丈高楼平地起嘛,先要做的,当然是要打好基础。
ST7920提供了用于绘图的GDRAM(graph display RAM)。
共64×32个字节的空间(由扩充指令设定绘图RAM 地址),最多可以控制256×64点阵的二维绘图缓冲空间。
在它的Datasheet给出了GDRAM的坐标地址对照表:
(原文件名:图片1.png)
引用图片
用坐标表示,就是这样:
(原文件名:图片2.png)
引用图片
它的横坐标每一个地址都是16 位的。
共16个地址,256位。
很明显,它能控制256*64像素的液晶屏,而我们的只是128*64像素液晶屏,显然只用到它的一部分。
我刚开始以为它对应屏幕的绘图RAM是这样分布的(如红色部分):
(原文件名:图片3.png)
引用图片
结果栽了大根头,后来终于弄明白,原来它对应屏幕的GDRAM是这样分布的:
2010-03-2 5,11:31:56
资料邮件回复引用回
复↑↑↓↓
编辑删除
【1楼】AI HH LI
咚冬积分:3 00 派别:等级:------ 来自:汗,发了一半不小心提交了,继续
(原文件名:图片4.png)
引用图片
只要我们清楚了它的GDRAM和屏幕上像素点的映射(对应)关系,点亮对应的像素点就容易多了。
要点亮某一个像素点,就是将这个像素点在GDRAM中对应的位置1,这个相信没人会不知道吧?
我们先讨论一下思路,再一步步写代码。
我觉得,思路要比代码重要的多,只要你的思路通了,正确了,那么写出代码肯定会很容易。
首先,给你x,y的坐标,要你点亮一个点,要怎么做呢?从上面的图我们知道,它是分为两个半屏的,首先,我们要确定这个点是在上半屏还是下半屏,然后确定它是在那一行(纵坐标Y),再确定它是在哪一个字节的哪一个位(也就是确定它在那一列,即横坐标X)。
这些都确定后我们就定位到某一个具体的位上了,只就将这个位置1,就OK了。
下面我们边写代码边讨论。
因为这里仅仅是讨论如何在12864上打点的,而不是给12864写一个驱动,所以对于基本的数据读写函数,我们不做讨论,这里假设已经有了如下基本函数:
void lcd_write_cmd(unsigned char); //lcd 命令写
void lcd_write_data(unsigned char); //lcd 数据写
unsigend char lcd_read_data(void); //lcd 数据读
好了,就这些了。
为了方便,我们定义如下宏:
#define BASIC_SET 0x00 //基本指令集,后
面的数字查数据手册,下同。
#define EXTEND_SET 0x00 //扩展指令集#define DRAW_ON 0x00 //绘图显示开
#define DRAW_OFF 0x00 //绘图显示关
我们现在开始写点亮某一个点的函数:
void lcd_set_dot(unsigned char x, unsigned char y)
{
unsigned char x_byet, x_bit; //在横坐标的哪一个字节,哪一个位
unsigned char y_byte, y_bit;
x_byte = x / 1
6; //算出它在哪一个字节(地址)
//注意一个地址是16位的
x_bit = x % 1
6; //算出它在哪一个位y_byte = y /3
2; //y是没在哪个字节这个说法
//这里只是确定它在上半屏还是下半屏
//0:上半屏1:下半屏
y_bit = y % 3
2; //y_bit确定它是在第几行
lcd_write_cmd(EXTEND_SET); //扩展指令集
lcd_write_cmd(DRAW_OFF); //绘图显示关闭
lcd_write_cmd(0x80 + y_bit); //先写垂直地址
//具体参照数据手册
lcd_write_cmd(0x80 + x_byte + 8 * y_byte); //水平坐标
//下半屏的水平坐标起始地址为0x 88
//(+8*y_byte)就是用来确定在上半屏还是下半屏
if (x_bi
t < 8)
//如果x_bit位数小于8
{
lcd_write_data(0x01 << (7 - x_bi
t)); //写高字节。
因为坐标是从左向右的
//而GDRAM高位在左,底位在右
lcd_write_data(0x0
0); //低字节全部填0
}
else
{
lcd_write_data(0x0
0); //高字节全部填0
lcd_write_data(0x01 << (15 - x_bit));
}
lcd_write_cmd(DRAW_O
N); //打开绘图显示lcd_write_cmd(BASIC_SE
T); //回到基本指令集,毕竟ST 7920是以字符为主的
return ;
}
基本画点函数算是完成了,但是我们如果使用这个函数,就会发现问题。
你且用它沿横坐标画几个连续的点试试,肯定不是你想要的结果。
出现问题的原因是因为我们画点时对其余的位全部填0处理了,造成对原来的信息的破坏。
所以我们要读出要写的那个地址原来的数据,再进行加工,写回去就可以解决问题了。
改进后的代码:
void lcd_set_dot(unsigned char x, unsigned char y)
{
unsigned char x_byet, x_bit; //在横坐标的哪一个字节,哪一个位
unsigned char y_byte, y_bit;
unsigned char tmph, tmpl; //定义两个临时变量,用于存放读出来的数据
x &= 0x7F;
y &= 0x3F;
x_byte = x / 1
6; //算出它在哪一个字节(地址)
//注意一个地址是16位的
x_bit = x&0x0
F; //算出它在哪一个位y_byte = y /3
2; //y是没在哪个字节这个说法
//这里只是确定它在上半屏还是下半屏
//0:上半屏1:下半屏
y_bit = y&0x3
F; //y_bit确定它是在第几行
lcd_write_cmd(EXTEND_SET); //扩展指令集
lcd_write_cmd(DRAW_OFF); //绘图显示关闭
lcd_write_cmd(0x80 + y_bit); //先写垂直地址(最高位必须为1)
//具体参照数据手册
lcd_write_cmd(0x80 + x_byte + 8 * y_byte); //水平坐标
//下半屏的水平坐标起始地址为0x 88
//(+8*y_byte)就是用来确定
//在上半屏还是下半屏
lcd_read_data(); //先空读一次tmph = lcd_read_data(); //读高位
tmpl = lcd_read_data();
lcd_write_cmd(0x80 + y_bit); //读操作会改变AC,所以重新设置一次
lcd_write_cmd(0x80 + x_byte + 8 * y_byte);
if (x_bi
t < 8)
//如果x_bit位数小于8
{
lcd_write_data(tmph | (0x01 << (7 - x_bi t))); //写高字节。
因为坐标是从左向右的
//而GDRAM高位在左,底位在右
lcd_write_data(tmp
l); //原数据送回
}
else
{
lcd_write_data(tmp
h); //原数据送回
lcd_write_data(tmpl | (0x01 << (15 - x_bi t)));
}
lcd_write_cmd(DRAW_ON); //打开绘图显示
lcd_write_cmd(BASIC_SET); //回到基本指令集,毕竟ST7920是以字符为主的
return ;
}
画点函数到此就完成了,剩下的事情就是对函数的优化了。
例如对入口参数的检查,对乘除法的优化等等。