-
用单片机
IO
口直接驱动段式
< br>LCD
的方法
用
IO
口驱动段式
LED<
/p>
(数码管)的方法相信大家比较清楚,但用
IO
< br>口直接驱动
段式
LCD
的方法相
对复杂一些。在网上搜了一下单片机
IO
口驱动段式
LCD
的方
法,大部分资料讲得不够清晰、具体,
而且简单问题复杂化。后来查了
LCD
的显
示原理,结合网上的相关介绍,发现
IO
口直接驱动段式<
/p>
LCD
原理比较简单,用
几句话就可以描
述清楚:
1.
LCD
和
LED
的显示原理不一样:
LED
是加正向电压发光,而
LCD
必须交替加
正、
反向电压才会持续显示
(可以做个实验,
如果把恒定电压加到
LCD
的一段上,
该段会显示一下,
但马上不能显示,
而且长时间加恒定电压,
会加速
LCD
的老化
和损坏)
2.
常听说
1/2bias
,
1/3bias
LCD
,是什么意思呢?对于
1/2bias LCD
,假如
LCD
的显示电压是
3V
,则
1/2bias
是
1.5V
,也就是说在
±
3V
电压作用时,
LCD
有显示;
±
1.5V
及以下的电压作用时没有显
示
3.
普通单片机
IO
口不能直接输出半高电平(
1.5V
),但可以用相等的上下拉
电阻实现,
当
IO
口设置为输入(高阻)时,由于上下拉电阻的分压作用,
则产
生一个半高电平(
1.5V
)
p>
知道了以上
3
点后,动态驱动
LCD
就不是难事了
,对于
4*8
段的
LCD
(
4
个
COM
,
8
个
SEG
,显示电压为
3V
,
1/2
bias
),驱动方法如下:
1
、
四个
COM
采用交替扫描的方式,每个
CO
M
在相邻两次扫描时又进行电压交
变的方式。
< br>
2
、
若扫描到某一个
COM
时,该
CO
M
输出
3V
(
0V
)
:
与该
COM
相连的
SEG
输出与
COM
相反,
Δ
V=<
/p>
±
3
V
,则该相
连点亮;
与该
COM
相连的
SEG
输出与
COM<
/p>
相同,
Δ
V=0
,则该相连点不亮。
3
、其他没有扫
描到的
COM
,单片机
IO
口为输入,从而产生
1/2 bias
(
1.5V
),
不管
SE
G
为何值,
Δ
V<
±
1.5V
,故该点不亮。
本人用
4*8
段的
LCD
自制了一个数字钟表,
验证了以上方法的可行性,
现把制作
过程罗列如下
1.
原理图
说明:由于管脚不够用,所以
时钟芯片
DS1302
的
RST
和
LCD
的一个
SE
G
是复用
的,只要在这个
SEG
无效的时候去读取时间就可以了,另外,
3PIN
串口是
ISP
下载程序用的。
2.
备料
3.
焊接
4.
实验结果
5.
不足之处
通过实验结果可以发现,不
显示的
SEG
也有阴影
原因分析:
纽扣电池电压
3.7V
< br>,
1/2bias
是
1.85V
,
大于
1.5V
,
所以会出现阴影。
解决办法:<
/p>
选择工作电压小于
3V
的单片机和电压等
于
3V
的电池
(如
2
节干电池)
6.
程序源代码
点击
< br>/dpjzhyy/clock.c
下载
代码
/*************
**************************************************
***
段式
LCD
驱动实验
外部晶体:
12MHz
作者:
邮箱:
wang9601@
日期:
2011.08.26
***************************************
**************************/
#include
#include
//
管脚定义
sbit COM0=P3^5;
sbit
COM1=P3^4;
sbit COM2=P3^3;
sbit COM3=P3^2;
sbit
BI_4=P3^7;
sbit RTC_CLK=P3^0;
sbit RTC_IO=P3^1;
sbit
RTC_RST=P3^7; //
复用
//P3
口模式寄存器
sfr P3M1=0xb1;
sfr
P3M0=0xb2;
//
当前时
间(
BCD
码):秒、分、时、日、月、星期、年
unsigned char ClockBuffer[8]={0x3
4,0x12,0x08,0x20,0x03,0x05,0x09};
//0
~
9
的段码查询
表
//
位序
D7 D6 D5 D4 D3 D2 D1 D0
//
段
A B C D
E F G DOT
code unsigned char
seg_code[10]={~0x03,~0x9f,~0x25,~0x0d,~0x99,~
0x49,~0x41,~0x1f,~0x01,~
0x09};
unsigned char ScanCoun=0;
//
动态扫描显示位数计数器
unsigned char DisplayBuf[4]={1,2,3,4};
//4
位数字对应的
显示暂存
//
段码缓冲区
unsigned
char
Seg
Buf[4]={0x00,0x00,0x00,0x00};//COM1
、
COM2
、
COM3
、
COM4
的段码
bit bi_4a=0;
//COM0
对应的
4a
bit
bi_4b=0; //COM1
对应的
4a
bit bi_4c=0;
//COM2
对应的
4a
//
延时
void dly(unsigned char x)
{unsigned char i;
<
br>
for (i=0; i
}
//ds
1302
写
1
字节
void rtc_wt_byte(unsigned char
sent_buf)
{unsigned char i;
for (i=0; i<8; i++)
{RTC_CLK=0;
if (sent_buf&0x01) RTC_IO=1;
else RTC_IO=0;
RTC_CLK=1;
dly(5);
sent_buf=sent_buf>>1;
}
RTC_CLK=0;
dly(5);
}
//d
s1302
读
1
字节
unsigned char rtc_rd_byte(void)
{unsigned char i,read_buf;
RTC_IO=1; //RTC_IO
p>
置
1
,保证为输入状态
for (i=0; i<8; i++)
{read_buf=read_buf>>1;
RTC_CLK=0;
dly(5);
if (RTC_IO)
read_buf=read_buf|0x80;
else read_buf=read_buf&0x7f;
RTC_CLK=1;
dly(5);
}
RTC_CLK=0;
dly(5);
return read_buf;
}
//ds1302
写入时间
void rtc_wr_time(unsigned char
*p_wt_time)
{unsigned char
i;
unsigned char tmp1;
dly(30);
RTC_RST=1;
rtc_wt_byte(0xbe);
//burst
写入时间
for (i=0; i<8; i++)
{tmp1=*p_wt_time++;
rtc_wt_byte(tmp1);