51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832

六.按键中断识别

[实验任务]

采用中断技术,每按一下按键,计数器加1,并用LED显示出来。

[硬件电路]

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第1张图片

注意:我们只用4位数码管中的两位。

注意:a接P0.0;b接P0.1;c接P0.3……

注意: 2H接P2.0; 1H接P2.1; 中断按键已经接好。

[C语言源程序]

#include

unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,

0x82,0xf8,0x80,0x90};

unsigned char dispcount=0; //计数

sbit gewei=P2^0; //个位选通定义

sbit shiwei=P2^1; //十位选通定义

void Delay(unsigned int tc) //延时程序

{ while( tc != 0 )

{

unsigned int i;

for(i=0; i<100; i++);

tc--;

}

}

void ExtInt0() interrupt 0 //中断服务程序

{

dispcount++; //每按一次中断按键,计数加一

if (dispcount==100) //计数范围0-99

{dispcount=0;}

}

void LED( ) //LED显示函数

{

if(dispcount>=10) //显示两位数

{

shiwei=0;

P0=table[dispcount/10];

Delay(8);

shiwei=1;

gewei=0;

P0=table[dispcount%10];

Delay(5);

gewei=1;

}

else //显示一位数

{

shiwei=1;                     

gewei=0;

P0=table[dispcount];

Delay(8);

}

}

void main()

{ TCON=0x01; //中断设置

IE=0x81;

while(1) //循环执行

{

LED(); //只须调用显示函数

}

}

-------------------------------------------------------------------------------------------------------------------------------------

七.定时器 T0 的应用---9.9 秒计时设计

[实验任务]

开始时,显示“00”,第 1 次按下 BY1 后就开始计时。第 2 次按 BY1 后,计时

停止。 第3次按BY1后,计时归零。

[硬件电路]

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第2张图片

[C语言源程序]

#include //必须用这个子函数库

unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,

0x82,0xf8,0x80,0x90};

unsigned char sec; //定义计数值,每过1/10 秒,sec 加一

unsigned char keycnt=0;

unsigned int tcnt; //键值判断

sbit gewei=P2^0; //个位选通定义

sbit shiwei=P2^1; //十位选通定义

void Delay(unsigned int tc) //延时程序

{

while( tc != 0 )                    

{

unsigned int i;

for(i=0; i<100; i++);

tc--;

}

}

void LED() //LED显示函数

{

shiwei=0;

P0=table[sec/10];

Delay(8);

shiwei=1;

gewei=0;

P0=table[sec%10];

Delay(5);

gewei=1;

}

void KEY() //按键扫描程序

{

unsigned char i,j;

if(P3_0==0)

{

for(i=20;i>0;i--) //延时去干扰

for(j=248;j>0;j--);

if(P3_0==0)

{

keycnt++;

switch(keycnt) //按下次数判断

{

case 1: //第一次按下

TH0=0x06; //对TH0 TL0 赋值

TL0=0x06;

TR0=1; //开始定时

break;

case 2: //第二次按下

TR0=0; //定时结束

break;

case 3: //第三次按下

keycnt=0; //重新开始判断键值

sec=0; //计数重新从零开始

break;

}

while(P3_0==0);

} } }                  //请注意写程序时的格式规范,此处是为了节省纸张

void t0(void) interrupt 1 using 0 //定时中断服务函数

{

tcnt++; //每过250ust tcnt 加一

if(tcnt==400) //计满400 次(1/10 秒)时

{

tcnt=0; //重新再计

sec++;

if(sec==100) //定时10 秒,在从零开始计时

{

sec=0;

}

}

}

void main(void)

{

TMOD=0x02; //定时器工作在方式2

ET0=1;

EA=1;

sec=0;

while(1)

{

KEY();

LED();

}

}

---------------------------------------------------------------------------------------------------------

八.利用定时器产生乐曲

[实验任务]

利用单片机的I/O口演奏乐曲。

[硬件电路图]

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第3张图片

[实验原理]                     

乐曲是按照一定的高低,长短和强弱关系组成的关系,在一首乐曲中,每一个音符与频率有关。所以我们只要把有关频率的占空比数据做成表格,在通过查表,在I/O口输出相关乐曲的方波,便产生了乐曲。

注意:无源蜂鸣器与有源蜂鸣器的区别可以同时学习一下

[C语言源程序]

#include "reg52.h"//这样用双引号也可以。

unsigned char Count;

sbit _Speak =P0^0 ; //讯响器控制脚

