第一次用到LCD12864滚屏功能#include <iom16v.h>
#include <macros.h>
#include <stdio.h>
#define LCDb_CTRL PORTD //12864控制端口定义
#define LCDb_CTRL_DDR DDRD //控制端口方向寄存器定义
#define LCDb_RS PD4 //定义四个控制引脚
#define LCDb_RW PD5
#define LCDb_E PD6
#define LCDb_RST PD7
#define LCDb_SET_RS LCDb_CTRL|=BIT(LCDb_RS) //写数据
#define LCDb_SET_RW LCDb_CTRL|=BIT(LCDb_RW) //读操作
#define LCDb_SET_E LCDb_CTRL|=BIT(LCDb_E) //使能信号
#define LCDb_SET_RST LCDb_CTRL|=BIT(LCDb_RST) //不是能复位
#define LCDb_CLR_RS LCDb_CTRL&=~BIT(LCDb_RS) //写指令
#define LCDb_CLR_RW LCDb_CTRL&=~BIT(LCDb_RW) //写操作
#define LCDb_CLR_E LCDb_CTRL&=~BIT(LCDb_E) //失能信号
#define LCDb_CLR_RST LCDb_CTRL&=~BIT(LCDb_RST) //使能复位
//#define roll_number 13 所显示文字的行数
unsigned char *string[]={
"----南怀瑾------",
"佛为心, ",//空白位空格键,两空格一个汉字空间
"道为骨, ",
"儒为表, ",
"大度看世界。 ",
"技在手, ",
"能在身, ",
"思在脑, ",
"从容过生活。 ",
"三千年读史, ",
"不外功名利禄。 ",
"九**悟道, ",
"终归诗酒田园。 "
};
void Delayus(unsigned int US)
{
unsigned int i;
US=US*5/4; //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for( i=0;i<US;i++);
}
void Delayms(unsigned int MS)
{
unsigned int i,j;
for( i=0;i<MS;i++)
for(j=0;j<1141;j++); //1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
}
void Board_init(void)
{
DDRA=0xFF; //将四个IO口全部配置为输出
DDRB=0xFF;
DDRC=0xFF;
DDRD=0xFF;
SPCR=0x00; //还原SPI口,使其为正常端口
PORTA|=BIT(PA6);//(BEEP)关闭蜂鸣器
PORTC&=~BIT(PC6); //(RELAY)初始化继电器为常闭连接状态
PORTA&=~BIT(PA1); //关闭SPI总线DA
PORTB=0xFF; //关闭LED
PORTA|=BIT(2); //锁存数据,使LED熄灭
Delayus(5);
PORTA&=~BIT(2);
PORTB=0x00; //输出段选
PORTA|=BIT(3);
Delayus(50);
PORTA&=~BIT(3);
PORTB=0xFF; //输出位选
PORTA|=BIT(4);
Delayus(50);
PORTA&=~BIT(4);
PORTD=0xFF;
PORTA|=BIT(PA7);
Delayus(50);
PORTA&=~BIT(PA7);
}
unsigned char Read_cmd(void)
{
unsigned char Rcmd,RD=0;
LCDb_CLR_RS;
LCDb_SET_RW; //RS-->L,RW-->H 读出忙标志位(BF)以及位址计数器(AC)的状态
LCDb_SET_E;
DDRB=0x00;
Delayms(1);
Rcmd=PINB;
LCDb_CLR_E;
DDRB|=0xff;
if(Rcmd&0x80)
RD=1; //忙
else
RD=0;
return RD;
}
void Write_cmd(unsigned char iCmd)
{
while(Read_cmd());
LCDb_CLR_RS;
LCDb_CLR_RW; //RS-->L,RW-->L MCU写指令到指令暂存器
LCDb_SET_E;
PORTB=iCmd;
Delayus(100);
LCDb_CLR_E;
}
void Write_dat(unsigned char iDat)
{
while(Read_cmd());
LCDb_SET_RS; //RS-->H,RW-->L MCU写数据到资料暂存器(DR)
LCDb_CLR_RW;
LCDb_SET_E;
PORTB=iDat;
Delayus(100);
LCDb_CLR_E;
}
void LCD12864_portini(void)
{
LCDb_CTRL_DDR |= BIT(LCDb_RS)|BIT(LCDb_RW)|BIT(LCDb_E)|BIT(LCDb_RST);//配置控制管脚为输出
DDRB |= 0xFF; //配置数据管脚为输出
LCDb_SET_RST; //不使能复位端
//并口设置在硬件上实现
}
//void main(void)
void roll_display(unsigned char roll_number)//所显示文字的行数#define roll_number 13
{
unsigned char i,j,row,roll_flag=0;
unsigned char row_addr=0x80,flag=0;
Board_init();
LCD12864_portini();
Delayms(500);
/*
显示前的初始化命令
*/
Write_cmd(0x38);//功能、模式设定
Write_cmd(0x0c);//打开显示
Write_cmd(0x01);//清屏
Write_cmd(0x06);//输入模式设定
Delayms(500);
for(i=0;i<2;i++)
{
row_addr=row_addr+i*0x10;
if(i%2==0)
{
Write_cmd(row_addr); //0x80
for(j=0;*(string[flag]+j)!='\0';j++) //*(string[0]+j)
Write_dat(*(string[flag]+j)); //写入"----南怀瑾------"
flag++; //flag-->1
Write_cmd(row_addr+0x10); //0x90
for(j=0;*(string[flag]+j)!='\0';j++) //*(string[1]+j)
Write_dat(*(string[flag]+j)); //写下"佛为心, "
flag++; //flag-->2
}
else
{
Write_cmd(row_addr-0x08); //0x88
for(j=0;*(string[flag]+j)!='\0';j++) //*(string[2]+j)
Write_dat(*(string[flag]+j)); //写下"道为骨, ",
flag++; //flag-->3
Write_cmd(row_addr+0x08); //0x98
for(j=0;*(string[flag]+j)!='\0';j++) //*(string[3]+j)
Write_dat(*(string[flag]+j)); //写下"儒为表, "
flag++; //flag-->4
}
}
row_addr=0xa0;
Write_cmd(row_addr); //0xa0
for(j=0;*(string[flag-2]+j)!='\0';j++) //*(string[2]+j)
Write_dat(*(string[flag-2]+j)); //写下"道为骨, ",
Write_cmd(row_addr+0x08); //0xa8
for(j=0;*(string[flag]+j)!='\0';j++) //*(string[4]+j)
Write_dat(*(string[flag]+j)); //写下"大度看世界。 ",
flag++; //flag-->5
Write_cmd(0x0c); //写入开显示命令
row=4;
while(1)
{
if(roll_flag>=64)
roll_flag=0;
switch(row)
{
case 1:row_addr=0x80;break;
case 2:row_addr=0x90;break;
case 3:row_addr=0xa0;break;
case 4:row_addr=0xb0;break;
}
switch(row)
{
case 1:row=2;break;
case 2:row=3;break;
case 3:row=4;break;
case 4:row=1;break;
}
if(flag==1)
flag=(roll_number+1);
for(i=0;i<8;i++)
{
Write_cmd(0x34);//功能设定,进入扩充指令
Write_cmd(0x03);//允许输入卷动地址
Write_cmd(0x40+roll_flag++);//输入卷动地址rollflag
Write_cmd(0x30);//功能设定,进入基本指令
Write_cmd(row_addr+i);//数据写入的地址
if((*(string[flag-2]+2*i)!='\0')&&((flag-2)>=0)) //*(string[3]...)
Write_dat(*(string[flag-2]+2*i)); //一个汉字的低字节
if((*(string[flag-2]+2*i+1)!='\0')&&((flag-2)>=0))
Write_dat(*(string[flag-2]+2*i+1)); //一个汉字的高字节
Delayms(150);
}
if(flag>=roll_number+1)
flag=1;
if(flag>=roll_number)
flag=0;
for(i=0;i<8;i++)
{
Write_cmd(0x34);//扩充指令
Write_cmd(0x03);//允许输入卷动地址
Write_cmd(0x40+roll_flag++);//输入卷动地址
Write_cmd(0x30);//进入基本指令
Write_cmd(row_addr+i+8);//数据写入的地址
if(*(string[flag]+2*i)!='\0') //*(string[5]...)
Write_dat(*(string[flag]+2*i));
if(*(string[flag]+2*i+1)!='\0')
Write_dat(*(string[flag]+2*i+1));
Delayms(150);
}
flag++;
}
}
,网上查找资料,最后调试通过,故封装成一个模块,在此分享,同时求教不同的实现方式。LCD使用的是ST7920版,本次实现汉字滚屏,英文要修改部分参数。
|