80C51 SMG12864 的汉字显示方式与函数作图显示方法 PROTEUS8 仿真附电路图和仿真过程与效果(供物联网传感器显示使用)(一)

2023-05-16

写这部分的应用,关键在于电路的连接方式与SMG12864的驱动方法。驱动来源于网络,这个博客说的比较详细,里面有时序图以及各种功能的使用方法列表,详细的说明了如何使用该模块显示常用的汉字信息,我对该方法做了一些修改,电路连接方式被简化,代码被修改,并没有直接搬运该博客内容。该方法也许对于波形发生器,波形测量,物联网应用的数据显示有一定的作用,所以写这篇文章。

以下为现在的电路连接方式,忽略了单片机的最小系统,大家可以自行添加。

现有的经过修改和编译的代码如下:

#include <reg52.h>
#include <intrins.h>
#include <math.h>

#define DATA P2
typedef unsigned char uchar;
sbit rs = P3 ^ 2;
sbit rw = P3 ^ 1;
sbit en = P3 ^ 0;
sbit cs1 = P3 ^ 4;
sbit cs2 = P3 ^ 3;

unsigned char number = 0;

/*** 水平的字符
uchar code zhCN[] =
{
    //每个位置占据1列8行
    //第1个字
    //上半部分:第1列,第2列,第3列...第8列
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    //下半部分
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
    //第2个字
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
    //第3个字
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
    //第4个字
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
    //第5个字
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
    //第6个字
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
    //第7个字
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
    //第8个字
    0x80,0xC0,0x40,0x40,0x60,0x20,0x30,0x10,0x10,0xF8,0xF8,0x0C,0x06,0x06,0x06,0x00,
    0x01,0x01,0x03,0x02,0x06,0x04,0x04,0x0C,0x08,0x0F,0x0F,0x18,0x10,0x10,0x30,0x00,
};
***/

/*** 垂直的字符 ***/
uchar code zhCN[] =
{
    //每个位置占据1列8行
    //第1个字
    //上半部分:第1列,第2列,第3列...第8列
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    //下半部分
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
    //第2个字
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
    //第3个字
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
    //第4个字
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
    //第5个字
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
    //第6个字
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
    //第7个字
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
    //第8个字
    0x00,0x00,0x00,0x00,0xC0,0x70,0x1E,0x03,0x07,0x1C,0xF0,0x80,0x00,0x00,0x00,0x00,
    0x00,0x70,0x78,0x0E,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x78,0x40,0x00,0x00,
};

