由于CC2530终端的IO端口很紧张,所以驱动12864屏幕采用串行驱动,接法很简单,只需要三根线
首先将PSB引脚接地,使12864处于串口模式;更简单的接法CS引脚都可以省略,直接将CS接到5v上,为了通信可靠,暂时保留CS引脚。
这样12864只需要4,5,6引脚,其中
4脚RS(CS) 为12864的片选信号,高电平有效
5脚R/W(SID)为12864串行的数据口
6脚E(CLK) 为12864串行的同步时钟,由CC2530提供
与cc2530的接法如下:
#define SCLK P0_7 //E
#define SID P0_6 //RW
#define CS P0_5
具体的底层通信协议:
串行数据传送共分三个字节完成:
第一字节:串口控制—格式 11111AB0
A为RW数据传送方向控制:H表示数据从LCD到MCU,L表示数据从MCU到LCD;与并行中的RW的作用相同
B为RS数据类型选择:H表示数据是显示数据,L表示数据是控制指令;与并行中的RS的作用相同
最后一位固定为0
第二字节:(并行)8位数据的高4位—格式 DDDD0000
第三字节:(并行)8位数据的低4位—格式 DDDD0000
注意,中文pdf介绍有错误
用C语言描述
//------------------------写指令函数--------------------------------------
void LCD_write_command(uchar command)
{
CS = 1;
/*
1111 1ABC
A为数据传送方向控制:H表示数据从LCD到MCU,L表示数据从MCU到LCD
B为数据类型选择:H表示数据是显示数据,L表示数据是控制指令
C固定为0
*/
LCD_write_byte(0xF8); // 1111 1000
LCD_write_byte(command&0xF0);
LCD_write_byte((command<<4)&0xF0);
CS = 0;
}
//------------------------写数据函数--------------------------------------
void LCD_write_data(uchar data)
{
CS = 1;
/*
1111 1ABC
A为数据传送方向控制:H表示数据从LCD到MCU,L表示数据从MCU到LCD
B为数据类型选择:H表示数据是显示数据,L表示数据是控制指令
C固定为0
*/
LCD_write_byte(0xFA); // 1111 1010
LCD_write_byte(data&0xF0);
LCD_write_byte((data<<4)&0xF0);
CS = 0;
}
1.在供电VCC 4.5V时候同步时钟SCLK最大频率为2.5MHz(根据ST7920 datasheet P43)
2.根据时序图数据在SCLK上升沿锁存
3.串行通信只能写,不能向外读数据(根据ST7920 datasheet P26),所以判断指令是否执行结束只能用延迟
4.12864内部的时钟约为540Khz,这个频率是由供电电压VCC和一个K级的电阻决定的,此电阻可以就是12864板子上写着XX3的电阻。
5.12864清屏时间为1.6 ms (根据ST7920 datasheet),其他的指令均为72us,注意中文介绍有误
CC2530的系统频率为32Mhz,一条指令的执行时间为1/32Mhz = 32.25ns,200ns的时间可以执行指令200/32.25 = 6.20条,所以延迟7个指令足够
写字节函数(包括延迟产时钟函数):
void LCD_write_byte(uchar byte)
{
SCLK = 0;
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 7; j++);
SID = byte/128;
SCLK = 1;//上升沿锁存数据
for(int j = 0; j < 7; j++);
byte = byte << 1;
SCLK = 0;
}
}
cc2530一个除法div用了5个时钟周期,一个左移用1个时钟周期
所以可以写成这样
void LCD_write_byte(uchar byte)
{
SCLK = 0;
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 2; j++);
SID = byte/128; //5 circle
SCLK = 1;//上升沿锁存数据
for(int j = 0; j < 6; j++);
byte = byte << 1;//1 circle
SCLK = 0;
}
}
当然以上写的也不是最优的,因为毕竟是IAR翻译了C语言,翻译的原则与结果到底是怎么样的跟具体的编译器有关
for(int j = 0; j < 2; j++);
是不是2个时钟周期。在这里只是大概的延迟,如果想精确延时建议还是用汇编写
根据Zigbee网关 CC2530驱动1602显示屏,将底层的程序改了一些,改好的驱动程序为
/*--------------------------------------------------------------*/
//Name: LCD12864串行驱动程序
//File: lcd12864_driver.c
//Date: 15-12-08
//Ver: 0.1
//连接方法请参考:http://blog.csdn.net/u010615629/article/details/50232559
/*--------------------------------------------------------------*/
#include "lcd12864_driver.h"
//LCD12864接口定义
#define SCLK P0_7 //E
#define SID P0_6 //RW
#define CS P0_5
//-------------------------1us延时函数---------------------------------
void delay_1us(void)
{
int i = 0;
for(i=0;i<32;i++);
}
//------------------------N us延时函数---------------------------------
void delay_nus(uint n)
{
uint i=0;
for (i=0;i=8)
{
x=0;
y++;
}
if(y>=4) y=0;
LCD_set_xy(x, y);
LCD_write_data(*DData);
DData++;
LCD_write_data(*DData);
DData++;
x++;
}
}
void LCD_init(void)
{
delay_nms(5); //延迟5ms等待液晶自身上电准备好
LCD_write_command(0x30);//功能设置,一次送8位数据,基本指令集
LCD_write_command(0x01);//0000,0001 清屏
delay_nms(5);
LCD_write_command(0x06);//点设定,显示字符/光标从左到右移位,DDRAM地址加 一//
LCD_write_command(0x0c);//显示设定,开显示,显示光标,当前显示位反白闪动
}
void System_init(void)
{
CLKCONCMD &= ~0x40; // 设置系统时钟源为 32MHZ晶振
while(CLKCONSTA & 0x40); // 等待晶振稳定
CLKCONCMD &= ~0x47;
P0DIR |= 1<<5|1<<6|1<<7;
}
void main(void)
{
int i,j;
System_init();
Key_init();
LCD_init();
LCD_PutStr("中国辽宁",1,1);
LCD_PutStr("web.nenewind.com",0,0);
}
有图为证,成功了
资料下载:Sitronix ST7920 12864液晶资料