写这部分的应用,关键在于电路的连接方式与SMG12864的驱动方法。驱动来源于网络,这个博客说的比较详细,里面有时序图以及各种功能的使用方法列表,详细的说明了如何使用该模块显示常用的汉字信息,我对该方法做了一些修改,电路连接方式被简化,代码被修改,并没有直接搬运该博客内容。该方法也许对于波形发生器,波形测量,物联网应用的数据显示有一定的作用,所以写这篇文章。
以下为现在的电路连接方式,忽略了单片机的最小系统,大家可以自行添加。
现有的经过修改和编译的代码如下:
#include
#include
#include
#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.