ATMEGA16 12864滚屏实现小记

[复制链接]
 楼主| 复仇之矛 发表于 2016-8-24 09:55 | 显示全部楼层 |阅读模式
第一次用到LCD12864滚屏功能
  1. #include <iom16v.h>
  2. #include <macros.h>
  3. #include <stdio.h>

  4. #define LCDb_CTRL            PORTD        //12864控制端口定义
  5. #define LCDb_CTRL_DDR        DDRD        //控制端口方向寄存器定义
  6. #define LCDb_RS                       PD4        //定义四个控制引脚
  7. #define LCDb_RW                        PD5
  8. #define LCDb_E                       PD6
  9. #define LCDb_RST                PD7
  10. #define LCDb_SET_RS                    LCDb_CTRL|=BIT(LCDb_RS)          //写数据
  11. #define LCDb_SET_RW                 LCDb_CTRL|=BIT(LCDb_RW)   //读操作
  12. #define LCDb_SET_E                  LCDb_CTRL|=BIT(LCDb_E)    //使能信号
  13. #define LCDb_SET_RST                  LCDb_CTRL|=BIT(LCDb_RST)  //不是能复位

  14. #define LCDb_CLR_RS                 LCDb_CTRL&=~BIT(LCDb_RS) //写指令
  15. #define LCDb_CLR_RW                 LCDb_CTRL&=~BIT(LCDb_RW) //写操作
  16. #define LCDb_CLR_E                  LCDb_CTRL&=~BIT(LCDb_E)  //失能信号
  17. #define LCDb_CLR_RST                 LCDb_CTRL&=~BIT(LCDb_RST) //使能复位
  18. //#define roll_number  13 所显示文字的行数
  19. unsigned char *string[]={

  20. "----南怀瑾------",
  21. "佛为心,        ",//空白位空格键,两空格一个汉字空间
  22. "道为骨,        ",
  23. "儒为表,        ",
  24. "大度看世界。    ",
  25. "技在手,        ",
  26. "能在身,        ",
  27. "思在脑,        ",
  28. "从容过生活。    ",
  29. "三千年读史,    ",
  30. "不外功名利禄。  ",
  31. "九**悟道,    ",
  32. "终归诗酒田园。  "
  33. };
  34. void Delayus(unsigned int US)                  
  35. {
  36. unsigned int i;
  37. US=US*5/4;                           //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
  38. for( i=0;i<US;i++);
  39. }
  40. void Delayms(unsigned int MS)                  
  41. {
  42. unsigned int i,j;
  43. for( i=0;i<MS;i++)
  44. for(j=0;j<1141;j++);        //1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
  45. }
  46. void Board_init(void)
  47. {
  48.         DDRA=0xFF;        //将四个IO口全部配置为输出
  49.         DDRB=0xFF;
  50.         DDRC=0xFF;
  51.         DDRD=0xFF;
  52.         SPCR=0x00;        //还原SPI口,使其为正常端口       
  53.         PORTA|=BIT(PA6);//(BEEP)关闭蜂鸣器
  54.         PORTC&=~BIT(PC6);          //(RELAY)初始化继电器为常闭连接状态       
  55.         PORTA&=~BIT(PA1);        //关闭SPI总线DA
  56.        
  57.         PORTB=0xFF;        //关闭LED
  58.         PORTA|=BIT(2);        //锁存数据,使LED熄灭
  59.         Delayus(5);               
  60.         PORTA&=~BIT(2);
  61.         PORTB=0x00;           //输出段选
  62.         PORTA|=BIT(3);                  
  63.         Delayus(50);                          
  64.         PORTA&=~BIT(3);            
  65.         PORTB=0xFF;           //输出位选
  66.         PORTA|=BIT(4);                  
  67.         Delayus(50);                                  
  68.         PORTA&=~BIT(4);       
  69.           
  70.         PORTD=0xFF;
  71.         PORTA|=BIT(PA7);
  72.         Delayus(50);
  73.         PORTA&=~BIT(PA7);
  74. }
  75. unsigned char Read_cmd(void)
  76. {
  77. unsigned char Rcmd,RD=0;
  78. LCDb_CLR_RS;
  79. LCDb_SET_RW;  //RS-->L,RW-->H 读出忙标志位(BF)以及位址计数器(AC)的状态
  80. LCDb_SET_E;
  81. DDRB=0x00;
  82. Delayms(1);
  83. Rcmd=PINB;
  84. LCDb_CLR_E;
  85. DDRB|=0xff;
  86. if(Rcmd&0x80)
  87. RD=1;            //忙
  88. else
  89. RD=0;

  90. return RD;  
  91. }
  92. void Write_cmd(unsigned char iCmd)
  93. {
  94. while(Read_cmd());
  95. LCDb_CLR_RS;
  96. LCDb_CLR_RW;  //RS-->L,RW-->L  MCU写指令到指令暂存器
  97. LCDb_SET_E;
  98. PORTB=iCmd;
  99. Delayus(100);
  100. LCDb_CLR_E;
  101. }
  102. void Write_dat(unsigned char iDat)
  103. {
  104. while(Read_cmd());
  105. LCDb_SET_RS; //RS-->H,RW-->L  MCU写数据到资料暂存器(DR)
  106. LCDb_CLR_RW;
  107. LCDb_SET_E;
  108. PORTB=iDat;
  109. Delayus(100);
  110. LCDb_CLR_E;
  111. }
  112. void LCD12864_portini(void)
  113. {
  114.         LCDb_CTRL_DDR |= BIT(LCDb_RS)|BIT(LCDb_RW)|BIT(LCDb_E)|BIT(LCDb_RST);//配置控制管脚为输出
  115.         DDRB |= 0xFF;  //配置数据管脚为输出
  116.         LCDb_SET_RST;                        //不使能复位端
  117.         //并口设置在硬件上实现
  118. }
  119. //void main(void)
  120. void roll_display(unsigned char roll_number)//所显示文字的行数#define roll_number  13
  121. {
  122. unsigned char i,j,row,roll_flag=0;
  123. unsigned char row_addr=0x80,flag=0;

  124. Board_init();
  125. LCD12864_portini();
  126. Delayms(500);
  127. /*
  128. 显示前的初始化命令
  129. */
  130. Write_cmd(0x38);//功能、模式设定
  131. Write_cmd(0x0c);//打开显示
  132. Write_cmd(0x01);//清屏
  133. Write_cmd(0x06);//输入模式设定
  134. Delayms(500);

  135. for(i=0;i<2;i++)
  136. {
  137.   row_addr=row_addr+i*0x10;
  138.   if(i%2==0)
  139.   {
  140.    Write_cmd(row_addr);                                                 //0x80
  141.    for(j=0;*(string[flag]+j)!='\0';j++)                //*(string[0]+j)
  142.    Write_dat(*(string[flag]+j));                        //写入"----南怀瑾------"
  143.    flag++;                                                                         //flag-->1                     
  144.    Write_cmd(row_addr+0x10);                                        //0x90
  145.    for(j=0;*(string[flag]+j)!='\0';j++)                //*(string[1]+j)
  146.    Write_dat(*(string[flag]+j));                        //写下"佛为心,        "
  147.    flag++;                                                                        //flag-->2
  148.   }
  149.   else
  150.   {
  151.    Write_cmd(row_addr-0x08);                                        //0x88
  152.    for(j=0;*(string[flag]+j)!='\0';j++)                //*(string[2]+j)
  153.    Write_dat(*(string[flag]+j));                        //写下"道为骨,        ",
  154.    flag++;                                                                        //flag-->3
  155.    Write_cmd(row_addr+0x08);                                        //0x98
  156.    for(j=0;*(string[flag]+j)!='\0';j++)                //*(string[3]+j)
  157.    Write_dat(*(string[flag]+j));                        //写下"儒为表,        "
  158.    flag++;                                                                        //flag-->4
  159.   }
  160. }
  161. row_addr=0xa0;
  162. Write_cmd(row_addr);                                                //0xa0
  163. for(j=0;*(string[flag-2]+j)!='\0';j++)                //*(string[2]+j)
  164. Write_dat(*(string[flag-2]+j));                        //写下"道为骨,        ",
  165. Write_cmd(row_addr+0x08);                                        //0xa8
  166. for(j=0;*(string[flag]+j)!='\0';j++)                //*(string[4]+j)
  167. Write_dat(*(string[flag]+j));                                //写下"大度看世界。    ",
  168. flag++;                                                                        //flag-->5
  169. Write_cmd(0x0c);                                                   //写入开显示命令
  170. row=4;
  171. while(1)
  172. {
  173.   if(roll_flag>=64)
  174.   roll_flag=0;
  175.   switch(row)
  176.   {
  177.    case 1:row_addr=0x80;break;
  178.    case 2:row_addr=0x90;break;
  179.    case 3:row_addr=0xa0;break;
  180.    case 4:row_addr=0xb0;break;
  181.   }
  182.   switch(row)
  183.   {
  184.    case 1:row=2;break;
  185.    case 2:row=3;break;
  186.    case 3:row=4;break;
  187.    case 4:row=1;break;
  188.   }
  189.   if(flag==1)
  190.   flag=(roll_number+1);
  191.   for(i=0;i<8;i++)
  192.   {
  193.    Write_cmd(0x34);//功能设定,进入扩充指令
  194.    Write_cmd(0x03);//允许输入卷动地址
  195.    Write_cmd(0x40+roll_flag++);//输入卷动地址rollflag
  196.    Write_cmd(0x30);//功能设定,进入基本指令
  197.    Write_cmd(row_addr+i);//数据写入的地址
  198.    if((*(string[flag-2]+2*i)!='\0')&&((flag-2)>=0))        //*(string[3]...)
  199.    Write_dat(*(string[flag-2]+2*i));                                //一个汉字的低字节
  200.    if((*(string[flag-2]+2*i+1)!='\0')&&((flag-2)>=0))
  201.    Write_dat(*(string[flag-2]+2*i+1));                                 //一个汉字的高字节
  202.    Delayms(150);
  203.   }
  204.   if(flag>=roll_number+1)
  205.   flag=1;
  206.   if(flag>=roll_number)
  207.   flag=0;
  208.   for(i=0;i<8;i++)
  209.   {
  210.    Write_cmd(0x34);//扩充指令
  211.    Write_cmd(0x03);//允许输入卷动地址
  212.    Write_cmd(0x40+roll_flag++);//输入卷动地址
  213.    Write_cmd(0x30);//进入基本指令
  214.    Write_cmd(row_addr+i+8);//数据写入的地址
  215.    if(*(string[flag]+2*i)!='\0')                                         //*(string[5]...)
  216.    Write_dat(*(string[flag]+2*i));
  217.    if(*(string[flag]+2*i+1)!='\0')
  218.    Write_dat(*(string[flag]+2*i+1));
  219.    Delayms(150);
  220.   }
  221.   flag++;
  222. }
  223. }

