本帖最后由 caizhiwei 于 2015-11-5 11:04 编辑
% ?( C: @3 T! d" f6 {
7 l5 |( |! _1 \* j+ a# [6 S7 ]) H% g 虽然很久之前(51时代)就开始接触lcd12864,如今在工控机里面,LCD12864还是应用比较普遍的!; f" F+ g% C/ Z E
我用的lcd12864类型为串行接口,3.3V st79206 e: `* ^3 e: o' n
代码优化说明:
4 @7 h& I& v) \1.修复了字符串,汉字串不能自动换行的bug
1 w* M0 ^ J: ^) V注意:2 ^/ U) r( V9 i D5 r/ }
1.在使用带jtag接口的I/O时要特别注意
3 M n6 O& \/ N, B6 \ R PA13:SWDIO/JTAG_TMS
2 K5 R- j6 q2 q( U8 h' T PA14:SWCLK/JTAG_TCK' k+ \: V& W! {. O3 ?" ~0 }" `3 Q8 s
PA15:JTAG_TDI5 W, G+ v6 I0 g* o! L9 V
PB3:JTAG_TDO3 I/ z6 x( ?8 m" x2 P
PB4:JTAG_RST# H! W/ Z0 y! I" {4 `4 B T% @
硬件设计缺陷:
+ b' D8 N, h+ ?1.没有引出LCM的复位引脚,导致偶尔显示不正常之后,mcu复位(LCM并没有复位)/ S# F! `& E" b _
也无法解决,只能强行断电重启。+ r. M( Y% q$ q7 k1 L# Q9 F
2.BLK液晶背光引脚的输入电流至少在20mA以上,没有用三极管驱动,而是直接用IO驱动,( v. M6 D: \2 w+ |( }2 R9 d
需要较大的驱动电流。
5 |' O* V3 ^+ C5 @) c3.
7 \5 C5 v3 }! b4 B+ m- }6 I编译器缺陷:
l4 W4 t! M( a9 j1.由于使用的是iar6.70版本,编译器在编译汉字串数组的时候可能会使带字库液晶产生乱码。
5 k1 c, Y. H4 @' | 所以在有汉字数组的C文件中统一使用简体中文(GB2312)(全选--右键--Charracter Encoding)
) }. w8 \) h# q9 K, L0 w
4 K! A0 Y V* H5 W/ ~" R: w部分硬件结构说明:
8 @. J6 ~3 h0 g1.按键按下,(上连接VCC)连接电阻下拉到地,检测IO连接上端,检测到高电平。
% n4 D4 u. M) n8 S {2.lcd12864底板反面接线图:
8 y2 Y, c1 }( }0 A% s5 a- E; L* V$ \4 B8 v* A8 \' U
从反面看:
2 R5 f d2 p0 q6 J5V RW GND GND LED K2 K4 GND, o, j) H8 a9 B% r" |0 {
GND RS E BLK GND K1 K3 5V
& Q2 J" K3 d" A! c4 M) z
' l" Q0 B, \1 j1 L6 L! u: |2015-6-10 原工程代码在23楼!|r l8 v! N/ @% w' E' E% Y: L
2015-7-12 程序更新了,,代码在35楼!
& \1 c" h1 Y8 p$ g+ k4 g9 a更新记录:
# P: q3 m( B) u( o( j1.增加了24*32大字体显示功能;. ?& w" Y- m: A4 Y+ S. r+ s
2.增加了16*32大字体显示功能;
3 e3 y3 Y8 ~8 t* n, d6 @+ |3.优化了读LCD忙的代码;$ p. K6 d+ ^4 e: m2 V
4.新增了是sprintf的任意位数数字直接显示;
9 z+ O; P, F U# M1 k% _5.新增了CGRAM的写入,读出操作函数;$ ?1 n" I/ t/ l& F
6.优化了绘图GDRAM函数的操作,绘图速度提高;! G' {# ?+ V$ R* ?
2015.11.04 ,看到很多评论说链接失效,现在重新找了一份完整的工程代码,整理之后传到网盘:
9 ` G; m9 U8 W3 w2 {* K这个代码优化了.h文件中的宏定义,方便用户移植,C文件和gui.c文件均不用修改。
+ E& u6 E: p( C& E8 Vhttps://pan.baidu.com/s/1pJw3wHd
; R8 g2 F$ b) k1 v0 |) f$ |5 O+ z- C' C7 Q
- 9 [# Y7 y. c0 u) E: y5 c# N; ]! Q
- #include "gui.h"
$ H! J+ A1 p' ]( L7 e" ]& |9 B3 f - ! s7 |0 i8 s w) R% D/ }( p& d
- /******************************************************************************* . k/ [3 `5 M+ L
- DDRAM地址
4 ?# k2 K9 f+ W! R - 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 //第一行汉字位置7 b; Y# g% n, A( I& l/ d
- 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 //第二行汉字位置
9 _) _8 b% S9 @1 a2 ^ - 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f //第三行汉字位置
6 \* q/ w: Q0 x9 `$ D; i9 ^9 l - 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f //第四行汉字位置; f* E1 b- B$ R( W6 f6 j! {. N
- % U. n) u, f" Y# A$ h; D6 Q ~/ V
- *******************************************************************************/ 0 D4 |- o o; w7 q3 K
- . x6 @- Y2 K( S( T( a/ ?$ @) ^
- /*******************************************************************************
( x( k; c0 Y: [/ h# t9 m; ~4 t - * 名称 : LCD_SetPos% Y/ u* N0 } a9 S6 U
- * 功能 : 设定显示位置 " p0 n6 u; E8 x
- * 输入 : x (0~3)行
0 f! }* D& A/ ^2 C( h - y (0~7)列
4 `- w1 E* _ ]2 K5 q N - * 输出 : 无 : Z4 A0 C4 ^ T0 b6 h) l- `
- *******************************************************************************/
8 e% y2 Q! I" @4 X+ V" R; k) \ - void LCD_SetPos(u8 row, u8 col) 4 r# H; q% T1 [1 Y
- { ' [4 o# f0 E# x$ N
- u8 pos; 7 C: J& v+ w9 Y! F: g$ T
- if( row == 0) . T& j# m4 X' V' x
- row = 0x80; 2 W+ Y+ k! v! B0 ~
- else if(row == 1) 4 @8 N! H4 R+ W* T7 a
- row = 0x90; " x# g$ W. N, f
- else if(row == 2) % \5 x$ g% w7 O) g0 @
- row = 0x88;
6 t( R T2 X. x( y* T4 I/ D - else if(row == 3) . u& d |$ W5 b
- row = 0x98;
, l m& V( z2 U# v9 {8 u4 ] - pos = row + col;
" V: b8 F* @! e' n7 H - LCD_WriteCMD(pos);//在写入数据前先指定显示地址 $ N- O( L! m" W! f6 B/ f
- delay_us(10);
/ Z' d# P! N# }: W& U- k9 o- _ f - }
" r$ b$ J1 Y. j9 I! i
) o3 S- v2 r7 R$ \3 {- P5 P
& g( w; h2 B8 d, C7 X# g0 w- /********************************************************************
- w( I& b( M! i \; B - * 名称 : ShowASCII % E+ J, o7 B7 m" T$ j
- * 功能 : 在当前坐标位置显示单个字符( o* H/ U i# `
- * 输入 : *s
/ w' w2 R2 G2 v+ Z - * 输出 : 无 - C: J6 O( L3 g( V( \! v+ s3 B: ?
- ***********************************************************************/
( n3 H' u( C- C9 j - void ShowASCII(u8 i): [# Q) Y0 [" C T& H) G
- {- I# D2 G. n4 n1 p
- LCD_WriteDATA(i);
" b" Y5 N2 f u' a8 z- f q. ~ - }
4 B, u! j- u% n1 d: _$ x9 d - 3 Y/ O& ^6 f5 ^
- void ShowCharPos(u8 row, u8 col,u8 dat)
: \) G) p5 P; q' v - { E/ u% C% ?9 k
- LCD_SetPos(row, col);: V* w& q! X/ U1 y( D7 O
- ShowASCII(dat);
+ F/ }$ }: m* j- U5 w) t( j6 w* @ - }# E: K' `1 p! H9 g6 }+ x* \
- + k; l4 z( H a2 o
- /*******************************************************************************
$ O+ X" q3 R$ d! s8 w! t/ V" E - * 名称 : ShowEnString(u8 *s) % \; @: h* E9 d7 a
- * 功能 : 显示英文字符串 - A$ R7 G s+ @" {* M
- * 输入 : *s
/ e, p2 V5 @! `2 J - * 输出 : 无 # c3 `/ N. Z2 }: C' \* {1 m `2 A R
- *******************************************************************************/
* i, Y% p" N7 l' V% R0 g0 A - void ShowString(u8 *s) 3 M {' ?* H* v) t3 D' _
- {
' ~: j8 ^5 L( f+ I) i5 j: f: n- H - u8 i = 0; 0 Y* T5 @+ d+ F; E
- while(s[i] != '\0') ! b0 A& m' d1 _. ^; n+ V8 e" A
- { ' y, z% T8 U& D/ D" w% r S* e! j
- ShowASCII(s[i++]); $ A) C0 X* [/ y$ I/ Z% e! `
- }
8 T9 F7 m& C! C! d2 E - } 0 l4 M4 c+ B- C; S* [; @
5 P: w/ K- u3 |# y- void ShowStringPos(u8 row, u8 col,u8 *s) //col is full char wide , G) R, k' M; m5 K
- { ( I$ [0 Z" L& N0 l( R2 A
- u8 i = 0;
& T+ U$ }+ {5 v- I4 v+ x! T K - LCD_SetPos(row, col);
+ w! o5 W f& A( m - while(s[i] != '\0') + M. F/ d6 a5 g$ c5 ^
- { 3 J* M& a- b0 a
- ShowASCII(s[i++]); ) U2 o' y6 O9 |/ X7 l6 B
- if((2*col+i)%(16)==0) //must 16, is OK4 Y5 q) m/ i4 b5 A) e$ L
- { G# e6 W6 p- U; {4 d! @
- LCD_SetPos(++row,0); //display start at next row.
& K7 w( P1 G2 T0 m" c" k - }
9 i; }& v+ s* ~" ~ -
! e8 X- L( G+ N4 C' ^ - } l8 S, X- D* m
- }
7 V' A) S' d: ~/ F
4 H; U# R( g, d) r; |6 V- ( h4 ~, N) }( O: Z9 h
- - S5 k( s5 [; J3 J& q _* x8 g2 M
- /******************************************************************************* # j# w$ _$ P$ w& N& J4 c
- * 名称 : ShowGB
- w: C E* w$ y# \ - * 功能 : 显示单个汉字
" R: Y3 `! S( U! E4 b) l* c - * 输入 : i 0 J/ X. Z$ e! {/ Z8 o
- * 输出 : 无
7 o5 M4 [0 ~6 e5 o - ********************************************************************************/
; v7 d9 F5 F( p3 U: q - void ShowGB( unsigned char *HZ)2 s* d$ ^3 G& G8 Z/ n
- {
2 U2 n- P i+ D2 ^9 ^ - LCD_WriteDATA(HZ[0]); //写入汉字的高八位数据: f5 I5 u9 `) ?/ V3 l
-
2 P% g- C$ i1 K2 }4 b! u5 | - LCD_WriteDATA(HZ[1]); //写入汉字的低八位数据 8 m8 ?$ [5 }( V5 y
-
% L: n6 I K0 D( ^4 e G' i - }
- W8 W6 G# k; M- ~ - ! y- c4 Y2 s4 Q- F, G
- void ShowGBPos(u8 row, u8 col, u8 *HZ)
. H1 S9 f7 i. J' q0 S - { \ d% `# {3 b- q4 B9 n
- LCD_SetPos(row, col);
% N7 q% ?/ S& f - ShowGB(HZ); i/ _4 O L1 |
- }! v5 ?& R4 w2 k5 ~. w- b' ^
' ?6 T; F5 Z* C- k- /********************************************************************
6 D2 V5 L/ l% O- H4 ^& t - * 名称 : ShowGBStringPos 4 w# j3 R3 c- z8 S
- * 功能 : 显示多个汉字( Z8 O9 |+ B/ }; E4 v, o
- * 输入 : u8 row, u8 col :汉字串的起始地址
- O) z g1 S' s9 Q8 l) w - * 输出 : 无 2 l: `8 E7 j3 s* h0 K. J
- * 说明 : 自动换行:lcm默认换行顺序是乱的,0--2--1--3--05 r2 \" ]5 ]0 ?3 o7 B* q
- ***********************************************************************/
/ y4 B1 G4 j( N+ c - void ShowGBStringPos(u8 row, u8 col, u8 *s)8 {) b: |3 d$ h; u1 K; T" M
- {3 K& j- x; ~( G# F: P4 g
- u8 i = 0;3 g' z, c) [8 N
- LCD_SetPos(row, col);
; l- k0 B6 P" M - while (s[i] != '\0'): q, I% e d' d0 p7 Q3 K
- {
- Y2 j% C/ z* P$ ` - ShowGB(s+i);
K* t! \' ?/ O+ ?) _ - i+=2; # J/ Q7 ~, Q9 U9 M4 ?
- if((2*col+i)%(16)==0) //如果满一行
8 w2 D/ i: q3 {2 T' b/ i# i - { ; c/ z1 a% R* B" D" e5 g9 D' N: O
- LCD_SetPos(++row,0); //重新设置显示的起始地址9 N* h7 _5 P9 i1 C9 n
- }7 ]8 l5 s# M* \& O5 f$ b
- 4 {* y: t9 k4 S) ?$ d2 S
- } + W3 q) H. o/ a. x. A, F
- }
9 D4 O* h0 ?' ` - - y, m( {5 ?. w1 w) d2 K. w
- /*******************************************************************************
( m8 j# Y. i# x t7 z3 t2 A - 测试函数
4 W' I. C+ Q1 H- s - Function: 用户移植程序之后,用该函数测试液晶是否初始化成功!1 Q; t. m- K1 Z6 \+ h# k
- ********************************************************************************/
; b N. p$ o* T2 {' ~$ X3 ]+ q' b - void LCD_Test(void)
) Y" y- {# z t2 p) T, ~ - {; |' r( t2 j2 q4 ^" k
- ShowCharPos(0,0,0x10); //右箭头
% v" x. ]3 ~. b+ ^ - ShowCharPos(1,0,0x10); //右箭头 ( g& a( Y. p' ?9 W3 U8 {
- ShowString("Hello,world!") ;
9 W8 i& E4 A, ~+ c - ShowCharPos(2,0,0x10); //右箭头) G- p' B% _# A0 H. G2 H( r
- ShowASCII(0x11);//左箭头
1 A* P4 J' h; T0 C - } O2 u) p3 p& C, \
-
0 w k: F) h1 c: ~3 t6 z E
" Y& G2 x+ v) g3 w: x4 T' S! B- r2 W. N7 s3 W/ a) H
3 q; {4 ?( L8 q+ B3 ?
6 h, P5 L7 g& [" J8 f# u; I- //自定义字符写入CGRAM R; n1 m4 v- n8 \6 T5 R- w
- void Write_USR_CGRAM(u8 data1,u8 data2,u8 addr)+ A) s6 U; s" q
- {
5 }0 ]% `$ \9 } - u8 i;
: A3 F: L) J& g% u0 C - for(i=0;i<16;)
' ^4 }+ [! @/ ]$ x" {" l6 s' _ - {4 z* X" Y! c# s6 r0 O i L% l
- LCD_WriteCMD(addr+i); //设定CGRAM地址- }/ x t" p; Z# \! o; G4 m
- LCD_WriteDATA(data1);9 C& S% R" i2 e
- LCD_WriteDATA(data1);
* E3 y6 n- {! Y/ R5 w- [7 @9 ? - i++;! K, J! W) A7 @) x: [0 k- ?4 A
- LCD_WriteCMD(addr+i); //设定CGRAM地址
6 R# Z" h1 `8 b$ A) ]$ Z7 R5 t - LCD_WriteDATA(data2);
0 h& C' b2 P, t5 V+ S - LCD_WriteDATA(data2);2 @$ H* q0 n- B# c1 l0 s3 K, P6 f
- i++;
' \3 f7 }& n# F1 S* H - } 9 p/ |% k( ]! O' ~
- }
1 y# g8 u, ~" t6 G" H3 q - . x6 I3 W3 ?% c7 E
- //显示自定义的字符,并把这个字符填满全屏16*16* ^4 Z2 z/ W/ L* E7 P" k }
- void Show_USR_CGRAM_Char(u8 addr,u8 i)+ q1 y5 |6 f! {) `
- {2 A1 F7 H2 E/ @4 h3 |: O1 ^
- u8 j;8 G3 C) |/ f, l
- for(j=0;j<0x20;)2 N& K* B3 |+ r; z: f/ e
- { ( u" n/ J1 L5 C3 v; \% B$ G! b5 \4 T9 s
- LCD_WriteCMD(addr+j); //设定DDRAM地址* M) M" S* L! l) f" u- q
- LCD_WriteDATA(0x00);+ U; I3 P$ n) D1 k/ F
- LCD_WriteDATA(i);5 v* j. \ e( w6 [7 c
- j++;
3 {* X9 |, b& E - } ( ^# O) e8 O5 b$ C
- }
( b' @+ e! \. `4 w - 9 b& E- D; n: k
- //写入GDRAM 绘图,Y是Y绘图坐标,2个字节一行,X是图形起始坐标,CLONG是图形长度,以字节
. c+ m; B( W7 n |$ U- y! A4 }! t - //为单位;HIGHT是图形高度,TAB是图形数据表.12864M的图形显示范围是256*32点阵.6 W: g( ?" n4 h* a u! u
- //要在12864M里显示全屏,取模时一幅图横切成两半
) O$ ]" m) ~0 j# ]6 H - 6 X/ {4 P( G7 s* d) ?
- /*
; i& w( d8 a# H( P z9 W - ST7920提供64×32 个字节的空间(由扩充指令设定绘图RAM 地址),最多可以控制256×64 n3 I- [$ U# p$ z- I4 w! [
- 点阵的二维绘图缓冲空间,在更改绘图RAM时,由扩充指令设置GDRAM地址先垂直地址后水平
! N) J1 i- s' H! A" j0 y3 q - 地址(连续2个字节的数据来定义垂直和水平地址),再2个字节的数据给绘图RAM(先高8位( q/ S0 D; W y5 e
- 后低8 位)
6 L+ f: x" \2 p \ - */
1 A! t# J2 _- S' N i) L - void WRGDRAM(u8 Y,u8 clong,u8 hight,u8 *TAB1)
" V' _& Y3 G7 w3 J' P - {
' x5 Q9 `, [5 _6 r N+ J - u16 k=0;& u# x0 v& ]6 @; z* ]
- u8 j;
8 x3 Q% e3 V/ r: E8 h - u8 i;, _% _7 o6 b6 u9 v/ G5 a$ `
- LCD_WriteCMD(0x34);
, n+ `0 @! m2 l4 g. r. a - LCD_WriteCMD(0x36);( \( S: V \2 k' n
- for(j=0;j<hight;)
3 S: {0 K8 B2 s( i5 y8 O. @ - {
1 t& X& M0 ?' q6 [1 N - LCD_WriteCMD(Y+j);
, J4 {" c: c+ z, m - LCD_WriteCMD(0x80);//X坐标. `0 ?0 p5 ?# ^5 K. v0 }% u% O
- for(i=0;i<clong;i++)//
, ?( }1 h0 q3 T' O, u - {
! i i3 Z% S t% G( F1 W - LCD_WriteDATA(TAB1[k]); b) I! o1 R5 ~9 R$ v6 w
- k++;
$ E' c" j, ^4 K* `+ n - }' X- Q, |- |6 ^( N/ y
- j++;$ k& q- T! l) s' O/ g% Q
- }# B; `, x$ O# m% O0 K2 w6 G5 c
- }0 p1 |4 k4 |: C8 I
- 8 S1 k4 f2 s/ k
- /********************************************************************
8 t: C! |0 x. w - * 名称 : ShowBlankPos
$ V& M* Y* r1 q' j - * 功能 : 在当前坐标位置显示单个字符
9 W* K) g. J# m* a - * 输入 : num 半宽字符的个数. J# h( @" S/ b7 l; b
- * 功能 : 黑板擦功能,擦除不显示的内容
' } w3 H+ H6 }" e% B6 l - ***********************************************************************/ + q: V6 u6 B" }7 J; |" f
- void ShowBlankPos(u8 row, u8 col, u8 num)+ Q/ J% t& Z2 ^, V O9 z
- {- j5 Q: Y' N& {5 [- m* t* x
- u8 i ;) k5 |1 ~0 B2 T2 m* v
- LCD_SetPos(row,col); # Y& Q% ~5 y# K
- for (i = 0; i < num;i++)
. R' s, D5 K2 F6 N - LCD_WriteDATA(0x20); //写空格
& t c7 ?" l* G - }
/ ^( I% A$ @, t5 T( _8 _; ^
$ F( A6 c2 {2 s/ Q/ i+ g' s/ q
2 J/ ]. s6 t2 p- & v5 P5 Q% Z2 e( O h3 f
- # r2 D3 ?4 d0 l
- " ^0 a6 l" O1 M0 H$ z' r6 g
+ J. Q" _ V1 H6 r0 T& i' w9 d C+ D
1 g+ U2 u3 A" j( S
. ? f2 L- n1 M- M+ z# V! }& n- 6 V2 E0 g, y( q$ J# ?. i; o5 E
$ o4 q+ Q- b3 U! O" e- / m. I$ b! a, | @
- % T: ^/ E3 b1 ~9 d: I* _
- $ Q+ h3 E8 [& f3 d
# w4 {/ K) E% ?5 L9 |- + d- Y/ `6 q# R. O1 m! \
5 d. H) H) P( }3 @( m, \7 {4 V
7 ^8 ?5 k$ q E
复制代码 上图:5 X$ S4 T/ F0 Y& y2 {/ E
6 E, S+ N# ~: B1 L1 t- X
Hellokity:
) w( v! h" X* Z0 M, n1 S! I% e: h& N
/ ~) D1 u* o6 f2 M
9 g) U0 r7 d' a1 F
" W+ o- A8 b, Y+ l
/ Q5 @, V' i8 U
. g1 h. P- x: D4 g) Y Q
0 o# ]: S6 }* E& @8 p
) l% v, q: ~" l* O |
点评
需要创建一个屏幕大小的缓冲区数组,将要显示的字模数据放入数组里面,后面再使用绘图模式,统一将数组刷上去就可以实现了
是的,多了一个字母~~
这个是3.3V的屏,很好驱动的撒,这个是标准屏,目前还是用的很广的
还是没有花羊羊好看吧!!!