找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 18885|回复: 15
打印 上一主题 下一主题
收起左侧

如何用12864液晶显示图片和绘制任意函数图象(打点)

  [复制链接]
跳转到指定楼层
楼主
ID:262 发表于 2015-12-8 05:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一. 显示图片

  显示图片的要点在于:1.取模 2.利用扩展指令设置液晶3.清楚液晶地址的概念

1.1取模

  取模软件用的是“字模221”下图是他的参数设置

         


   

  这里对参数设置先解释一下,所谓横向取模就是,一张图片从图片最左上角的8位开始取模,从左向右,每次取8位二进制数据转化为16进制保存,第一排取完之后,接着到第二排最左边8位开始取模,以此类推。为什么要这样取模呢?因为12864液晶的横纵坐标就是这个取模顺序,这点在之后还会详细提到。

1.2液晶的设置

  液晶显示图片必须用扩充指令集,初始化和显示字符的初始化不一样。我用的初始化函数如下:


void init_picture()//显示图片的初始化函数

{

   lcd_wcmd(0x36);//写指令函数,扩充指令集,绘图G=1打开

   lcd_wcmd(0x36);

   lcd_wcmd(0x3E);

   lcd_wcmd(0x01);//清屏

    Light= 0;//打开背光

}

1.3将取出的字模写进相应地址

  首先应该知道地址究竟是怎样的,结合下图讲清楚。12864液晶分为半屏和下半屏。当你想要点亮某个地方时,必须先写这个地方的垂直地址紧接着写入它的水平地址,水平地址液晶可以自动加1,而垂直地址不会。图中水平坐标从0x80+00到0x80+0F,一共16个,其中0x80+00到0x80+07是上半屏的坐标,其中0x80+08到0x80+0F是下半屏的坐标。水平坐标每个两字节,先写入的数据填充在高字节。垂直坐标只有0x80+00到0x80+1F,图中上半截0x80+00到0x80+1F是上半屏的垂直地址,另外的那部分一样的是下半屏垂直地址。每个垂直地址只确定一排,所以水平和垂直地址不能确定某个点的位置,只能确定某个两字节的位置,通过写进2字节数据确定点亮某个点或几个点。比如我们写入lcd_wcmd(0x81;(垂直地址)lcd_wcmd(0x80)(水平地址); 这就是说我们将在图中水平坐标00,垂直坐标01的位置(红圈处)输入数据。

                                   

               


                           

  知道地址的知识之后就明白为什么要横向取模了,接下来只要将取模的数据一个个按取模生成的顺序写进液晶就行了。下面是我用的代码,其中uchar=unsignedchar,uint=unsigned int。

void show_Pic(uchar*address)//显示图片函数

{          //address是是指向数组的指针,用法:show_Pic(XY)当中XY为数组名

    uchari,j;

   for(i=0;i<32;i++)     //上半屏的32排依次先写满

   {

       lcd_wcmd(0x80+i);//先送垂直地址

       lcd_wcmd(0x80);  //再送水平地址,水平地址可自加1

       for(j=0;j<16;j++)//每排128个点,所以一共要16个两位16进制数(也就是8位二进制数)才能全部控制

       {

          lcd_wdat(*address);   

          address++;

       }

   }

   for(i=0;i<32;i++)    //下半屏的32排操作原理和上半屏一样

   {

      lcd_wcmd(0x80+i);

      lcd_wcmd(0x88);

      for(j=0;j<16;j++)

       {

          lcd_wdat(*address);   

          address++;

       }

   }

}

1.4实际显示结果

  下图是我显示的一个坐标系和一条龙




  下面的代码是我的主函数,这部分加上上面我上面讲的函数和一些基本设置就是整个代码,XY是这幅坐标图片取模得到的数组


void main()

{

   init_picture();

   show_Pic(XY);

   while(1)           //进入程序主循环

    {        

    }  

}

二. 用打点方式显示任意图像

   有的同学认为打点只需按照上面的显示图片的方法点亮需要的点就是了,其实这不行。因为你写进去的是八个点的控制,会影响周围的点,很容易出现乱码。比如,你写进去的是0x80,x想的是只点亮左边一个点,其他的都不要影响,但是右边的7个0也是会显示的,如果在要显示0的地方原来显示的是1的话,你现在写进去的0就把1覆盖了,这样就容易产生乱码。所以我建议,你先把液晶的数据读出来,再用data&=(~(0x01<<(7-bit)))(bit是你点亮哪一位,data是读出来的数据)置0,置1也是类似的,最后再把data重新写进去就行了。

  我的单片机接口是乱的,所以每一个液晶接口都用了位定义,并且用到了寄存器B,寄存器B的每一个当做一个变量的位来操作。我的具体代码如下:


bit lcd_busy()        // 读写判断数据的D7读写位,用于判断1602是否忙

{                     

    bitresult;

    D7 =1;       //数据口D7置1,为读状态做准备

   LCD_RS = 0;   // 选择指令寄存

   LCD_RW = 1;   // 选择读控制线

   LCD_EN = 1;   // 开使能控制线

   delayNOP();   // 时序延时

   result = D7;  // 读D7的电平

   LCD_EN = 0;   // 关使能

   return(result); // 返回值1:忙,0可以执行操作

}

unsigned charreadData(void) //读取数据函数

{

     uchar i;

     D0 = 1;        D1 = 1;       D2 = 1;      D3 = 1;   

     D4 = 1;        D5 = 1;       D6 = 1;      D7 = 1;   

    lcd_busy();

     LCD_RS=1; LCD_RW=1;

     LCD_EN=0; LCD_EN=1;

     B_0=D0;B_1=D1; B_2=D2; B_3=D3;//B_1=B^1,在程序前段有位定义

     B_4=D4;B_5=D5; B_6=D6;B_7=D7;

     for(i=1;i<=7;i++)

     delayNOP();//这个函数是{_nop_();_nop_();_nop_();_nop_();};

     LCD_EN=0;      

     returnB;

  }

uchar DrawDots(uchar x,uchar y,ucharcolor)//打点函数

  {

     ucharrow,xlabel,xlabel_bit;

     uchar Read_H=0,Read_L=0;

     lcd_wcmd(0x34);      //扩充指令

     lcd_wcmd(0x36);      //绘图指令

     xlabel=x>>4;         //去16*16首地址

     xlabel_bit=x & 0x0F;

     if(y<32) row=y;

     else

     {

       row=y-32;

       xlabel+=8;

     }

     lcd_wcmd(row+0x80);

     lcd_wcmd(xlabel+0x80);

     readData();

     Read_H=readData();

     Read_L=readData();

        

     lcd_wcmd(row+0x80);

     lcd_wcmd(xlabel+0x80);

        

     if(xlabel_bit<8)

     {

      switch(color)

       {

         case 0:Read_H&=(~(0x01<<(7-xlabel_bit))); break; //变暗,看不见

         case 1:Read_H |=(0x01<<(7-xlabel_bit));break; //变亮  ,看得见

         case 2:Read_H ^=(0x01<<(7-xlabel_bit));break; //反转

         default:break;

       }

      lcd_wdat(Read_H);

       lcd_wdat(Read_L);  

     }

     else

     {

      switch(color)

       {

         case 0:Read_L&=(~(0x01<<(15-xlabel_bit))); break; //变暗   ,看不见

         case 1:Read_L |=(0x01<<(15-xlabel_bit));break; //变亮  ,看得见

         case 2:Read_L ^=(0x01<<(15-xlabel_bit));break; //反转

         default:break;

       }  

      lcd_wdat(Read_H);

       lcd_wdat(Read_L);  

     }

     lcd_wcmd(0x30);//恢复正常模式

  }

  如果你的单片机和12864接口不是乱的,那可以这样写读取函数

unsigned charreadData(void)

{

     uchar i ,data;

     P0=0xFF;

    lcd_busy();

     LCD_RS=1; LCD_RW=1;//

     LCD_EN=0; LCD_EN=1;

     data=P0;

     for(i=1;i<=7;i++)

    delayNOP();

     LCD_EN=0;      

     returndata;

  }

     这样,整个代码就全部讲完了,下面是显示正弦波的图片



     若有疏漏之处,希望大家多指正


评分

参与人数 3黑币 +10 收起 理由
半路 + 3 共享资料的黑币奖励!
科学小怪蛋 + 5 赞一个!
2715644932 + 2 很给力!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏14 分享淘帖 顶2 踩
回复

使用道具 举报

沙发
ID:1 发表于 2016-1-3 19:39 | 只看该作者
解释得非常清楚,补充一下51黑论坛 12864液晶取模软件的下载地址:http://www.51hei.com/mcudown/
回复

使用道具 举报

板凳
ID:79544 发表于 2016-1-5 09:34 | 只看该作者
楼主强大,值得学习,长知识,谢谢分享!
回复

使用道具 举报

地板
ID:162142 发表于 2017-1-17 13:05 来自手机 | 只看该作者
楼主我试了一下但是那个我数组指针学的不好总是运行不了 能帮我一下吗
回复

使用道具 举报

5#
ID:161822 发表于 2017-1-17 13:15 | 只看该作者
不错,收下了,谢谢!
回复

使用道具 举报

6#
ID:159270 发表于 2017-2-6 22:14 | 只看该作者
不错啊,值得学习
回复

使用道具 举报

7#
ID:163711 发表于 2017-2-7 15:23 | 只看该作者
不错  好啊
回复

使用道具 举报

8#
ID:162634 发表于 2017-5-19 20:01 | 只看该作者
刚好我需要
回复

使用道具 举报

9#
ID:105778 发表于 2017-9-3 20:11 | 只看该作者
感谢楼主无私奉献 能不能讲解彩屏这方面的例子 边学习逐步提高。
回复

使用道具 举报

10#
ID:195884 发表于 2017-9-4 20:24 | 只看该作者
亮出来,大家分享
回复

使用道具 举报

11#
ID:497325 发表于 2019-5-18 10:39 | 只看该作者
B_1这些事怎么定义的
回复

使用道具 举报

12#
ID:318672 发表于 2019-6-28 23:20 来自手机 | 只看该作者
感谢分享
回复

使用道具 举报

13#
ID:575229 发表于 2019-8-11 07:48 | 只看该作者
很有用,谢谢分享
回复

使用道具 举报

14#
ID:276663 发表于 2021-11-25 01:22 | 只看该作者
原作在这里,可让人好找
回复

使用道具 举报

15#
ID:1064915 发表于 2023-12-30 08:28 | 只看该作者
ks0108的是列行式的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表