本帖最后由 caizhiwei 于 2015-11-5 11:04 编辑
& Y7 s7 t& c5 i: r0 d5 T5 @7 b$ ?7 J" e) J
虽然很久之前(51时代)就开始接触lcd12864,如今在工控机里面,LCD12864还是应用比较普遍的!
6 I( q7 Z4 }: X! o8 c: V% l; T我用的lcd12864类型为串行接口,3.3V st7920
$ A/ \) K! |+ j' x代码优化说明:' u- Z: c2 z! ]
1.修复了字符串,汉字串不能自动换行的bug7 K- u" n: k; n+ i% r
注意:: @2 L" D6 Z2 q! Y2 g6 ^, Z, O
1.在使用带jtag接口的I/O时要特别注意3 L+ _' N3 r& ?& A! V3 F
PA13:SWDIO/JTAG_TMS; W+ p; P3 ]# W3 U$ J
PA14:SWCLK/JTAG_TCK4 ]( d8 s# c4 h% B. _9 R
PA15:JTAG_TDI
; g9 x/ }$ N( z+ C" I PB3:JTAG_TDO# w% i+ C; c" f# }; q, y
PB4:JTAG_RST
2 h* R8 v4 u8 I" c, W2 ]硬件设计缺陷:
. S( L( S( C! C/ M# [+ H6 e1.没有引出LCM的复位引脚,导致偶尔显示不正常之后,mcu复位(LCM并没有复位)4 }5 p5 L# X6 \2 h1 T! ^
也无法解决,只能强行断电重启。
3 A+ t* U5 k' E% ]2.BLK液晶背光引脚的输入电流至少在20mA以上,没有用三极管驱动,而是直接用IO驱动,
0 }& i F* J+ \2 v 需要较大的驱动电流。3 X& R1 U$ Y0 E$ W6 y% v+ t. g
3. ' X9 |" J( V1 \
编译器缺陷:; i( U- A3 `1 t8 i2 ~5 [3 |3 ]
1.由于使用的是iar6.70版本,编译器在编译汉字串数组的时候可能会使带字库液晶产生乱码。
, y" s* E D! X& ]) t% ?- { l 所以在有汉字数组的C文件中统一使用简体中文(GB2312)(全选--右键--Charracter Encoding)
; I2 ]$ |4 c& Z4 U
: U0 R: W/ H% Y; G2 E' P- r8 K部分硬件结构说明:
$ k& m# ^2 E% l$ o5 T1.按键按下,(上连接VCC)连接电阻下拉到地,检测IO连接上端,检测到高电平。
( ~' t/ f1 d7 } T2 r& l2.lcd12864底板反面接线图:
- H' x" Y) c0 o6 |5 N+ F" ^7 R: ~# g
从反面看:
4 \' w4 ~ s6 O: e p" }* a0 ^5V RW GND GND LED K2 K4 GND
0 l2 ]; q4 D8 v& F7 ]' ]. C( J5 KGND RS E BLK GND K1 K3 5V; d' k3 I m g' T- o2 W
. b- D# j+ `' x/ L2015-6-10 原工程代码在23楼!|r1 }: v( U" t. n
2015-7-12 程序更新了,,代码在35楼!, i a, N) k$ @: g( B# p( A/ [: z! t
更新记录:& y0 U+ F/ M. f+ _4 J
1.增加了24*32大字体显示功能;4 B+ L( s3 Y; R% v$ B
2.增加了16*32大字体显示功能;
% M0 \5 ?. p. K7 }& g: S4 Z3.优化了读LCD忙的代码;3 d, u/ }+ M7 \; Z
4.新增了是sprintf的任意位数数字直接显示;9 g# S$ \$ ?1 e A, `, r n
5.新增了CGRAM的写入,读出操作函数;
6 h3 L" U0 q; J6.优化了绘图GDRAM函数的操作,绘图速度提高;: T- |+ {( c% l4 f' K
2015.11.04 ,看到很多评论说链接失效,现在重新找了一份完整的工程代码,整理之后传到网盘:
8 j5 t/ t2 i9 J6 \. S4 R ~这个代码优化了.h文件中的宏定义,方便用户移植,C文件和gui.c文件均不用修改。; \- Q; x% @( d* N, t/ Y* E
https://pan.baidu.com/s/1pJw3wHd . |0 j- O N1 Y' @9 _2 Z* e$ z
4 S) I4 u; m3 e& c$ Q
-
2 W8 p) }- P# J5 E& p4 |6 i - #include "gui.h" |7 x" f0 M+ Q, I A6 l# n& }
- * q! z( Q7 Z. y1 ^, s
- /*******************************************************************************
+ d/ ~) q1 p3 n/ |& h: e% {0 V& K - DDRAM地址' F6 h( {0 p# h8 p3 ^
- 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 //第一行汉字位置; F) k" K" {( U7 _- ?
- 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 //第二行汉字位置) ?0 O, X& v* i9 L
- 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f //第三行汉字位置2 H& I- h+ l1 m9 b
- 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f //第四行汉字位置1 b7 d* M! W5 k1 x
- $ Y7 A! Q( b- u. T
- *******************************************************************************/ & u+ [9 Q5 d0 H* G9 T
- 9 j! ~) C6 N8 I* U6 ^" M
- /*******************************************************************************
; e C7 J7 m o6 n) G' u( ~ - * 名称 : LCD_SetPos
. H8 r+ e( S! I& g7 N3 e/ e, ?7 U - * 功能 : 设定显示位置 2 B( ^. Z2 u Q. D2 Y8 T0 q( m( q, b
- * 输入 : x (0~3)行
. B" T" c1 p6 d2 L$ G - y (0~7)列$ m- i5 j, d2 d% I+ G
- * 输出 : 无 / A6 X5 r, C. C* Y+ F
- *******************************************************************************/ " n+ g( D8 T: u7 Q! o
- void LCD_SetPos(u8 row, u8 col) E; j- ?" n/ I3 T
- {
5 A) y( }0 U; K) v - u8 pos; , X* Y3 S& s: x, a: ~* O$ j. l
- if( row == 0) , k) v0 e5 @- T! i) V
- row = 0x80;
/ J. M+ Y/ t$ N; Z - else if(row == 1)
* R2 A7 Y8 c$ O - row = 0x90;
6 R5 p: s' x' K; e# t - else if(row == 2)
4 y0 K$ J: I9 m* l) a( B- m - row = 0x88;
0 i! C3 e' V$ n, y - else if(row == 3)
# @& d; G. K1 T3 t1 C# L - row = 0x98; 6 z0 V' w' W$ I$ E h
- pos = row + col;
" U4 _- T# B; j. } - LCD_WriteCMD(pos);//在写入数据前先指定显示地址 $ O0 i% `0 D4 Y T. {! I0 }
- delay_us(10);. R) z' h9 h9 E" p& H
- }
2 V7 B% V Y* ~% C - 0 O- C E9 X7 B" l: Z0 `% n
/ F& V0 n+ v6 ~* Y. H( G- /********************************************************************
. {$ }( X* ]. M, ?6 H; L& R, | - * 名称 : ShowASCII
: k% F. Z; ]; ~+ m) k% F - * 功能 : 在当前坐标位置显示单个字符
+ U) m* F" @6 l/ ] - * 输入 : *s - u0 s6 p1 @4 m8 E8 E, k9 W* N
- * 输出 : 无 ; r4 o0 ]6 r! Y' I, H& u
- ***********************************************************************/
* ?& w$ R* b8 d" m - void ShowASCII(u8 i). D: n6 G1 ~- r' ]' C3 ]: {
- {
" i8 x+ }$ p0 t8 d5 _5 o8 h - LCD_WriteDATA(i);
4 b( I. C$ {* [; j* [" Z - }- x: J3 v5 H8 M% z& K% L
- & s0 B: F; e; A$ q& ]
- void ShowCharPos(u8 row, u8 col,u8 dat)9 Q3 n4 ?" k& O% s9 C
- { 7 ^, J: E& a; r& V# x K
- LCD_SetPos(row, col);# g" I2 a" A C2 G
- ShowASCII(dat);' A6 v+ I# c: C+ E3 r6 }
- }* f: F0 i# m; D2 J
2 N# E, }4 b! [7 t% W2 n- /******************************************************************************* 1 N: R3 A" \. g- h: B; R
- * 名称 : ShowEnString(u8 *s)
% z, T, ?/ g2 \) v# G - * 功能 : 显示英文字符串
9 J; }. a i& _# x - * 输入 : *s : P3 b( t! y4 P
- * 输出 : 无
/ U- t5 d1 k: l - *******************************************************************************/ 1 k6 f4 k% W; P3 U
- void ShowString(u8 *s)
7 |/ d- \# e, e- ]# j' k - { 3 q! B# P- f0 g
- u8 i = 0;
/ |0 d& p7 d9 U8 [3 E* r - while(s[i] != '\0')
( A; _1 n- k, `' v# V8 n3 A - { + q8 {; @+ w# `# C9 A, I
- ShowASCII(s[i++]); $ y- j0 ` B# E% X, A; u5 h
- } - _' b, k. Y& v# Q$ _( U
- } 0 w' v% L5 g3 `$ z8 ]" j
- 6 i2 R. Z4 r) Z- s7 l! t- f
- void ShowStringPos(u8 row, u8 col,u8 *s) //col is full char wide 8 t$ P" v" F4 r% V1 X
- { + f* J2 O& f1 S& P0 X, e9 H1 m V( s
- u8 i = 0; 6 L, A5 f3 v' e/ ^
- LCD_SetPos(row, col); ( K ~9 `# ]/ [1 E% k; I3 S
- while(s[i] != '\0') d" a: C! h3 ^& D' d# A/ l( ?
- {
- i* {) n! H4 C+ m8 j6 |) E - ShowASCII(s[i++]);
8 \. d$ v) W* V8 w0 t$ p8 _" a - if((2*col+i)%(16)==0) //must 16, is OK$ C+ [; K7 I8 W( o0 R* y* ?) Y
- {
( t, X k& L- K1 G( ~ - LCD_SetPos(++row,0); //display start at next row.
+ \( d/ p: m, A3 K - }! {! [" L" _7 z
-
; m' t) {/ g( i - } ( y2 q1 D! B2 L6 h! r
- }
- s0 T0 ^$ x; T6 t - / A, \- ]4 W, q* o4 I7 P
- : Q$ W o; `8 N/ e
- V% f0 d- H" _% K- /******************************************************************************* $ i J% m" Q w# |0 w, H+ i; G+ X
- * 名称 : ShowGB
3 \5 H7 c: q. \4 K m# L# Q/ n - * 功能 : 显示单个汉字5 b* A- u4 f; D5 v1 a, u! H
- * 输入 : i , W: g% K( P& e. j( F; N5 l! |
- * 输出 : 无 1 H4 c' A4 a, A! W
- ********************************************************************************/ " i! v1 N! S; d* [0 W( V, S
- void ShowGB( unsigned char *HZ)" a! H' L' [7 [2 ]6 u
- {
- r8 Q4 Q+ j! g. d+ s0 I - LCD_WriteDATA(HZ[0]); //写入汉字的高八位数据
0 Q8 v! Q* E5 j7 w( Z! D -
, {2 ^. P% W9 O+ q5 V/ t - LCD_WriteDATA(HZ[1]); //写入汉字的低八位数据
" H$ W% u9 c7 U7 U - $ z/ R( u! s1 V7 R& c: w
- }4 K( y4 v. H, p, e2 }" w
- 3 I1 C9 S0 q/ H2 Y+ Z
- void ShowGBPos(u8 row, u8 col, u8 *HZ)
7 u3 b5 h1 W# z7 Q - {
8 z3 L1 ^5 m& h5 a5 D9 `/ C - LCD_SetPos(row, col);5 b1 S& W" A/ F. P+ X) \7 B
- ShowGB(HZ);
' b) ~7 e' @7 h8 ~! w$ H - }
$ M. U1 j' C z0 X- h
" y6 L4 g/ L- x2 q) o$ W- /******************************************************************** 1 @% B1 y2 u3 E( y# G6 v
- * 名称 : ShowGBStringPos , Q: X, V7 K6 n- I- `* k! U
- * 功能 : 显示多个汉字, ~8 A, }( o% X
- * 输入 : u8 row, u8 col :汉字串的起始地址
% o1 A {3 ]% K+ o - * 输出 : 无 6 b* z, d4 R5 K% d( r! O
- * 说明 : 自动换行:lcm默认换行顺序是乱的,0--2--1--3--0! N7 p' _( o7 i6 m, r$ M
- ***********************************************************************/ + D/ h0 I! }9 Z5 s& Y) o
- void ShowGBStringPos(u8 row, u8 col, u8 *s)
0 S9 i$ t, f. t% q- k - {
% i0 p" G0 m4 _/ y) k, }% s0 P - u8 i = 0;1 n2 l- r: S' L: m5 ]. X& L7 ~& O
- LCD_SetPos(row, col);# z' r+ p e Y
- while (s[i] != '\0')+ O9 }2 G! }$ S* s/ v( B% o
- {
# K: [+ d: `$ x7 q6 _) J - ShowGB(s+i);
; S- D$ J* m" F - i+=2; / P) d: o. b# @9 |; Y, \
- if((2*col+i)%(16)==0) //如果满一行
/ K+ K6 J0 n' F# q7 @% r! \- n - {
I# J" ?6 z+ I! e# Q1 I1 K9 y8 |) C - LCD_SetPos(++row,0); //重新设置显示的起始地址- Y; m A- l- x
- }
$ o) Y( a# J2 _! c% C; k0 {; Z -
' O$ k9 ]' ~# x) f K- E - }
& `3 v2 i$ I6 O. `* `& q! h6 L - }
+ D1 W9 j! F! k8 F' F - 9 Y1 U9 G( n3 z1 G3 |; ~! J% x. F
- /*******************************************************************************
2 S5 N, T9 q* Q1 {8 P$ q3 c - 测试函数
- ^' W4 I& v3 f. h, U, o1 c U2 l2 W - Function: 用户移植程序之后,用该函数测试液晶是否初始化成功!( }: E6 L1 O# i* g+ {
- ********************************************************************************/
& M# y# \: B4 g; ]+ u7 D& @# r - void LCD_Test(void)9 d; r# J2 H2 q9 X) ^. l
- {
6 F+ Z* g, Q( j+ ^ Y& u - ShowCharPos(0,0,0x10); //右箭头
4 q1 m5 B5 c2 U( \1 m3 _ - ShowCharPos(1,0,0x10); //右箭头 9 u6 M8 Y1 n$ V/ P1 c, q
- ShowString("Hello,world!") ; ; Z+ C; Z5 O4 @* |$ }4 i4 J
- ShowCharPos(2,0,0x10); //右箭头$ X) d2 r# ?3 y- p7 U
- ShowASCII(0x11);//左箭头
2 d5 F% R& d5 l" o - }
7 U c0 C1 M- b% ? - 9 |: H r1 j A' h5 d
- % |; D6 Z; _: L; h; k Z0 v
- 2 q/ ?2 l6 J" I8 D# d4 j' ~
0 K% S1 L: d6 ?1 }& E- ; R: H$ N$ ~9 R6 {
- //自定义字符写入CGRAM# r: n9 F# [5 j+ n
- void Write_USR_CGRAM(u8 data1,u8 data2,u8 addr)( Q! F" b# M: \6 p! X
- { : e: _/ |: O" N6 Q# N
- u8 i;/ J7 h) N, c }/ U0 r
- for(i=0;i<16;)" W5 e/ [( I: A8 U& S( {; \% I
- {
) T" {; ~* @+ G3 `, ]" F - LCD_WriteCMD(addr+i); //设定CGRAM地址
3 Z' |/ u" a- e3 M s" ^. J9 ]' T - LCD_WriteDATA(data1); q% v M2 r& ?2 t2 _+ L4 J
- LCD_WriteDATA(data1);
5 a+ E& F1 ?) _7 ?/ M0 z# c) N - i++;
1 C+ U& \. a7 Z% b- ?. X - LCD_WriteCMD(addr+i); //设定CGRAM地址1 P# p+ x9 r- I# _
- LCD_WriteDATA(data2);
3 h. w# {( ^8 F3 I - LCD_WriteDATA(data2);8 m8 u0 N/ W0 _, @+ u
- i++;* t% ^4 G& e6 v, T. q
- } $ Y0 R7 T5 L+ j( \% k" V
- }
' O/ G2 a1 o( i: H - * _* A4 g0 v3 W( f' m' |
- //显示自定义的字符,并把这个字符填满全屏16*16: A- e9 C1 ^/ I) J' Z% W5 E u
- void Show_USR_CGRAM_Char(u8 addr,u8 i)6 w P" j) \6 H& N
- {
7 s, f/ v6 t- }$ i" I2 a - u8 j;/ z7 L E- O2 v9 X
- for(j=0;j<0x20;)+ `( i0 D5 m( W8 N
- {
+ ?7 Z: J" U9 `5 K( z, M4 e' b) ^; { - LCD_WriteCMD(addr+j); //设定DDRAM地址
% s' h* {" Y3 U6 F. h - LCD_WriteDATA(0x00);: c' r$ I$ o9 R3 d
- LCD_WriteDATA(i);5 Y1 \2 s3 y1 J H, \% m1 k
- j++;( }" c K% k+ S& v+ m
- } / [) ~" k( R) {
- }
) J* Q( q! V7 l3 q: d - Q3 P2 K- }: \+ I5 f% X
- //写入GDRAM 绘图,Y是Y绘图坐标,2个字节一行,X是图形起始坐标,CLONG是图形长度,以字节
" f, |# K3 r4 a( t k) J" k, }: H - //为单位;HIGHT是图形高度,TAB是图形数据表.12864M的图形显示范围是256*32点阵.
t2 w% B- c0 T9 T* L \7 p+ e - //要在12864M里显示全屏,取模时一幅图横切成两半7 Z: n' A9 R% a8 ~; d+ ]" i/ k
! i, S# [- i( ~9 V/ f- /*
) r, h+ k9 |6 x/ o - ST7920提供64×32 个字节的空间(由扩充指令设定绘图RAM 地址),最多可以控制256×64
. |0 i5 f7 x2 j0 A& j - 点阵的二维绘图缓冲空间,在更改绘图RAM时,由扩充指令设置GDRAM地址先垂直地址后水平
% z1 [; `; p* M7 ] c- C' { - 地址(连续2个字节的数据来定义垂直和水平地址),再2个字节的数据给绘图RAM(先高8位0 T0 _7 j: j" ]! ]
- 后低8 位)8 o0 k+ t' P% m9 ]
- */% W! R& t/ [( R4 L' b
- void WRGDRAM(u8 Y,u8 clong,u8 hight,u8 *TAB1)
9 v& n4 k& J3 _ N; z: Y$ x' B0 c - {
% g5 o/ V3 f" L) r: h& f% d7 @ - u16 k=0;: z4 K2 G# b) a2 g6 N, K
- u8 j;8 b; q& o- U. U4 [* C. f3 e) [- }
- u8 i;2 ?( ^3 A, f5 E/ l5 }4 X1 K; Y* z
- LCD_WriteCMD(0x34);! B& }6 a, X7 Q1 s! }
- LCD_WriteCMD(0x36);+ W- t1 G& ~1 g
- for(j=0;j<hight;)6 S4 s0 _% ~ l2 @& p
- {
5 g: f" p1 k% K8 \* Y: Y7 x' A - LCD_WriteCMD(Y+j);
5 n+ }7 z" T% z1 P2 L - LCD_WriteCMD(0x80);//X坐标
% u- N4 Y) s. B% I l. T( x& I - for(i=0;i<clong;i++)//" v- x# l; `2 O1 i3 h9 R, o
- {
9 d* Q3 r1 l5 z; O g - LCD_WriteDATA(TAB1[k]);
$ g/ E! ?* ]8 o2 p - k++;
7 g2 F2 ~+ ~7 p4 [ - }
* U1 ~! |9 o. y( U - j++;
. s% ~1 Q. m$ X ~& f - }/ C# k1 z* ?# q M2 q
- }
& _; c: o; U6 d( @; i. N
* A, \- C2 f& R1 x; C- /********************************************************************
$ }% ~5 l* f* K, Z. h( \6 ~. s - * 名称 : ShowBlankPos
% e( M* B9 G- }+ q% C' O" O+ c - * 功能 : 在当前坐标位置显示单个字符' @7 ^3 I" c5 t w! ?2 P
- * 输入 : num 半宽字符的个数
P# I* ^& m2 l# Q3 d+ F6 ^ - * 功能 : 黑板擦功能,擦除不显示的内容4 c$ z7 v0 D3 ^& L; i
- ***********************************************************************/
& |+ y3 k: b, H! N - void ShowBlankPos(u8 row, u8 col, u8 num)
# Y( V4 j/ F3 Q0 i% [ - {9 Q# ]& {5 H* M' V& X
- u8 i ;+ `0 M+ ^5 _7 p9 N" q& s$ g$ L
- LCD_SetPos(row,col); ' m. |- r& n! X( U& ^
- for (i = 0; i < num;i++) ) ^6 R- V+ \( x+ e4 g, E
- LCD_WriteDATA(0x20); //写空格' R$ m, c+ t1 ]# p+ x
- }
$ v3 Z' T' v9 o1 p& y
) `2 K8 D8 @3 B; [7 |- ) {9 z! [/ h6 R. o0 a
- W5 X' O1 b: O5 V5 O9 y6 C
- ' C k7 y8 @- j% f/ ?
8 v( v2 W9 x4 ~" }4 u) p, c V- 1 ]7 C5 e9 ]* f$ R* Z
2 \) @) s3 a9 h# M
( d3 T5 @# \- C1 E* G5 s% b- + y: b7 U. ?& R: @% O
- 2 O, V# C: Q5 [# E9 ]
8 P; x1 o0 B E- ) ]' f- D8 c9 H: Z: M9 H7 H5 W" h
- 4 t$ m2 e7 `- e* k; o# Z, {
- " h) M( S( o2 o7 l, T
8 X% x6 S8 D+ t" S; q* ]- 9 p: a8 L/ Z+ i( v- P" q
# |% z+ i" n7 M+ n" Q
复制代码 上图:! l) O$ _ y1 t. S% ]+ P' X' k
) c! Y# v M2 v4 K5 D( x, I" B
Hellokity:
; D" T* n; {2 A o& Z( {) K2 J2 l
" w: e3 e8 t5 b$ D, [
) _+ [; Z) `: a0 h4 p
8 D J; k1 k1 B4 }& V5 K1 D4 d. O% h& M& a
4 P, W4 @4 ^* l( z4 T; _6 f
+ z& O5 p3 H3 a; E) E0 n
* V) X1 a- q% d2 \4 o1 C9 r. @/ L |
点评
需要创建一个屏幕大小的缓冲区数组,将要显示的字模数据放入数组里面,后面再使用绘图模式,统一将数组刷上去就可以实现了
是的,多了一个字母~~
这个是3.3V的屏,很好驱动的撒,这个是标准屏,目前还是用的很广的
还是没有花羊羊好看吧!!!