【Proteus仿真】STC15单片机 + LCD1602+5X8点阵字符显示

【Proteus仿真】STC15单片机 + LCD1602+5X8点阵字符显示


  • Proteus仿真演示
    在这里插入图片描述

相关函数说明

  • unsigned char *uchartostr(unsigned num); //将一个字节的数据转换为字符串 或10进制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned char \*uchartostr(unsigned num)	//将一个字节的数据转换为字符串 或10进制
{
unsigned char x2,x1,x0,i;
x2=num/100;
x1=num%100/10;
x0=num%100%10;
i=0;
if(x2!=0)
{
str[i]=x2+48;
i++;
}
if(x1!=0)
{
str[i]=x1+48;
i++;
}
str[i]=x0+48;
i++;
str[i]='\0';
return str;
}

  • WriteROM(); // 将自定义字形码写入LCD1602内部存储器

将84bit,8字节的数据写入到LCD1602 CGRAM寄存器,

1
2
3
4
5
6
7
8
9
10
void WriteROM()//LCD1602内部数据寄存器写入函数
{
unsigned char i;
Write\_CMD(0x40); // 操作CGRAM的命令码,
for(i=0;i<64;i++) // 写入数组中数据
{
Write\_DIS\_Data(table[i]);
}
}

CGRAM的容量是64个字节,而一个字符是8个字节,所以一共能显示8个自定义的字符。内部常用字符的显示是从0x20开始的,0x00 ~ 0x0F是专门留给自定义字符显示用的,0x00-0x07和0x08~0x0F显示的内容是一样的,也就是说0x00=0x08,0x01=0x09,以此类推。CGRAM共128个位,地址是0x40-0x7F,128/8=16正好对应的是0x00-0x0F共16个.
在这里插入图片描述

程序源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417

/\*\*\*\*\*\*\*\*\*\*\*\*\* 本程序功能说明 \*\*\*\*\*\*\*\*\*\*\*\*\*\*

驱动LCD1602字符屏.

显示效果为: DS1302 + LCD1602显示时间

\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
#include "STC15Fxxxx.H"

#define T1MS (65536-MAIN\_Fosc/12/1000) //12T模式1ms定时
#define interval 1000 //设置延时时间间隔
/\*\*\*\*\*\*\*\*\*\*\*\*\* 本地变量声明 \*\*\*\*\*\*\*\*\*\*\*\*\*\*/
static volatile unsigned long sysRunmillis = 0; //系统运行时间计数,保存单片机从上电复位以来运行的时间,单位是毫秒。该数值由定时器T0的中断响应子函数更新
unsigned long previousMillis = 0;
unsigned char str[4];//uchartostr函数转换的字符串 同时可以把16进制转成10进制
sbit Buzzer = P3^7;
unsigned char code table[]=
{
0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00, // 一,显示时的ASCII码 0x00
0x00,0x00,0x00,0x0e,0x00,0xff,0x00,0x00, // 二,显示时的ASCII码 0x01
0x00,0x00,0xff,0x00,0x0e,0x00,0xff,0x00, // 三,显示时的ASCII码 0x02
0x00,0x00,0xff,0xf5,0xfb,0xf1,0xff,0x00, // 四,显示时的ASCII码 0x03
0x00,0xfe,0x08,0xfe,0x0a,0x0a,0xff,0x00, // 五,显示时的ASCII码 0x04
0x00,0x04,0x00,0xff,0x00,0x0a,0x11,0x00, // 六,显示时的ASCII码 0x05
0x00,0x1f,0x11,0x1f,0x11,0x11,0x1f,0x00, // 日,显示时的ASCII码 0x06
0x18,0x18,0x07,0x08,0x08,0x08,0x07,0x00, // ℃,显示时的ASCII码 0x07
};