void Delay(uchar m)
{
    uchar i;
    for (; m > 0; --m)
        for (i = 0; i < 110; ++i)
            ;
}
/* 检查忙碌状态 */
void CheckState()
{
    //通过读取BF标志位(引脚9,对应P0^7)状态判断模块是否繁忙
    uchar dat;
    //读状态下RS=0,R/W=1,E=1
    rs = 0;
    rw = 1;
    do
    {
        DATA = 0x00; //RST=0正常,BUSY=0准备状态,ON/OFF=0显示关,
        en = 1;
        _nop_(); //打开使能后检测模块状态
        dat = DATA; //状态读入dat
        en = 0;
        dat = 0x80 & dat; // 1000 0000 & dat 通过与操作隔离后7位,仅判断最高位
    }
    while(dat != 0x00); //P0^7为0时跳出循环,BUSY=0准备状态
}
/* 选择要显示的屏幕 */
void SelectScreen(uchar screen)
{
    //CS为低电平时亮
    switch(screen)
    {
    case 0: //全屏显示
        cs1 = 0; //IC1控制右半屏
        _nop_();
        _nop_();
        _nop_();
        cs2 = 0; //IC2控制左半屏
        _nop_();
        _nop_();
        _nop_();
        break;
    case 1: //右屏显示
        cs1 = 0;
        _nop_();
        _nop_();
        _nop_();
        cs2 = 1;
        _nop_();
        _nop_();
        _nop_();
        break;
    case 2: //左屏显示
        cs1 = 1;
        _nop_();
        _nop_();
        _nop_();
        cs2 = 0;
        _nop_();
        _nop_();
        _nop_();
        break;
    }
}
/* 写命令操作 */
void SendCommandToLCD(uchar com)
{
    //p.s.在CS1或CS2低电平情况下才能写入命令
    CheckState();
    rs = 0;
    rw = 0;
    DATA = com;
    en = 1;
    _nop_();
    _nop_();
    en = 0;
}
/* 显示开闭 */
void SetOnOff(uchar onoff)
{
    //传入0,关显示,00111110|00000000 = 00111110
    //传入1,开显示,00111110|00000001 = 00111111
    onoff = 0x3E | onoff;
    SendCommandToLCD(onoff); //写指令onoff
}
/* 行(页)建立 */
void SetLine(uchar page)
{
    //10111000|00000000 = 10111000
    //10111000|00000001 = 10111001
    //10111000|00000010 = 10111010
    //...
    //10111000|00000111 = 10111111
    //共8页,设置页地址
    page = 0xb8 | page;
    SendCommandToLCD(page);
}
/* 列建立 */
void SetColumn(uchar column)
{
    //01xxxxxx 后六位为列地址
    //先通过与操作屏蔽前2位,将地址范围限制在0-63之间
    //再通过或操作将列操作指令前两位代入
    column = column & 0x3F; //00000000 & 00111111 = 00000000
    column = 0x40 | column; //01000000 | 00000000 = 01000000
    SendCommandToLCD(column);
}
/* 写入数据 */
void WriteByte(uchar dat)
{
    CheckState();
    rs = 1;
    rw = 0;
    DATA = dat;
    en = 1;
    _nop_();
    _nop_();
    en = 0;
}
/* 清屏 */
void ClearScreen(uchar screen)
{
    uchar i, j;
    SelectScreen(screen);
    for (i = 0; i < 8; ++i) //书上源码建立16页,此处建立8页正常运行
    {
        SetLine(i); //建立行
        SetColumn(0); //建立列
			  for (j = 0; j < 64; ++j) //通过遍历该行的64列写入内容,列地址自动
        WriteByte(0x00);
    }
}
/* 设置开始行 */
void SetStartLine(uchar startline)
{
    //设置开始行时前两位为11
    startline = 0xC0 | startline;
    SendCommandToLCD(startline);
}
/* 初始化 */
void InitLCD()
{
    CheckState(); //检查LCD状态,是否繁忙,每次操作前都要进行检查
    SelectScreen(0); //全屏显示,将要显示的屏幕部分置为低电平
    SetOnOff(0); //关显示,1为开显示,0位关显示
    SelectScreen(0);
    SetOnOff(1); //开显示
    SelectScreen(0);
    ClearScreen(0); //0清全屏,1清左屏,2清右屏
    SetStartLine(0); //从第0行开始
}
/* 显示汉字 */
void Display(uchar screen, uchar page, uchar column, uchar num)
{
    uchar i;
    SelectScreen(screen); //选择对应要亮的屏
    /* 显示字的上半部分 */
    SetLine(page); //建立行(页)
    column = column & 0x3F; // column & 00111111 屏蔽前两位
    SetColumn(column); //建立列
    //写入字库第32*num~32*num+16位的数据
    //第1个字:0~15,对应字库第1行
    //第2个字:32~47,对应字库第3行
    //第3个字:64~79,对应字库第5行
    //...
    for (i = 0; i < 16; ++i)
        WriteByte(zhCN[i + 32 * num]);
    /* 显示字的下半部分 */
    SetLine(page + 1);
    SetColumn(column);
    //写入字库第32*num+16~32*num+32位的数据
    //第1个字:16~31,对应字库第2行
    //第2个字:48~63,对应字库第4行
    //第3个字:80~95,对应字库第6行
    //...
    for (i = 0; i < 16; ++i)
        WriteByte(zhCN[i + 32 * num + 16]);
}
/* 主函数 */
int main()
{
    uchar i;
	  uchar j;
	  uchar line; //+
	  uchar m; //+
		uchar n; //+
	  uchar screen; //+
	  uchar tempt; //+
	  uchar n2 = 1,n3 = 0,s = 1,t = 1;
    /* 初始化LCD,书上进行了一系列初始化操作,仅清屏的话不影响运行结果 */
    // InitLCD();
    ClearScreen(0); //清屏
    /* 动态显示 */
    while(1) //余晖效应
    {
			  
        for (i = 0; i < 64; ++i) //如果此处改成10,则在向上移动10行后重新出现在第0行,此处使用64的倍数来实现无限循环(无间断),书上源码循环128次,64次也无影响
        {
					  /*** 字符显示效果 ***/
            /* 滚动控制 */
					 if(i==0){
						for(t == 1;t<64;t++){
            SetStartLine(t); //循环建立开始行,每一次循环都上移1行
            /* 汉字显示 */
            Display(2, 0, 0 * 16, 0); //左屏,第0页,  0列,第0个字
            Display(2, 0, 1 * 16, 1); //左屏,第0页, 16列,第1个字
            Display(2, 0, 2 * 16, 2); //左屏,第0页, 32列,第2个字
            Display(2, 0, 3 * 16, 3); //左屏,第0页, 48列,第3个字
            Display(1, 0, 4 * 16, 4); //右屏,第0页, 64列,第4个字
            Display(1, 0, 5 * 16, 5); //右屏,第0页, 80列,第5个字
            Display(1, 0, 6 * 16, 6); //右屏,第0页, 96列,第6个字
            Display(1, 0, 7 * 16, 7); //右屏,第0页,128列,第7个字
						}
					 }
		 
		 /*** 三角波函数全屏单周期作图显示效果 ***/
		 ClearScreen(0); //清屏		
		 for(screen = 1;screen<3;screen++){
     SelectScreen(screen);
     for (m = 0; m < 8; ++m) //书上源码建立16页,此处建立8页正常运行
     {
         SetLine(m); //建立行
			//for (line = 0; line < 64; ++line) {
         SetColumn(m*8-8); //建立列
         //for (n = 0; n < 64*2; ++n){ //通过遍历该行的64列写入内容,列地址自动+1
            for (j = 0; j < 64 - m*8; ++j){ //通过遍历该行的64列写入内容,列地址自动+1
			      n2 = (j+m*8)/8+1;
			      n3 = n2;
						s = 1;
			      for(;n2>0;n2--)
			          s = s*2;
						//if(m - 1 == (j + m*8)/8){
						if((m+1)*8 == j+1+m*8){
							if(screen == 2){
							 SetLine(7-m); //建立行
							 for(tempt = 0x80;tempt>0x01;tempt=tempt/2)
						   WriteByte(tempt);
							 break;
							}
							else{
							 for(tempt = 0x01;tempt<0x80;tempt=tempt*2)
						   WriteByte(tempt);
							 break;	
							}								
						}
						else{
						//if((m+1)*8 == j+1+m*8)
            //    WriteByte(s);
						//else
							  WriteByte(0x00);
						//}
					 }
				 }
				 //}
     }						
	   //}
	   }		 
            SelectScreen(0); //由于显示后四个字符时左屏处于关显示状态,需要打开全屏
            Delay(50);
        }
     }
}

 编译后的效果图,文字显示(一):

 编译后的效果图,简单三角函数全屏显示(二):

文字的取模方式为软件PCTOLCD2002:

注意取模大小为16*16,方向或数据样式为列行式。 

文章源代码来源:https://www.cnblogs.com/hughdong/p/6895631.html

THANK YOU FOR YOUR READING!

THE END.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

80C51 SMG12864 的汉字显示方式与函数作图显示方法 PROTEUS8 仿真附电路图和仿真过程与效果(供物联网传感器显示使用)(一) 的相关文章

随机推荐