打印

ST7920中文字库液晶显示模块LCD12232并行8位显示C30演示程序

[复制链接]
8485|27
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hotpower|  楼主 | 2007-12-8 10:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*------------------------------------------------------------
ST7920中文字库液晶显示模块LCD12232并行8位显示C30演示程序
C30菜鸟HotPower@126.com             2007.12.8 于雁塔菜地
-------------------------------------------------------------*/

#include "lcd.h"

unsigned char LcdRowWriteEnable[2] = {0, 0};//显示行刷新允许标志
unsigned char LcdBuffer[2][15];//LCD显示缓冲区(2行15个字符)
unsigned char LcdRow = 0, LcdCol = 0;//虚拟光标

void LcdInit(void)//LCD初始化
{
    LcdIOInit();//LCD管脚初始化
    LcdClearBuffer();//清空LCD显示缓冲区

//    LcdWriteCommand(0x20);//发送功能设定控制命令(4位)
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x02);//发送位址归位命令,设定DDRAM位址计数器为0
    LcdWriteCommand(0x04);//发送进入点命令 
    LcdWriteCommand(0x0c);//发送开显示关光标命令
    LcdWriteCommand(0x01);//发送清除显示命令 
    LcdWriteCommand(0x80);//发送设定DDRAM地址0x00命令,光标定位到(0,0)

/*----------------------------------------------------------------------
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x01);//发送清除显示命令 
    LcdWriteCommand(0x06);//发送进入点命令0x06 
    LcdWriteCommand(0x0a);//发送开关显示关光标命令
    LcdWriteCommand(0x0c);//发送开显示关光标命令
    LcdWriteCommand(0x02);//发送位址归位命令,设定DDRAM位址计数器为0
    LcdWriteCommand(0x17);//游标或显示移位控制
    LcdWriteCommand(0x80);//发送设定DDRAM地址0x00命令,光标定位到(0,0)
----------------------------------------------------------------------*/
    LCD_BK = 0;//打开背光
}

void LcdIOInit(void)//LCD管脚初始化
{
    LCD_BK = 0;//打开背光
    LCD_E = 0;//不使能 
    LCD_RW = 1;//写读数据 
    TRIS_E  =  PORTOUTMODE;//定义E为输出IO
    TRIS_RW =  PORTOUTMODE;//定义RW为输出IO
    TRIS_RS =  PORTOUTMODE;//定义RS为输出IO
    TRIS_BK =  PORTOUTMODE;//定义BK为输出IO
    TRIS_DATA = 0;//定义RE0~RE7为输出IO
}

void LcdWriteCommand(unsigned char Command)//写LCD命令字
{
    LCD_RS = 0;//命令 
    Nop(); 
    LCD_RW = 0;//写命令 
    Nop(); 
    LCD_E = 1;//使能       
    Nop(); 
    LCD_BUS = Command;//发送8位命令 
    Nop();     
    LCD_E = 0;//不使能,读出数据 打入命令
    Nop();     
    LCD_RW = 1;//写命令结束 
      if (Command == 0x01)//清除显示命令,需要等待时间相对较长
    {
         _delay_loop(1600);//st7920要求等待1.6mS
    }
      else
    {
         _delay_loop(72);//st7920要求等待72uS
    }
}

void LcdWriteData(unsigned char data)//写LCD显示数据 

    LCD_RS = 1;//数据 
    Nop(); 
    LCD_RW = 0;//写数据 
    Nop(); 
    LCD_E = 1;//使能       
    Nop(); 
    LCD_BUS = data;//发送8位数据 
    Nop();     
    LCD_E = 0;//不使能,打入数据 
    Nop();     
    LCD_RW = 1;//写数据结束 
    _delay_loop(72);//st7920要求等待72uS


