/* MCU: AT89S52
/* MCU-crystal: 12M
/* Version: 01
/* Last Updata: 2009-2-21
/* Author:
/* Description:
/* 使用定时器0,定时中断2ms一次对数码管显示扫描;
/* 三个位管要以扫描方式显示,使用共阳管,计灶首春数速度为1S;
/* 段A-H接到P0.1....7,位选为 P1.0,1,2;
/* 流水也以计数方式从200到250在P2口显示,低电平有效;
/****************************************************/
#include <reg52.h>
unsigned char code num_disp[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90}//共阳数字字形芹凯0到9
unsigned char code bit_sel[]={0xfb,0xfd,0xfe}//低电平有效数字个十百位选择
unsigned char buf[3]={0,0,2}//计算中的个十百位暂时存放处
unsigned char one,ten,second//个十位变量和流水灯显示3秒的时间变量
unsigned char rate//扫描速度,调整以适应显示效果
unsigned char stop=0, flag=1,flag1=0//隐耐闪烁3秒的标志位,用于主函数对中断的关断参数传递
unsigned int t,tt//2ms变量
unsigned char rate//与变量t同步,辅助赋值变
/**********主函数**********/
main(void)
{
TMOD=0X01
TH0=0xf8//定时2ms
TL0=0x30
ET0=1
EA=1
TR0=1
while(1)
{ if(stop==1)//判断stop信号,为1后便关闭定时器
{ TR0=0
ET0=0
EA=0
}
}
}
/*******************中断*******************/
void timer0() interrupt 1
{
TH0=0xf8//重新赋值定时2ms
TL0=0x30
if(flag==0)//定义用于判断计数是否到了250,若到了则不再计数,转向else执行流水灯闪烁任务
{
t++
if(t==500)
{ t=0
one++
P2=200+ten*10+one//在P2口的流水等,也是从200开始计数。
if(one==10)
{ one=0
ten++
if(ten==5)
{ flag=1//转向执行闪烁任务
}
}
}
}
else//flag已经==1;转向else执行流水灯闪烁任务
{ tt++
if(tt==500)
{ tt=0
second++
P2=~P2//流水灯全部以1S速度闪烁
if(second==3)stop=1//判断3秒时间到,关闭中断,停止闪烁,数码管熄灭
}
}
rate++
P0=0XFF//消隐
if(rate==3)rate=0
P0=num_disp[buf[rate]]
P1=bit_sel[rate]
buf[0]=one
buf[1]=ten
//因为百位没有变,所以不用赋值
}
你的第二次修改,还有一处不足:……
CLR C
MOV DPTR,#TABLE
LOOP:
CLR A 这里少了一句,下面每次读出的,
就不知哪伍道是什么了
MOVC A,@A+DPTR
JNZ CONT_P
INC R2
SJMP NEXT
……
可以正常计数的程序如下。
=========================================
ORG 0H
MOV A,#00H
MOV R2,A
MOV R3,A
MOV R4,A
MOV R6,A
MOV R5,#40
CLR C
MOV DPTR,#TABLE
LOOP:
CLR A
MOVC A,@A+DPTR
JNZ CONT_P
CJNE A,#00H,CONT_P
INC R2
SJMP NEXT
CONT_P:
JB ACC.7, CONT_N
INC R3
SJMP NEXT
CONT_N:
INC R4
NEXT:
INC DPTR
DJNZ R5, LOOP
MOV P0,R4
SJMP $
实际个数 保存单元 统计个数
零个数 14R2 21
正数个数19R3 19
负数个数:7R4 0
其实是零和负数没有山告分开统计,请高手指教一李唯或下,谢谢!
ORG 400H
TABLE:
DB 01H, 15H, 22H,0FFH, 00H, 02H, 09H,0F9H, 00H, 00H
DB 01H, 15H, 22H,0FFH, 00H, 02H, 09H,0F9H, 00H, 00H
DB 01H, 15H, 22H,0FFH, 00H, 02H, 09H,0F9H, 00H, 00H
DB 02H, 05H, 00H,0FFH, 26H, 34H, 00H, 00H, 00H, 00H
END
波形发生器是一种常用的信号源,广泛地应用于电子电路、自动控制系统和教学实验等领域。本次课程设计使用的AT89S51 单片机构成的发生器可产生锯齿波、三角波、正弦波等多种波形,波形的周期可以用程序改变,并可根据需要选择单极性输出或双极性输出,具有线路简单、结构紧凑等优点。在本设计的基础上,加上按钮控制和LED显示器,则可通过按钮设定所需要的波形频率,并在LED上显示频率、幅值电压,波形可用示波器显示。二、系统设计
波形发生器原理方框图如下所示。波形的产生是通过AT89S51 执行某一波形发生程序,向D/A转换器的输入端按一定的规律发生数据,从而在D/A转换电路的输出端得到相应的电压波形。在AT89S51的P2口接5个按扭,通过软件编程来选择各种波形、幅值电压和频率,另有3个P2口管脚接TEC6122芯片,以驱动数码管显示电压幅值和频率,每种波形对应一个按钮。此方案的有点是电路原理比较简单,实现起来比较容易。缺点是,采样频率由单片机内部产生故使整个系统的频率降低。
1、波形发生器技术指标
1)波形:方波、正弦波、锯齿波;
2)幅值电压:1V、2V、3V、4V、5V;
3)频率:10HZ、20HZ、50HZ、100HZ、200HZ、500HZ、1KHZ;
2、 *** 作设计
1)上电后,系统初始化,数码显示6个‘-链带团’,等待输入设置命令。
2)按钮分别控制“幅值”、“频率”、“方波”、“正弦波”、“锯齿波”。
3)“幅值“键初始值是1V,随后再次按下依次增长1V,到达5V后在按就回到1V。
4)“频率“键初始值是10HZ,随后在按下依次为20HZ、50HZ、100HZ、200HZ、500HZ、1000HZ循环。
三、硬件设计
本系统由单片机、显示接口电路,波形转换(D/A)电路和电源等四部分构成。电路图2附在后
1、单片机电路
功能:形成扫描码,键值识别、键处理、参数设置;形成显示段码;产生定时中断;形成波形的数字编码,并输出到D/A接口电路和显示驱动电路。
AT89S51外接12M晶振作为时钟频率。并采用电源复位设计。复位电路采用上电复位,它的工作原理是,通电时,电容两端相当于短路,于是RST引脚上为高电平,然后电源通过对电容充电。RST端电压慢慢下降,降到一定程序,即为低电平,单片机开始工作。
AT89S51的P2口作为功能按钮和TEC6122的接口。P1口做为D/A转换芯片0832的接口。用定时/计数器作为中断源。不同的频率值对应不同的定时初值,允许定时器溢出中断。定时器中断的特殊功能寄存器设置如下:
定时控制寄存器TCON=20H;
工作方式选择寄存器TMOD=01H;
中断允许控制寄存器IE=82H。
2、显示电路
功能:驱动6位数码管显示,扫描按钮。
由集成驱动芯片TEC6122、6位共阴极数码管和5个按钮组成棚橘。当某一按钮按下时,扫描程序扫描到之后,通过P2口将数字信号发送到 TEC6122芯片。TEC6122是一款数字集成芯片。它的外接电压也是+5V,并行信且由于数码管的载压较小,为了保护数码管,必须在两者间接电阻,大约是560欧。
扫描利用软件程序实现,当某一按键按下时,扫描程序立即检测到,随后调用子程序,执行相应的功能。
3、D/A电路
功能:将波形样值的编码转换成模拟值,完成双极性的波形输出。
由一片0832和两块LM358运放组成。DAC0832是一个具有两个输入数据寄存器的8位DAC。目前生产的DAC芯片分为两类,一类芯片内部设置有数据寄存器,不需要外加电路就可以直接与微型计算机接口。另一类芯片内部没有数据寄存器,输出信号随数据输入线的状态变化而变化,因此不能直接与微型计算机接口,必须通过并行接口与微型计算机接口。DAC0832是具有20条引线的双列直插式CMOS器件,它内部具有两级数据寄存器,完成8位电流D/A转换,故不需要外加电路。0832是电流输出型,示波器上显示波形,通常需要电压信号,电流信号到电压信号的转换可以由运算放大器LM358实现,用两片LM358可以实现双极性输出。
单片机向0832发送数字编码,产生不同的输出。先利用采样定理对各波形进行抽样,然后把各采样值进行编码,的到的数字量存入各个波形表,执行程序时通过查表方法依次取出,经过D/A转换后输出就可以得到波形。假如N个点构成波形的一个周期,则0832输出N个样值点后,样值点形成运动轨迹,即一个周期。重复输出N个点,成为第二个周期。利用单片机的晶振控制输出周期的速度,也就是控制了输出的波形的频率。这样就控制了输出的波形及其幅值和频率。
四、 软件设计
主程序和子程序都存放在AT89S51单片机中。
主程序的功能是:开机以后负责查键,即做键盘扫描及显示工作,然后根据用户所按的键转到相应的子程序进行处理,主程序框图如图1所示。
子程序的功能有:幅值输入处理、频率输入处理、正弦波输出、锯齿波输出、方波输出、显示等。
下面是程序
include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit LCP=P2^2
sbit SCP=P2^1
sbit SI=P2^0
sbit S1=P2^3
sbit S2=P2^4
sbit S3=P2^5
sbit S4=P2^6
sbit S5=P2^7
sbit DA0832=P3^3
sbit DA0832_ON=P3^2
uchar fun=0,b=0,c=0,d=0,tl,th
uchar code tab[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}
uchar code tosin[256]={0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,0x99,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,0xb1,0xb4,0xb7,0xba,0xbc,0xbf,0xc2,0xc5
,0xc7,0xca,0xcc,0xcf,0xd1,0xd4,0xd6,0xd8,0xda,0xdd,0xdf,0xe1,0xe3,0xe5,0xe7,0xe9,0xea,0xec,0xee,0xef,0xf1,0xf2,0xf4,0xf5
,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd
,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf2,0xf1,0xef,0xee,0xec,0xea,0xe9,0xe7,0xe5,0xe3,0xe1,0xde,0xdd,0xda
,0xd8,0xd6,0xd4,0xd1,0xcf,0xcc,0xca,0xc7,0xc5,0xc2,0xbf,0xbc,0xba,0xb7,0xb4,0xb1,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x99
,0x96,0x93,0x90,0x8d,0x89,0x86,0x83,0x80,0x80,0x7c,0x79,0x76,0x72,0x6f,0x6c,0x69,0x66,0x63,0x60,0x5d,0x5a,0x57,0x55,0x51
,0x4e,0x4c,0x48,0x45,0x43,0x40,0x3d,0x3a,0x38,0x35,0x33,0x30,0x2e,0x2b,0x29,0x27,0x25,0x22,0x20,0x1e,0x1c,0x1a,0x18,0x16
,0x15,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02 ,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0d,0x0e,0x10,0x11,0x13,0x15
,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x25,0x27,0x29,0x2b,0x2e,0x30,0x33,0x35,0x38,0x3a,0x3d,0x40,0x43,0x45,0x48,0x4c,0x4e
,0x51,0x55,0x57,0x5a,0x5d,0x60,0x63,0x66 ,0x69,0x6c,0x6f,0x72,0x76,0x79,0x7c,0x80 }
void display(unsigned char command)
{
unsigned char i
LCP=0
for(i=8i>0i--)
{
SCP=0
if((command &0x80)==0)
{
SI=0
}
else
{
SI=1
}
command<<=1
SCP=1
}
LCP=1
}
void key1(void)
{
fun++
if(fun==4)
fun=0x00
}
void key2(void)
{
tl++
if(tl==0x1f)
th++
}
void key3(void)
{
tl--
if(tl==0x00)
th--
}
void key4(void)
{
double t
int f
TR0=0
t=(65535-th*256-tl)*0.4
f=(int)(1000/t)
S3=tab[f%10]
f=f/10
S2=tab[f%10]
f=f/10
if(f==0)
S1=0
else
S1=tab[f]
TR0=1
}
void key5(void)
{
tl--
if(tl==0x00)
th++
}
void judge(void)
{
uchar line,row,de1,de2,keym
P1=0x0f
keym=P1
if(keym==0x0f)return
for(de1=0de1<200de1++)
for(de2=0de2<125de2++){}
P1=0x0f
keym=P1
if(keym==0x0f)return
P1=0x0f
line=P1
P1=0xf0
row=P1
line=line+row/*存放特征键值*/
if(line==0xde)key1()
if(line==0x7e)key2()
if(line==0xbd)key3()
if(line==0x7d)key4()
}
void time0_int(void) interrupt 1 //中断服务程序
{
TR0=0
if(fun==1)
{
DA0832=tosin[b]//正弦波
b++
}
else if(fun==2) //锯齿波
{
if(c<128)
DA0832=c
else
DA0832=255-c
c++
}
else if(fun==3) // 方波
{
d++
if(d<=128)
DA0832=0x00
else
DA0832=0xff
}
TH0=th
TL0=tl
TR0=1
}
void main(void)
{
TMOD=0X01
TR0=1
th=0xff
tl=0xd0
TH0=th
TL0=tl
ET0=1
EA=1
while(1)
{
display()
judge()
}
}
五、心得体会
开始的时候由于没有经验,不知如何下手,所以就去图书管找了一些书看,尽管有许多的设计方案,可是总感觉自己还是有许多的东西弄不太清楚,于是就请教同学。他常做一些设计,有一些经验。经过他的解释分析各方案之后,决定用查表的方法来做。这样可以降低一些硬件设计的难度,初次设计应切合自己的水平。用8031需要扩展ROM,这样还要进行存储器扩展。而且现在8031实际中已经基本上不再使用,实际用的AT89S51芯片有ROM,这样把经过采样得到的数值制成表,利用查表来做就简单了。我认为程序应该不大,片内ROM应该够用的。用LED显示频率和幅值,现有集成的接口驱动芯片,波形可通过示波器进行显示,单片机接上D/A转换芯片即可,这样硬件很快就搭好了。
我以为这些做好了,构思也有了,写程序应该是相对容易的。谁知道,写起程序来,才想到功能键要有扫描程序才行呀,我真的感到很难。那时真的有点想放弃?于是就去请教了老师,老师帮忙分析了一下,自己又查阅了一些资料,终于明白了扫描程序怎么写。
于是在自己的努力下,程序很快就写好了。这次是我的第一个设计器件,尽管经历了不少的艰辛,但给我积累了一点设计的经验,最后也有点小小的成就感。后面的路还很长,我还的努力!
参考文献
[1] 童诗白,华成英.模拟电子技术基础〔M〕.北京:高等教育出版社,2003.345-362
[2] 潘永雄,沙河,刘向阳.电子线路CAD实用教程〔M〕.西安:西安电子科技大学出版社,2001.13-118.
[3] 张毅刚,彭喜源,谭晓昀,曲春波.MCS-51单片机应用设计[M].哈尔滨:哈
尔滨工业大学出版社,1997.53-61.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)