,网上查找资料,最后调试通过,故封装成一个模块,在此分享,同时求教不同的实现方式。LCD使用的是ST7920版,本次实现汉字滚屏,英文要修改部分参数。
 楼主| 复仇之矛 发表于 2016-8-24 14:40 | 显示全部楼层
  1. unsigned char *string[]={
  2. "-Comes and goes-",//00
  3. "The ones that   ",//01
  4. "seek and find   ",//02
  5. "Only to be let  ",//03
  6. "down            ",//04
  7. "Time after time ",//05
  8. "This one's for  ",//06
  9. "the torn down   ",//07
  10. "The experts at  ",//08
  11. "the fall        ",//09
  12. "Common friends  ",//10
  13. "get up now      ",//11
  14. "You're not along",//12
  15. "at all          ",//13
  16. };
  17. 将此段定义与已有定义进行对换,就可以实现英文滚动。
ccxlslr 发表于 2016-9-5 20:58 | 显示全部楼层
很不错哦!
 楼主| 复仇之矛 发表于 2016-9-18 10:53 | 显示全部楼层
最近在使用滚屏显示时,遇到一个不顺心的事儿,就是如果数组内容变更,或者多个数组不同界面显示时,这个模块函数封装还是不能够满足使用,所以今天进行改进。将被显示数组更名为
  1. unsigned char *allchar[]

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

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

已经验证无误。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

23

主题

185

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部