本帖最后由 caizhiwei 于 2015-11-5 11:04 编辑
( U9 u2 T$ }; O ]2 x
0 \1 M$ M0 u5 m, \ 虽然很久之前(51时代)就开始接触lcd12864,如今在工控机里面,LCD12864还是应用比较普遍的!1 g8 A# `, s4 R4 U
我用的lcd12864类型为串行接口,3.3V st7920) I ~0 E% Q5 K
代码优化说明:- J ?! w. U, x, k! @
1.修复了字符串,汉字串不能自动换行的bug w2 @; Z) `, g& g! i4 Y- t
注意:8 R f1 j: a* p# _. r# B" T7 B* s
1.在使用带jtag接口的I/O时要特别注意0 n& t+ {0 r2 n% o0 Q V
PA13:SWDIO/JTAG_TMS) |/ P/ ~" \( _5 _$ X/ C
PA14:SWCLK/JTAG_TCK
. n2 {+ }- y. d PA15:JTAG_TDI
! E& E6 @% u- ^" G PB3:JTAG_TDO
. p/ y; o: R3 Z3 x! d7 B PB4:JTAG_RST5 y% t! w" V8 i# N( A
硬件设计缺陷:/ B4 |$ W1 o' X. g
1.没有引出LCM的复位引脚,导致偶尔显示不正常之后,mcu复位(LCM并没有复位)5 u: r; R3 o6 e% A8 n
也无法解决,只能强行断电重启。
3 a1 y+ ?. Z* p, D N4 `; n) p0 J! t% l2.BLK液晶背光引脚的输入电流至少在20mA以上,没有用三极管驱动,而是直接用IO驱动,2 y" T: I$ K$ l
需要较大的驱动电流。
" H, Y" |# T+ u0 u$ U3. 1 H5 t/ w2 G" X q2 Y2 j; l% A
编译器缺陷:
' T& J$ A' t% E/ D' I" p1.由于使用的是iar6.70版本,编译器在编译汉字串数组的时候可能会使带字库液晶产生乱码。# J, |9 p& s* ^+ e
所以在有汉字数组的C文件中统一使用简体中文(GB2312)(全选--右键--Charracter Encoding)
: ?% y8 h2 L5 u- [- V8 n0 i# Q! b6 X3 F
部分硬件结构说明:8 Y+ ?# O0 Z D# n! d
1.按键按下,(上连接VCC)连接电阻下拉到地,检测IO连接上端,检测到高电平。$ x) ?! ~2 A( T) I
2.lcd12864底板反面接线图:5 u6 {' b6 c% O) L" i2 b' U
$ d7 b/ Q, |- p5 E a从反面看:0 r$ y' k; E* d! f
5V RW GND GND LED K2 K4 GND
3 x5 d- ]% M7 @3 m b! ~GND RS E BLK GND K1 K3 5V
# B& h; f# R v( ~, K) v* D
0 O* J0 A7 x" j' d6 C& O, X2015-6-10 原工程代码在23楼!|r
, s7 X* ?2 w: F$ h e2015-7-12 程序更新了,,代码在35楼!
: J6 ^2 ^+ }. |, u7 ]" u; Y更新记录:2 A* t' v8 T! B' e, E$ Y
1.增加了24*32大字体显示功能;* Q5 z/ \" L/ e! `) Q* n2 ?
2.增加了16*32大字体显示功能;8 z0 Z4 W* ]' z, U2 b
3.优化了读LCD忙的代码;4 I( v3 M" |; S. Z
4.新增了是sprintf的任意位数数字直接显示;
5 q) l" l3 v! |/ p9 q4 S# w1 M+ ^5.新增了CGRAM的写入,读出操作函数;
0 r$ P: B3 M- `3 P% j- Z9 ~' \4 z6.优化了绘图GDRAM函数的操作,绘图速度提高;
4 N9 [2 `3 A/ i6 ^! H% s2015.11.04 ,看到很多评论说链接失效,现在重新找了一份完整的工程代码,整理之后传到网盘:
. B; U$ ?! }, y' E# v7 N: m3 V# I/ ?这个代码优化了.h文件中的宏定义,方便用户移植,C文件和gui.c文件均不用修改。5 m" A/ G! o: y1 m
https://pan.baidu.com/s/1pJw3wHd 9 G% ^9 M, o2 W" g+ \
+ u, W1 s- A7 M' @0 f X
- * {% i0 W% f. X7 J; d% n. {- @
- #include "gui.h"' Z- o, {( L& r, m1 Z
- ' S5 l7 H; Q6 s: ~7 w; W1 Z( R
- /******************************************************************************* % z' Y& }" r3 x- R$ {
- DDRAM地址
2 y Q9 f6 z& C" y0 J - 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 //第一行汉字位置/ g% p3 f, W3 Q" |
- 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 //第二行汉字位置
! W3 s k. o7 x# t, f! x - 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f //第三行汉字位置
5 {' w8 m: w- h+ H: W) V4 f - 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f //第四行汉字位置 M7 `. |8 ~) l2 _9 E& L, b
* B Y3 I: q! t' G" v# g- *******************************************************************************/ " W# j# b5 v+ f* B
- g8 Q% ]$ c" }1 A3 J5 e& {- /******************************************************************************* 4 e/ c6 H9 V' s6 Y2 T
- * 名称 : LCD_SetPos
" {4 K- Z A# Z4 [0 c# X4 |3 I - * 功能 : 设定显示位置
! H/ j5 J) C1 F - * 输入 : x (0~3)行6 U# `% I7 S: K$ N
- y (0~7)列- g) o6 _: k' U0 |4 F; c
- * 输出 : 无 . K$ D8 g4 j5 ]# M7 f: ^; {& i+ k
- *******************************************************************************/
8 g) b0 R2 m P) d - void LCD_SetPos(u8 row, u8 col) 7 Z" C6 X' T1 K3 b
- { . ]+ E0 p" t2 L! n2 g/ q
- u8 pos;
" x8 F D5 ?$ e - if( row == 0) 4 z9 a. i$ G4 t" i) d; m# s
- row = 0x80; 3 }2 O y1 u a+ r H- [
- else if(row == 1) ) G+ [0 S! ~; ?' m* Y6 C. n
- row = 0x90; / U0 A" [. P5 T5 q+ Q2 C
- else if(row == 2)
9 }. f) x) a7 \9 j |4 }- Z g - row = 0x88;
7 z& w6 `- I. b - else if(row == 3)
/ X3 ^* U! Z# ? - row = 0x98;
. X* f2 s4 F) v3 S" i, B! a - pos = row + col; / L6 q5 O6 w1 p7 @
- LCD_WriteCMD(pos);//在写入数据前先指定显示地址 / c# e5 F" e# @0 o
- delay_us(10);/ ?1 @8 a o$ m! d$ z6 Z
- }
$ Z" g9 ~: J1 V# Y, z! F - 4 N1 c5 v6 @& d v9 h: F2 [9 X# a
- 5 C3 {" t- f S! `9 M
- /******************************************************************** 3 K8 q& N2 l j7 N" A
- * 名称 : ShowASCII
+ u# Y ?+ d9 O, A8 N; L3 X) { - * 功能 : 在当前坐标位置显示单个字符
+ ^* N! o! m7 E. ~ - * 输入 : *s
$ Y7 @' K h' ]7 U: H - * 输出 : 无
& t* x& b% _! U+ A - ***********************************************************************/
9 V6 t0 G& Z/ }, Q7 d - void ShowASCII(u8 i)
& ?- p$ o+ c f# g% Y' f - {; L E0 ^; j+ ^( D6 T1 `
- LCD_WriteDATA(i);& f) C+ I, O8 Y: D U f
- }
; S* n# `5 y: q" ~! | - . p9 Q% ], ^' R1 k
- void ShowCharPos(u8 row, u8 col,u8 dat)
. E Y: L; p; l* s e - { . \# P6 m, w2 z" `* h8 p+ U5 |
- LCD_SetPos(row, col);7 \/ L/ u& f( ^2 K @
- ShowASCII(dat);
! a( C& i! ^% D) f4 c - }% u3 L9 C* Y. |+ k" @4 ]
* b5 Y. s5 ?* W2 v- /******************************************************************************* 6 K4 a* T& @/ c# Y! Q
- * 名称 : ShowEnString(u8 *s) 4 E" \3 Q: k6 D& c+ e, V- B
- * 功能 : 显示英文字符串 ) x8 {. I9 |" V6 r- G7 M( K
- * 输入 : *s 2 c0 U8 q5 z* ~1 u. q
- * 输出 : 无 . y2 B! L3 P) F6 f
- *******************************************************************************/
+ K+ {9 p' s3 v/ f - void ShowString(u8 *s) . t4 Y/ |1 U6 A
- { 2 ]; B+ R4 H9 w2 I, t3 p& z
- u8 i = 0; 0 H2 S3 J+ r5 j. @. A+ W, _1 H
- while(s[i] != '\0')
R- C7 x! }( c4 n6 ^ v - {
) @" x: |/ X5 V, H - ShowASCII(s[i++]); * d! U! b4 J/ `3 K' Z+ S
- }
7 d$ ^8 o) M5 E - } 4 E$ D0 Q- m8 d4 [
- 5 W" @9 i% L! k, d3 {
- void ShowStringPos(u8 row, u8 col,u8 *s) //col is full char wide ! a. n, ^0 e* x, N& N
- {
" j% e# o |" Q - u8 i = 0;
. h9 u! ^/ Y# y* U7 x8 ~ - LCD_SetPos(row, col);
6 z" a! V5 U7 Y - while(s[i] != '\0')
1 a$ U& _$ ]/ t+ K/ E' | - {
8 D. A# r1 Y" z3 ]) o& { - ShowASCII(s[i++]);
% l' A* e7 `" c" a9 {/ L - if((2*col+i)%(16)==0) //must 16, is OK& U9 ~% F+ P6 t
- { - P% z+ d! d9 L1 x! S7 S8 u+ C
- LCD_SetPos(++row,0); //display start at next row.* M% F8 X4 r% R8 _$ w
- }' y: o0 n. k- V, F) z
-
2 Z& g1 m) H) |) F$ p2 l - }
+ B( |5 ^- ^; F0 @) \6 @ - } $ `7 ~; z9 o- D4 f6 J" Z7 y
3 u. O: p6 j- ^! E- 2 [- a* z! n; V2 w& U
- 9 I. H( Z; a: _
- /*******************************************************************************
. L+ `4 r& s7 j( R* p - * 名称 : ShowGB
6 Z7 E( K0 U! I. N - * 功能 : 显示单个汉字0 b' a! Y. k( ~' q; {
- * 输入 : i
6 \, k& L- `" d6 U" U" v - * 输出 : 无 ! T% E8 y: a& Y4 c
- ********************************************************************************/ 4 I, g2 ^% \# G8 x' S' i: Y5 A
- void ShowGB( unsigned char *HZ)
" K$ w6 v" q4 Y. C3 T6 l% K - {7 O3 U7 I& v) P3 T3 A
- LCD_WriteDATA(HZ[0]); //写入汉字的高八位数据% q5 u- k( Q; [, C2 o
-
6 M6 f: R- U, t. N. q - LCD_WriteDATA(HZ[1]); //写入汉字的低八位数据 0 k; v4 G d! W( u
- ) w/ d1 W/ {8 ~7 x8 `' ]. k# ?
- }% L8 X U0 c9 f3 a3 _& a
- 5 {" P8 t# b1 d5 m. c
- void ShowGBPos(u8 row, u8 col, u8 *HZ)$ q2 d9 q& K6 |1 s2 H0 b
- {
) D; B( x6 x) g0 v' F' [+ | - LCD_SetPos(row, col);" |3 k: H* N6 {( o' e" z1 w# b$ P3 h
- ShowGB(HZ);
9 o! R) l" ]2 N5 r1 q8 Y- F - }
5 E' Q8 j& P2 h& ]: v
7 t- `9 I; |; A) a- /********************************************************************
7 n/ ^: W& r# b7 l/ E, |; m - * 名称 : ShowGBStringPos ; G' a- a$ y6 M1 D8 H9 d
- * 功能 : 显示多个汉字
$ }9 W! `4 z/ c - * 输入 : u8 row, u8 col :汉字串的起始地址
8 Q" {8 V9 J. H( G - * 输出 : 无 % v1 y8 V4 k( T- Z2 v* E' W
- * 说明 : 自动换行:lcm默认换行顺序是乱的,0--2--1--3--0
, M' o* P) c9 y8 C& B5 m - ***********************************************************************/
( r# S1 W+ E. E- K( R3 T. I/ L - void ShowGBStringPos(u8 row, u8 col, u8 *s)/ ?. a' w' u5 C9 G e( {8 _5 [
- {
" k, n9 N4 f7 u- Z* R/ e - u8 i = 0;
& q9 k" ~9 G$ h - LCD_SetPos(row, col);
2 B8 ]4 p. A: Q6 c' a - while (s[i] != '\0')0 Z( Y/ Q1 L; H% U/ B
- {- S' v6 @- q2 g& t! q
- ShowGB(s+i);
. A& }6 ]: q* [1 ]0 G: U8 e# T - i+=2;
3 F1 Y) f3 A \4 R8 f/ @. o" b: S - if((2*col+i)%(16)==0) //如果满一行& D$ d4 w2 }9 e! w) e
- {
8 Z0 Z4 r' K8 ^& }9 b# J - LCD_SetPos(++row,0); //重新设置显示的起始地址7 Y1 N% }+ N& j: h" s
- }2 m2 k/ d* A: Z- D
-
' q! `' [+ H$ J' a- U. e+ J - } 4 Z1 x$ r4 a* K! \+ q. d, |
- }
% l6 D' x; @+ ~% ^: i! `( G - % s) f" j( `3 w
- /*******************************************************************************
; G/ j; R' z0 { - 测试函数
( R. g; y1 e5 S) V, R - Function: 用户移植程序之后,用该函数测试液晶是否初始化成功!
3 h1 Q6 J# Z, d0 z - ********************************************************************************/" G$ _, \( A c! b. d: D
- void LCD_Test(void)( R8 ~1 C) a( o F* X, T% G
- {
; f Q0 ?: M j L/ Z; v - ShowCharPos(0,0,0x10); //右箭头+ R% N* Q) q, d! {9 E! O
- ShowCharPos(1,0,0x10); //右箭头 3 S f/ v" ?6 z
- ShowString("Hello,world!") ; " j7 Q, |* F: }$ k' }
- ShowCharPos(2,0,0x10); //右箭头3 h/ X o, _2 [- h$ P9 K; \' ~
- ShowASCII(0x11);//左箭头
% P1 I, @/ W+ v { - } : d# P( p+ i! ?, W
- # M& K% c* F9 [; m8 j
' R, s9 A5 m! r6 D4 V- 2 ]! Y, |% m: |' P8 U( ^" @ h) |
2 H; {5 ^ v) B0 v4 T- . u, K" m, R" e( l4 b
- //自定义字符写入CGRAM
M, V) ^- I% x& ^1 _% p. u - void Write_USR_CGRAM(u8 data1,u8 data2,u8 addr)
0 A+ g$ b! T& ~, _+ K" O - {
" k8 i0 u9 l+ V/ ?: d. [6 } - u8 i;
' K4 S/ Z4 Z* _7 T2 c6 C - for(i=0;i<16;)+ e8 l& F7 R: a7 i
- {( w9 O$ V) C# i- }9 }* ]
- LCD_WriteCMD(addr+i); //设定CGRAM地址
7 l3 r5 @+ O1 h2 V e7 e0 b6 h - LCD_WriteDATA(data1);4 ^- ~* |7 Z V1 [
- LCD_WriteDATA(data1);
, d/ v: n. c% h( j- ]5 C3 J3 m - i++;% [) y6 g/ d7 X* y: o! [; g
- LCD_WriteCMD(addr+i); //设定CGRAM地址. }" f9 r; P C/ M
- LCD_WriteDATA(data2);
- E Z, Y) x" u; b# V! O - LCD_WriteDATA(data2);+ R) F1 a: i7 z6 C0 q
- i++;$ L; l- f( |0 u; U) |
- }
& d* j$ }; P E4 d& P" c: w' q - }
3 ~0 A$ ^) ?% h, g0 K. V' F5 Q - 6 E4 b1 ?. j+ w& Z0 G6 @
- //显示自定义的字符,并把这个字符填满全屏16*16
. Q2 v: `" x7 T - void Show_USR_CGRAM_Char(u8 addr,u8 i)
! ?7 r) q" f8 z' c8 I1 L - {) u$ D2 \: g. Q* |
- u8 j;
$ [, C. S6 ?4 O - for(j=0;j<0x20;)
5 v3 Q& z% X0 [) A+ A* ` - {
4 \, x7 ?: U/ d - LCD_WriteCMD(addr+j); //设定DDRAM地址
* L6 X. J9 F+ E; _( C0 |' o2 ] - LCD_WriteDATA(0x00);% d* Y; k" E8 c4 \ s4 m: M
- LCD_WriteDATA(i);
: ~) P2 Y- d$ m h: C, }" U - j++;
- l0 x0 O/ q9 y, G6 |9 _9 | - } 5 c1 x* P, Q% o$ m7 t. R0 `# j
- }
$ Q/ Y1 i z8 _9 i* M6 I* a
$ P2 f x% r. f6 N- //写入GDRAM 绘图,Y是Y绘图坐标,2个字节一行,X是图形起始坐标,CLONG是图形长度,以字节
7 l8 \$ U( V% P - //为单位;HIGHT是图形高度,TAB是图形数据表.12864M的图形显示范围是256*32点阵.% S" L& s! \+ U' v, `! c
- //要在12864M里显示全屏,取模时一幅图横切成两半
! V. U8 |+ [: Z8 ] - 5 m( Z* ]0 j! L! n
- /*
0 V# x; F2 g! l' L - ST7920提供64×32 个字节的空间(由扩充指令设定绘图RAM 地址),最多可以控制256×64 6 N% H! n( q3 ]9 |, }! m, g8 u
- 点阵的二维绘图缓冲空间,在更改绘图RAM时,由扩充指令设置GDRAM地址先垂直地址后水平6 [* V0 c# ?6 T5 k: F
- 地址(连续2个字节的数据来定义垂直和水平地址),再2个字节的数据给绘图RAM(先高8位
# T' i% ~% F( Y8 c - 后低8 位)/ E7 \1 N+ V, ?/ v4 W% F
- */
9 Z0 r9 w" E& p - void WRGDRAM(u8 Y,u8 clong,u8 hight,u8 *TAB1)$ {. k& {# @* ]3 t; ~! y. g& p
- { 0 H; }+ c4 x8 k B& p' q
- u16 k=0;: R% I9 T1 A% [! L) Q P
- u8 j;
8 s6 `/ Z* _9 z7 \ - u8 i;% N5 c2 z3 ~+ u' R4 ~6 p
- LCD_WriteCMD(0x34);1 X9 g! D6 H- O% c" a4 p
- LCD_WriteCMD(0x36);- a" O4 b" X# ]& }: Q8 w! w. K
- for(j=0;j<hight;)0 p9 G) V! o& x- F/ x: H$ k
- {
% k8 h {! [% N9 {3 v - LCD_WriteCMD(Y+j);
: x+ X& a" l. S1 s8 l% g/ c - LCD_WriteCMD(0x80);//X坐标
* w2 ? d. v( A) C; Z8 ~ - for(i=0;i<clong;i++)//
6 o( j$ Q4 t" x) n6 F" Y - {
0 k2 w, Y+ G2 N0 z7 b - LCD_WriteDATA(TAB1[k]);
, O8 P- f) d0 q- ]3 ?5 ?# `' N - k++;! N1 s2 T. S. S f/ f; Q
- }
% Z n' Y# C U+ S! h8 o5 f$ n. u - j++;
( o4 Q! h- D* n5 Q - }5 V4 d( Y( Y; h/ b3 e5 @$ R
- }
3 d2 \' N: V$ i# G0 L - / S7 p9 g! U8 c1 F6 ^
- /********************************************************************
& L7 _1 O4 e$ k, X6 o - * 名称 : ShowBlankPos 1 |$ E, o! k$ `4 d0 U9 G% I
- * 功能 : 在当前坐标位置显示单个字符* A# G8 O# ]2 c
- * 输入 : num 半宽字符的个数7 j9 S6 k8 |( ]( t' C
- * 功能 : 黑板擦功能,擦除不显示的内容, M! r0 X( w8 N+ Z5 K
- ***********************************************************************/
& E; b* E) _6 E) ^! b' \" s - void ShowBlankPos(u8 row, u8 col, u8 num)) D+ F( I; j( V' R1 ~2 W/ b% R9 F
- {
: H; e! r( l7 L0 i - u8 i ;* u+ D x( p# {/ c' H/ t
- LCD_SetPos(row,col);
7 p5 n- x1 k4 y- n* T9 u. E+ w% e3 | - for (i = 0; i < num;i++)
/ h+ t9 @. Q( N6 b( `" a4 U - LCD_WriteDATA(0x20); //写空格
2 J& V7 |8 {8 a" ^9 f* d, s: [: c - }
" o2 J$ S; |) N4 s - ! Y8 W- Y9 `# e$ T
. s* S- }# n* {9 P6 W K3 M- 4 }2 F# g7 X: j; J8 T
- 1 L* T% }9 W$ [: p1 _; |
( y3 z9 u! W% B* l- - L9 E# x* X5 e/ t
- 2 g' Z0 r8 b" o& l4 Q
: T# x o0 U2 S' u) j0 `2 G- E- 1 W& m! }1 x& a9 R) }, F M
; C8 H* A3 N4 O' O& G; }% g z- 6 v; a4 J2 j; E$ h, l7 U
- 6 K& p9 @% m( ~8 b
- 3 s+ y! h+ [2 R9 i1 J
7 j/ A& D @: G
* d x! W2 N. r" f3 t" F) L9 \2 ^- " M, O1 u- i: b" [. S1 J
- 7 ?/ y% E" q) p @) O* v! |3 W
复制代码 上图:
0 @ \) W2 r& [/ o! G+ P8 b- F* O! X
" e( H e4 P5 ^( s
Hellokity:, l# N4 \* E- J( r) G( U
; W+ n. H* V. ], d I( r! q4 h9 d
2 c( I8 L0 ], J7 D) N- G+ p& r7 G0 x" J0 k9 V4 x1 E' w
- a- V6 t0 M5 t) }( ?% J9 R! ~+ Y
6 e$ b6 r( S" b- f; W3 m8 O% L! P0 X
|
点评
需要创建一个屏幕大小的缓冲区数组,将要显示的字模数据放入数组里面,后面再使用绘图模式,统一将数组刷上去就可以实现了
是的,多了一个字母~~
这个是3.3V的屏,很好驱动的撒,这个是标准屏,目前还是用的很广的
你居然认识我哟?TA在第10楼~
还是没有花羊羊好看吧!!!