void LcdWaitBusy(void)//LCD忙标志测试(有时死机,故没用)  

    TRIS_DATA = 0xff;//定义RE0~RE7为输入IO 
    LCD_BUS = 0xff;
    Nop(); 
    LCD_RS = 0;//命令         
    Nop(); 
    LCD_RW = 1;//读数据
    Nop(); 
    LCD_E = 1;//使能       
    Nop(); 
    while(LCD_BF)//读取忙碌标志BF(LCD_DATA.7)
    {
        Nop();//搞不清有时死机在此处,所以用_delay_loop()代替
    }
    LCD_E = 0;//不使能,读出状态 
    Nop();     
    TRIS_DATA = 0;//定义RE0~RE7为输出IO
    Nop();     


void LcdClearBuffer(void)
{
unsigned char i, j;
    for (i = 0;i < 2;i ++)//2行字符 
    {//2行汉字
        for (j = 0;j < 15; j ++)//15个字符
        {//每行7个半汉字15个字符
            LcdBuffer[j] = ' ';//空白字符
        }
        LcdRowWriteEnable = 1;//允许此行刷新汉字显示
    }
    LcdRow = 0;//虚拟光标定位在0行
    LcdCol = 0;//虚拟光标定位在0列
}


void LcdDisplayPos(unsigned char row, unsigned char col)
{
    if ((row < 2) && (col < 15))//容错处理,光标越界
    {
        LcdRow = row;//刷新虚拟光标
        LcdCol = col;//刷新虚拟光标
        LcdRowWriteEnable[row] = 1;//允许此行刷新汉字显示
    }
}

void LcdDisplay(const char * string)//不真的LCD显示
{
    while(*string)//0字符结束
    {
        LcdBuffer[LcdRow][LcdCol ++] = *string ++;//写入显示缓冲区
    }
}

unsigned char LcdDisplayBuffer(void)//显示刷新LCD缓冲区内的数据(一般0.25S~0.5S刷新一次)
{
unsigned char i, j;
unsigned char num = 0;//刷新字符个数
    for (i = 0; i < 2; i ++)
    {//2行汉字
        if (LcdRowWriteEnable)
        {//允许此行刷新汉字显示
            LcdWriteCommand(0x80 + (i << 4));//移动真的LCD光标
            for (j = 0; j < 15; j ++)
            {//每行7个半汉字15个字符
                LcdWriteData(LcdBuffer[j]);//刷新显示字符
                num ++;//刷新字符个数计数
            }
            LcdRowWriteEnable = 0;//过后不允许此行刷新汉字显示
        }
    }
    return num;//返回实际刷新字符个数
}

void _delay_loop(unsigned long count)//软件延时
{
    while(count --)
    {
        //ClrWdt();//注意大延时要记住喂狗
    }
}

相关链接:http://blog.**/hotpower/65478/message.aspx
沙发
幸福DE饭团| | 2007-12-8 10:52 | 只看该作者

站位

进度好快

使用特权

评论回复
板凳
hotpower|  楼主 | 2007-12-8 10:57 | 只看该作者

哈哈~~~俺做这些MCU菜鸟真像喝稀饭似的,感觉味道都一样~~~

使用特权

评论回复
地板
fzj| | 2007-12-8 11:01 | 只看该作者

都一种语言,当然快了

写过ST7920驱动,直接COPY就OK了,呵呵

使用特权

评论回复
5
幸福DE饭团| | 2007-12-8 11:07 | 只看该作者

差距

光着屁股都追不上.
本想开始学ARM和Linux 看来还是好好的精通PIC吧

使用特权

评论回复
6
hotpower|  楼主 | 2007-12-8 11:10 | 只看该作者

这种缓冲的控制方式不会产生乱屏

俺反对直接操作写屏~~~

只要在定时中断内嵌入LcdDisplayBuffer(),即可刷新LCD.

当然也可在主消息环内.

用户只需操作LcdDisplay()即可.

例如:

int main(void)
{
    disable_interrupts();//关中断
    SystemInit();//系统初始化
    LcdDisplayPos(0, 0);//0行0列开始
    LcdDisplay("123456789012345");//
    LcdDisplayPos(1, 0);//1行0列开始
    LcdDisplay("看你晕不晕~~~");//
    enable_interrupts();//开中断
    while(1)
    {
        Nop();//"黑奔"开始    
    }
    return 0;
}

使用特权

评论回复
7
幸福DE饭团| | 2007-12-8 11:38 | 只看该作者