unsigned char code SONG[] ={ //祝你平安

0x26,0x20,0x20,0x20,0x20,0x20,0x26,0x10,0x20,0x10,0x20,0x80,0x26,0x20,0x30,0x20,

0x30,0x20,0x39,0x10,0x30,0x10,0x30,0x80,0x26,0x20,0x20,0x20,0x20,0x20,0x1c,0x20,

0x20,0x80,0x2b,0x20,0x26,0x20,0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x80,0x26,0x20,

0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x60,0x40,0x10,0x39,0x10,0x26,0x20,

0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x80,0x26,0x20,0x2b,0x10,0x2b,0x10,

0x2b,0x20,0x30,0x10,0x39,0x10,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x20,

0x20,0x10,0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x18,0x20,0x18,0x20,0x26,0x20,

0x20,0x20,0x20,0x40,0x26,0x20,0x2b,0x20,0x30,0x20,0x30,0x20,0x1c,0x20,0x20,0x20,

0x20,0x80,0x1c,0x20,0x1c,0x20,0x1c,0x20,0x30,0x20,0x30,0x60,0x39,0x10,0x30,0x10,

0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x10,0x26,0x10,0x26,0x10,0x2b,0x10,0x2b,0x80,

0x18,0x20,0x18,0x20,0x26,0x20,0x20,0x20,0x20,0x60,0x26,0x10,0x2b,0x20,0x30,0x20,

0x30,0x20,0x1c,0x20,0x20,0x20,0x20,0x80,0x26,0x20,0x30,0x10,0x30,0x10,0x30,0x20,

0x39,0x20,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x10,0x40,0x10,0x20,0x10,

0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x00,

//路边的野华不要采

0x30,0x1C,0x10,0x20,0x40,0x1C,0x10,0x18,0x10,0x20,0x10,0x1C,0x10,0x18,0x40,0x1C,

0x20,0x20,0x20,0x1C,0x20,0x18,0x20,0x20,0x80,0xFF,0x20,0x30,0x1C,0x10,0x18,0x20,

0x15,0x20,0x1C,0x20,0x20,0x20,0x26,0x40,0x20,0x20,0x2B,0x20,0x26,0x20,0x20,0x20,

0x30,0x80,0xFF,0x20,0x20,0x1C,0x10,0x18,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,

0x20,0x2B,0x40,0x20,0x20,0x1C,0x10,0x18,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,

0x20,0x2B,0x40,0x20,0x30,0x1C,0x10,0x18,0x20,0x15,0x20,0x1C,0x20,0x20,0x20,0x26,

0x40,0x20,0x20,0x2B,0x20,0x26,0x20,0x20,0x20,0x30,0x80,0x20,0x30,0x1C,0x10,0x20,

0x10,0x1C,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,0x20,0x2B,0x40,0x20,0x15,0x1F,

0x05,0x20,0x10,0x1C,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,0x20,0x2B,0x40,0x20,

0x30,0x1C,0x10,0x18,0x20,0x15,0x20,0x1C,0x20,0x20,0x20,0x26,0x40,0x20,0x20,0x2B,

0x20,0x26,0x20,0x20,0x20,0x30,0x30,0x20,0x30,0x1C,0x10,0x18,0x40,0x1C,0x20,0x20,

0x20,0x26,0x40,0x13,0x60,0x18,0x20,0x15,0x40,0x13,0x40,0x18,0x80,0x00,};

void Time0_Init()

{ TMOD = 0x01;

IE = 0x82;

TH0 = 0xD8;

TL0 = 0xEF; //12MZ晶振,10ms

}

void Time0_Int() interrupt 1

{ TH0 = 0xD8;

TL0 = 0xEF;                     

Count++; //长度加1

}

void Delay_xMs(unsigned int x) //1MS 延时子程序

{ unsigned int i,j;

for( i =0;i < x;i++ )

{for( j =0;j<3;j++ );}

}

void Play_Song(unsigned char i) //:歌曲播放子程序i 为播放哪一段曲目

{ unsigned char Temp1,Temp2;

unsigned int Addr;

Count = 0; //中断计数器清0

Addr = i * 217;

while(1)

{ Temp1 = SONG[Addr++];

if ( Temp1 == 0xFF ) //休止符

{TR0 = 0; Delay_xMs(100); }

else if ( Temp1 == 0x00 ) //歌曲结束符

{return;}

else {Temp2 = SONG[Addr++];

TR0 = 1;

while(1)

{ _Speak = ~_Speak;

Delay_xMs(Temp1);

if ( Temp2 == Count )

{Count = 0;

break;

} } } } } //请注意写程序时的格式规范,此处是为了节省空间

void main() //主程序

{Time0_Init(); //定时器0 中断初始化

while(1)

{Play_Song(0);} //播放

}

-----------------------------------------------------------------------------------------------------------------------

九.数摸转换 ADC0804 的应用

[实验任务]

从 ADC0804 的通道 IN+输入 0-5V 之间的模拟量,通过 ADC0804 转换成数字

量在数码管上以十进制形成显示出来。

[硬件电路图]

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第4张图片