void Timer0Init(void); //1毫秒@12.000MHz
void delay\_ms(unsigned long ms);
void Initialize\_LCD(void);
void Write\_AC(u8 hang,u8 lie);
void Write\_DIS\_Data(u8 DIS_Data);
void WriteROM();//LCD1602内部数据寄存器写入函数
void ClearLine(u8 row);
u8 BIN\_ASCII(u8 tmp);
void PutString(u8 row, u8 column, u8 \*puts);
void WriteChar(u8 row, u8 column, u8 dat);
void Buzzer\_Di(void);
unsigned char \*uchartostr(unsigned num); //将一个字节的数据转换为字符串 或10进制
//========================================================================
// 函数: void main(void)
// 描述: 主函数。
//========================================================================
void main(void)
{
unsigned long currentMillis;//当前时间
unsigned char i =0;
P0M1 = 0; P0M0 = 0; //设置为准双向口
P1M1 = 0; P1M0 = 0; //设置为准双向口
P2M1 = 0; P2M0 = 0; //设置为准双向口
P3M1 = 0; P3M0 = 0; //设置为准双向口
P4M1 = 0; P4M0 = 0; //设置为准双向口
P5M1 = 0; P5M0 = 0; //设置为准双向口
P6M1 = 0; P6M0 = 0; //设置为准双向口
P7M1 = 0; P7M0 = 0; //设置为准双向口
Timer0Init(); //1毫秒@12.000MHz
Initialize\_LCD();//LCD初始化函数
ClearLine(0);
ClearLine(1);
PutString(0,0,"STC15W4K");
WriteROM(); // 将自定义字形码写入LCD1602内部存储器
WriteChar(1, 0, 0);
WriteChar(1, 1, 1);
WriteChar(1, 2, 2);
WriteChar(1, 3, 3);
WriteChar(1, 4, 4);
WriteChar(1, 5, 5);
WriteChar(1, 6, 6);
WriteChar(1, 7, 7);
while(1)
{
currentMillis = sysRunmillis;
if (currentMillis - previousMillis >= interval)
{//每隔1秒翻转一次
previousMillis = sysRunmillis;
if(++i <= 255){
PutString(0,9,uchartostr(i));
WriteChar(0, 14, i);

PutString(1,9,uchartostr(255 -i));
WriteChar(1, 14, 255 -i);

}

}
}

}

void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = T1MS ; //设置定时初始值
TH0 = T1MS >>8; //设置定时初始值
// TL0 = 0x18; //设置定时初始值
// TH0 = 0xFC; //设置定时初始值

TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //enable timer0 interrupt
EA = 1; //open global interrupt switch
}

/\* Timer0 interrupt routine \*/
void tm0\_isr() interrupt 1
{
// TL0 = 0x18; //设置定时初始值
// TH0 = 0xFC; //设置定时初始值
TL0 = T1MS; //reload timer0 low byte
TH0 = T1MS >> 8; //reload timer0 high byte
sysRunmillis ++;
}


//========================================================================
// 函数: void delay\_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void delay\_ms(unsigned long ms)
{
unsigned long temp = sysRunmillis ;
while(sysRunmillis - temp < ms );
// unsigned int i;
// do{
// i = MAIN\_Fosc / 13000;
// while(--i) ; //14T per loop
// }while(--ms);
}




/\*\*\*\*\*\*\*\*\*\*\*\*\* LCD1602相关程序 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
//8位数据访问方式 LCD1602 标准程序 梁工编写 2014-2-21

#define LineLength 16 //16x2

/\*\*\*\*\*\*\*\*\*\*\*\*\* Pin define \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

sfr LCD_BUS = 0x80; //P0--0x80, P1--0x90, P2--0xA0, P3--0xB0

sbit LCD_B7 = LCD_BUS^7; //D7 -- Pin 14 LED- -- Pin 16
sbit LCD_B6 = LCD_BUS^6; //D6 -- Pin 13 LED+ -- Pin 15
sbit LCD_B5 = LCD_BUS^5; //D5 -- Pin 12 Vo -- Pin 3
sbit LCD_B4 = LCD_BUS^4; //D4 -- Pin 11 VDD -- Pin 2
sbit LCD_B3 = LCD_BUS^3; //D3 -- Pin 10 VSS -- Pin 1
sbit LCD_B2 = LCD_BUS^2; //D2 -- Pin 9
sbit LCD_B1 = LCD_BUS^1; //D1 -- Pin 8
sbit LCD_B0 = LCD_BUS^0; //D0 -- Pin 7

