本帖最后由 caizhiwei 于 2015-11-5 11:04 编辑 , T# ]$ U$ h& [. l
% ^* c6 n {7 I I% ?# L7 W 虽然很久之前(51时代)就开始接触lcd12864,如今在工控机里面,LCD12864还是应用比较普遍的!
2 \9 o" p+ F: B我用的lcd12864类型为串行接口,3.3V st7920. e, v2 L6 q7 V5 R) {8 N8 r
代码优化说明:
; C% ^3 g2 f5 Y* M- T1.修复了字符串,汉字串不能自动换行的bug
( R! Z5 I2 i) r5 ], H- U8 O注意:
0 @2 w" q6 e0 Z) y0 n1.在使用带jtag接口的I/O时要特别注意
% N' _% z: k: C; D( B; q- I PA13:SWDIO/JTAG_TMS
' L% k( K. `+ @* X( ]# F, o/ M PA14:SWCLK/JTAG_TCK8 j! B% G+ y7 a
PA15:JTAG_TDI
+ G$ [; j- } U. N6 m1 y2 M2 F- ~ PB3:JTAG_TDO
7 q/ F4 J, K+ y) L; Q- L- _6 X PB4:JTAG_RST7 ^8 L2 _" j* K2 y
硬件设计缺陷:
2 N4 D1 F1 H! {$ [' c1.没有引出LCM的复位引脚,导致偶尔显示不正常之后,mcu复位(LCM并没有复位)* s: i" J$ }5 m1 M6 A
也无法解决,只能强行断电重启。
8 Z+ g! M' P2 B2.BLK液晶背光引脚的输入电流至少在20mA以上,没有用三极管驱动,而是直接用IO驱动,
% f( u2 B5 t$ C/ o" H) H 需要较大的驱动电流。+ O% }7 \) _- h
3. s0 ^2 ^; c t9 S$ `
编译器缺陷:
% R( s6 n5 S1 D+ f* F1.由于使用的是iar6.70版本,编译器在编译汉字串数组的时候可能会使带字库液晶产生乱码。1 d* A8 n( W3 `1 O0 Z- C3 n
所以在有汉字数组的C文件中统一使用简体中文(GB2312)(全选--右键--Charracter Encoding)
$ E7 E" U. a* o% i
4 r7 Y& S% A! [, j, I; ]部分硬件结构说明:
6 [; v. [/ ~8 z' j1.按键按下,(上连接VCC)连接电阻下拉到地,检测IO连接上端,检测到高电平。8 g/ L: ?6 t1 d. a# p
2.lcd12864底板反面接线图:
! ]( x# d, ^8 M% ^* i9 Q) W7 r8 L# H9 g N" v u/ u
从反面看:
2 d3 x$ n( a) g5V RW GND GND LED K2 K4 GND' \# h7 }: a; C* p8 I* y& @
GND RS E BLK GND K1 K3 5V$ D; \8 z8 l0 z0 o0 x3 S, ]5 x
& ? B4 R3 {7 M- \' N# b) @2015-6-10 原工程代码在23楼!|r3 Q! K& b Z C! l9 w
2015-7-12 程序更新了,,代码在35楼!2 x6 x1 v6 J4 M4 u0 O0 R# x
更新记录:
* o9 d% T! Q% ~* X% d V1.增加了24*32大字体显示功能;+ O6 k' V( O* ?9 y' G* p
2.增加了16*32大字体显示功能;
- x2 L0 W# S# ?9 p3.优化了读LCD忙的代码;
6 X& e4 M. E, a4.新增了是sprintf的任意位数数字直接显示;
+ B5 H: U/ G) ]5 k1 `1 t) i5.新增了CGRAM的写入,读出操作函数;
! T6 L: H+ d0 Z! q0 @" t4 \/ M6.优化了绘图GDRAM函数的操作,绘图速度提高;5 a& J8 s, }% p1 W& K" _7 D8 d8 A
2015.11.04 ,看到很多评论说链接失效,现在重新找了一份完整的工程代码,整理之后传到网盘:, }" f6 h8 G8 o/ h5 y# T: `# S
这个代码优化了.h文件中的宏定义,方便用户移植,C文件和gui.c文件均不用修改。
n0 @+ b; E% `. W# z& [https://pan.baidu.com/s/1pJw3wHd
4 s% Z e) J7 r6 r1 ]3 y# M9 d3 h" Y2 v, ]
- 6 o4 x( x" O/ w. s! f8 A+ c ^
- #include "gui.h"
( Z/ G' M5 r, \/ V
. l" k- `5 ^+ S1 n d4 I- /******************************************************************************* 4 X: f% v& N. G0 ?( X
- DDRAM地址; c' @2 F0 w& O1 z! V
- 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 //第一行汉字位置
% v7 W* g0 c4 A6 p# K. d - 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 //第二行汉字位置3 e' D# q3 Y" m) V
- 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f //第三行汉字位置* }/ }% F8 L5 _0 p; t
- 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f //第四行汉字位置
5 Z! h; a m0 v - ) r! @3 c& ] _6 p6 l* W7 G
- *******************************************************************************/
$ g1 f. W4 n0 Y4 T$ b7 p
/ w5 o7 d/ Z# m- /*******************************************************************************
1 q* Q8 X# ?* R* |) {8 U - * 名称 : LCD_SetPos, c( d6 n+ U; ~ t2 F: w2 c9 q
- * 功能 : 设定显示位置
7 J/ k" X% p) ]* L" @0 b+ J' {( D - * 输入 : x (0~3)行
4 h9 x" |: U# L; l - y (0~7)列
8 e+ N3 ]8 j! \0 C) d% s1 } - * 输出 : 无 + y: J4 ~8 w+ U
- *******************************************************************************/
P' Z) I+ O Z - void LCD_SetPos(u8 row, u8 col) ; |& A. [: Q) T B9 Y! U7 O
- {
( W9 a5 A* X I5 T1 k) h& U. r/ [ - u8 pos;
- d+ j r9 y# O" K( ^$ N. v5 f - if( row == 0) & l+ C2 ^0 M+ s1 {, w6 e) W
- row = 0x80;
% @" V! ]5 Q3 u3 y2 u; v' a! ?. L - else if(row == 1) + c4 o- S2 T4 I. X# e/ q. X
- row = 0x90;
5 j v& H6 K. z/ R( p - else if(row == 2)
3 @* _2 P" Q" F( d% z3 v: x - row = 0x88;
2 n: C( V9 K; j - else if(row == 3) 4 ?& B4 t; @9 r. k
- row = 0x98;
3 b& V3 p+ r+ T5 }# P - pos = row + col;
" R" f) D+ M/ \. C X - LCD_WriteCMD(pos);//在写入数据前先指定显示地址 1 a- B) u; v, q. `
- delay_us(10);
3 W. X) q: X5 t1 `- D - }
6 l- U; C# x& q) t1 T) m6 }
6 B6 c! C' _' q$ m9 g$ N4 w- 8 s: P1 q; _7 z2 ~( W1 _. t
- /******************************************************************** ; U" g+ u( P% V
- * 名称 : ShowASCII
3 r1 B7 s0 \( _0 b" ?4 N7 T5 ]4 F* U - * 功能 : 在当前坐标位置显示单个字符
$ c! J, M; h K - * 输入 : *s ) S1 }9 K# |+ M+ X$ ?
- * 输出 : 无
1 G' z7 T5 Y& d - ***********************************************************************/
- V4 l+ Y6 _# {! z3 ]1 C! v - void ShowASCII(u8 i)0 h/ G) X) @, K
- {( } c5 ]' ~% C
- LCD_WriteDATA(i);
$ M; f4 J: z% d3 ~9 { - }
/ g& |5 c2 f7 l- ?2 D2 R - : {. N8 K& }5 g& Z' d2 b: K5 r9 \
- void ShowCharPos(u8 row, u8 col,u8 dat)
6 _( H0 v C' z% _1 Q* H - { ( {/ K- a" q A7 m! f. I8 I
- LCD_SetPos(row, col);
3 f( Q- J& \: m) a! k - ShowASCII(dat);- O/ W! z% ` |3 `
- }
; N7 j9 p* I" V0 `) K - % B/ j- P) n2 `9 O( x$ v3 x
- /*******************************************************************************
& c9 k1 M X/ E1 {0 M! w! q - * 名称 : ShowEnString(u8 *s)
% U* ?% y4 e9 h6 V - * 功能 : 显示英文字符串 * I7 ?9 {, S2 h P' Z
- * 输入 : *s
( J1 F! M4 N+ U2 z7 ^4 Y$ ` - * 输出 : 无 , r% d/ M/ b- Q2 J
- *******************************************************************************/
7 A0 c6 e2 x) J, S& r - void ShowString(u8 *s) + k8 `' K. ~- e
- { + \& l3 \% a, ], C; T' }4 |# g
- u8 i = 0; U$ u. a3 o: |' M# O
- while(s[i] != '\0') 1 B' z6 e: z2 d0 \ q
- {
4 R* H) P7 T q, q7 O( R" ` - ShowASCII(s[i++]); 9 n0 }. \9 b" M5 f
- }
9 D% W7 S6 o5 A - }
% D. I9 G1 I+ |/ R4 f8 l+ g- d - ; M& A; E, b$ C' l+ a0 j' A
- void ShowStringPos(u8 row, u8 col,u8 *s) //col is full char wide
" J1 }8 Z x% m - {
0 B. M; n# |& o9 x6 s+ K - u8 i = 0;
, i$ k; S' D, g - LCD_SetPos(row, col);
$ s) U: q& p* K9 c. K3 N' N - while(s[i] != '\0') - { v2 V! {3 w1 _+ A ~
- { % A- D$ M2 T3 f$ W
- ShowASCII(s[i++]);
8 |+ I4 J- X T1 k - if((2*col+i)%(16)==0) //must 16, is OK9 y8 o/ k9 D5 p7 r4 k6 R. Z
- { ) @1 C& p% n( S7 n" M
- LCD_SetPos(++row,0); //display start at next row.
0 b$ H7 S! L; r/ c - }
6 S* P6 W8 H" }1 d% P - 1 U$ x; O0 @+ m$ |# ~
- }
& |& d2 X0 R& Z+ a - }
`+ o' d' D" Y - $ Q) ~$ r+ u6 D( A# d
- + `! D1 g; W, U
- ' C) A0 y* {3 R; z' S; T5 \
- /*******************************************************************************
" Q. E7 Y4 ~) F - * 名称 : ShowGB 9 `, k+ @3 V8 Z- _9 f7 c. I% N
- * 功能 : 显示单个汉字0 a$ o, k7 t( x
- * 输入 : i
, Y3 L/ e4 f8 U- m - * 输出 : 无 " X) i+ E, ?0 ^! t: F9 q
- ********************************************************************************/ 5 l# }/ D! T. t) T* t
- void ShowGB( unsigned char *HZ)
8 ]3 o6 \8 X2 \3 E' A - {$ r& h. d# l! g9 i4 T2 S+ D
- LCD_WriteDATA(HZ[0]); //写入汉字的高八位数据) B) M# i/ e: d
-
! _( d- `8 h5 R/ |8 u - LCD_WriteDATA(HZ[1]); //写入汉字的低八位数据 ! d; O/ q/ R$ y! J" r3 h G: q
-
- l! V3 H# ]$ i/ e- y, c1 t - }
5 n' P+ e3 X) V2 f0 H
$ S9 ~* ^( k# m# O4 D( X9 n9 N$ a7 h- void ShowGBPos(u8 row, u8 col, u8 *HZ)
+ R& k4 s; R! d2 w0 ]# v - {: c: ?* J5 d( W" _+ y
- LCD_SetPos(row, col);/ i8 N$ d( V8 z# G+ d1 V* z
- ShowGB(HZ);1 S5 o- ^7 c) I$ u/ J- V/ @7 q
- }
[% u8 B" A: ?7 l2 u0 l8 B \
( O, d, O; z/ Z2 j. l- /******************************************************************** . j: q/ j2 P+ c% \
- * 名称 : ShowGBStringPos # S5 ^% j5 ^8 b5 s: C+ a3 {
- * 功能 : 显示多个汉字5 W& F5 R! w, n! L/ C- w3 a
- * 输入 : u8 row, u8 col :汉字串的起始地址+ u; T9 f" w' A, G$ {; [
- * 输出 : 无 , F( ^; k6 \# V* k9 N
- * 说明 : 自动换行:lcm默认换行顺序是乱的,0--2--1--3--0
1 y; |1 P3 ]! y6 A# L% h" _2 \ - ***********************************************************************/
* H; W) h" [' ?6 H A - void ShowGBStringPos(u8 row, u8 col, u8 *s)
G. @% D6 s% R" j* O - {8 c; S0 m) M1 P! Q. e
- u8 i = 0;
! A# ~% ^/ v: O" d) ~ - LCD_SetPos(row, col);
) b' d) M* L2 q. o - while (s[i] != '\0'): W. I- p) O4 k
- {! \* q. R' d8 R" O" X5 n$ `% O$ ^
- ShowGB(s+i);
8 s/ U0 i! ~( b1 G - i+=2; - t6 }) G7 ]/ I( R5 X
- if((2*col+i)%(16)==0) //如果满一行
& r. j% O3 D' m* }% r9 C - {
5 T: [) ^. ^( [$ R( P - LCD_SetPos(++row,0); //重新设置显示的起始地址4 S) a, P2 {9 g7 }) Z4 A
- }* K. I; H5 C, T! g# e8 r
- # j6 E q1 f/ Y/ y# {% ]( U2 L
- } / f! x4 S2 c$ K# Z" t- @
- }
* g7 s- @& c; s5 ?4 \
1 Z$ a& Y o4 V1 r0 z- /*******************************************************************************4 ]- \' n" t; g6 {9 `, z: D) L: M& l
- 测试函数
2 W# V* s- k( z; {! i% B - Function: 用户移植程序之后,用该函数测试液晶是否初始化成功!
# M/ P6 m) a4 u - ********************************************************************************/ B2 P8 K0 d" |# e) t( l& @
- void LCD_Test(void)* @- ]* S: N2 f# `8 a$ ~
- {
" j G" A* q h* Y4 }3 ]" ` - ShowCharPos(0,0,0x10); //右箭头' k2 J; K# A2 }" o, b
- ShowCharPos(1,0,0x10); //右箭头 , y- i+ n- Y, B
- ShowString("Hello,world!") ; & b* N# u+ z, b# s
- ShowCharPos(2,0,0x10); //右箭头3 F, v. V1 s# t" x# F3 [4 T" o, m
- ShowASCII(0x11);//左箭头$ D E; G: }& V- K. ~/ c' |
- }
- @; m# L0 c) n! f - - M: B0 s/ l! f2 a
- 0 _1 o8 n8 h2 r
4 @5 B- n* P( v5 U9 l# @- % G* T9 `9 g/ P9 w
7 K5 P0 m; c; i) X& U- //自定义字符写入CGRAM2 s$ b6 w- r$ Z# d. @
- void Write_USR_CGRAM(u8 data1,u8 data2,u8 addr)/ _7 y! Z+ {/ H- `
- { - g1 Y/ i+ R+ x; I4 f
- u8 i;
) k5 n) H9 ^( Q, H7 Y - for(i=0;i<16;)
7 l" E. n2 s# c+ ^6 b& A. ^$ b - {
& {3 J1 c6 B3 b$ o - LCD_WriteCMD(addr+i); //设定CGRAM地址
* Y4 U4 P0 m3 j2 e; ~: f - LCD_WriteDATA(data1);
% v/ b" _0 d9 [ - LCD_WriteDATA(data1);; ^1 I: B3 A: F! \) \4 o6 e# J
- i++;
( F% Z* G4 M) o! L3 D* W - LCD_WriteCMD(addr+i); //设定CGRAM地址) q0 ^; q% Y M; z) y# Z. ?
- LCD_WriteDATA(data2);
! P9 r& j' r7 W - LCD_WriteDATA(data2);) c1 a' g: M" a6 ?1 Q
- i++;4 G* G$ }0 O9 u& y
- } - p8 I F. S2 m
- }
+ T! Y9 Z5 v, k$ I+ P - % c9 L# m; L* Q
- //显示自定义的字符,并把这个字符填满全屏16*16/ O' t7 y4 [8 b+ X! n, O3 ~
- void Show_USR_CGRAM_Char(u8 addr,u8 i)# J: _ k8 J# p, p! |
- {
# M3 C8 Y, `9 D2 R - u8 j;
6 b, w; J; _( e+ J: M - for(j=0;j<0x20;)
" c* \1 r4 n" P: ]2 K- N. m3 M - { % Z) _4 F' h+ f9 |
- LCD_WriteCMD(addr+j); //设定DDRAM地址: ?6 B6 q v2 S% J
- LCD_WriteDATA(0x00);
( V) g2 @( D! }# W, c0 u! V9 N - LCD_WriteDATA(i);
% ]+ T0 k9 j) Z" n: B3 K - j++;
) W) Z+ @" @1 v G - } # h- U" d8 G9 @) w2 ^1 w6 i
- }
" }! y, }, I1 I9 F" Y8 e7 m - 5 T5 c( G1 H* k$ S/ \% @
- //写入GDRAM 绘图,Y是Y绘图坐标,2个字节一行,X是图形起始坐标,CLONG是图形长度,以字节 C/ T' H6 T# S, P' ] x
- //为单位;HIGHT是图形高度,TAB是图形数据表.12864M的图形显示范围是256*32点阵.
2 s) A' N x1 O4 U% D2 e2 H - //要在12864M里显示全屏,取模时一幅图横切成两半
1 s+ _! L9 \7 |5 h$ R - 9 z* L4 Y& k# E# \/ ~
- /*" x& m: \- ^# P7 X+ S7 G8 D
- ST7920提供64×32 个字节的空间(由扩充指令设定绘图RAM 地址),最多可以控制256×64 * b& M' B# y7 M. J5 E
- 点阵的二维绘图缓冲空间,在更改绘图RAM时,由扩充指令设置GDRAM地址先垂直地址后水平
A" T1 k& M( v2 H/ a - 地址(连续2个字节的数据来定义垂直和水平地址),再2个字节的数据给绘图RAM(先高8位
8 u6 |7 E8 q/ ~+ c' ~' o/ ]" R6 Y/ r5 ~ - 后低8 位)
2 T' M6 _( Z6 w2 D/ o4 g - */7 e" s) B3 k9 X2 r( b
- void WRGDRAM(u8 Y,u8 clong,u8 hight,u8 *TAB1)* q5 Q: l+ T$ W% C
- {
: [4 Y% ]* I8 ?5 _ - u16 k=0;. Q6 c( ~9 [2 x' t3 x1 X
- u8 j;
8 g1 `: p6 S; E% F# m6 \ - u8 i;$ W6 d, S9 P( ]" j$ p
- LCD_WriteCMD(0x34);
* v* v! e9 f3 M0 W/ c& h" \ - LCD_WriteCMD(0x36); L3 b U6 N9 |/ ^
- for(j=0;j<hight;)
- o% E _2 q4 o# E2 e - {7 e" z- ^5 S W+ K; i! ~- e2 w0 s8 a
- LCD_WriteCMD(Y+j);
, R) Y& N/ B$ t: W - LCD_WriteCMD(0x80);//X坐标
* [" j$ j* R/ A! d - for(i=0;i<clong;i++)//6 W) m$ R7 U# N$ g8 Y# a) d
- {
; i) z% n1 Z2 b* [ r - LCD_WriteDATA(TAB1[k]);$ O2 C+ S0 w% Q$ @5 Q2 S
- k++;
! |" H! l U+ U1 W8 c1 O/ w - }
2 e. }9 ]! m2 B0 ~- ^ - j++;, j2 R9 \( l3 G4 N
- }
% I; F/ A3 `1 V/ S* z - }6 Y& r8 y2 X4 d. t8 e* B* e
( }0 K( W. Q6 s( R5 B- }% |- /********************************************************************
: N) @8 g u+ B+ @& Z6 D7 a8 P - * 名称 : ShowBlankPos
4 A# H i9 M$ x - * 功能 : 在当前坐标位置显示单个字符. [4 _. O& Q9 l/ g
- * 输入 : num 半宽字符的个数
1 Q+ v' R. }+ |4 G5 V - * 功能 : 黑板擦功能,擦除不显示的内容; b$ C: O7 X7 S
- ***********************************************************************/
1 Z. P4 y) Z: D% R: V5 }) T" N) z - void ShowBlankPos(u8 row, u8 col, u8 num)
: l: w2 i5 A' D! u - {
^! p7 W! j# F# ? - u8 i ;- W o* q/ V8 v- Q/ X$ L. {& X
- LCD_SetPos(row,col); ' W2 Z# L% O7 V) n9 R
- for (i = 0; i < num;i++)
7 E6 Z8 G' R% e+ p$ D3 _1 \ - LCD_WriteDATA(0x20); //写空格
8 d4 y" q8 x: k& p - }
7 o4 G3 O( }$ s4 O1 T( r - 9 t* s- m$ L6 t" y" M1 |- Q" O+ Q7 k
5 d9 A$ B% C1 i# Q: P& F% ]8 d4 f
q- P6 `* ~- R7 p2 H) m- & z. f2 t. e; M" i/ P" Z( L$ @/ v
- ; L8 }& l2 C) j8 Q c
- - a H0 T9 {# I& @+ ~0 \" M$ `: ~
- / S* v& ~4 |; E- M8 j% t1 p9 H0 T
- + e6 N1 V9 C, Q# b2 p+ i
- + E( a9 G. e" }2 m
0 x- u/ K; c8 |$ |1 C
6 f( l [$ _. O/ h8 d- }9 a E& r& h- 5 S1 l1 n, r$ E; R
- 2 O8 l$ b1 l3 ^
& K& a- Z2 R4 M' |# K. v! K( y! x- 0 a9 {+ ^: u5 N) t5 u3 f% `
- 5 A" e: k x, H
# v/ g7 U- h# @; E
复制代码 上图:7 f; C5 A# x7 E" a
L3 S: G" V5 b4 f4 G
Hellokity:+ x8 G/ v) c- O& b
( {7 r' d0 c# `2 L# P
9 C: r; Q& t" o! n9 B" X* a% F3 t6 X5 i; W
% w* {- j! [. V1 ^8 R2 k B/ V. ^) e6 J( ? P3 L& J
+ G1 n+ B1 S7 O" C ?1 O
* i* N: _5 s8 F. X8 i# E) I' C: l2 H) Q" @7 l& P0 d
|
点评
需要创建一个屏幕大小的缓冲区数组,将要显示的字模数据放入数组里面,后面再使用绘图模式,统一将数组刷上去就可以实现了- b" ]5 E' y/ W
是的,多了一个字母~~
这个是3.3V的屏,很好驱动的撒,这个是标准屏,目前还是用的很广的
还是没有花羊羊好看吧!!!