本帖最后由 caizhiwei 于 2015-11-5 11:04 编辑 3 S1 b; Q% S" `- f3 e# L6 m
6 \- G9 h! [: P( a! M. G# ~
虽然很久之前(51时代)就开始接触lcd12864,如今在工控机里面,LCD12864还是应用比较普遍的! M! d! A) V* f
我用的lcd12864类型为串行接口,3.3V st7920
# m% i6 R+ T$ ~3 m8 ]; L$ p! r4 h代码优化说明:3 h& e& N6 |3 y2 Q, @( u- {
1.修复了字符串,汉字串不能自动换行的bug
A, u$ a1 z! q7 w- p4 R注意:4 t' P& z% A- `/ j, B m* ~6 B/ ^2 t
1.在使用带jtag接口的I/O时要特别注意$ |+ G6 h, k6 {. B% x* s8 m
PA13:SWDIO/JTAG_TMS
5 y4 G7 S! @, l PA14:SWCLK/JTAG_TCK% g- l, |# f* [8 E5 S v! f
PA15:JTAG_TDI/ |9 r. Q9 [$ N) N% T
PB3:JTAG_TDO8 u4 T: g( H% \' t" Y/ g0 A( d" Y
PB4:JTAG_RST+ Q* r5 h: ]6 j$ f! n
硬件设计缺陷:2 D0 ]: t5 X7 l R J
1.没有引出LCM的复位引脚,导致偶尔显示不正常之后,mcu复位(LCM并没有复位)
+ m# }0 i1 m3 Y7 X$ M也无法解决,只能强行断电重启。
/ M! W1 P0 p+ X- w2 m6 i* R2.BLK液晶背光引脚的输入电流至少在20mA以上,没有用三极管驱动,而是直接用IO驱动,+ ~8 j4 e4 u+ ~
需要较大的驱动电流。
% k$ k' W3 H, F. P) X3.
/ \* Q/ q) r( q+ q: U# @" I编译器缺陷:) q& ?# Q, v$ r. M" Q M
1.由于使用的是iar6.70版本,编译器在编译汉字串数组的时候可能会使带字库液晶产生乱码。, M9 w" O8 R2 r2 w) Z9 j
所以在有汉字数组的C文件中统一使用简体中文(GB2312)(全选--右键--Charracter Encoding)
4 C8 ` N, h! I: P0 b+ f; \8 o3 N h% J( [
部分硬件结构说明:
, F# l+ W- Q8 b5 g1.按键按下,(上连接VCC)连接电阻下拉到地,检测IO连接上端,检测到高电平。* A3 S( X' g9 B$ J3 Y& S, ~# l
2.lcd12864底板反面接线图:. ^6 C/ w1 M; D$ q$ B
6 i, M6 ~% c) k Z$ u! L
从反面看:9 k7 C: E# R h3 S, r* w
5V RW GND GND LED K2 K4 GND
" E6 s3 s% {% y# e R& ?. IGND RS E BLK GND K1 K3 5V% F5 ]' _/ Q4 m8 N. W8 |
+ ?3 g; D9 y" t4 N
2015-6-10 原工程代码在23楼!|r7 q4 P. D V1 O
2015-7-12 程序更新了,,代码在35楼!
d# y* K3 e5 N) L* ^2 ^ x9 P G更新记录:
4 b& I( O* j6 R; ]1.增加了24*32大字体显示功能;# \- g- V. k5 ^4 V2 [, E3 o: o$ E
2.增加了16*32大字体显示功能;) q S$ }3 } ~' Q9 c
3.优化了读LCD忙的代码;
& z, n5 J( O6 j1 T4.新增了是sprintf的任意位数数字直接显示;9 u( A# J. l1 s/ G7 f0 L/ ^8 Q
5.新增了CGRAM的写入,读出操作函数;# ]2 ]! R+ O! ?8 v
6.优化了绘图GDRAM函数的操作,绘图速度提高;* ~" X* I, c, T0 q5 r \, ?0 h$ Q
2015.11.04 ,看到很多评论说链接失效,现在重新找了一份完整的工程代码,整理之后传到网盘:3 v" r/ {( c0 M* B3 g
这个代码优化了.h文件中的宏定义,方便用户移植,C文件和gui.c文件均不用修改。6 I5 s# Z3 C( A/ A) S T
https://pan.baidu.com/s/1pJw3wHd 2 @# v& h$ H2 L. o( n: U
7 k. p9 I" H0 x. r8 a
-
. d, w: l, J0 p6 ?' Q4 d - #include "gui.h"4 C1 O- k3 B: C) m3 E' Y
- , {& E9 A- y/ C; ~- q4 r6 M' ~
- /******************************************************************************* # ~" C, N% N( q# ^0 ~
- DDRAM地址
; L7 Z9 |+ U5 g" g8 ]7 ~9 O( R - 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 //第一行汉字位置
! w q- n7 e- H - 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 //第二行汉字位置
" Z: O7 I$ |, K5 v8 \+ I; ` - 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f //第三行汉字位置4 s n: Z7 o( T! w! n
- 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f //第四行汉字位置
3 M) V; ]8 y' N8 w& x" F" e - ! {+ r% M) T$ `5 l
- *******************************************************************************/ : @6 P/ N: u) N/ X
- 6 d3 n( o( e; ~. v6 k
- /******************************************************************************* 9 y6 n: h+ J8 ^; N/ R% s# p0 j
- * 名称 : LCD_SetPos! i2 Q/ K. k; P# {+ }! G1 p
- * 功能 : 设定显示位置
$ [; F$ @4 V, c! D( t - * 输入 : x (0~3)行6 S: l o- q* m z7 g
- y (0~7)列- T4 w- w/ ?1 @# g8 g# ~
- * 输出 : 无
2 l4 Q/ w5 r4 K/ J- z# R. d - *******************************************************************************/
e/ z3 l( P: x - void LCD_SetPos(u8 row, u8 col)
5 r0 X- U5 Z5 y$ t+ J6 k% e7 _ - {
0 L Q: D8 L9 d5 v - u8 pos; & q+ ?% t+ K; @$ }
- if( row == 0) 5 {4 h# ^. ]+ _5 } w
- row = 0x80;
" o7 }: b! m1 ^# Y - else if(row == 1) ; j1 \9 `% o* e; j( D
- row = 0x90;
/ S) d) V: w- [3 D/ W: N - else if(row == 2)
" M4 ?7 k- A, @- ?& ~# j4 J2 N - row = 0x88; ' j+ m% q9 N! S' \
- else if(row == 3)
9 z9 c# z& u8 h - row = 0x98; 8 l8 s, c2 A' h" S
- pos = row + col; + j3 `, {0 ` q1 s( T6 o
- LCD_WriteCMD(pos);//在写入数据前先指定显示地址
J% J' Y: o! D' Z9 {1 d7 n' t+ V9 g2 M - delay_us(10);# Y4 X7 \4 {% W1 b, m
- } 5 j" s: ^* | q8 t- w. X4 a! G
: A) j& ^ q5 D# L1 v- . a% Q" U, b4 I' G* D' b+ e X
- /********************************************************************
4 C( j/ v4 }0 { - * 名称 : ShowASCII
' N' U1 K& |8 D0 P: n: i F) { - * 功能 : 在当前坐标位置显示单个字符. T8 r, c2 e1 S( A
- * 输入 : *s 9 j7 `# M5 n) r+ R6 T
- * 输出 : 无 ( i* d# I6 B. `
- ***********************************************************************/
! J# v$ i2 P# W - void ShowASCII(u8 i): L6 s E0 e3 R2 i+ F
- {% [: \' g5 L% V, E5 f3 U0 b$ i7 n
- LCD_WriteDATA(i);
2 @7 w8 Y: s' @; A - }2 ^4 s- f0 x! F6 q
- ( s# m+ r4 R. H0 x& E+ Q$ F
- void ShowCharPos(u8 row, u8 col,u8 dat)4 _& R' [0 F5 n9 S% j- k
- {
9 K% F3 b5 Q1 z% ]/ z k2 r- Z! @ - LCD_SetPos(row, col);% L5 Z# f/ a7 V3 ~5 z
- ShowASCII(dat);8 c8 j: x C% j4 Z. ?% M: f
- }$ D; }( H( y3 N. o; r9 E
- $ `8 u+ Q3 J2 R. S+ F# U" o
- /******************************************************************************* ; F6 J& S* A# }4 L8 M4 I$ [
- * 名称 : ShowEnString(u8 *s) 7 ?7 S2 v' }3 D a2 ~9 ?9 ?/ A
- * 功能 : 显示英文字符串
7 v& f b K) Q7 t; z( f& ] - * 输入 : *s c, w+ Y3 d3 r% }" I: p* P# ]
- * 输出 : 无 ) T7 F* [/ R I& _+ l# X
- *******************************************************************************/ $ a/ U7 r, G. z7 y, \1 L# J
- void ShowString(u8 *s)
5 D* T5 ]* T/ E - {
$ A/ ~" g4 m8 f1 Q n% Z - u8 i = 0;
$ N2 a* S+ ]& r: d2 o" S4 t/ E - while(s[i] != '\0') & c7 ?. ~& V0 \ c
- {
7 t- O/ l1 |, ~( H4 ^+ R' d7 y - ShowASCII(s[i++]); / }* [3 L7 {$ [9 @ T! A6 o8 P
- }
+ W9 S: T& v7 N: y, r8 U - }
7 j. J0 e) m0 X" ~$ T
8 j a7 ~1 I' E4 m$ j# R3 V- void ShowStringPos(u8 row, u8 col,u8 *s) //col is full char wide
8 q5 A' q D2 W T' U' @+ f! m/ o - {
+ M) ?0 x! X! d5 H; Y - u8 i = 0;
& L. M0 i7 X6 p - LCD_SetPos(row, col); 4 _) ?. N* u" j7 m
- while(s[i] != '\0')
+ Y. Z6 i& o& D& i; m$ D - {
. U( E, h p' S+ x - ShowASCII(s[i++]);
' i4 P7 {- ?/ _+ @' K - if((2*col+i)%(16)==0) //must 16, is OK m$ ~0 y, w) L6 f7 k7 @! I: y
- {
1 G7 Z c" G; f0 w/ R1 H - LCD_SetPos(++row,0); //display start at next row.
2 h$ e' O- i+ g1 ~ - }
; G( o6 b4 L w' A9 R% ?" C% z -
S2 C2 S+ [- k: C - }
/ D# b% S) n7 C- J/ a9 b - } ) O( {4 L0 ~: p* F
% g6 y. ]' O* o4 E) V
2 F2 z; c# M0 c5 \8 |' E- ; m* D; Q( [+ Y! ^6 G& E' Z
- /******************************************************************************* 7 Y! F& O! O0 |& M" Z) [2 Y4 g* a
- * 名称 : ShowGB 6 y; Z# p+ E3 b' W7 ]$ S$ q
- * 功能 : 显示单个汉字
; `& v/ z) q( T4 r - * 输入 : i
; @5 T7 s/ `' o. L9 g; K, d! [ - * 输出 : 无 2 Q- e0 M/ F% m+ Z! y+ O
- ********************************************************************************/ / q7 A- \/ \* h) t2 J# e$ ]
- void ShowGB( unsigned char *HZ)
* i3 x+ ]' I: S; w& B# [8 K4 @) O4 D - {
. z r) x# C7 r( R - LCD_WriteDATA(HZ[0]); //写入汉字的高八位数据
! C$ Q" s# m9 m0 v+ U( Q0 e -
6 ~; W! Q0 T7 B+ N - LCD_WriteDATA(HZ[1]); //写入汉字的低八位数据 " X) u9 D, n% t2 G$ Q Y
- 2 m3 q; }5 O' m
- }; u- v: O/ G( B! w3 b
$ o4 f, x f3 u% p4 Z9 w6 K( `- void ShowGBPos(u8 row, u8 col, u8 *HZ)
' b0 y; x" x& y7 W' j - {
$ U9 X. k: ~; {7 F8 J4 _ - LCD_SetPos(row, col);9 r5 A4 l. E0 `. j8 v H: x' r
- ShowGB(HZ);
; E- ~! v- I/ Q; H' d0 @7 E" h+ { - }# U8 u% F/ G6 _% h1 g/ J& t
- ! R4 `" C0 Q8 J- p2 e7 Y1 j
- /******************************************************************** ! h4 k3 b: D4 H9 G
- * 名称 : ShowGBStringPos 4 p% N9 ?# `, }7 {
- * 功能 : 显示多个汉字
; \7 O5 F7 ?; H1 \6 p - * 输入 : u8 row, u8 col :汉字串的起始地址
+ D' q5 C* |& \0 g, U' S3 _ - * 输出 : 无 % z- ^! q$ j/ g. ]# Z; |) m' M
- * 说明 : 自动换行:lcm默认换行顺序是乱的,0--2--1--3--0
5 B/ {; F# S6 |" p - ***********************************************************************/
; t; J4 C$ ?9 e. }+ R# U; \# I - void ShowGBStringPos(u8 row, u8 col, u8 *s)/ J3 N6 ]; w" U2 |& s4 @ k
- {
H0 ^# D9 z- i- x3 a. ? - u8 i = 0;
3 _$ x/ `9 H1 Q. W8 X - LCD_SetPos(row, col);5 y' Q2 e `; `' w
- while (s[i] != '\0')/ c8 ^8 P8 d! e, L0 M+ R+ r, q/ T! H
- {
7 `7 X6 b% A* ~7 v9 ?6 n _8 G% a - ShowGB(s+i);
- k& T) M. m& Z/ ^3 \5 C9 C - i+=2;
7 W( _" g( X1 S2 c - if((2*col+i)%(16)==0) //如果满一行9 k, G2 u0 {; s; b, c4 G
- { ( k, h0 m( R0 p: Q0 `1 n( d3 A
- LCD_SetPos(++row,0); //重新设置显示的起始地址
' U: A3 a/ g: Y4 ~8 v* l: j7 o7 T - }
! x5 J/ X' F+ y' K7 H3 d - ( H* {$ K2 X0 {" y% d, M
- } + I7 u: Z2 T' I* s1 L# m4 t
- }9 x( y7 [/ K1 d Z& d3 V
5 _9 ~1 K2 S2 j. s. u/ x3 F- /*******************************************************************************
6 `8 Y5 q, i# f - 测试函数8 t6 @! R$ }+ W5 G
- Function: 用户移植程序之后,用该函数测试液晶是否初始化成功!
* c( g8 U' i% T - ********************************************************************************/
' |& ~- G4 {& v5 q+ D - void LCD_Test(void)
+ S e3 t; f& z* n7 o - {6 Z1 y2 w6 w" I$ B' U- S: U% z
- ShowCharPos(0,0,0x10); //右箭头
5 W J* x2 s# l; M- F - ShowCharPos(1,0,0x10); //右箭头
" I: w4 `7 w& {7 g4 Z: C5 l5 v - ShowString("Hello,world!") ;
: m5 m! E% s6 ]/ H g( ~. ~ - ShowCharPos(2,0,0x10); //右箭头
, [4 l p( {; Q- Q - ShowASCII(0x11);//左箭头0 E- |- } x8 y* W
- }
% M7 i; F) p. H: c* Z7 P" Y& M - 4 ^* b$ @0 Q! } u
- 3 W9 w' V) ^; X" H4 `+ h7 s
- ( S8 B4 B" ^0 ^7 q, O; E2 l; [
5 X* s2 }- U3 @7 A% Z
. R; \) l) E$ _- //自定义字符写入CGRAM3 e/ O7 P# f3 H& F: {% j2 r0 s' `
- void Write_USR_CGRAM(u8 data1,u8 data2,u8 addr)6 I8 j5 K6 Q" [, e2 j1 w/ @2 ?
- {
* J1 `/ t& c+ q4 P/ O - u8 i;6 ?3 ~. r% k( c# c( s1 X! q
- for(i=0;i<16;)1 V$ w5 f4 n: H- v, n% |; Q$ f
- {
. K8 l/ e, g) l# t! f* l6 {; p4 v - LCD_WriteCMD(addr+i); //设定CGRAM地址6 B% O# n5 l; F8 F4 O) {4 Y1 p
- LCD_WriteDATA(data1);) l- d5 q! Z7 @2 _9 e( ^
- LCD_WriteDATA(data1);
' x. o8 m/ z; p( j* D - i++;
# D$ r6 |+ u! z, P0 I1 b - LCD_WriteCMD(addr+i); //设定CGRAM地址" }3 d% I! `6 D5 V
- LCD_WriteDATA(data2);
/ B9 V; E" }) Q6 K6 p; c3 C - LCD_WriteDATA(data2);
) W" D! F% O* N; F - i++;# p$ x! k4 ^1 U" ?+ g/ i
- } 1 O4 ^. U1 `4 m0 p; `, r
- }: J8 r) y) r$ a$ ~0 z5 p
- + Q1 K2 y; S( n+ ?8 D7 S8 V( E2 b
- //显示自定义的字符,并把这个字符填满全屏16*16
; z8 D$ f0 d J - void Show_USR_CGRAM_Char(u8 addr,u8 i)
( |* d0 r# p3 p/ G6 u4 Q( O - {1 x. p4 r# o1 P0 \# y/ {
- u8 j;* q- Y ?( U( |7 k$ b$ L! S1 @
- for(j=0;j<0x20;)+ t7 I, h9 T: Y% f
- {
8 F2 l) _6 Q* S. ` - LCD_WriteCMD(addr+j); //设定DDRAM地址1 _$ y6 z* c9 J/ g) Y
- LCD_WriteDATA(0x00);
: k2 }- I! b" l- K- S - LCD_WriteDATA(i);
% M% i3 e& H- Q3 f% W - j++;
+ c4 V7 [' K- e - }
6 g. T. \& C0 q$ [3 Y' A - }6 y5 M4 Y2 o# T$ w: [
- 3 L# o$ N* C/ _3 x/ B4 z
- //写入GDRAM 绘图,Y是Y绘图坐标,2个字节一行,X是图形起始坐标,CLONG是图形长度,以字节/ u/ U/ ~$ U' i6 j
- //为单位;HIGHT是图形高度,TAB是图形数据表.12864M的图形显示范围是256*32点阵.& T7 y9 _" F6 Z& _& H% ^
- //要在12864M里显示全屏,取模时一幅图横切成两半
( v+ z- s- u- w( ]
3 V4 H- J% r1 B: Z- /*: _) Y% W' m2 [- n. J2 `* Y- q( L
- ST7920提供64×32 个字节的空间(由扩充指令设定绘图RAM 地址),最多可以控制256×64 . M3 w% E, T/ R; l2 C/ Q; y
- 点阵的二维绘图缓冲空间,在更改绘图RAM时,由扩充指令设置GDRAM地址先垂直地址后水平
0 y$ T& L. }9 i5 ]0 h' Q1 B- u& h* K - 地址(连续2个字节的数据来定义垂直和水平地址),再2个字节的数据给绘图RAM(先高8位
) J4 g' y2 [7 ^ - 后低8 位)
( I3 R1 K: Q/ }+ g3 k7 r" ^) n - */
8 B4 l5 p4 d/ I - void WRGDRAM(u8 Y,u8 clong,u8 hight,u8 *TAB1), n2 ?0 r. ]% j" {3 c, M
- {
' G% F9 S- t o$ N* w* f6 Z - u16 k=0;& Y1 V& L8 Q" Q. f5 t% {; e
- u8 j;
4 Y$ t0 [# d% ^ - u8 i;
$ [: o" l* t1 j! w8 X+ s - LCD_WriteCMD(0x34);
' J [+ R' k! x3 d: R - LCD_WriteCMD(0x36);1 w5 Y" s7 `) w
- for(j=0;j<hight;)+ t7 ?0 T8 X9 u" |3 G
- {
7 A3 q& S2 d) v" E* c3 v - LCD_WriteCMD(Y+j);7 l1 `( X |" @, R5 ]4 O. j# d
- LCD_WriteCMD(0x80);//X坐标" t0 _7 y' ~/ I X0 D5 Z
- for(i=0;i<clong;i++)//& D# t/ s0 G# P6 p0 x1 ?/ i
- {! |* S+ b4 {/ L
- LCD_WriteDATA(TAB1[k]);
0 U* q4 K5 k; o( }9 I3 d - k++;
/ u7 C, _ @& B/ d' e, u+ G; H - }
, d; q4 v0 d/ m2 U+ V, h0 R% ~ - j++;# s# C4 g/ @$ v+ u
- }0 J8 V2 a8 q9 H
- }- s+ r3 m0 {$ F k, Z7 x
- ( Z$ ?: G* b; W% t
- /******************************************************************** , v: p( |3 D5 m' p9 e E
- * 名称 : ShowBlankPos " p- I$ Q5 c6 S# @: N
- * 功能 : 在当前坐标位置显示单个字符
* B& e+ p# b, a8 s& s - * 输入 : num 半宽字符的个数
, p1 w2 W3 o- O& c7 H, l6 V - * 功能 : 黑板擦功能,擦除不显示的内容
3 d3 g }: c1 R) B - ***********************************************************************/ + B5 N) ~- q7 U- f' n2 y. p# |1 j
- void ShowBlankPos(u8 row, u8 col, u8 num)7 R! }- ]6 G+ N5 B5 P4 I: `
- {) X/ D: ^9 A8 A
- u8 i ;2 V: i! c$ m0 M- Y: o
- LCD_SetPos(row,col);
/ Y' |3 {. z& G3 z9 Z4 k - for (i = 0; i < num;i++)
F: y/ D* I8 K/ t2 P - LCD_WriteDATA(0x20); //写空格
, q M1 z& T9 a: F) g. Q0 n - }1 q1 L' L& M9 y; p2 a, q9 L, T
& G4 _, {- n( t
& E4 J2 f* R- C2 X7 B
8 `9 V ` C- o2 k
% b1 Y) q* A4 b2 P; F v' t- 3 [% O# X% U3 x& z% R% {) f
- 5 w. l! U: q4 s- c/ G$ d6 K
% U ^% \) O& k7 z! c' }8 r- ' o3 y5 V7 |( |) B( T; g
$ J1 t- z- H& O% q. h1 J
4 N+ Z# [2 ]3 n; b3 [$ p
/ ?0 ]6 a7 \1 P; R f$ w% K- U
: J: i6 b+ k+ F% S/ N. |- F; M# V
5 m- s% L( P0 i- C- 6 M' J/ }1 j# W( V8 T5 u" J# w
- . T, T, N3 h- o, `% o2 A* s* |
; d2 t8 F' U% `) f# Z
* [; B: O2 Y3 s! [+ a
复制代码 上图:4 ~, p# K: o" X, b3 D
1 Y2 k9 |+ n+ x
Hellokity:
( Q# w) }/ Q5 {# k y, ]* y, p( Q
( X! L! i# S& q2 Y) A7 O( G! {
1 Q$ W& ]: A# P) y' K9 A! ?5 k2 h4 k9 M% A6 L
' ?, H/ i5 n2 M' A
$ x2 i' e d5 {" v2 s" t2 e$ V
! `! h8 A; B c* h5 f
8 u" V0 l9 z. L1 e* k" k' C7 h |
点评
需要创建一个屏幕大小的缓冲区数组,将要显示的字模数据放入数组里面,后面再使用绘图模式,统一将数组刷上去就可以实现了
是的,多了一个字母~~
这个是3.3V的屏,很好驱动的撒,这个是标准屏,目前还是用的很广的
还是没有花羊羊好看吧!!!