sbit LCD_ENA = P2^2; //Pin 6
sbit LCD_RW = P2^1; //Pin 5 //LCD\_RS R/W DB7--DB0 FOUNCTION
sbit LCD_RS = P2^0; //Pin 4 // 0 0 INPUT write the command to LCD model
// 0 1 OUTPUT read BF and AC pointer from LCD model
// 1 0 INPUT write the data to LCD model
// 1 1 OUTPUT read the data from LCD model
/\*
total 2 lines, 16x2= 32
first line address: 0~15
second line address: 64~79

\*/

#define C\_CLEAR 0x01 //clear LCD
#define C\_HOME 0x02 //cursor go home
#define C\_CUR\_L 0x04 //cursor shift left after input
#define C\_RIGHT 0x05 //picture shift right after input
#define C\_CUR\_R 0x06 //cursor shift right after input
#define C\_LEFT 0x07 //picture shift left after input
#define C\_OFF 0x08 //turn off LCD
#define C\_ON 0x0C //turn on LCD
#define C\_FLASH 0x0D //turn on LCD, flash
#define C\_CURSOR 0x0E //turn on LCD and cursor
#define C\_FLASH\_ALL 0x0F //turn on LCD and cursor, flash
#define C\_CURSOR\_LEFT 0x10 //single cursor shift left
#define C\_CURSOR\_RIGHT 0x10 //single cursor shift right
#define C\_PICTURE\_LEFT 0x10 //single picture shift left
#define C\_PICTURE\_RIGHT 0x10 //single picture shift right
#define C\_BIT8 0x30 //set the data is 8 bits
#define C\_BIT4 0x20 //set the data is 4 bits
#define C\_L1DOT7 0x30 //8 bits,one line 5\*7 dots
#define C\_L1DOT10 0x34 //8 bits,one line 5\*10 dots
#define C\_L2DOT7 0x38 //8 bits,tow lines 5\*7 dots
#define C\_4bitL2DOT7 0x28 //4 bits,tow lines 5\*7 dots
#define C\_CGADDRESS0 0x40 //CGRAM address0 (addr=40H+x)
#define C\_DDADDRESS0 0x80 //DDRAM address0 (addr=80H+x)


#define LCD\_DelayNop() NOP(15)

#define LCD\_BusData(dat) LCD\_BUS = dat


//========================================================================
// 函数: void CheckBusy(void)
// 描述: 检测忙函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void CheckBusy(void)
{
u16 i;
for(i=0; i<5000; i++) {if(!LCD_B7) break;} //check the LCD busy or not. With time out
// while(LCD\_B7); //check the LCD busy or not. Without time out
}

//========================================================================
// 函数: void IniSendCMD(u8 cmd)
// 描述: 初始化写命令(不检测忙)
// 参数: cmd: 要写的命令.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void IniSendCMD(u8 cmd)
{
LCD_RW = 0;
LCD\_BusData(cmd);
LCD\_DelayNop();
LCD_ENA = 1;
LCD\_DelayNop();
LCD_ENA = 0;
LCD\_BusData(0xff);
}

//========================================================================
// 函数: void Write\_CMD(u8 cmd)
// 描述: 写命令(检测忙)
// 参数: cmd: 要写的命令.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void Write\_CMD(u8 cmd)
{
LCD_RS = 0;
LCD_RW = 1;
LCD\_BusData(0xff);
LCD\_DelayNop();
LCD_ENA = 1;
CheckBusy(); //check the LCD busy or not.
LCD_ENA = 0;
LCD_RW = 0;

LCD\_BusData(cmd);
LCD\_DelayNop();
LCD_ENA = 1;
LCD\_DelayNop();
LCD_ENA = 0;
LCD\_BusData(0xff);
}

