目录
1.任务一:定时器产生周期为1s的方波控制LED灯亮灭,间隔1s
3.任务三:利用定时器设计秒表并用LCD显示,同时显示自己的学号和姓名拼音
一、实验任务
- 定时器产生周期为1s的方波控制LED灯亮灭,间隔1s;
- 在LCD上分行显示学号和姓名拼音;
- 利用定时器设计秒表并用LCD显示,同时显示自己的学号和姓名拼音。
二、实验目的及原理
1.实验目的:掌握定时器原理并会编程;掌握LCD显示原理并会编程。
2.实验原理:定时器通过控制计数个数来精确控制时间;LCD是利用液晶经过处理后能改变光线通过方向的特性,从而达到白底黑子或黑底白字显示的目的。
三、实验中使用的仪器与材料
Keil、PZ-ISP、普中科技51单片机、数码管、发光二极管、独立按键、定时器、LCD
四、实验方案、步骤及原始记录(数据、图表、计算等)
1.任务一:定时器产生周期为1s的方波控制LED灯亮灭,间隔1s
(1)用keil编写程序,输出.hex文件
/*
定时原理:位+1-->1个机器周期x秒
定时T--->n(T/x)个机器周期
一般晶振为12MHZ,则x为1us,定时1s则n=10^6;
然而16位计数器最多计65536个,所以可以将1秒分为20个50ms,则计50000位则溢出,n+1--->n=20
要想计50000位就溢出,初值可设为(65536-50000),然而这个数字太大,得用两个8位计数器显示
高8位=(65536-50000)/256,低八位=(65536-50000)%256
*/
#include<reg52.h>
sbit D1 = P2^0;
void main()
{
//step1:TMOD确定工作方式
TMOD = 0x01; //定时器0工作方式1
//step2:计算初值(与定的时间有关,每隔50ms溢出)
TH0 = (65536 - 50000)/256;//高四位初值
TL0 = (65536 - 50000)%256;//低四位初值
//step3:打开需要的中断
EA = 1; //开总允许中断
ET0 = 1; //开启T0溢出中断
//step4:打开定时器
TR0 = 1; //开启定时器
while(1);
}
void ET0_ISR(void) interrupt 1 //定时0中断
{
static unsigned int cnt = 0;
//初值重赋
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
cnt++;//溢出一次,+1
if(cnt >= 20) //当为1秒时D1灯状态改变
{
cnt = 0;
D1 =~D1; //取反改变灯的状态
}
}
(2)将输出的hex文件烧录到开发板上
2.任务二:在LCD上分行显示学号和姓名拼音
(1)用keil编写程序,输出.hex文件
#include<reg52.h>
sbit LCD_RS=P2^6; //命令/数据选择
sbit LCD_RW=P2^5; //读写口
sbit LCD_EN=P2^7; //锁存控制
#define uchar unsigned char
int pow(int x,uchar y)
{
int mi=1;
for(;y>0;y--)
{
mi*=x;
}
return mi;
}
//延迟函数定义
void delay()
{
uchar i,j;
for(i=1;i>0;i--)
for(j=239;j>0;j--);
}
//向LCD写指令
void LCD_write_cmd(uchar command)
{
LCD_RS=0; //选择指令寄存器---写的是指令
LCD_RW=0; //写--状态
P0=command; //写入命令--将指令赋给8位数据总线
LCD_EN=1; //使能信号1
delay(); //等待写入,如果时间太短,会导致液晶无法显示
LCD_EN=0; //使能信号从1->0 下降沿有效 LCD执行写入命令
delay();
}
//向LCD写数据
void LCD_write_data(uchar Data)
{
LCD_RS=1; //选择数据寄存器,写数据
LCD_RW=0; //写操作
P0=Data; //将数据赋给8位数据总线DB0-DB7,
//这里的P0为LCD上8位数据总线所连接的单片机IO端口
LCD_EN=1; //使能端拉高
delay();
LCD_EN=0; //使能端拉低,下降沿有效,数据写入DDRAM
delay();
}
//初始化
void LCD_Init()
{
LCD_write_cmd(0x38); //指令--显示模式设置
LCD_write_cmd(0x0c); //指令--显示光标开及光标设置
LCD_write_cmd(0x06); //指令--显示光标移动设置
LCD_write_cmd(0x01); // 指令--清屏
}
//LCD显示字符串
void LCD_dstr(uchar line,uchar column,uchar *str)
{
if(line==1)
{
LCD_write_cmd(0x80|(column-1));
}
else
{
LCD_write_cmd(0x80|(column-1)+0x40);
}
while(*str!='\0')
{
LCD_write_data(*str++);
}
}
//LCD显示整形数字
void LCD_dnum(uchar line,uchar column,int num,uchar length)
{
uchar i;
if(line==1)
{
LCD_write_cmd(0x80|(column-1));
}
else
{
LCD_write_cmd(0x80|(column-1)+0x40);
}
for(i=length;i>0;i--)
{
LCD_write_data('0'+num/pow(10,i-1)%10);
}
}
//LCD显示字符
void LCD_dchar(uchar line,uchar column,uchar Char)
{
if(line==1)
{
LCD_write_cmd(0x80|(column-1));
}
else
{
LCD_write_cmd(0x80|(column-1)+0x40);
}
LCD_write_data(Char);
}
void main()
{
uchar *str1,*str2;
uchar xuehao[]="2022210491";
uchar xin[]="shidan";
str1=&xuehao[0];
str2=&xin[0];
LCD_Init();
LCD_dstr(1,1,str1);
LCD_dstr(2,1,str2);
}
(2)将输出的hex文件烧录到开发板上
3.任务三:利用定时器设计秒表并用LCD显示,同时显示自己的学号和姓名拼音
(1)用keil编写程序,输出.hex文件
#include<reg52.h>
sbit LCD_RS=P2^6; //命令/数据选择
sbit LCD_RW=P2^5; //读写口
sbit LCD_EN=P2^7; //锁存控制
#define uchar unsigned char
unsigned char m=4,n=5;
//延时函数
void delay7ms()
{
long int i,j;
for(i=0;i<1;i++)
for(j=0;j<14;j++);
}
//x^y
int pow(int x,uchar y)
{
int mi=1;
for(;y>0;y--)
{
mi*=x;
}
return mi;
}
//延时
void delay()
{
uchar i,j;
for(i=1;i>0;i--)
for(j=250;j>0;j--);
}
//向LCD写指令
void LCD_write_cmd(uchar command)
{
LCD_RS=0; //选择指令寄存器---写的是指令
LCD_RW=0; //写--状态
P0=command; //写入命令--将指令赋给8位数据总线
LCD_EN=1; //使能信号1
delay(); //等待写入,如果时间太短,会导致液晶无法显示
LCD_EN=0; //使能信号从1->0 下降沿有效 LCD执行写入命令
delay();
}
//向LCD写数据
void LCD_write_data(uchar Data)
{
LCD_RS=1; //选择数据寄存器,写数据
LCD_RW=0; //写操作
P0=Data; //将数据赋给8位数据总线DB0-DB7,
//这里的P0为LCD上8位数据总线所连接的单片机IO端口
LCD_EN=1; //使能端拉高
delay();
LCD_EN=0; //使能端拉低,下降沿有效,数据写入DDRAM
delay();
}
//初始化
void LCD_Init()
{
LCD_write_cmd(0x38); //指令--显示模式设置
LCD_write_cmd(0x0c); //指令--显示光标开及光标设置
LCD_write_cmd(0x06); //指令--显示光标移动设置
LCD_write_cmd(0x01); // 指令--清屏
}
//LCD显示字符串
void LCD_dstr(uchar line,uchar column,uchar *str)
{
if(line==1)
{
LCD_write_cmd(0x80|(column-1));
}
else
{
LCD_write_cmd(0x80|(column-1)+0x40);
}
while(*str!='\0')
{
LCD_write_data(*str++); //先写十位,再地址后移,写个位
}
}
//LCD显示整形数字
void LCD_dnum(uchar line,uchar column,int num,uchar length)
{
uchar i;
if(line==1)
{
LCD_write_cmd(0x80|(column-1));
}
else
{
LCD_write_cmd(0x80|(column-1)+0x40);
}
for(i=length;i>0;i--)
{
LCD_write_data('0'+num/pow(10,i-1)%10);
}
}
//LCD显示字符
void LCD_dchar(uchar line,uchar column,uchar Char)
{
if(line==1)
{
LCD_write_cmd(0x80|(column-1));
}
else
{
LCD_write_cmd(0x80|(column-1)+0x40);
}
LCD_write_data(Char);
}
void main()
{
unsigned int j;
//step1:TMOD确定工作方式
TMOD = 0x01; //定时器0工作方式1
//step2:计算初值(与定的时间有关,每隔50ms溢出)
TH0 = (65536 - 50000)/256;//高四位初值
TL0 = (65536 - 50000)%256;//低四位初值
//step3:打开需要的中断
EA = 1; //开总允许中断
ET0 = 1; //开启T0溢出中断
//step4:打开定时器
TR0 = 1; //开启定时器
while(1)
{
uchar *ge,*shi,*str2;
for(j=0;j<50;j++)
{
uchar xin[]=" 2022210491 sdd ";
uchar Dig_code[]="0123456789"; //仅用于确定初始数字,与累加无关
uchar Dig[2]=" ";
Dig[1] = Dig_code[n];//个位 确立初始状态
Dig[0] = Dig_code[m];//十位 比如Dig=14 那么它就先写4,再写
shi=&Dig[0]; //取地址,ge取Dig[0]的地址
ge=&Dig[1];
str2=&xin[0];
LCD_Init();
LCD_dstr(1,1,shi);
LCD_dstr(2,1,str2);
}
}
}
void ET0_ISR(void) interrupt 1 //定时0中断
{
static unsigned int cnt = 0;
//初值重赋
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
cnt++;//溢出一次,+1
if(cnt >= 20) //当为1秒时+1
{
cnt = 0;
n++;
if(n>=10)
{
m++; n=0;
}
if(m>=6) m=0;
}
}
(2)将输出的hex文件烧录到开发板上
五、实验结果及分析、实验过程中遇到问题及处理过程说明
1.任务一结果
2.任务二结果
3.任务三结果
4.遇到的问题及处理过程
在任务三中烧录程序后发现秒表数字为倒着的,即个位在前,十位在后。查看程序,shi=&Dig[1],ge=&Dig[0],LED_dstr(1,1,ge)就表示先写个位,再写十位,故需要交换shi与ge,代码改成shi=&Dig[0],ge=&Dig[1],最终得到理想效果。
六、实验总结及心得体会
通过本次实验课,明白了定时器定时原理,LCD显示字符、字符串原理,并掌握了它们的编程方法。在编程过程中,要理清楚逻辑,可从一个简单的功能入手,逐步增加代码以实现更多的功能。