中级会员
 
- 积分
- 205
- 金钱
- 205
- 注册时间
- 2018-6-20
- 在线时间
- 45 小时
|
本帖最后由 ningzhen 于 2023-1-12 19:38 编辑
一、理解原子哥的画点函数
我想很多同学都和我一样,最懵圈的就是一件事:x,y的坐标是以哪里为原点的坐标系?
http://47.111.11.73/forum.php?mo ... hlight=%BB%AD%B5%E3
从这个帖子原子的回复,我知道了是以插在开发板之后的左上角为原点,向右向下的坐标系。
结合各位先进的帖子、SSD1306手册和实际仿真理解此画点函数:
void OLED_DrawPoint(u8 x,u8 y,u8 t);
1.OLED模块放在手里,插座在右下时,OLED才是正放;当OLED模块插在开发板上时,其实是倒着的(相当于逆时针旋转了180度);
2.OLED正放时,按数据手册,无重映射的情况下,是从左到右0->127,从上到下PAGE0->PAGE7,COM0->COM63(COM我的理解是硬件的顺序),每个字节低位在上,高位在下,如图1,图2;
3.OLED旋转180度安装到开发板上,所以编写程序时,在初始化函数中,通过
- OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
复制代码 这样一条命令,将列地址(即x轴)重映射re-mapping了,所以x轴还是从左到右0->127。而y轴却没有重映射,所以y轴现在PAGE0->PAGE7,row0->row63都是从下到上递增的,
每写一个字节,也是高位在上低位在下了,如图3;
而画点函数的坐标系是如何建立的呢?答案是以左上角为原点,向右向下建系(在主函数里清屏然后OLED_DrawPoint(100,7,1))再停住,验证一下就知道了)。
所以(100,29)的页数是7-y/8=4,该坐标的字节的bit7(最上面,y坐标24)写1然后右移(y%8)位,即bit2写1,就相当于最低位(最下面,y坐标31)写1然后左移(7-y%8)=2位。
4.在将GRAM写入OLED的OLED_Refresh_Gram()中,我们注意到是给出了页地址和列起始地址,然后自动一列一列的写完了一页,再自动加页。
- void OLED_Refresh_Gram(void)
- {
- u8 i,n;
- for(i=0;i<8;i++)
- {
- OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
- OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
- OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
- for(n=0;n<128;n++)
- OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
- }
- }
复制代码 先写PAGE0,最后写PAGE7。PAGE0对应的是OLED_GRAM[n][0],PAGE7对应OLED_GRAM[n][7],也就是说我们定义的OLED_GRAM和此时倒过来的OLED显示区域就是一一对应的了。
千万不要将画点函数的y坐标与OLED_GRAM[n]的纵坐标i弄混,二者是经过转换的。还是以(100,7)(当然是右下坐标系)的画点为例,该点的位置预计在OLED的右上部分,
转换成OLED_GRAM[100][7]的确是在右上角的一个字节。
其实可以仿真一下程序,在主函数只保留显示"ALIENTEK",然后在OLED_Refresh_Gram(void)单步运行,就很清楚的看出来扫描显示的过程了。
二、一种修改原子哥画点函数y坐标的思路与实验
http://47.111.11.73/forum.php?mo ... hlight=%BB%AD%B5%E3
就是按照这位先进的思路走吧,但是我认为二维数组部分可以不动,只需要在OLED初始化中把y轴的扫描方向也重定义下,即从COM63->COM0进行扫描,相当于把y轴也re-mapping了,
- OLED_WR_Byte(0xC8,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
复制代码 还是看图1的绿色字体的部分,现在倒过来的OLED模块从上到下是COM63->COM0,就是从上到下PAGE0->PAGE7,row0->row63,每个字节也是低位在上,高位在下,所有的坐标都统一为右下坐标系,如图4:
这样画点函数中,(x,y)画点就是
OLED_GRAM[x][y/8] |= 1<<(y%8);
也就是说,我们定义的OLED_GRAM[n]数组,现在也是纵坐标越小越在上面了。
那么是否需要修改取字模的时候的顺向(高前低后)为逆向(低前高后)呢?
答案是不需要。因为这个和OLED的扫描方向无关,只和OLED_ShowChar();函数有关:
- void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
- {
- ......
- for(t1=0;t1<8;t1++)
- {
- if(temp&0x80) //y坐标越小,位置越靠上,对应的字模的字节的位越高
- OLED_DrawPoint(x,y,mode);
- else
- OLED_DrawPoint(x,y,!mode);
- temp<<=1; //左移temp一位,即从最高位开始取,取到最低位
- y++;
- if((y-y0)==size)
- {
- y=y0; //取完本列了,开始下一列
- x++;
- break;
- }
- }
- }
复制代码 以写入字符的位置坐标为起点,从字符模的最高位逐位取到最低位,同时纵坐标从y逐次加到(y+size),也就是从上到下写完这个字符的第一列,然后换行。本函数只是调用画点函数,不管画点或者后面是怎么实现的。
|
|