...

晕乎乎,现在看论坛都不敢放心大胆的看了,看到是hotpower名字尤其小心,浏览器要一点一点往下拖,一见到头发马上跳过(杀伤力太强了).
看 HotPower的文潭 收获不小,如 键扫描及动态显示刷新  非常实用,解决了当时自学PIC时的一大难题.现在还影像深刻.

使用特权

评论回复
8
hotpower|  楼主 | 2007-12-8 12:04 | 只看该作者

哈哈~~~网管回来了,不然让你再晕些~~~

使用特权

评论回复
9
fzj| | 2007-12-8 12:53 | 只看该作者

HOTPOWER老师:有问题请教

    while(LCD_BF)//读取忙碌标志BF(LCD_DATA.7)
    {
        Nop();//搞不清有时死机在此处,所以用_delay_loop()代替
    }
个人觉得查询忙标志不能这样死等待的查询,这样的查询方式CPU很被动可否搞成这样的方式?另外你的死机是否跟没开WDT有关啊?
while  ((LCD_BF)||(++DELAY<5000)) CLRWDT();
if   (DELAY>=5000)   LCD_ERR();  //错误处理
else
{............ //正常处理
}

使用特权

评论回复
10
幸福DE饭团| | 2007-12-8 14:20 | 只看该作者

我原来写12864的时候也出现这问题

程序中加入检测BUSY位 运行出现问题 后来直接用1ms延时代替

使用特权

评论回复
11
hotpower|  楼主 | 2007-12-9 16:34 | 只看该作者

不要叫俺什么老师,叫俺戴草帽的农民~~~

这个帖子是昨天下午写的,由于俺家网管回来了,路由器上传不了...

因为做菜鸟还没进行到WDT和系统配置~~~

俺从来反对用while();
主张用for();

这样就不会死机了~~~

但俺发现总死机,所以还不如直接用_delay_loop();

实际运行时,主要运行

unsigned char LcdDisplayBuffer(void)//显示刷新LCD缓冲区内的数据(一般0.25S~0.5S刷新一次)
{
unsigned char i, j;
unsigned char num = 0;//刷新字符个数
    for (i = 0; i < 2; i ++)
    {//2行汉字
        if (LcdRowWriteEnable)
        {//允许此行刷新汉字显示
            LcdWriteCommand(0x80 + (i << 4));//移动真的LCD光标
            for (j = 0; j < 15; j ++)
            {//每行7个半汉字15个字符
                LcdWriteData(LcdBuffer[j]);//刷新显示字符
                num ++;//刷新字符个数计数
            }
            LcdRowWriteEnable = 0;//过后不允许此行刷新汉字显示
        }
    }
    return num;//返回实际刷新字符个数
}

其中LcdWriteCommand()和LcdWriteData()都用了
_delay_loop(72);//st7920要求等待72uS

可是俺还没学定时器和每天指令运行机器周期到底是多少~~~

void _delay_loop(unsigned long count)//软件延时
{
    while(count --)
    {
        //ClrWdt();//注意大延时要记住喂狗
    }
}

这那里是uS软件延时呀~~~

俺只是在仿真器上调试通过的,烧写的还不能运行~~~

昨晚看了配置好象大概在0xaafc中(忘了~~~).看了是默认打开WDT.

而俺的main()没有clrwdt(),所以烧写后肯定不能运行了~~~

上班再做实验,争取早日菜鸟毕业~~~



使用特权

评论回复
12
gglu| | 2007-12-9 16:35 | 只看该作者

这农民还挺会种菜

使用特权

评论回复
13
hotpower|  楼主 | 2007-12-9 17:20 | 只看该作者

使用LcdWaitBusy()并通过测试的LCD12232并行显示C30演示程序

/*------------------------------------------------------------
ST7920中文字库液晶显示模块LCD12232并行8位显示C30演示程序
C30菜鸟HotPower@126.com             2007.12.9 于雁塔菜地
-------------------------------------------------------------*/

#include "lcd.h"

