打印

ATMEGA16 12864滚屏实现小记

[复制链接]
2322|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
复仇之矛|  楼主 | 2016-8-24 09:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
第一次用到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版,本次实现汉字滚屏,英文要修改部分参数。

相关帖子

沙发
复仇之矛|  楼主 | 2016-8-24 14:40 | 只看该作者
unsigned char *string[]={
"-Comes and goes-",//00
"The ones that   ",//01
"seek and find   ",//02
"Only to be let  ",//03
"down            ",//04
"Time after time ",//05
"This one's for  ",//06
"the torn down   ",//07
"The experts at  ",//08
"the fall        ",//09
"Common friends  ",//10
"get up now      ",//11
"You're not along",//12
"at all          ",//13
};
将此段定义与已有定义进行对换,就可以实现英文滚动。

使用特权

评论回复
板凳
ccxlslr| | 2016-9-5 20:58 | 只看该作者
很不错哦!

使用特权

评论回复
地板
复仇之矛|  楼主 | 2016-9-18 10:53 | 只看该作者
最近在使用滚屏显示时,遇到一个不顺心的事儿,就是如果数组内容变更,或者多个数组不同界面显示时,这个模块函数封装还是不能够满足使用,所以今天进行改进。将被显示数组更名为
unsigned char *allchar[]

将函数名更改为
void roll_display(unsigned char roll_number,unsigned char *string[])

如此显示时调用实现如下
while(1)
{roll_display(14,allchar);}

已经验证无误。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

23

主题

185

帖子

3

粉丝