登录  | 立即注册

游客您好!登录后享受更多精彩

扫一扫,访问微社区

QQ登录

只需一步,快速开始

开启左侧

[寒假笔记] stc12c5a60s2单片机LCD液晶显示屏移动显示

[复制链接]
发表于 2019-2-1 20:37:35 | 显示全部楼层 |阅读模式
学习笔记
学习科目: stc12c5a60s2单片机LCD液晶显示屏移动显示与时序图
学习安排: 达到熟练应用的程度
开始时间: 2019-02-01
结束时间: 2019-02-01
20190201174559.png 20190201174632.png 20190201174652.png
想要对LCD1602液晶显示屏有更好的理解,学会看时序图是必不可少的,把手册中的表与时序图结合起来看。先来看一下读操作时序的RS引脚和R/W引脚,这两个引脚先进行变化,因为是读操作,所以是R/W引脚首先要置位高电平,而不管它原来是什么。读指令还是读数据,都是读操作,而且都有可能,所以RS引脚既有可能置位高电平,也有可能置位低电平,而RS和R/W变化了经过tsp1这段时间后,使能引脚E才能从低电平到高电平发生变化。而使能引脚E拉高经过tD这段时间后,LCD1602输出DB的数据就是有效数据了,就可以来读取DB的数据了。读完后,要先把使能E拉低,经过一段时间后RS、R/W和DB才可以变化继续为下一次读写做准备了。
tc:指的是使能引脚E从本次上升沿到下次上升沿的最短时间是是400ns。
tpw:使能引脚E高电平的持续时间最短是150ns。
tr,tf:指使能引脚E的上升沿时间和下降沿时间,不能超过25ns。
tsp1:指的是RS和R/W引脚使能后至少保持30ns,使能引脚E才可以变成高电平。
tHD1:使能引脚E变成变成电平后,至少保持10ns后,RS和R/W才能进行变化。
TD:使能引脚E变成高电平后,最多100ns后,1602就把数据送出来了,就可以正常去读取状态或者数据了。
thd2:指的是读操作过程中,使能引脚E变成高电平后,至少保持20ns后,DB数据总线才可以进行变化。
tsp2:DB数据总线准备好后,至少保持40ns后,使能引脚E才可以从低到高进行使能变化。
thd2:指的是写操作过程中,要引脚E变成低电平后,至少保持10ns后,DB数据总线才可以变化。
#include <STC12C5A60S2.H>

sbit                RS = P2^0;                                         
sbit           RW = P2^1;                                         
sbit            E = P1^2;                                         
#define                Data P0                                         

bit flag500ms = 0;//50ms定时标志
unsigned char T0RH=0;//T0重载值的高字节
unsigned char T0RL=0;//T0重载值的低字节
unsigned char code str1[]="Welcome to HPU";//待显示的第一行字符串
unsigned char code str2[]="HPU EDDHPU EDD";//待显示的第二行字符串

void LCD_init();
void LCD_Display(unsigned char x,unsigned char y,
                       unsigned char *p,unsigned char len);
void ConfigTimer0(unsigned int ms);

void main()
{
        unsigned char i;
        unsigned char index = 0;//移动索引
  unsigned char pdata bufMove1[16+sizeof(str1)+16];//移动显示缓冲区1
        unsigned char pdata bufMove2[16+sizeof(str2)+16];//移动显示缓冲区2
       
        EA = 1;//开总中断
        ConfigTimer0(10);//配置T0定时10ms
        LCD_init();//初始化液晶1602
        for(i=0;i<16;i++)//缓冲区开头一段填充为空格
        {
                bufMove1=' ';
                bufMove2=' ';
        }
        for(i=0;i<(sizeof(str1)-1);i++)//待显示字符拷贝到缓冲区中间位置
  {
                bufMove1[16+i] = str1;
                bufMove2[16+i] = str2;
        }
        for(i=(16+sizeof(str1)-1);i<sizeof(bufMove1);i++)////缓冲区结尾一段填充为空格
        {
                bufMove1 = ' ';
                bufMove2 = ' ';
        }
        while(1)
        {
                if(flag500ms)//每500ms移动一次屏幕
                {
                        flag500ms=0;
                        LCD_Display(0,0,bufMove1+index,16);//从缓冲区抽出需显示的一段字符显示到液晶上
                        LCD_Display(0,1,bufMove2+index,16);
                        index++;//移动索引递增,实现左移
                        if(index>=(16+sizeof(str1)-1))//起始位置达到字符串尾部后即返回重头开始
                        {index=0;}       
                }       
        }       
}