unsigned char LcdRowWriteEnable[2] = {0, 0};//显示行刷新允许标志
unsigned char LcdBuffer[2][15];//LCD显示缓冲区(2行15个字符)
unsigned char LcdRow = 0, LcdCol = 0;//虚拟光标

void LcdInit(void)//LCD初始化
{
    LcdIOInit();//LCD管脚初始化
    LcdClearBuffer();//清空LCD显示缓冲区

//    LcdWriteCommand(0x20);//发送功能设定控制命令(4位)
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x02);//发送位址归位命令,设定DDRAM位址计数器为0
    LcdWriteCommand(0x04);//发送进入点命令 
    LcdWriteCommand(0x0c);//发送开显示关光标命令
    LcdWriteCommand(0x01);//发送清除显示命令 
    LcdWriteCommand(0x80);//发送设定DDRAM地址0x00命令,光标定位到(0,0)

/*----------------------------------------------------------------------
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x30);//发送功能设定控制命令(8位)
    LcdWriteCommand(0x01);//发送清除显示命令 
    LcdWriteCommand(0x06);//发送进入点命令0x06 
    LcdWriteCommand(0x0a);//发送开关显示关光标命令
    LcdWriteCommand(0x0c);//发送开显示关光标命令
    LcdWriteCommand(0x02);//发送位址归位命令,设定DDRAM位址计数器为0
    LcdWriteCommand(0x17);//游标或显示移位控制
    LcdWriteCommand(0x80);//发送设定DDRAM地址0x00命令,光标定位到(0,0)
----------------------------------------------------------------------*/
    LCD_BK = 0;//打开背光
}

void LcdIOInit(void)//LCD管脚初始化
{
    LCD_BK = 0;//打开背光
    LCD_E = 0;//不使能 
    LCD_RW = 1;//写读数据 
    TRIS_E  =  PORTOUTMODE;//定义E为输出IO
    TRIS_RW =  PORTOUTMODE;//定义RW为输出IO
    TRIS_RS =  PORTOUTMODE;//定义RS为输出IO
    TRIS_BK =  PORTOUTMODE;//定义BK为输出IO
    TRIS_DATA = 0;//定义RE0~RE7为输出IO
}

void LcdWriteCommand(unsigned char Command)//写LCD命令字
{
    LCD_RS = 0;//命令 
    Nop(); 
    LCD_RW = 0;//写命令 
    Nop(); 
    LCD_E = 1;//使能       
    Nop(); 
    LCD_BUS = Command;//发送8位命令 
    Nop();     
    LCD_E = 0;//不使能,读出数据 打入命令
    Nop();     
    LCD_RW = 1;//写命令结束 
      if (Command == 0x01)//清除显示命令,需要等待时间相对较长
    {
        LcdWaitBusy(1600);
//        _delay_loop(1600);//st7920要求等待1.6mS
    }
      else
    {
        LcdWaitBusy(72);
//         _delay_loop(72);//st7920要求等待72uS
    }
}

void LcdWriteData(unsigned char data)//写LCD显示数据 

    LCD_RS = 1;//数据 
    Nop(); 
    LCD_RW = 0;//写数据 
    Nop(); 
    LCD_E = 1;//使能       
    Nop(); 
    LCD_BUS = data;//发送8位数据 
    Nop();     
    LCD_E = 0;//不使能,打入数据 
    Nop();     
    LCD_RW = 1;//写数据结束 
    LcdWaitBusy(72);
//    _delay_loop(72);//st7920要求等待72uS


