ATMega16驱动12864lcd-绘图-画点

tvn   2009-11-29 16:04 楼主
因为我在网上看了很久,12864绘图中的画点有些难度。因为可以液晶芯片不一样驱动会有差别。
所以把我写的贴出来大家分享,不明白的加我QQ:343700980一起交流!
我使用的环境是:
单片机:ATMega16
开发板:DDC-16B
液晶是:YJD12864C-1(可以参考《ST7920中文手册》)
硬件链接:
LCD    MCU
RS     PA5
RW     PA6
EN     PA7
DB0-7  PD0-7

废话不说,源码:



回复评论 (8)

2推荐 zxhnet 



  1. 文件delay.h

  2. /*
  3. 欢迎喜欢单片机的朋友一起交流
  4. QQ:343700980
  5. 加时注明:“单片机”
  6. */
  7. #ifndef __delay_h
  8. #define __delay_h
  9. void delay_1ms(void);
  10. void delay_nus(unsigned char n);
  11. void delay_nms(unsigned int n);
  12. void s_ms(unsigned int ms);
  13. /*******************************************************************
  14. 微秒级精确延时(ICC)
  15. *******************************************************************/
  16. void delay_nus(unsigned char tt)
  17. {
  18.         asm("_L2: subi R16,1");  
  19.         asm(" nop")
  20.         asm(" brne _L2");
  21.         asm(" nop");
  22.         asm(" ret");
  23. }
  24. /*************************************************************************
  25. 毫秒级精确延时(ICC)
  26. *************************************************************************/

  27. #define xtal 4 //以MHz为单位,不同的系统时钟要修改。

  28. void delay_1ms(void)
  29. {
  30. unsigned int i;
  31. for(i=0;i<(unsigned int)(xtal*143-2);i++);
  32. }

  33. void delay_nms(unsigned int num)
  34. {
  35. unsigned int i;
  36. for(i=0;i
  37. }

  38. //自定义延时函数
  39. void s_ms(unsigned int ms)
  40. {
  41.         for(;ms>1;ms--);
  42. }
  43. #endif


  44. 文件lcd.h
  45. /*
  46. 欢迎喜欢单片机的朋友一起交流
  47. QQ:343700980
  48. 加时注明:“单片机”
  49. */
  50. extern volatile unsigned char *LCD_DIR_PORT;        //DDRD
  51. extern volatile unsigned char *LCD_IP_PORT;                //PIND
  52. extern volatile unsigned char *LCD_OP_PORT;            //PORTD

  53. extern volatile unsigned char *LCD_DIR_CTL;    //DDRA

  54. extern volatile unsigned char *LCD_EN_PORT;                //PORTA7
  55. extern char LCD_EN_BIT;                                            //BIT(7)
  56. extern volatile unsigned char *LCD_RS_PORT;                //PORTA5
  57. extern char LCD_RS_BIT;                                            //BIT(5)
  58. extern volatile unsigned char *LCD_RW_PORT;                //PORTA6
  59. extern char LCD_RW_BIT;                                            //BIT(6)

  60. // *** LCD Function *** //
  61. void Init_LCD(void);

  62. void LCD_Display_Off(void);
  63. void LCD_Display_On(void);
  64. void LCD_Clear(void);
  65. void LCD_Home(void);
  66. void LCD_Cursor(char row, char column);

  67. void LCD_Cursor_On(void);
  68. void LCD_Cursor_Off(void);
  69. void LCD_DisplayCharacter(char Char);

  70. void LCD_DisplayString_F(char row, char column, const unsigned char *string);
  71. void LCD_DisplayString(char row, char column, unsigned char *string);


  72. 主程序文件:
  73. /*
  74. 欢迎喜欢单片机的朋友一起交流
  75. QQ:343700980
  76. 加时注明:“单片机”
  77. */
  78. #include
  79. #include "LCD.h"
  80. #include "delay.h"
  81. #define uchar unsigned char
  82. #define uint unsigned int
  83. static void test(const char *s);

  84. void main (void)
  85. {       
  86.     //DDRA=0x00;
  87.         unsigned char aa;
  88.         unsigned char bb;
  89.         unsigned char add_x=0x80;                 //GDRAM水平地址  
  90.         unsigned char add_y=0x80;                 //GDRAM垂直地址
  91.         float temp = 0.0;       
  92.         unsigned char x_low,x_hight;     //定义列地址的高低位指令
  93.     unsigned char Dot_Mask_Buf=0x01;
  94.         int i=0;
  95.        
  96.         uchar tem,key;
  97.         //LCD_Init();
  98.         //LCD_DisplayCharacter('A');
  99.         //LCD_Init_G();
  100.         //LCD_WriteControl(0x34);
  101.         //LCD_WriteControl(0x80|0x03);
  102.         //LCD_WriteControl(0x80|0x03);
  103.         //LCD_WriteData(0xff);
  104.         //LCD_WriteControl(0x34);
  105.         //lcd_draw_dot(11,11);
  106.         LCD_Fill(0xff);
  107.        
  108. //这里利用了开发板4键键盘做了下测试
  109.    DDRB=0x00;
  110.     PORTB=0xff;
  111.     while(1)
  112.    {
  113.    tem=PINB;       //读取端口b
  114.    if(tem!=0xff)   //判断是否有按键按下
  115.      {
  116.           s_ms(500);   //排除按键抖动和抗干扰
  117.           key=PINB;
  118.           if(key==tem)
  119.             {LCD_Fill(0xff);
  120.            if(key==0x7f)
  121.                    {aaaa(2);}
  122.                    if(key==0xbf)
  123.                    {aaaa(4);}
  124.                    if(key==0xdf)
  125.                    {aaaa(6);}
  126.                    if(key==0xef)
  127.                    {aaaa(8);}
  128.                  }
  129.           }
  130.    }
  131. //这里利用了开发板键盘做了下测试
  132.   
  133.        
  134. }

点赞  2009-11-29 16:06
文件lcd.c

#include "LCD.h"
#include
#include
#include
/**IO定义**/
#define BIT7 0x80
#define BIT6 0x40
#define BIT5 0x20
#define BIT4 0x10
#define BIT3 0x08
#define BIT2 0x04
#define BIT1 0x02
#define BIT0 0x01

volatile unsigned char *LCD_EN_PORT = &PORTA;
volatile unsigned char *LCD_DIR_PORT = &DDRD;   //DDRD  0输入  1输出
volatile unsigned char *LCD_DIR_CTL = &DDRA;    //DDRA  0输入  1输出
volatile unsigned char *LCD_IP_PORT = &PIND;
volatile unsigned char *LCD_OP_PORT = &PORTD;
volatile unsigned char *LCD_RS_PORT = &PORTA;
volatile unsigned char *LCD_RW_PORT = &PORTA;
char LCD_EN_BIT = BIT(7);
char LCD_RS_BIT = BIT(5);
char LCD_RW_BIT = BIT(6);

//宏设置
#define SET_LCD_E                *LCD_EN_PORT |= LCD_EN_BIT  //EN=1
#define CLEAR_LCD_E       *LCD_EN_PORT &= ~LCD_EN_BIT //EN=0
#define SET_EN_1          *LCD_EN_PORT |= LCD_EN_BIT  //EN=1
#define SET_EN_0          *LCD_EN_PORT &= ~LCD_EN_BIT //EN=0

#define SET_LCD_DATA      *LCD_RS_PORT |= LCD_RS_BIT  //RS=1
#define SET_LCD_CMD       *LCD_RS_PORT &= ~LCD_RS_BIT //RS=0
#define SET_RS_1          *LCD_RS_PORT |= LCD_RS_BIT  //RS=1
#define SET_RS_0          *LCD_RS_PORT &= ~LCD_RS_BIT //RS=0

#define SET_LCD_READ      *LCD_RW_PORT |= LCD_RW_BIT  //RW=1
#define SET_LCD_WRITE     *LCD_RW_PORT &= ~LCD_RW_BIT //RW=0
#define SET_RW_1          *LCD_RW_PORT |= LCD_RW_BIT  //RW=1
#define SET_RW_0          *LCD_RW_PORT &= ~LCD_RW_BIT //RW=0

//LCD指令宏定义
#define LCD_ON                                0x0C   
#define LCD_CURS_ON                        0x0D
#define LCD_OFF                                0x08
#define LCD_HOME                        0x02  
#define LCD_CLEAR                        0x01
#define LCD_NEW_LINE                0xC0
#define LCD_FUNCTION_SET        0x38
#define LCD_MODE_SET                0x06

#define LCD_EXTOFF   0x34     // 扩充指令集,关闭绘图显示
#define LCD_EXTON   0x36     // 扩充指令集,打开绘图显示

//888888888888888888硬件底层接口88888888888888888888888//
//忙检测
unsigned char LCD_Busy ( void )
{
    unsigned char temp;

    CLEAR_LCD_E;

    *LCD_DIR_PORT = 0x00;
        *LCD_DIR_CTL |= LCD_RS_BIT|LCD_RW_BIT|LCD_EN_BIT; //控制端口方向设定

    SET_LCD_READ;
    SET_LCD_CMD;

    SET_LCD_E;

    asm("nop");

    temp = *LCD_IP_PORT;

    CLEAR_LCD_E;

    return temp;
}

//写指令
void LCD_WriteControl (unsigned char CMD)
{
        while (LCD_Busy()& 0X80);

        CLEAR_LCD_E;

        SET_LCD_WRITE ;
        SET_LCD_CMD;

        *LCD_DIR_PORT = 0xFF;       
       
  asm("nop");
  
        SET_LCD_E;
       
        asm("nop");
       
        *LCD_OP_PORT = CMD;
       
        asm("nop");
        asm("nop");
       
        CLEAR_LCD_E;
}

//写数据
void LCD_WriteData (unsigned char Data)
{

        while (LCD_Busy() & 0X80);                 // Test if LCD Busy

        CLEAR_LCD_E;                                           // Disable LCD

        SET_LCD_WRITE ;                                        // Set LCD to write
        SET_LCD_DATA;                                        // Set LCD to data

        *LCD_DIR_PORT = 0xFF;                        // LCD port output       
       
  asm("nop");
  
        SET_LCD_E;                                                    // Write data to LCD
       
        asm("nop");
       
        *LCD_OP_PORT = Data;                                // Load data to port

        asm("nop");
        asm("nop");

        CLEAR_LCD_E;                                            // Disable LCD
}
//读数据
unsigned char LCD_ReadData(void)
{        
  unsigned char Read_Data;
  *LCD_DIR_PORT = 0x00;                 //的端口想要输入前,要先给端口全置1
  *LCD_OP_PORT = 0xff;
  SET_LCD_DATA;                      //A0置高,示意进行显存数据操作
  SET_LCD_READ;                     //RW置高,示意进行读出操作
  s_ms(10);
  CLEAR_LCD_E;                     //EP先置低,以便后面产生跳变沿   
  SET_LCD_E;                      //产生有效的跳变沿
  s_ms(10);
  Read_Data = *LCD_IP_PORT;           //读出数据
  s_ms(10);
  CLEAR_LCD_E;
  return Read_Data;                  //返回读到的数据
}


////////8888888888888888字符操作88888888888888888//////////
//初始化LCD
void LCD_Init(void)
{
        LCD_WriteControl (LCD_FUNCTION_SET);   //0x38    0011 1000
        asm("nop");
        LCD_WriteControl (LCD_OFF);            //0x08    0000 1000
        LCD_WriteControl (LCD_CLEAR);          //0x01    0000 0001
        LCD_WriteControl (LCD_MODE_SET);       //0x06    0000 0110
        LCD_WriteControl (LCD_ON);             //0x0C    0000 1100
        LCD_WriteControl (LCD_HOME);           //0x02    0000 0010
}

//清屏
void LCD_Clear(void)
{
        LCD_WriteControl(0x01);
}

//市焦点回到起始位置
void LCD_Home(void)
{
        LCD_WriteControl(0x02);
}

//在当前焦点输出一个字符
void LCD_DisplayCharacter (char Char)
{
        LCD_WriteData (Char);
}

//通过坐标输出字符串
void LCD_DisplayString_F (char row, char column ,const unsigned char *string)
{
        LCD_Cursor (row, column);
        while (*string)
                LCD_DisplayCharacter (*string++);
}

//通过坐标输出字符串
void LCD_DisplayString (char row, char column ,unsigned char *string)
{
        LCD_Cursor (row, column);
        while (*string)
                LCD_DisplayCharacter (*string++);
}

//字符光标定位
void LCD_Cursor (char row, char column)
{
        switch (row) {
                case 1: LCD_WriteControl (0x80 + column - 1); break;
                case 2: LCD_WriteControl (0x90 + column - 1); break;
                case 3: LCD_WriteControl (0x88 + column - 1); break;
                case 4: LCD_WriteControl (0x98 + column - 1); break;
                default: break;
        }
}

//显示光标
void LCD_Cursor_On (void)
{
        LCD_WriteControl (LCD_CURS_ON);
}

//关闭光标
void LCD_Cursor_Off (void)
{
        LCD_WriteControl (LCD_ON);
}


//关闭LCD
void LCD_Display_Off (void)
{
        LCD_WriteControl(LCD_OFF);
}

//打开LCD
void LCD_Display_On (void)
{
        LCD_WriteControl(LCD_ON);
}

//888888888888888图形驱动888888888888888888888888888///////////
//延时程序
void TimeDelay(int Time)
{
        int i;
        if(Time > 0)
        {
                for(i = 0;i < 800;i++)
                {
                }
                Time --;
        }
}
//图形模式初始化
void LCD_Init_G(void)
{
        //LCD 驱动所使用到的端口的初始化(如果有必要的话)
        // LCD_PortInit();
        SET_RS_0;
        TimeDelay(200);
        SET_RS_1;
        LCD_WriteControl(0xaf); //LCD On
        LCD_WriteControl(0x2f); //设置上电控制模式
        LCD_WriteControl(0x81); //电量设置模式(显示亮度)
        LCD_WriteControl(0x1f); //指令数据0x0000~0x003f
        LCD_WriteControl(0x27); //V5 内部电压调节电阻设置
        LCD_WriteControl(0xa2); //LCD 偏压设置
        LCD_WriteControl(0xc8); //Com 扫描方式设置,反向
        LCD_WriteControl(0xa0); //Segment 方向选择,正常
        LCD_WriteControl(0xa4); //全屏点亮/变暗指令
        LCD_WriteControl(0xa6); //正向反向显示控制指令
        LCD_WriteControl(0xac); //关闭静态指示器
        LCD_WriteControl(0x00); //指令数据
        LCD_WriteControl(0x40 +32); //设置显示起始行对应RAM
        LCD_WriteControl(0xe0); //设置读写改模式
        LCD_WriteControl(0x34);
}
//========================================================================
// 绘点函数
//========================================================================
void LCD_Point(unsigned char x,unsigned char y,unsigned char i)
{
        unsigned char add_x=0x80;                 //GDRAM水平地址  
        unsigned char add_y=0x80;                 //GDRAM垂直地址
       
        unsigned char x_low,x_hight;     //定义列地址的高低位指令
        unsigned char x_low_old=0xff;
        unsigned char x_hight_old=0xff;
        //控制x,y的值
        x = 0x7f&x;
        y = 0x3f&y;
       
        if(i==0)
        {
                switch(x&0x0f)
  {
     case 0: x_hight = ~0x80;x_low = ~0x00;break;
     case 1: x_hight = ~0x40;x_low = ~0x00;break;
     case 2: x_hight = ~0x20;x_low = ~0x00;break;
     case 3: x_hight = ~0x10;x_low = ~0x00;break;
     case 4: x_hight = ~0x08;x_low = ~0x00;break;
     case 5: x_hight = ~0x04;x_low = ~0x00;break;
     case 6: x_hight = ~0x02;x_low = ~0x00;break;
     case 7: x_hight = ~0x01;x_low = ~0x00;break;
     case 8: x_hight = ~0x00;x_low = ~0x80;break;
     case 9: x_hight = ~0x00;x_low = ~0x40;break;
     case 10: x_hight = ~0x00;x_low = ~0x20;break;
     case 11: x_hight = ~0x00;x_low = ~0x10;break;
     case 12: x_hight = ~0x00;x_low = ~0x08;break;
     case 13: x_hight = ~0x00;x_low = ~0x04;break;
     case 14: x_hight = ~0x00;x_low = ~0x02;break;
     case 15: x_hight = ~0x00;x_low = ~0x01;break;
  }
        }else
                {
               
        switch(x&0x0f)
  {
     case 0: x_hight = 0x80;x_low = 0x00;break;
     case 1: x_hight = 0x40;x_low = 0x00;break;
     case 2: x_hight = 0x20;x_low = 0x00;break;
     case 3: x_hight = 0x10;x_low = 0x00;break;
     case 4: x_hight = 0x08;x_low = 0x00;break;
     case 5: x_hight = 0x04;x_low = 0x00;break;
     case 6: x_hight = 0x02;x_low = 0x00;break;
     case 7: x_hight = 0x01;x_low = 0x00;break;
     case 8: x_hight = 0x00;x_low = 0x80;break;
     case 9: x_hight = 0x00;x_low = 0x40;break;
     case 10: x_hight = 0x00;x_low = 0x20;break;
     case 11: x_hight = 0x00;x_low = 0x10;break;
     case 12: x_hight = 0x00;x_low = 0x08;break;
     case 13: x_hight = 0x00;x_low = 0x04;break;
     case 14: x_hight = 0x00;x_low = 0x02;break;
     case 15: x_hight = 0x00;x_low = 0x01;break;
  }
}
  
  add_y = add_y+(y&0x1f);
  
  if(y>>5)
  {
           add_x = 0x88;
  }
  
  add_x = add_x+(x>>4);
  
  //打开绘图显示  
  //LCD_WriteControl(0x34);
  asm("nop");
  LCD_WriteControl(add_y);          //垂直地址
  LCD_WriteControl(add_x);          //水平地址  
  LCD_ReadData();
  asm("nop");
  LCD_WriteControl(0x34);
  x_hight_old = LCD_ReadData();
  x_low_old = LCD_ReadData();
  asm("nop");
  LCD_WriteControl(add_y);          //垂直地址
  LCD_WriteControl(add_x);          //水平地址
  asm("nop");
  LCD_WriteData(x_hight&x_hight_old);
  LCD_WriteData(x_low&x_low_old);
  LCD_WriteControl(0x36);
}

void LCD_Fill(unsigned char dat)                 //填充GDRAM数据
{
        unsigned char i,j,k;
        unsigned char add_x=0x80;                 //GDRAM水平地址  
        unsigned char add_y=0x80;                 //GDRAM垂直地址
  //打开绘图显示  
  LCD_WriteControl(0x36);//init_lcd12864();     
        for(i=0;i<2;i++)
  {
      for(j=0;j<32;j++)
      {
          for(k=0;k<8;k++)
          {   
              LCD_WriteControl(0x36);   //打开绘图显示
                                                        asm("nop");
              LCD_WriteControl(add_y+j);          //垂直地址
              LCD_WriteControl(add_x+k);          //水平地址
              LCD_WriteData(dat);
              LCD_WriteData(dat);
          }
      }
      add_x=0x88;
  }   
  
        //LCD_WriteControl(0x30);                          //恢复基本指令集   
}

void aaaa(unsigned char x)
{
        int i = 0;
        int j;
        for(;i<128;i++)
        {
                j = sinf(i*(x*_PI/128))*20+30;
                LCD_Point(i,j,0);
        }
}

点赞  2009-11-29 16:06
有个小问题:
在我调用LCD_ReadData()方法读GDRAM数据时,如果数据为0x00  读出来为0x01不知道为什么!
有没有人能帮我解答一下!
点赞  2009-11-29 16:26
ding
点赞  2009-11-29 21:24
引用: 引用 3 楼 whrnkl 的回复:
有个小问题:
在我调用LCD_ReadData()方法读GDRAM数据时,如果数据为0x00? 读出来为0x01不知道为什么!
有没有人能帮我解答一下!
单步调试一下看看 到底是0还是1
点赞  2009-11-30 13:18
你那些宏定义要加上大括号呀
点赞  2009-11-30 14:53
顶下; 没有仿真器的情况下,可以多实验下;

我都用MCU驱动2.4寸的TFT,关键就靠分析--怀疑--有目的的试验--验证--成功。
点赞  2009-12-2 09:47
  LCD_WriteData(x_hight&x_hight_old);
  LCD_WriteData(x_low&x_low_old);
似乎有问题?
i=0可用,i=1会出现问题
点赞  2010-4-17 19:37
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复