注意:上图未显示全的是四个共阴极数码管。

[实验原理]

ADC0804 是 8 位全 MOS 中速 A/D 转换器、它是逐次逼近式 A/D 转换器,片内有三态数据输出锁存器,可以和单片机直接接口。单通道输入,转换时间大约为100us。ADC0804转换时序是:当CS=0许可进行A/D转换。WR由低到高时,A/D开始转换,一次转换一共需要66-73个时钟周期。CS与WR同时有效时启动A/D转换,转换结束产生 INTR 信号(低电平有效),可供查询或者中断信号。在 CS和RD的控制下可以读取数据结果。

[C语言源程序]

#include

code unsigned char seg7code[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,

0x82,0xf8,0x80,0x90

}; //显示段码

sbit int1=P3^3; //定义管脚功能

sbit cs=P3^2;

sbit wr=P3^6;

sbit rd=P3^7;

void Delay(unsigned int tc) //显示延时程序

{while( tc != 0 )

{unsigned int i;

for(i=0; i<100; i++);

tc--;}

}

unsigned char adc0804( void ) //读AD0804 子程序

{ unsigned char addata,i;

rd=1;wr=1;int1=1; //读ADC0804 前准备

P1=0xff; //P1全部置一准备

cs=0;wr=0;wr=1; //启动ADC0804 开始测电压

while(int1==1); //查询等待A/D转换完毕产生的INT(低电平有效)信号

rd=0; //开始读转换后数据

i=i; i=i; //无意义语句,用于延时等待ADC0804 读数完毕

addata=P1;//读出的数据赋与addate

rd=1;cs=1;//读数完毕

return(addata);//                     返回最后读出的数据

}

unsigned int datpro(void)//ADC0804 读出的数据处理

{ unsigned char x;

unsigned int dianyah,dianyal; //用于存储读出数据的高字节和低字节

unsigned int dianya=0; //存储最后处理完的结果 注意数据类型

for(x=0;x<10;x++) //将10 次测得的结果存储在dianya 中

{dianya=adc0804()+dianya; }

dianya=dianya/10; //求平均值

dianyah=dianya&0xf0; //屏蔽低四位

dianyah=dianyah>>4; //右移四位 取出高四位

dianyal=dianya&0x0f; //屏蔽高四位 取出低四位

dianya=dianyal*20+dianyah*320; //最后的结果是一个四位数,便于显示

return(dianya);//返回最后处理结果

}

void Led()

{ unsigned int date;

date=datpro(); //调用数据处理最后结果

P2=P2&0xef;

P0=seg7code[date/1000]|0x80; //输出个位数和小数点

Delay(8); P2=P2|0xf0; P2=P2&0xdf;

P0=seg7code[date%1000/100]; //输出小数点后第一位

Delay(8); P2=P2|0xf0; P2=P2&0xbf;

P0=seg7code[date%100/10]; //输出小数点后第二位

Delay(8); P2=P2|0xf0; P2=P2&0x7f;

P0=seg7code[date%10]; //输出小数点后第三位

Delay(8); P2=P2|0xf0;

}

main()

{

while(1)

{

Led( ); //只需调用显示函数

}

}

ADC0809是带有8位A/D转换器、8路多路开关以及微处理机兼容的控制逻辑的CMOS组件。它是逐次逼近式A/D转换器,可以和单片机直接接口。

(1)ADC0809的内部逻辑结构

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第5张图片

由上图可知,ADC0809由一个8路模拟开关、一个地址锁存与译码器、一个A/D转换器和一个三态输出锁存器组成。多路开关可选通8个模拟通道,允许8路模拟量分时输入,共用A/D转换器进行转换。三态输出锁器用于锁存A/D转换完的数字量,当OE端为高电平时,才可以从三态输出锁存器取走转换完的数据。

(2)引脚结构

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第6张图片51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第7张图片

IN0-IN7:8条模拟量输入通道

    ADC0809对输入模拟量要求:信号单极性,电压范围是0-5V,若信号太小,必须进行放大;输入的模拟量在转换过程中应该保持不变,如若模拟量变化太快,则需在输入前增加采样保持电路。

地址输入和控制线:4条

    ALE为地址锁存允许输入线,高电平有效。当ALE线为高电平时,地址锁存与译码器将A,B,C三条地址线的地址信号进行锁存,经译码后被选中的通道的模拟量进转换器进行转换。A,B和C为地址输入线,用于选通IN0-IN7上的一路模拟量输入。通道选择表如下表所示。

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第8张图片

数字量输出及控制线:11条

    ST为转换启动信号。当ST上跳沿时,所有内部寄存器清零;下跳沿时,开始进行A/D转换;在转换期间,ST应保持低电平。EOC为转换结束信号。当EOC为高电平时,表明转换结束;否则,表明正在进行A/D转换。OE为输出允许信号,用于控制三条输出锁存器向单片机输出转换得到的数据。OE=1,输出转换得到的数据;OE=0,输出数据线呈高阻状态。D7-D0为数字量输出线。

