一、设计目的
- 掌握定时/计数器工作的基本原理;
- 掌握一个完整的C语言程序结构;熟悉定时/计数器的编程
二、设计环境
- Keil开发环境
- Proteus软件。
三、设计及调试
(1) 设计内容
- 通过定时计数器实现秒与分的定时;
- 将定时的秒与分在LCD上显示。
(2) 设计硬件电路
AT89C51单片机,LCD1602
(3) 设计过程及调试关键步骤
首先在Proteus仿真软件上进行硬件电路的连接,连接完后用一个简单的显示程序检测能否显示,显示无误后开始编程。编程需要在原来LCD1602程序上添加初始化、中断,写入时钟三个子函数,首先在Keil中设置晶振频率为12MHz,之后根据晶振频率进行初值的运算与转载,运用T1定时器进行方式1中断。调试时观察显示位置并进行调整
四、设计结果与分析
(1) 程序
#include <reg51.h>
#include <intrins.h> //包含_nop_( )空函数指令的头文件
#define uchar unsigned char
#define uint unsigned int
sbit RS=P2^0; //位变量
sbit RW=P2^1; //位变量
sbit E=P2^2; //位变量
void lcduchar digit;//全局变量判断中断次数
uchar second; //秒
uchar minute; //分
void clock_initial();//时钟初始化
void clock_write(uchar s,uchar m);//写入时钟
void lcd_initial(void); //LCD初始化函数
void check_busy(void); //检查忙标志函数
void write_command(uchar com); //写命令函数
void write_data(uchar dat);//写数据函数
void delay(uint);//延时函数
uchar displaydata1[]=" LYZ CLOCK TIME "; //LCD显示第一行的内容
uchar displaydata2[]=" 00:00 ";//LCD显示第二行的内容
void main(void) //主函数
{
lcd_initial( ); //调用对LCD初始化函数
clock_initial(); //时钟初始化
TMOD=0x10; //设置定时器T1以方式1定时
EA=1; //开总中断
ET1=1; //允许T1中断
TH1=(65536-50000)/256; //12MHz下装载高八位初值
TL1=(65536-50000)%256; //12MHz下装载低八位初值
TR1=1; //启动定时器
digit=0; //开始计数
second=0;//初值
minute=0;
while(1){
clock_write(second,minute);}}
void T1_interserve(void) interrupt 3//T1中断服务
{
digit++;
if(digit==20){
digit=0;
second++;}
if(second==60){
second=0;
minute++;}
if(minute==60){
minute=0;}
TH1=(65536-50000)/256; //12MHz下装载高八位初值
TL1=(65536-50000)%256; //12MHz下装载低八位初值
}
void clock_initial()//时钟初始化
{
uchar i;
write_command(0x80);
for(i=0;i<16;i++){
write_data(displaydata1[i]);}
write_command(0xc0);
for(i=0;i<16;i++){
write_data(displaydata2[i]);} }
void clock_write(uchar s,uchar m) //写入时钟
{
write_command(0xc1);
write_data(m/10+0x30);
write_data(m%10+0x30);
write_command(0xc4);
write_data(s/10+0x30);
write_data(s%10+0x30);}
void delay(uint j)//1ms延时子程序
{
uchar i=250;
for(;j>0;j--)
{
while(--i);
i=249;
while(--i);
i=250; }}
void check_busy(void) { //检查忙标志函数
uchar dt;
do
{
dt=0xff;
E=0;
RS=0;
RW=1;
E=1;
dt=P3; }
while(dt&0x80);
E=0;}
void write_command(uchar com) { //写命令函数
check_busy();
E=0;
RS=0;
RW=0;
P3=com; E=1;
_nop_( );
E=0;
delay(1);}
void write_data(uchar dat) //写数据函数
{
check_busy();
E=0;
RS=1;
RW=0;
P3=dat;
E=1;
_nop_();
E=0;
delay(1); }
void LCD_initial(void) //液晶显示器初始化函数
{
write_command(0x38); //写入命令0x38:8位两行
显示,5×7点阵字符
write_command(0x0c); //写入命令0x0C:开整体
显示,光标关,无黑块
write_command(0x06); //写入命令0x06:光标右移
write_command(0x01); //写入命令0x01:清屏
delay(1);}
(2) 实现结果及现象
最初,LCD1602第一行显示LYZ CLOCK TIME,第二行显示00:00表示0分0秒
时钟开始计数
计数到分时
(3) 实验结果的分析与总结,有无改进方案?
实验结果的分析与总结:第一行第二行都显示清晰,时钟计时与实际中相差不大,由于使用的是方式1的计时,会有些许误差。改进方案:可使用方式2的方式进行计时,减小误差。