void LcdWaitBusy(unsigned int count)//LCD忙标志测试(有时死机,故没用参数可以防止死机)  
{
    TRIS_DATA = 0xff;//定义RE0~RE7为输入IO 
    LCD_BUS = 0xff;
    Nop(); 
    LCD_RS = 0;//命令         
    Nop(); 
    LCD_RW = 1;//读数据
    Nop(); 
    LCD_E = 1;//使能       
    while (count --)
    {
        if (!LCD_BF) break;//读取忙碌标志BF(LCD_DATA.7)
        ClrWdt();
    }
    LCD_E = 0;//不使能,读出状态 
    Nop();     
    TRIS_DATA = 0;//定义RE0~RE7为输出IO
    Nop();     


void LcdClearBuffer(void)
{
unsigned char i, j;
    for (i = 0;i < 2;i ++)//2行字符 
    {//2行汉字
        for (j = 0;j < 15; j ++)//15个字符
        {//每行7个半汉字15个字符
            LcdBuffer[j] = ' ';//空白字符
        }
        LcdRowWriteEnable = 1;//允许此行刷新汉字显示
    }
    LcdRow = 0;//虚拟光标定位在0行
    LcdCol = 0;//虚拟光标定位在0列
}


void LcdDisplayPos(unsigned char row, unsigned char col)
{
    if ((row < 2) && (col < 15))//容错处理,光标越界
    {
        LcdRow = row;//刷新虚拟光标
        LcdCol = col;//刷新虚拟光标
        LcdRowWriteEnable[row] = 1;//允许此行刷新汉字显示
    }
}

void LcdDisplay(const char * string)//不真的LCD显示
{
    while(*string)//0字符结束
    {
        LcdBuffer[LcdRow][LcdCol ++] = *string ++;//写入显示缓冲区
    }
}

unsigned char LcdDisplayBuffer(void)//显示刷新LCD缓冲区内的数据(一般0.25S~0.5S刷新一次)
{
unsigned char i, j;
unsigned char num = 0;//刷新字符个数
    for (i = 0; i < 2; i ++)
    {//2行汉字
        if (LcdRowWriteEnable)
        {//允许此行刷新汉字显示
            LcdWriteCommand(0x80 + (i << 4));//移动真的LCD光标
            for (j = 0; j < 15; j ++)
            {//每行7个半汉字15个字符
                LcdWriteData(LcdBuffer[j]);//刷新显示字符
                num ++;//刷新字符个数计数
            }
            LcdRowWriteEnable = 0;//过后不允许此行刷新汉字显示
        }
    }
    return num;//返回实际刷新字符个数(这个"黑奔时有用~~~")
}

使用特权

评论回复
14
hotpower|  楼主 | 2007-12-19 21:24 | 只看该作者

哈哈~~~菜农半天的菜鸟例程看来很稳定呀~~~自贺一番~~~

当然俺也样的帖子也无法和斑竹们的"精华贴"相比了~~~


哈哈~~~自己发贴自贺一番~~~也算菜农对大家的"贡献"吧~~~

俺从不相信书上的"范例",俺只认可通过实际运行的"例程"...

使用特权

评论回复
15
violit| | 2007-12-22 00:11 | 只看该作者

hotpower开始玩dsPIC了~太好了!

有没有打算加上操作系统?比如FreeRTOS?
向你学习啊!!!

使用特权

评论回复
16
程序匠人| | 2007-12-22 00:14 | 只看该作者

此帖应该加裤子,请斑竹明察

使用特权

评论回复
17
hotpower|  楼主 | 2007-12-24 00:46 | 只看该作者

哈哈~~~菜农在PIC的全是垃圾贴!!!就此声明!!!

使用特权

评论回复
18
hotpower|  楼主 | 2007-12-24 00:52 | 只看该作者

哈哈~~~查查菜农在此的垃圾贴有多少呀...声明俺并非要裤子!!

俺发表的"演示程序"的本意是什么???

几年了...俺一直不想说~~~

还有俺的LPC213X的垃圾贴真不知道有多少!!!

哈哈~~~还好,俺现在有文潭---俺的底盘俺做主~~~

记得俺拥有"菜农的自留地"时,也不乱给自己加裤子...

但俺写的"演示程序"全是给"菜鸟"写得...

使用特权

评论回复
19
兰天白云| | 2007-12-24 08:18 | 只看该作者

本斑主加的第一条裤子

使用特权

评论回复
20
兰天白云| | 2007-12-24 08:29 | 只看该作者

回头看一下,有没有加好?

已加,OK

hotpower,好贴啊

欢迎hotpower大叔以后多支持

一个私下请求

能不能玩玩PIC32,然后给俺们菜鸟说说?

使用特权

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

本版积分规则

1460

主题

21619

帖子

506

粉丝