//========================================================================
// 函数: void Write\_DIS\_Data(u8 dat)
// 描述: 写显示数据(检测忙)
// 参数: dat: 要写的数据.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void Write\_DIS\_Data(u8 dat)
{
LCD_RS = 0;
LCD_RW = 1;

LCD\_BusData(0xff);
LCD\_DelayNop();
LCD_ENA = 1;
CheckBusy(); //check the LCD busy or not.
LCD_ENA = 0;
LCD_RW = 0;
LCD_RS = 1;

LCD\_BusData(dat);
LCD\_DelayNop();
LCD_ENA = 1;
LCD\_DelayNop();
LCD_ENA = 0;
LCD\_BusData(0xff);
}

unsigned char \*uchartostr(unsigned num) //将一个字节的数据转换为字符串 或10进制
{
unsigned char x2,x1,x0,i;
x2=num/100;
x1=num%100/10;
x0=num%100%10;
i=0;
if(x2!=0)
{
str[i]=x2+48;
i++;
}
if(x1!=0)
{
str[i]=x1+48;
i++;
}
str[i]=x0+48;
i++;
str[i]='\0';
return str;
}

//========================================================================
// 函数: void Initialize\_LCD(void)
// 描述: 初始化函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void Initialize\_LCD(void)
{
LCD_ENA = 0;
LCD_RS = 0;
LCD_RW = 0;

delay\_ms(100);
IniSendCMD(C_BIT8); //set the data is 8 bits

delay\_ms(10);
Write\_CMD(C_L2DOT7); //tow lines 5\*7 dots

delay\_ms(6);
Write\_CMD(C_CLEAR); //clear LCD RAM
Write\_CMD(C_CUR_R); //Curror Shift Right
Write\_CMD(C_ON); //turn on LCD
}



//========================================================================
// 函数: void ClearLine(u8 row)
// 描述: 清除1行
// 参数: row: 行(0或1)
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void ClearLine(u8 row)
{
u8 i;
Write\_CMD(((row & 1) << 6) | 0x80);
for(i=0; i<LineLength; i++) Write\_DIS\_Data(' ');
}

//========================================================================
// 函数: void WriteChar(u8 row, u8 column, u8 dat)
// 描述: 指定行、列和字符, 写一个字符
// 参数: row: 行(0或1), column: 第几个字符(0~15), dat: 要写的字符.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void WriteChar(u8 row, u8 column, u8 dat)
{
Write\_CMD((((row & 1) << 6) + column) | 0x80);
Write\_DIS\_Data(dat);
}

//========================================================================
// 函数: void PutString(u8 row, u8 column, u8 \*puts)
// 描述: 写一个字符串,指定行、列和字符串首地址
// 参数: row: 行(0或1), column: 第几个字符(0~15), puts: 要写的字符串指针.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void PutString(u8 row, u8 column, u8 \*puts)
{
Write\_CMD((((row & 1) << 6) + column) | 0x80);
for ( ; \*puts != 0; puts++) //遇到停止符0结束
{
Write\_DIS\_Data(\*puts);
if(++column >= LineLength) break;
}
}
void WriteROM()//LCD1602内部数据寄存器写入函数
{
unsigned char i;
Write\_CMD(0x40); // 操作CGRAM的命令码
for(i=0;i<64;i++) // 写入数组中数据
{
Write\_DIS\_Data(table[i]);
}
}

//\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* LCD20 Module END \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
//\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
//蜂鸣器程序
//\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
void Buzzer\_Di(void){
Buzzer = 0;
delay\_ms(3);
Buzzer = 1;
delay\_ms(3);
}

程序源码和仿真资源

本实验基于Proteus8.12平台

1
2
3
链接:https://pan.baidu.com/s/1Q7PCk5sDC2lwsVZjvHmvlw 
提取码:pzl3 //请使用复制粘贴命令,手工输入容易出错