因为我在网上看了很久,12864绘图中的画点有些难度。因为可以液晶芯片不一样驱动会有差别。
所以把我写的贴出来大家分享,不明白的加我QQ:343700980一起交流!
我使用的环境是:
单片机:ATMega16
开发板:DDC-16B
液晶是:YJD12864C-1(可以参考《ST7920中文手册》)
硬件链接:
LCD MCU
RS PA5
RW PA6
EN PA7
DB0-7 PD0-7
废话不说,源码:
文件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);
}
}
有个小问题:
在我调用LCD_ReadData()方法读GDRAM数据时,如果数据为0x00 读出来为0x01不知道为什么!
有没有人能帮我解答一下!
顶下; 没有仿真器的情况下,可以多实验下;
我都用MCU驱动2.4寸的TFT,关键就靠分析--怀疑--有目的的试验--验证--成功。
LCD_WriteData(x_hight&x_hight_old);
LCD_WriteData(x_low&x_low_old);
似乎有问题?
i=0可用,i=1会出现问题