CLK为时钟输入信号线。因ADC0809的内部没有时钟电路,所需时钟信号必须由外界提供,通常使用频率为500KHZ,

VREF(+),VREF(-)为参考电压输入。

2. ADC0809应用说明

(1). ADC0809内部带有输出锁存器,可以与AT89S51单片机直接相连。

(2). 初始化时,使ST和OE信号全为低电平。

(3). 送要转换的哪一通道的地址到A,B,C端口上。

(4). 在ST端给出一个至少有100ns宽的正脉冲信号。

(5). 是否转换完毕,我们根据EOC信号来判断。

(6). 当EOC变为高电平时,这时给OE为高电平,转换的数据就输出给单片机了。

电路原理图:

 

adc0809内部结构图:

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第9张图片

----------------------------------------------------------------------------------------------------------------------------------------------

十.摸数转换 DAC0832的应用

[实验任务]

用两个按键通过单片机控制 DAC0832 的输出,使 OUT 端可以输出 0—5V 的幅

值,频率为1KHZ的锯齿波和三角波两种波形。通上电源后;按下INT1则输出三

角波,在按下INT0输出锯齿波。

[硬件电路图]

51单片机实例学习二 按键中断识别、定时器、利用定时器产生乐曲、数摸转换 ADC0804和DAC0832_第10张图片

注意:D0对应P0.0;D1对应P0.1;D2对应P0.2……

按键可以直接使用INT0和INT1按键(程序中以扫描方式识别按键)。

硬件电路图中的画框的部分,运放 LM324 的连接部分需要用户自己搭建,注

意LM324使用的是正负12V的双电源供电。我们只使用LM324四个运放中的两个

[实验原理]

ADC0804是8位全MOS 中速D/A转换器,采用R—2RT形电阻解码网络,转换结果为一对差动电流输出,转换时间大约为 1us。使用单电源+5V―+15V 供电。参考电压为-10V-+10V。在此我们直接选择+5V 作为参考电压。DAC0832 有三种工作方式:直通方式,单缓冲方式,双缓冲方式;在此我们选择直通的工作方式将XFER WR 1WR2 CS管脚全部接数字地。管脚8接参考电压,在此我们接的参考电压是+5V。那么经过第一级运放后,输出电压将是-5V-0V,在经过第二级运放反相放大1倍以后将可以输出0V—5V了。我们在控制P1口输出数据有规律的变化将可以产生三角波,锯齿波,梯型波等波形了。

[C语言源程序]

#include

unsigned char keycnt=0;

unsigned char tcnt=0; //键值判断

bit sjz=0; //产生三角波时用到的标志

void delayl() //延时子程序

{ unsigned char i,j;

for(i=20;i>0;i--)

for(j=248;j>0;j--); }

void KEY() //按键扫描程序

{

if(P3_2==0)

{

delayl(); //延时跳过按下时的抖动

if(P3_2==0)

{                     

keycnt=0; //定时器产生锯齿波标志

TR0=0; //暂时停止波形输出

TH0=0x256-40; //对TH0 TL0 赋值

TL0=0x256-40;

TR0=1; //开始定时,产生锯齿波

while(P3_2==0); //如果一直按着键,则等待松键开

delayl(); //延时跳过松开后的抖动

} }

if(P3_3==0)

{

delayl(); //延时跳过按下时的抖动

if(P3_3==0)

{

keycnt=1; //定时器产生三角波标志

TR0=0; //暂时停止波形输出

TH0=0x256-40; //对TH0 TL0 赋值

TL0=0x256-40;

TR0=1; //开始定时 产生三角波

}

while(P3_2==0); //如果一直按着键,则等待松键开

delayl(); //延时跳过松开后的抖动

}

} //请注意写程序时的格式规范,此处是为了节省纸张

void t0(void) interrupt 1 using 0 //定时中断服务函数

{

if(keycnt==0) //产生锯齿波

{

P0=tcnt;

tcnt=+0x0a; //步进0.2V/一次中断

if(tcnt==0xfb)

{tcnt=0;}

}

if(keycnt==1) //产生三角波

{ if(sjz==0)

{P0=tcnt;

tcnt=+0x0a;//步进0.2V/一次中断

if(tcnt==0xfa)

{sjz=1;}

}

if(sjz==1)

{

P0=tcnt;

tcnt=-0x0a;

if(tcnt==0)                    

{sjz=0;}

}

}

}

void main(void)

{

TMOD=0x02; //定时器工作在方式2

ET0=1;

EA=1;

while(1)

{ KEY(); }

}

你可能感兴趣的:(笔记,51单片机,单片机)