void delay_us(unsigned int n)//微秒级延时函数
{
    extern void _nop_(void);
    register unsigned char i = n, j = (n>>8);
    _nop_(); _nop_(); _nop_();
    if ((--i) | j)
    {
        do
        {
            _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
            if (0xFF == (i--)) j--; else {_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();};
        } while (i | j);
    }
}

void delay_ms(unsigned int n)//毫秒级延时函数
{
while (n--) delay_us(1000);
}

void LCD_Write_Cmd(unsigned char cmd)//向LCD液晶写入一字节命令,cmd为待写入的命令值
{
    RS = 0;
    RW = 0;
    Data = cmd;
    delay_us(1);
    E = 1;
    delay_us(1);
    E = 0;
    delay_ms(2);
}

void LCD_Write_Data(unsigned char dat)//向LCD液晶写入一字节数据,cmd为待写入的数据值
{
    RS = 1;
    RW = 0;
    Data = dat;
    delay_us(1);
    E = 1;
    delay_us(1);
    E = 0;
    delay_ms(2);
}
void LcdSetCursor(x,y)//设置显示RAM起始地址,亦即光标位置,(x,y)为对应屏幕上的字符坐标
{
        unsigned char addr;

        if(y==0)//由输入的屏幕坐标计算显示RAM地址
                addr = 0x00+x;//第一行字符从0x00起始
  else
                addr = 0x40+x;//第二行字符地址从0x40起始
        LCD_Write_Cmd(addr|0x80);//设置RAM地址
}
void LCD_Display(unsigned char x,unsigned char y,
        unsigned char *p,unsigned char len)//在液晶上显示字符串,(x,y)为对应屏幕上的起始坐标,p为字符串指针,len为需显示的字符长度
{
     LcdSetCursor(x,y);//设置起始地址
     while (len--)//连续写入len个字符数据
     {
         LCD_Write_Data(*p++);//先显示p指向的数据,然后p自加1
     }
}
void LCD_init()//LCD 初始化函数
{
    delay_ms(40);
    LCD_Write_Cmd(0x38);
    delay_ms(5);
    LCD_Write_Cmd(0x38);
    delay_ms(1);
    LCD_Write_Cmd(0x38);
    LCD_Write_Cmd(0x38);//16*2显示,5*7点阵,8位数据接口
          LCD_Write_Cmd(0x08);//关闭显示
    LCD_Write_Cmd(0x01);//清屏
    LCD_Write_Cmd(0x06);//文字不动,地址自动加1
    LCD_Write_Cmd(0x0c);//显示器开,光标关闭
}
void ConfigTimer0(unsigned int ms)//配置并启动T0,ms为T0定时时间
{
        unsigned int tmp;//临时变量
       
        tmp = 33177600/12;//定时器计数频率
        tmp = (tmp*ms)/1000;//计数所需的计数值
        tmp = 65536 - tmp;//计算定时器重载值
        T0RH = (unsigned char)(tmp>>8);//定时器重载值拆分为高低字节
        T0RL = (unsigned char)tmp;
        TMOD &= 0xF0;//清零T0的控制位
        TMOD |= 0x01;//配置T0为模式1
        TH0 = T0RH;
        TL0 = T0RL;
        ET0 = 1;//使能T0中断
        TR0 = 1;//启动T0
}       
void InterruptTimer0() interrupt 1//T0中断服务函数,定时500ms
{
        static unsigned char tmr500ms = 0;
       
        TH0 = T0RH;//重新加载重载值
        TL0 = T0RL;
        tmr500ms++;
        if(tmr500ms>=100)
        {
                tmr500ms=0;
                flag500ms=1;
        }
}       
还请各位高手斧正,谢谢。

好懒~~不想说~~~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表