实验六 定时器实验
一 、实验目的
掌握定时器的初始化,中断服务程序的编写及调试方法。
二 、实验电路
如图所示,将实验仪上的JP3短接,将JP2、JP4断开,选择发光二极管。
三 、实验内容
用定时器T0的方式2,控制发光二极管每秒闪一次。
四 、参考程序
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit LED=P0^0; //发光管控制位
uint count=0; //方式2中断计数器
void time0(void) interrupt 1
{ count++; //每中断一次,计数器加1
if(count==2000) //2000次为0.5秒
{count=0;
LED=~LED;
}
}
void main(void)
{ TMOD=0x02; //T0工作于方式2
TH0=-250; //时间常数为250us
TL0=-250;
ET0=1; //允许T0中断
TR0=1; //允许T0定时
EA=1; //CPU开中断
while (1);
}
五 、思考题
该实验如果用定时器方式1来实现,程序应作如何修改?
实验七 计数器模拟外部中断实验
一、实验目的
掌握用定时器来扩展外部中断的方法。
二 、实验电路
如图所示,将实验仪上的JP2短接,将JP3、JP4断开,选择LED显示器,将单脉冲电路输出J6的PH脚与单片机T0脚相连,作为外部计数输入。
三、实验内容
将定时器工作于计数方式,来扩展外部中断,编程统计外部中断的次数,并在LED数码管上显示出来。
四、参考程序
#include <reg51.h>
#define uchar unsigned char
uchar code segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c,0xff};
uchar dbuf[4]={0,0,0,0x12};
uchar count;
void delay(void)
{ uchar i;
for(i=0;i<100;i++);
}
void disp(void)
{ uchar n,bsel;
bsel=0xfe; //最初点亮最低位
for(n=0;n<4;n++)
{ P2=bsel; //位选口
P0=segtab[dbuf[n]];//显示缓冲单元的数据查出字段码表
bsel=(bsel<<1)+1; //准备显示下一位
delay(); //每位显示约1毫秒
P0=0xff; //熄灭数码管,防止当前位在下一位置显示出来
}
}
void time0(void) interrupt 1 //用定时器中断来模拟外部中断
{ count++; //中断次数加1
dbuf[2]=count/100; //将中断次数转换成三位BCD码
dbuf[1]=count%100;
dbuf[0]=count%10;
dbuf[1]=dbuf[1]/10;
}
void main(void)
{
TMOD=0x06; //T0工作于计数方式2
TH0=0xff; //TH0、TL0的初值设为0XFF,每当T0脚有负跳变的中断
TL0=0xff; //请求输入,定时器即溢出,产生定时中断
ET0=1; //允许T0中断
TR0=1; //允许计数
EA=1; //CPU开中断
while(1)
disp();
}
实验八 电子秒表实验
一 、实验目的
掌握用定时器的应用方法。
二 、实验电路
如图所示,将实验仪上的JP2短接,将JP3、JP4断开,选择LED显示器,将JP1的2脚与4*1脚相连,选择独立式键盘。
三、实验内容
设计一电子秒表,计时单位为0.1秒,第一次按键时启动计时,第二次按键时,停止计时,第三次按键时,计时器清0。
四、参考程序
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit KEY1=P2^4; //按键定义
uchar code segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c,0xff};
uchar dbuf[4]={0,0,0,0};
uint count;
uint n;
void delay(void)
{ uchar i;
for(i=0;i<200;i++);
}
void disp(void)
{ uchar n,bsel;
bsel=0xfe; //最初点亮最低位
for(n=0;n<4;n++)
{ P2=bsel; //位选口
P0=segtab[dbuf[n]];//显示缓冲单元的数据查出字段码表
bsel=(bsel<<1)+1; //准备显示下一位
delay(); //每位显示约1毫秒
P0=0xff; //熄灭数码管,防止当前位在下一位置显示出来
}
}
void time0(void) interrupt 1 //用定时器中断来模拟外部中断
{ n++;
if(n==400)
{ n=0;
count++; //中断次数加1
if(count==1000) count=0;
dbuf[3]=count/1000;
dbuf[2]=count%1000;
dbuf[2]=count/100; //将中断次数转换成三位BCD码
dbuf[1]=count%100;
dbuf[0]=dbuf[1]%10;
dbuf[1]=dbuf[1]/10;
}
}
void main(void)
{ uchar st=2;
TMOD=0x02; //T0工作于定时方式2
TH0=-230; //定时时间为250us
TL0=-230;
ET0=1; //允许T0中断
TR0=0; //暂停计时
EA=1; //CPU开中断
while(1)
{ while(KEY1==1) disp();//等待按键
disp(); //延时去抖动
if(KEY1==0) //如果有键按下
{ st++; //当前状态加1
if(st==3) st=0; //状态值取值为0、1、2
if(st==1) TR0=0;//为1时暂停
if(st==2) //为2时清计数器0
{ n=0;
count=0;
dbuf[3]=0;
dbuf[2]=0;
dbuf[1]=0;
dbuf[0]=0;
}
if(st==0) TR0=1;//为0时启动
}
while(KEY1==0) disp();//等待按键释放
}
}
实验九 发光二极管亮度调节实验
一 、实验目的
掌握定时器的应用,发光二极管亮度调节的方法。
二 、实验电路
如图所示,将JP3短接,将JP2、JP4断开,选择发光二极管,同时将JP1的2脚与4*1脚相连,选择独立式键盘。
三 、实验内容
将发光二极管的亮度分为16个等级, 用K13、K14按键去调节发光二极管的亮度。
四 、参考程序
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sfr LED=0x80; //发光管对应P0口
sbit K13=P2^4; //亮度加按键定义
sbit K14=P2^5; //亮度减按键定义
uchar count=0; //方式2中断计数器,每个周期为16次中断
uchar light=0; //LED发光二极管当前亮度等级
/*延时程序,n:入口参数为,单位:2毫秒*/
void delay(uchar n)
{ uchar i;
while(n--)
for(i=0;i<200;i++);
}
void time0(void) interrupt 1
{ count++; //定时中断计数器加1
count=count&0xf; //计数器的值在0~0x0f之间
if(count<light) LED=0x00;//如果计数器的值小于当前亮度等级,则点亮LED
else LED=0xff; //否则,关闭发光管
}
void main(void)
{ TMOD=0x02; //T0工作于方式1
TH0=-200; //时间常数为200us
TL0=-200;
ET0=1; //允许T0中断
TR0=1; //启动定时
EA=1; //CPU开中断
while (1)
{ while((P2&0x30)==0x30); //等待按键
delay(10); //去抖动延时
if(K13==0) //是KINC键,亮度等级加1
{ light++;
light=light&0xf;
}
else if(K14==0) //是KDEC键,亮度等级减1
{ light--;
light=light&0xf;
}
while((P2&0x30)!=0x30);//等待按键释放
delay(10); //去抖动
}
}
实验十 行列式键盘实验
一、实验目的
掌握行列式键盘硬件电路的工作原理及程序的设计与调试方法。
二 、实验电路
将实验仪上的JP2短接,将JP3、JP4断开,选择LED显示器,将JP1的2脚与4*4脚相连,选择4*4行列式键盘。
三、实验内容
编写行列式键盘扫描程序,将所按键值送LED显示器显示。
四、参考程序
#include<reg51.h>
#include<absacc.h>
#define uchar unsigned char
#define uint unsigned int
uchar code segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c};
uchar dbuf[4]={0,0,0,0};// 显示缓存
void dlms(void); //延时程序
uchar getkey(void); //键盘扫描程序
void disp(void); //动态显示程序
void main(void)
{ uchar key;
while(1)
{ disp();
key=getkey(); //扫描键盘
if(key!=0xff) //如果有键压下
{ dbuf[3]=dbuf[2];//将显示缓存的数据左移一位
dbuf[2]=dbuf[1];
dbuf[1]=dbuf[0];
dbuf[0]=key; //最后填入所按键值
}
}
}
uchar getkey()
{ uchar i;
uchar key=0;
uchar scode,recode;
P2=0xf0; //低四位行线输出全为0
if((P2&0xf0)!=0xf0) //如果有键被压下
{ for(i=1;i<20;i++)disp();//去抖动延时
P2=0xf0; //低四位行线输出全为0
if((P2&0xf0)!=0xf0)//如果仍有键被压下
{ scode=0xfe; //准备将四位行线逐位输出为低
while ((scode&0x10)!=0)//如果扫描没有结束
{ P2=scode; //将当前行线设为低
if((P2&0xf0)!=0xf0)//如果该行上有键被压下
{ recode=~(P2&0xf0);//令按键所在列的那一位变高
scode=0x10;//准备扫描是那一列为高
while(scode&0xf0)//如果四列还没有扫描结束
if(recode&scode)//如果当前列为高,说明该列有键被压下
{
while((P2&0xf0)!=0xf0) //等待按键释放
{ disp();
P2=0xf0;
}
return(key); //返回键值
}
else { scode=scode<<1;//准备对下一列检测
key++; //键值加1
}
}
else
{ scode=(scode<<1)|0x01;//准备对下一行扫描
key=key+4; //键值加4
}
}
}
}
return(0xff); //无键按下,返回0XFF
}
void disp(void)
{ uchar i,n,bsel;
bsel=0xfe; //首先点亮最低位
for(n=0;n<4;n++)
{ P2=bsel; //位选口
P0=segtab[dbuf[n]];//将显示缓存的数据转换为字段码显示
bsel=(bsel<<1)+1; //准备显示下一位
for(i=1;i<200;i++);//延时
P0=0xff; //熄灭所有字段
}
}
实验十一 串行口数据接收实验
一、实验目的
掌握串行口的初始化,接收中断服务程序的编写。
二、实验电路
如果所示,PC机的串口其实时由USB口模拟的,经CH341T转换后得到的串口信号其实是TTL电平,所以单片机的TXD、RXD无需经RS232电平转换。同时将JP2短接,将JP3、JP4断开,选择LED显示器
三、实验内容
将串行初始化为方式1,9600波特率, 用中断方式接收来自PC机的数据,并在数码管上显示出来。
说明:在进行串口实验时,不能在KEIL下仿真调试,可先在KEIL下用Start/Stop Debug命令将目标代码装入,并用RUN命令全速运行目标代码,之后退出Debug(此时,目标代码仍在运行,但串口已释放),运行串口调试助手,设定好波特率、串口号后,发送数据,此时,实验仪上的数码管将显示来自PC的数据。
四、参考程序
#include<reg52.h>
#include<absacc.h>
#include "DISP_KEY16.H"
#define uchar unsigned char
#define uint unsigned int
extern uchar dbuf[4];
void init_RS232(void)
{ ES=0; //禁止串行口中断
SCON=0x50; //0101,0000 8位数据位,无奇偶校验
TCON=0x34; //0011,0100 由T2作为波特率发生器
RCAP2H=0xff; //时钟为11.0592MHZ,9600波特率
RCAP2L=0xdb;
ES=1; //允许串行口中断
}
void serial_int(void) interrupt 4
{ uchar dat;
RI=0; //清除接收中断标志
dat=SBUF; //从接收缓冲区取出数据
if(dat>=0x41) dat=dat-7;//将ASCII码转换为十进制数
dat=dat-0x30;
dbuf[3]=dbuf[2];//将显示缓存的数据左移一位
dbuf[2]=dbuf[1];
dbuf[1]=dbuf[0];
dbuf[0]=dat&0x0f; //最后填入所按键值
}
void main(void)
{ init_RS232();//初始化串行口
EA=1; //CPU开中断
while(1)
{ disp();
}
}
实验十二 串行口数据发送实验
一、实验目的
掌握串行口的初始化以及发送程序的编写与调试。
二、实验电路
如果所示,PC机的串口其实时由USB口模拟的,经CH341T转换后得到的串口信号其实是TTL电平,所以单片机的TXD、RXD无需经RS232电平转换。同时将JP2短接,将JP3、JP4断开,选择LED显示器,将JP1的2脚与4*4脚相连,选择行列式键盘。
三、实验内容
将串行初始化为方式1,9600波特率, 从键盘输入数据并在LED显示器上显示出来,随后通过串行口发送给PC机。
说明:在进行串口实验时,不能在KEIL下仿真调试,可先在KEIL下用Start/Stop Debug命令将目标代码装入,并用RUN命令全速运行目标代码,之后退出Debug(此时,目标代码仍在运行,但串口已释放),运行串口调试助手,设定好波特率、串口号,此时,再从实验仪上的键盘上输入数据,在数码管上显示的同是,也将显示在PC的的数据接收窗口。
四、参考程序
#include<reg52.h>
#include<absacc.h>
#include "DISP_KEY16.H"
#define uchar unsigned char
#define uint unsigned int
extern uchar dbuf[4];
void init_RS232(void)
{ ES=0; //禁止串行口中断
SCON=0x50; //0101,0000 8位数据位,无奇偶校验
TCON=0x34; //0011,0100 由T2作为波特率发生器
RCAP2H=0xff; //时钟为11.0592MHZ,9600波特率
RCAP2L=0xdb;
ES=1; //允许串行口中断
}
void send_byte(uchar dat)
{ TI=0; //清除发送中断标志
SBUF=dat; //数据送发送缓冲区
while(TI==0); //等待发送完成
TI=0; //清除中断标志
}
void main(void)
{ uchar key;
init_RS232();//初始化串行口
while(1)
{ disp(); //显示键盘输入的数据
key=getkey(); //扫描键盘
if(key!=0xff) //如果有键压下
{ dbuf[3]=dbuf[2];//将显示缓存的数据左移一位
dbuf[2]=dbuf[1];
dbuf[1]=dbuf[0];
dbuf[0]=key; //最后填入所按键值
if(key>9) key=key+7;//将键值转换为ASCII码送出
send_byte(0x30+key);
}
}
}
实验十三 24C02的读写实验
一、实验目的
掌握II2总线的协议以及驱动程序的设计与调试方法。
二 、实验电路
实验电路见下图,
P16
三、实验内容
编程将数据写入24C02的指定地址单元,然后从该地址读出数据,如果读出的数据与写入数据一致,蜂鸣器发一声“嘟”,否则长鸣。
四、参考程序
#include <reg51.h> /*头文件的包含*/
#include <intrins.h>
#define uchar unsigned char /*宏定义*/
#define uint unsigned int
extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no);
extern bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no);
sbit BEEP=P1^6;
void delay(void)
{ uchar i;
for(i=0;i<120;i++) ;
}
void beep(void)
{ uint i;
for(i=0;i<1000;i++)
{delay();
BEEP=~BEEP;
}
}
void main(void)
{ uchar wd[8]={1,2,3,4,5,6,7,8};
uchar rd[8];
uchar i;
ISendStr(0xa0,0x00,wd,8);//将数组wd中的8个数据写入24C02地址为00开始的单元
for(i=0;i<100;i++) delay();//等待写操作完成
IRcvStr(0xa0,0x00, rd,8); //从24C02地址为00的单元中读取8个字节到数组rd中
for(i=0;i<8;i++) //比较读出与写入的数据是否一致
if(wd[i]!=rd[i]) break;
if(i==8) //正确,蜂鸣器发一声”嘟“
{ beep();
while(1);
}
while(1)beep(); //出错,蜂鸣器长鸣
}
实验十四 PCF8563实时时钟实验
一、实验目的
掌握II2总线的协议以及驱动程序的设计与调试方法。
掌握实时时钟芯片PCF8563的功能特点及应用。
二 、实验电路
实验电路见下图,同时将JP2短接,JP3、JP4断开,选择LED显示器。
三、实验内容
编程对实时时钟芯片PCF8563进行初始化,并读取当前时间,在LED显示器上显示出来。
四、参考程序
#include <reg51.h> /*头文件的包含*/
#include <intrins.h>
#define uchar unsigned char /*宏定义*/
#define uint unsigned int
#define PCF8563 0XA2
#define WRADDR 0X00
#define RDADDR 0X02
sbit BEEP=P1^6;
extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no);
extern bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no);
uchar code segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c};
uchar dbuf[4]={0,0,0,0};
void delay(void)
{ uchar i;
for(i=0;i<100;i++) ;
}
void beep(void)
{ uchar i;
for(i=0;i<100;i++)
{delay();
BEEP=~BEEP;
}
for(i=0;i<200;i++)
delay();
}
void disp(void)
{ uchar i,n,bsel;
bsel=0xfe;
for(n=0;n<4;n++)
{ P2=bsel;
P0=segtab[dbuf[n]&0x7f];
if(dbuf[n]>=0x80) P0=P0&0x7f;//如果有间隔符,则点亮小数点
bsel=(bsel<<1)+1;
for(i=1;i<250;i++);
P0=0xff;
}
}
void main(void)
{ uchar wd[5]={0x00,0x12,0x00,0x26,0x22};//8563初始化,设定当前时间为22:26
uchar rd[3];
uchar count=0; //变量count 用于时分间隔符的闪烁控制
ISendStr(PCF8563,WRADDR,wd,0x05);//将控制字写入8563从地址为00H的单元
while(1)
{ count++; //每循环一次变量加1,最大值为127
count=count&0x7f;
IRcvStr(PCF8563,RDADDR, rd,0x3);//读取当前时间
dbuf[3]=(rd[2]>>4)&0x3; //取时的十位值,并屏蔽其最高位
dbuf[2]=rd[2]&0x0f; //取时的个位
if(count<=0x3f) dbuf[2]=dbuf[2]|0x80;//count变量的前63次显示间隔符,后//63次不显示
dbuf[1]=rd[1]>>4; //取出分的十位值
dbuf[0]=rd[1]&0x0f; //取出分的个位值
disp();
}
}
实验十五 串行A/D转换实验
一、实验目的
掌握串行A/D转换芯片TLC549的功能特点,与单片机的连接,A/D转换程序的设计与调试。
二 、实验电路
实验电路见下图,同时将JP2短接,JP3、JP4断开,选择LED显示器。
三、实验内容
编写TLC549的A/D转换程序,读取模拟输入量的值,并将其显示在LED显示器上。
四、参考程序
#include <reg51.h>
#define uchar unsigned char
uchar code segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c,0xff};
uchar dbuf[4]={0,0,0,0x12};//只显示低三位
sbit AD_CS=P1^4;
sbit AD_CLK=P1^2;
sbit AD_DAT=P1^3;
bdata uchar adin;
sbit adin0=adin^0;
void delay(void)
{ uchar i;
for(i=0;i<20;i++);
}
uchar getad(void) // A/D转换程序
{ uchar i;
AD_CS=0; //令CS为低选中TLC549
delay(); //延时
for(i=0;i<8;i++) //循环读取8位A/D转换结果
{ AD_CLK=0; //令CLK引脚为低
adin=adin<<1;//先读取高位,后读低位
adin0=AD_DAT;//读取数据线的一位数据
AD_CLK=1; //令CLK恢复为高
}
return adin;
}
void disp(void)
{ uchar i,n,bsel;
bsel=0xfe; //首先点亮最低位
for(n=0;n<4;n++)
{ P2=bsel; //位选口
P0=segtab[dbuf[n]];//将显示缓存的数据转换为字段码显示
bsel=(bsel<<1)+1; //准备显示下一位
for(i=1;i<200;i++);//延时
P0=0xff; //熄灭所有字段
}
}
void main(void)
{ uchar ad;
while(1)
{ ad=getad(); //读取A/D转换结果
dbuf[2]=ad/100;//将转换结果转换为三位BCD码送显示缓存
ad=ad%100;
dbuf[1]=ad/10;
dbuf[0]=ad%10;
disp();
}
}
实验十六 频率测量实验
一、实验目的
掌握PCF8563的功能特点,频率测量的原理,测量程序的编写
二 、实验电路
如图所示,将被测信号PCF8563的CLKOUT脚与单片机的P35(T1)相连,作为外部计数信号,将JP1的2脚与4*1脚相连,构成独立式键盘。将JP2短接,JP3、JP4断开,选择LED显示器。
三、实验内容
编写频率测量程序,测量PCF8563实时时钟芯片所产生的时钟CLKOUT的频率,用四个按键控制PCF8563产生不同的频率,数码管的显示应分别为32.76K和1024、32、1HZ。
四、参考程序
#include <reg51.h> /*头文件的包含*/
#include <intrins.h>
#define uchar unsigned char /*宏定义*/
#define uint unsigned int
#define PCF8563 0XA2
#define WRADDR 0X00
#define RDADDR 0X02
sbit KEY13=P2^4;
sbit KEY14=P2^5;
sbit KEY15=P2^6;
sbit KEY16=P2^7;
extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no);
extern bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no);
uchar code segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c};
uchar dbuf[4]={0,0,0,0};
uint count;//定时器溢出中断次数
bit ok; //1秒钟时间到
void disp(void)
{ uchar i,n,bsel;
bsel=0xfe;
for(n=0;n<4;n++)
{ P2=bsel;
P0=segtab[dbuf[n]&0x7f];
if(dbuf[n]>=0x80) P0=P0&0x7f;//如果有小数点,则点亮小数点
bsel=(bsel<<1)+1;
for(i=1;i<250;i++);
P0=0xff;
}
}
void timer0(void) interrupt 1
{
count++; //中断计数器加1
if (count==4006) //4006次中断近似1S
{ ok=1; //设置时间到标志
count=0; //计数器清0
TR0=0; //停止T0、T1定时、计数
TR1=0;
}
}
void main(void)
{ uint fre;
uchar ctr=0x80; //8563的控制字
uchar temp=0x80;
bit dp; //小数点标志
ISendStr(PCF8563,0x0d,&ctr,0x01);//将控制字写入8563从地址为0DH的单元
TMOD=0x52; // T0工作于定时方式2,T1工作于计数方式1
ET0=1;
EA=1;
while(1)
{
TH0=-230;//当fosc=11.0592时,T0定时时间为250us
TL0=-230;
TH1=0; //T1工作于计数方式,初值为0
TL1=0;
TR0=1; //启动T0定时
TR1=1; //T1开始对8563的CLKOUT计数
while(ok==0) //当1秒的闸时间未到时
{ if((P2&0xf0)!=0xf0) //检测是否有键被按下
{ disp(); //去抖动
if(KEY13==0) temp=0x80; //根据键值设定8563时钟输出控制字
if(KEY14==0) temp=0x81; //产生频率分别为32768/1024/32/1HZ
if(KEY15==0) temp=0x82;
if(KEY16==0) temp=0x83;
}
disp();//保证显示器能正常显示当前频率
}
ok=0; //清除时间到标志,为下次测量作准备
fre=TH1*256+TL1;//从T1读取频率值
if(fre>=10000) //如果频率为5位数,舍去未位数,加上小数点,单位为KHZ
{ fre=fre/10;
dp=1; //小数点标志有效
}
else dp=0;
dbuf[3]=fre/1000; //将频率值的千位\百位\十位\个位求出
fre=fre%1000;
dbuf[2]=fre/100;
if(dp==1) dbuf[2]=dbuf[2]|0x80;//如果有小数点标志,则在百位加上小数点
fre=fre%100;
dbuf[1]=fre/10;
dbuf[0]=fre%10;
if(temp!=ctr) //如果控制字发生变化
{ ctr=temp; //更新当前控制字
ISendStr(PCF8563,0x0d,&ctr,0x01);//将新控制字写入8563的 0DH的单元
}
}
}
实验十七 温度测量实验
一、实验目的
掌握脉数字温度传感器DS1820的基本特点,与单片机的连接,温度测量程序的设计与调试。
二 、实验电路
P15
如图所示,将实验仪上的JP2短接,JP3、JP4断开,选择LED显示器。
三、实验内容
编程读取温度传感器DS1820所测的温度值,并将其在LED显示器上显示出来,保留一位小数。
四 、参考程序
#define uchar unsigned char
#define uint unsigned int
#include <reg51.h>
#include <intrins.h>
#include "DISP_KEY16.H"
extern uchar dbuf[4];
sbit DQ=P1^5;
bdata uchar dat;
sbit dat0=dat^0;
sbit dat7=dat^7;
uchar code segtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c};
uchar dbuf[4]={0,0,0,0};// 显示缓存
void disp(void)
{ uchar i,n,bsel;
bsel=0xfe; //首先点亮最低位
for(n=0;n<4;n++)
{ P2=bsel; //位选口
P0=segtab[dbuf[n]];//将显示缓存的数据转换为字段码显示
if(n==1) P0=P0&0x7F; //定点显示小数点
bsel=(bsel<<1)+1; //准备显示下一位
for(i=1;i<200;i++);//延时
P0=0xff; //熄灭所有字段
}
}
void delay15(uchar n)
{ do {
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
n--;
}while(n);
}
//该函数返回为0,表示有DS1820,否则没有
bit reset(void)
{ bit err;
DQ=0;
delay15(40);
DQ=1;
delay15(6);
err=DQ;
delay15(18);
return(err);
}
void wrbyte(uchar d)
{ uchar i;
dat=d;
for(i=8;i>0;i--)
{ DQ=0;
delay15(1);
DQ=dat0;
dat=dat>>1;
delay15(1);
DQ=1;
}
}
uchar rdbyte(void)
{ uchar i;
dat=0;
for(i=8;i>0;i--)
{ dat=dat>>1;
DQ=0;
_nop_();
DQ=1;
delay15(1);
dat7=DQ;
}
return(dat);
}
void convert(void)
{ bit err;
err=reset();
wrbyte(0xcc); //跳过多传感器识别
wrbyte(0x44); //启动温度转换
}
int readt(void)
{ uchar h,l;
bit err;
err=reset();
wrbyte(0xcc); //跳过多传感器识别
wrbyte(0xbe); //读暂存器
l=rdbyte(); //温度低位
h=rdbyte(); //温度高位
return(h*256+l);
}
main()
{ uint t;
uchar dp[16]={0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9};//小数部分转换
P3=0XFF;
P1=0X7F;
while(1)
{ convert();//启动温度转换
t=readt();//读取温度值
dbuf[0]=dp[t&0x0f];//求出温度的小数
t=t>>4;
dbuf[3]=t/100;//求出百位
t=t%100;
dbuf[2]=t/10;//求出十位
dbuf[1]=t%10;//求出个位
disp();
}
}
实验十八 红外线收发实验
一、实验目的
掌握红外线收发的基本原理,以及发送收接程序的设计与调试。
二 、实验电路
如下图所示,将红外线调控制P34引脚与HSOUT脚相连,将红外线解调输入接P32脚,将JP2短接,JP3、JP4断开,将JP1的2脚与4*4脚相连,选行列式键盘。
三、实验内容
通过行列式键盘输入要发送的数字,经调制后发送出去,本机接收后对解调的信号进行解码,成功后送LED显示器显示出来。
四、参考程序
/*红外线自发自收程序*/
/*发送的数据在0x00--0x0f之间,每个数据以3ms的引导位开始,*/
/*如果发送的数据为n,引导位后跟 n位宽度为1ms的数据位*/
#include <reg51.h>
#include "DISP_KEY16.H"
#define uchar unsigned char
#define uint unsigned int
sbit HSIN=P3^2; //红外管收输入
sbit HSOUT=P3^4;//红外接发送控制
extern uchar dbuf[4];
bit out_mk; //为1时输出调制脉冲
uchar count; //调制脉冲计数,第一个数据位有125个脉冲,约3ms,随后的数据位有42个//脉冲,约1ms
uchar out_dat;//要发送的数据
uchar in_dat;//接收到的数据
uchar wide;//收到的第一个解调数据位的宽度
void int1(void) interrupt 0 using 2
{ if(in_dat==0) //如果是第一位,则测量的宽度,防止干扰
while(HSIN==0) wide++;
in_dat++; //每产生一次中断,数据值加1
}
void timer0(void) interrupt 1 using 1
{ if(out_mk) HSOUT=~HSOUT;//out_mk标志为1时输出调制脉冲
count--; //计数器减1
if(count==0) //如果为0,重新初始化
{ count=84; //第一个数据位之外的任一位数据有42个调制脉冲
out_mk=~out_mk; // out_mk标志求反
HSOUT=0;
out_dat--;
if(out_dat==0) //如果数据位均以发完,则关闭定时器
{ TR0=0;
ET0=0;
}
}
}
void main(void)
{ uchar i;
uchar key;
TMOD=0x02; //定时器T0工作于定时式2,
TH0=0xf4; //产生38KHZ的方波
TL0=0xf4;
PT0=1; //T0为高优先级中断
IT0=1; //外部中断0为负跳变触发
EX0=1;
PX0=0; //低优先级中断
EA=1;
HSOUT=0; //红外输出设为低电平
while(1)
{ while((key=getkey())==0xff) disp();//等待按键
count=250; //第一个数据位有125调制脉冲
out_dat=(key+1)*2;//每一位数据均要有高电平及低电平两个状态
in_dat=0; //接收数据初始化为0
out_mk=1; //out_mk标志为1,输出调制脉冲
wide=0; //第一位数据宽度值清0
ET0=1; //启动定时器,发送调制脉冲
TR0=1;
for(i=0;i<30;i++) disp();//等待接收完成
if(wide>0x40) //如果接收到的第一位数据宽度小于x40,数据无效
{
dbuf[3]=dbuf[2]; //显示缓存左移一位,将收到的数据送显示缓存
dbuf[2]=dbuf[1];
dbuf[1]=dbuf[0];
dbuf[0]=in_dat-1;
disp();
}
}
}
实验十九 LCD液晶显示器实验
一、实验目的
掌握字符型液晶显示器与单片机的连接,显示程序的设计与调试
二、实验电路
如图所示,将JP4短接,JP2、JP2断开。
三 、实验内容
编程LCD显示器的屏幕上分别显示字符串“www.ccit.js.cn”和"2006-10-19";
四、参考程序
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit RS=P3^7; //数据/命令寄存器选择控制端
sbit RW=P3^6; //读写控制端
sbit E =P1^7; //使能控制端
sfr LCD=0x80; //P0口作为总线端口
sbit RDY=LCD^7; //就绪线,低电平有效
void lcd_cmd(uchar cmd) //发送命令函数
{ LCD=cmd; //命令码送总线
RS=0; //选择命令寄存器
RW=0; //执行写数据操作
E=0; //使能信号有效
while(1)
{ LCD=0xff; //总线变高
RS=0; //选择命令寄存器
RW=1; //读操作
E=0; //使能信号有效
_nop_(); //延时
E=1; //撤肖使能信号
if(RDY==0) break;//如果就绪,返回
}
}
void lcd_dat(uchar dat) //发送数据函数
{
LCD=dat; //显示数据送总线
RS=1; //选择数据寄存器
RW=0; //执行写数据操作
E=0; //使能信号有效
while(1)
{ LCD=0xff;//总线变高
RS=0; //选择命令寄存器
RW=1; //读操作
E=0; //使能信号有效
_nop_(); //延时
E=1; //撤肖使能信号
if(RDY==0) break;//如果就绪,返回
}
}
void main()
{
uchar *p;
uchar str1[16]="www.ccit.js.cn";
uchar str2[16]="2006-10-19";
lcd_cmd(0x01);//清屏幕
lcd_cmd(0x3c);//设置双行显示,5X10点阵
lcd_cmd(0x0C);//开显示,关闭光标
lcd_cmd(0x80);//显示在第一行
p=str1;
while(*p) lcd_dat(*p++); //显示"www.ccit.js.cn"
lcd_cmd(0xc0);//显示在第二行
p=str2;
while(*p) lcd_dat(*p++);//显示"2006-10-19";
while(1);
}
实验二十 脉宽测量实验
一、实验目的
掌握脉宽测量的基本原理,程序的设计与调试
二、实验电路
如图所示,将PCF8563的外部脉冲输出引脚CLKOUT作为被测信号,与单片机的/INT0脚相连,单脉冲的电路的输出与/INT1相连,用于选择被测信号CLKOUT的频率,同时将JP4短接,JP2、JP2断开。
三、实验内容
将定时器T0工作于定时方式1,初值为0,GATE位为1,由CLKOUT的高电平来控制其定时,用单脉冲所产生的外部中断1来选择CLKOUT的频率,测量其脉宽,并在LCD显示器上显示出来。
四、参考程序
/*测量PCF8563实时时钟芯片所产生的时钟CLKOUT的周期*/
/*用脉冲按键产生中断,控制PCF8563产生不同的频率,测出期脉宽后,送LCD显示器显示。*/
#include <reg51.h> /*头文件的包含*/
#include <intrins.h>
#define uchar unsigned char /*宏定义*/
#define uint unsigned int
#define ulong unsigned long
#define PCF8563 0XA2
#define WRADDR 0X00
#define RDADDR 0X02
extern bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no);
extern bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no);
sbit CLKOUT=P3^2;//被测信号输入端
sbit RS=P3^7; //数据/命令寄存器选择控制端
sbit RW=P3^6; //读写控制端
sbit E =P1^7; //使能控制端
sfr LCD=0x80; //P0口作为总线端口
sbit RDY=LCD^7; //就绪线,低电平有效
uchar count; //T0溢出次数
uchar sel; //CLKOUT输出频率选择
void lcd_cmd(uchar cmd)
{ LCD=cmd; //命令码送总线
RS=0; //选择命令寄存器
RW=0; //执行写数据操作
E=0; //使能信号有效
while(1)
{ LCD=0xff; //总线变高
RS=0; //选择命令寄存器
RW=1; //读操作
E=0; //使能信号有效
_nop_(); //延时
E=1; //撤肖使能信号
if(RDY==0) break;//如果就绪,返回
}
}
void lcd_dat(uchar dat)
{
LCD=dat; //显示数据送总线
RS=1; //选择数据寄存器
RW=0; //执行写数据操作
E=0; //使能信号有效
while(1)
{ LCD=0xff;//总线变高
RS=0; //选择命令寄存器
RW=1; //读操作
E=0; //使能信号有效
_nop_(); //延时
E=1; //撤肖使能信号
if(RDY==0) break;//如果就绪,返回
}
}
void int1(void) interrupt 2
{ sel++;
sel=sel&0x03;
}
void timer0(void) interrupt 1
{ count++; //中断计数器加1
}
void main(void)
{ ulong wide;
uchar ctr=0x83;
uchar temp=0x00;
uchar i;
uchar str1[16]="Wide of CLK is";
uchar str2[16]=" uS ";
uchar *p;
lcd_cmd(0x01);//清屏幕
lcd_cmd(0x3c);//设置双行显示,5X10点阵
lcd_cmd(0x0C);//开显示,关闭光标
lcd_cmd(0x80);//显示在第一行
p=str1;
while(*p) lcd_dat(*p++); //显示"Wide of CLK is"
sel=0x03; //默认32768HZ的CLKOUT
ISendStr(PCF8563,0x0d,&ctr,0x01);//将控制字写入8563从地址为0DH的单元
TMOD=0x09; //T0工作于定时方式1,GATE=1,由CLKOUT高电平启动计时
ET0=1; //允许T0中断
EA=1; //CPU开中断
IT1=1; //外部中断负跳变触发
EX1=1; //允许INT1中断
while(1)
{
TH0=0; //测试前,计数器清0
TL0=0;
count=0;
while(CLKOUT==1); //等待被测信号变低
TR0=1; //启动T0定时,
while(CLKOUT==0); //但因PLUSE当前为低,定时器并示开始计时
while(CLKOUT==1); //此时才开始对脉宽计时
TR0=0; //停止计时
wide=(count*65536)+(TH0<<8)+TL0;//算出脉宽
wide=(wide*12)/11;
for(i=0;i<6;i++) str2[i]=0x20; //显示缓冲区清0
for(i=6;i>0;i--)
{
str2[i]=(wide%10)+0x30; //将结果转换为ASCII存入显示缓存
wide=wide/10;
if(wide==0) break;
}
p=str2;
lcd_cmd(0xc0); //显示在第二行p=str2;
while(*p) lcd_dat(*p++);
if(temp!=sel)
{ temp=sel;
ctr=0x80|temp;
ISendStr(PCF8563,0x0d,&ctr,0x01);//将控制字写入8563的0DH的单元
}
}
}
实验二十一 在应用中编程(IAP)实验
一、实验目的
掌握SST89E58单片机在应用中编程的方法。
二、实验电路
SST89E58内部电路
三、实验内容
编程将SST89E58单片机从BLOCK1开始的一个扇区擦除,然后依次0X00~0X7F编程写入,并检查编程是否成功,如果成功,则蜂鸣器发一“嘟”声,否则长鸣。
四、参考程序
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit BEEP=P1^6;
/*****************************************************
* MCU特殊功能寄存器地址
*****************************************************/
sfr SFCF = 0xB1; /*FLASH配置位*/
sfr SFCM = 0xB2; /*FLASH命令位*/
sfr SFAL = 0xB3; /*FLASH地址低位*/
sfr SFAH = 0xB4; /*FLASH地址高位*/
sfr SFDT = 0xB5; /*FLASH数据位*/
sfr SFST = 0xB6; /*FLASH状态位*/
/*********************************************************
* MCU IAP命令
**********************************************************/
#define SFCM_SE 0x0B; /*扇区擦除IAP指令*/
#define SFCM_VB 0x0C; /*字节校读IAP指令*/
#define SFCM_PB 0x0E; /*字节编程IAP指令*/
/*******************************************************
* 全局变量定义
*******************************************************/
const uint BLK1_DST_ADDR = 0x0F000;
/*SST89x554RC、SST89x58RD2、SST89x54RD2和SST89x53RD2准备写入的目标地址。*/
const uchar SECT_SIZE = 0x80; /*一个扇区的字节数*/
uchar ErrorCode; /*标示操作的结果*/
/****************************************************
* Function Prototype
*****************************************************/
void sector_erase(uint dataAddr);
void byte_program(uint dataAddr, uchar dataByte);
uchar byte_verify(uint dataAddr);
int ready();
void error();
void beep();
/*******************************************************
* 主程序
* 改写块1一个扇区的数据(从0开始,每次加1),地址从BLK1_DST_ADDR开始。
* 当IAP执行成功,ErrorCode=0,否则ErrorCode=1.
*******************************************************/
void main()
{
uint destAddr = BLK1_DST_ADDR;
uchar byteCnt ; /*字节数*/
uchar origData; /*存储IAP操作的数据*/
uchar verifyData; /*校对数据*/
sector_erase(destAddr); /*写数据前先擦除要写的扇区*/
origData = 0x00;
for(byteCnt=0; byteCnt<SECT_SIZE; byteCnt++)
{
byte_program(destAddr, origData); /*编程一个字节*/
verifyData=byte_verify(destAddr); /*校对编程的字节是否正确*/
if(verifyData!=origData)
while(1) error(); /*如果编程不正确跳到error */
destAddr++;
origData++;
}
ErrorCode=0; /*IAP正确*/
beep();
while(1);
}
/*****************************************************/
* IAP子程序
* 1. Sector-Erase 扇区擦除
* 2. Byte-Program 字节编程
* 3. Byte-Verify 字节校读
*****************************************************/
/******************************************************
* 扇区擦除子程序
*******************************************************/
void sector_erase(uint dataAddr)
{
uint destAddr = dataAddr;
SFCF = SFCF | 0x40; /*IAP使能*/
SFAH = destAddr>>8; /*存入地址的高位字节*/
SFAL = destAddr; /*存入地址的低位字节*/
SFCM = SFCM_SE; /*发出扇区擦除指令*/
if(!ready())
error();
return;
}
/********************************************
* 字节编程子程序
*********************************************/
void byte_program(uint dataAddr, uchar dataByte)
{
uint destAddr = dataAddr;
SFCF = SFCF | 0x40; /* IAP使能*/
SFAH = destAddr>>8; /*存入地址的高位字节*/
SFAL = destAddr; /*存入地址的低位字节*/
SFDT = dataByte; /*存入要编程的数据*/
SFCM = SFCM_PB; /*发出字节编程指令*/
if(!ready())
error();
return;
}
/*******************************************
* 字节校读子程序
********************************************/
uchar byte_verify(uint dataAddr)
{
uint destAddr = dataAddr;
uchar readByte;
SFCF = SFCF | 0x40; /*IAP使能*/
SFAH = destAddr>>8; /*存入地址的高位字节*/
SFAL = destAddr; /*存入地址的低位字节*/
SFCM = SFCM_VB; /*发出字节校读指令*/
readByte = SFDT;
SFCF = SFCF & 0xBF; /*关闭IAP*/
SFDT = 0;
return readByte;
}
/*******************************************
* 准备子程序
* 检查IAP操作是否完成。如果结束,关闭IAP。
*******************************************/
int ready()
{
unsigned long int TimeOut = 0;
while (TimeOut < 100000)
{
if ((SFST&4) == 0) /*查IAP是否完成*/
{ /*IAP完成*/
SFCF = SFCF & 0xBF; /*关闭IAP*/
SFDT = 0;
return 1; /* IAP操作结束*/
}
TimeOut++;
}
SFCF = SFCF & 0xBF; /*关闭IAP*/
SFDT = 0;
return 0; /*IAP操作没有完成*/
}
/***********************************
* Error Function
***********************************/
void error()
{
ErrorCode=1; /*IAP出错*/
while(1) beep(); /*软件陷阱*/
}
void delay(void)
{ uchar i;
for(i=0;i<120;i++) ;
}
void beep(void)
{ uint i;
for(i=0;i<1000;i++)
{delay();
BEEP=~BEEP;
}
}
评论