《单片机课程设计说明书》-占空比可调信号发生器

《单片机课程设计说明书》-占空比可调信号发生器
《单片机课程设计说明书》-占空比可调信号发生器

占空比可调信号发生器

1 软件介绍

1.1proteus软件

Proteus ISIS是英国Labcenter公司开发的电路分析与实物仿真软件。它运行于Windows操作系统上,可以仿真、分析(SPICE)各种模拟器件和集成电路,该软件的特点是:(1)实现了单片机仿真和SPICE电路仿真相结合。具有模拟电路仿真、数字电路仿真、单片机及其外围电路组成的系统的仿真、RS232动态仿真、I2C调试器、SPI调试器、键盘和LCD系统仿真的功能;有各种虚拟仪器,如示波器、逻辑分析仪、信号发生器等。

(2)支持主流单片机系统的仿真。目前支持的单片机类型有:68000系列、8051系列、AVR系列、PIC12系列、PIC16系列、PIC18系列、Z80系列、HC11系列以及各种外围芯片。

(3) 提供软件调试功能。在硬件仿真系统中具有全速、单步、设置断点等调试功能,同时可以观察各个变量、寄存器等的当前状态,因此在该软件仿真系统中,也必须具有这些功能;同时支持第三方的软件编译和调试环境,如Keil C51 uVision2等软件。

(4) 具有强大的原理图绘制功能。总之,该软件是一款集单片机和SPICE分析于一身的仿真软件,功能极其强大。本章介绍Proteus ISIS软件的工作环境和一些基本操作。

特点:支持ARM7,PIC ,AVR,HC11以及8051系列的微处理器CPU模型,更多模型正在开发中:

交互外设模型有LCD显示、RS232终端、通用键盘、开关、按钮、LED等;

强大的调试功能,如访问寄存器与内存,设置断点和单步运行模式;

支持如IAR、Keil和Hitech等开发工具的源码C和汇编的调试;

一键“make”特性:一个键完成编译与仿真操作;

内置超过6000标准SPICE模型,完全兼容制造商提供的SPICE模型;

DLL界面为应用提供特定的模式;

基于工业标准的SPICE3F5混合模型电路仿真器

14种虚拟仪器:示波器、逻辑分析仪、信号发生器、规程分析仪等;

高级仿真包含强大的基于图形的分析功能:模拟、数字和混合瞬时图形;频率;转换;

噪声;失真;付立叶;交流、直流和音频曲线;

模拟信号发生器包括直流、正旋、脉冲、分段线性、音频、指数、单频FM;数字信号

发生器包括尖脉冲、脉冲、时钟和码流;

集成PROTEUS PCB设计形成完整的电子设计系统。

1.2Keil软件

Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起。运行Keil软件需要WIN98、NT、WIN2000、WINXP等操作系统。如果你使用C语言编程,那么Keil几乎就是你的不二之选,即使不使用C语言而仅用汇编语言编程,其方便易用的集成环境、强大的软件仿真调试工具也会令你事半功倍。

Keil C51开发系统基本知识Keil C51开发系统基本知识

(1)系统概述

Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。下面详细介绍Keil C51开发系统各部分功能和使用。

(2)Keil C51单片机软件开发系统的整体结构

C51工具包的整体结构,uVision与Ishell分别是C51 for Windows和for Dos的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程。开发人员可用IDE本身或其它编辑器编辑C或汇编源文件。然后分别由C51及C51编译器编译生成目标文件(.OBJ)。目标文件可由LIB51创建生成库文件,也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS)。ABS文件由OH51转换成标准的Hex文件,以供调试器dScope51或tScope51使用进行源代码级调试,也可由仿真器使用直接对目标板进行调试,也可以直接写入程序存贮器如EPROM中。

Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。

2设计原理及方法

2.1 定时器、的工作原理

定时/计数器实质上是一个加1计数器,它可以工作于定时方式,也可以工作于计数方式,两种工作方式实际是对脉冲计数,只不过是所计脉冲来源不同。定时/计数器的内部结构和控制信号如下图2.1.1所示。

图2.1.1定时器/计数器内部结构和控制信号

当其工作于定时方式时, =0,开关S打向上,计数器,的计数脉冲来自振荡器的12分频后的脉冲(即/12),即对系统的机器周期计数。档开关K受控合上时,每过一个周期,计数器,加1;当记满了预设的个数,,回零,置位定时/计数器溢出中断标志位,产生溢出中断。定时/计数器亦是如此。

工作方式寄存器TMOD(地址:89H)为8位寄存器,用于设置定时/计数器的工作方式,低四位用于,高四位用于。其格式如下表2.1.1所示。

表2.1.1 定时/计数器方式控制寄存器TMOD

GATE C/T M1 M0 GATE C/T M1 M0 GATE:门控位。GATE=0时,只要用软件使TCON中的为1,就可以启动定时/计数器工作;GATA=1时,要用软件使为1,同时外部中断引脚也为高电平时,才能启动定时/计数器工作。即此时定时器的启动多了一条件。

:定时/计数模式选择位。=0为定时模式; =1为计数模式。

:工作方式设置位。定时/计数器有四种工作方式,由进行设置。

C/T

C/T C/T C/T

定时/计数器控制寄存器TCON(地址88H)设置如下表2.1.3所示。

表2.1.3 定时/计数器控制寄存器TCON

在TCON寄存器中,定时/计数器的控制仅用了其中的高四位。

:溢出中断请求标志位。,计数溢出时由硬件自动置为1。CPU响应中断后由硬件自动清0。工作时,CPU可随时查询的状态。所以,可用作查询测试的标志。也可以用软件置1或清0,同硬件置1或清0的效果一样。

:运行控制位。置1时,开始工作;置0时,停止工作。由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。

:溢出中断请求标志位,其功能与类同。

:运行控制位,其功能与类同。

定时/计数器工作方式设置如下表2.1.2所示。

表2.1.2 定时/计数器工作方式设置表

M1M0 工作方式说明

00 方式0 13位定时/计数器

01 方式1 16位定时/计数器

10 方式2 8自动重装定时/计数器

11 方式3 分成两个独立的8位定时/计数器;此方式停止计数

方式0为13位计数,由的低5位(高3位未用)和的8位组成,最大计数值为(8192个脉冲)。启动后计数器加1计数。的低5位计数满回零后向进位,当13位计数满回零时,中断溢出位置1,产生中断请求。

定时器模式时有:N=t/ Tcy

计数初值计算的公式为:

定时器的初值还可以采用计数个数直接取补法获得。

方式1和方式0基本相同,唯一的区别是方式1的计数位数是16位,由作为低8位、作为高8位,组成了16位加1计数器。其最大计数值为(65536个脉冲),是几种方式中计数值最大的方式。

计数个数与计数初值的关系为:

13

X=2-N

16

X=2-N

方式2为自动重装初值的8位计数方式。在这种方式下,在和两个寄存器中,专用于寄存8位计数初值并保持不变,进行8位加1计数,当

计数溢出时,

除产生溢出中断请求外,还自动将

中不变的初值重新装载到

计数个数与计数初值的关系为:

方式3只适用于定时/计数器,定时器处于方式3时相当于=0,停止计数。

工作方式3将

分成为两个独立的8位计数器

2.2 定时器的工作原理

定时器/计数器

也是一个16 位定时器/计数器。除了具备定时/计数器

的定

时计数功能外,还具有16位自动重装载、捕获方式和加、减计数方式。所谓捕获方式,就是把16位瞬时计数值同时记录在特殊功能寄存器的RCAP2H 和RCAP2L 中,这样CPU 在读数值的时候,就避免了在读高字节时低字节在变化,从而引起误差。

定时/计数器

的内部结构和捕捉方式原理如图2.2.1所示。由图可见,除了具有

相同的定时计数结构外,增加了特殊功能寄存器的RCAP2H/RCAP2L

和控制位,在不同的工作方式下有不同的作用。

图2.2.1 定时/计数器

的内部结构和捕捉方式原理

引用了两个外部引脚和

作用如下:

(

):定时/计数器2的外部计数脉冲输入,定时脉冲输出。

(T2EX):定时/计数器2的捕捉/重装方式的触发和检测控制。

定时器

/计数器

控制寄存器T2CON (地址C8H )的设置如下表2.2.1所示。

8X=2-N

表2.2.1 定时/计数器控制寄存器T2CON

(MSB) (LSB) EXF2 RLCLK TCLK EXEN2 C/CP/RL2 :计数溢出标志位,当允许中断,将引起中断,必须软件清零。=1,有溢出;=0,无溢出。如果RCLK=1或TCLK=1,此位无效。

EXF2:的外部标志位。当外部使能位EXEN2=1,且T2EX(引脚)有一个下降沿产生,EXF2被置1,如果允许中断将引起中断,EXF2必须软件清零。

RCLK、TCLK:发送时钟、接收时钟允许。如果RCLK=1或TCLK=1,则8XX51的串行使用作为波特率发生器,分别产生发送时钟或接收时钟,两个可以分别控制。如果RCLK=0或TCLK=0,则定时器作为串行口波特率发生器。

:的启动控制标志;=0:停止;=1:启动

C/:定时计数器选择。只能通过软件的置位或清除;C/=0,工作于定时器方式,对/12的脉冲(机器周期)计数;C/=1,工作于计数器方式,对(引脚)外部输入脉冲的下降沿计数。

CP/RT2:捕获/重装方式选择,只能通过软件的置位或清除。CP/RT2=0时,工作于重装方式,RCAP2H,RCAP2L;CP/RT2=1时,工作于捕获方式,RCAP2H,RCAP2L。

定时器/计数器方式控制寄存器T2MOD(地址C9H)的设置如下表2.2.2所示。

表 2.2.2定时器/计数器方式控制寄存器T2MOD

(MSB) (LSB)

T2OE DCEN T2OE:输出允许位,T2OE=1,允许定时时钟输出到。T2OE=1,禁止定时时钟输出到。

DCEN:计数方式选择。DCEN=1,的计数方式由引脚状态分配:=1,减计数;=0,加计数。DCEN=0,计数方式与无关,同和一样,采用加计数方式。

的数据寄存器、和、的用法一样,而捕获寄存器RCAP2H、RCAP2L只是在捕获方式下,产生捕获操作时自动保存、的值。

定时器/计数器的工作方式见下表2.2.3所示。

表2.2.3定时器/计数器的工作方式

RCLK+TCLK CP/RL2 方式

0 0 1 X 0

1

X

X

1

1

1

16位自动重装

16位捕捉方式

波特率发生器

停止工作

自动捕捉方式下,如果从检测到一个下降沿,和的当前值就会被捕捉到RCAP2H 和RCAP2L中,同时使EXF2=1.如果允许中断,将产生中断。

自动重装方式1(DCEN=0)下,如果从检测到一个下降沿,RCAP2H和RCAP2L中的值就会被重装到和中,同时使EXF2=1。

自动重装方式2(DCEN=1)下,=1,减计数,当计数溢出时,和中自动重装为0FFH;=0,加计数,当计数溢出时,和中自动重装为RCAP2H和RCAP2L中的值。无论是加计数还是减计数,溢出时=1。

波特率发生器方式下,的计数脉冲可以由/2或输入。此时,RCAP2H和RCAP2L 中的值用做计数初值,溢出后此值自动装到和中。如果RCLK或TCLK中某值为1时,表示收发时钟一个用,一个用。在这种方式下,如果在检测到一个下降沿,则EXF2变为1,可引起中断。

(波特率)==

时钟输出方式

的溢出脉冲从输出。输出脉冲频率由下式决定:

=

2.3 设计方法

(1)方波的产生

在本设计方案中,采用的定时器产生频率和占空比可调的方波。对于工作方式0,工作方式1具有16位的寄存器,定时时间更长,产生的频率范围更宽。对比于工作方式2,虽然方式2的自动重载功能使定时更加准确,但对于产生低频来说,方式2的只有256us 的定时时间,产生的中断多,误差更大,因此选择设置在工作方式1下,GATE=0。

设定定时器设置初始值,即给高低电平分别分配定时时间。当程序启动,由输入给定高电平,定时器开始加1计数,当高电平16位计数满回零时,置1,产生中断,高电平转为低电平,当低电平16位计数满回零时,置1,产生中断,低电平再转为高电平,得出方波。

定时器初始值计算如下所示:

高电平初始值=-高电平时间

低电平初始值=-低电平时间

(2)高电平时间的测量

本设计方案中,采用定时器测量高电平的时间。将定时器设置在工作方式1下,并设置GATE=1,此时要用软件使为1,同时外部中断1(INT1)引脚也为高电平时,才能启动定时/计数器工作。所以将控制输出的方波接在外部中断1的输入引脚上,当输入高电平,定时器开始启动,在下降沿的时候,读、的值,同时将、

清零,即可算出高电平时间T1_high。

(3)频率的测量

在本设计方案中,采用定时器测量输出方波一周期的时间。将定时器设置在工作方式16位捕捉方式下,为了更加准确,在前两个下降沿的时候,先清、、、,当第三个下降沿来临的时候,读取RCAP2(即、)的值(相当于三个周期中只测量了一个周期)即为输出方波的周期T2。

综合(2)(3)上述,根据以下公式

f=1/T2

占空比=高电平时间/周期=T1_high/T2

由此测出所输出方波的频率和占空比。

3系统硬件线路设计图3.1仿真电路连线图

图3.1.1 仿真线路连接图3.2 实物连线图

图3.2.1 实物线路连接图

4 程序框图

图4.1 主程序框图

图4.2 定时器0中断程序框图

图4.3 定时器2中断程序框图

5 资源分配表

I/O口分配表如下表5.1所示。

表5.1 I/O口分配表

-、

液晶数据线捕捉方式

下方波信号

输入端液晶控制器键盘扫描方波输出测高电平

时方波输入

内部资源分配表如下表5.2所示。

表5.2 内部资源分配表

定时器定时器定时器

产生频率、占空比可调方波测量高电平的时间测量输出方波的周期6 源程序

函数声明:文件public.h

#include

#include

#define uchar unsigned char

#define uint unsigned int

void delay1ms(void);

void write_data(uchar date);

void write_com(uchar com);

void lcd_init();

void display_init();

void store_num();

void ok();

void refresh_time_0();

void refresh_duty();

void keycode_return();

uchar keyscan();

void init();

void dis_freq_futy();

主程序:文件main.c

#include"public.h"

sbit out=P3^0;//输出

sbit out2=P3^1;

sfr16 RCAP2 = 0xCA; //T2捕获寄存器

sfr T2MOD = 0xC9;

char th0_low,tl0_low,th0_high,tl0_high,th1_out,tl1_out;

float time0,freq_test,duty_test;

uchar freq_out_num[4],duty_test_num[3],vaule=1;

uint

freq=100,duty_factor=50,flag=1,time0_high,time0_low,high_count=0,low_count=0, count1,count2;

uint Last,Now,freq_test1=500,duty_test1=0;

void time_2() interrupt 5 //T2中断程序

{

if(EXF2)

{

if(vaule==2)

{

th1_out=TH1;

tl1_out=TL1;

EXF2=0;//外部标志位需要软件清零;

Now=RCAP2;

vaule=0;

}

else

{

EXF2=0;

vaule++;

TH2=TH1=0;

TL2=TL1=0;

}

}

else

{

TF2=0;

}

}

void time_0() interrupt 1 //T0中断程序{

if(flag==0)

{

TH0=th0_low;

TL0=tl0_low;

flag=1;

out=0;

out2=0;

}

else

{

TH0=th0_high;

TL0=tl0_high;

flag=0;

out=1;

out2=1;

}

}

void main()

{

init();

while(1)

{

keycode_return();

time0=1000000/freq; //不求time0直接求高低电平,可能精度高些

time0_high=time0/100*duty_factor; //高电平时间

time0_low=time0-time0_high; //低电平

high_count=low_count=0;

th0_high=(65536-time0_high)/256; // 高低电平的定时器初值

tl0_high=(65536-time0_high)%256;

th0_low=(65536-time0_low)/256;

tl0_low=(65536-time0_low)%256;

//************T2频率测量处理************************

// ET2=0;

freq_test=1000000/Now; //计算出频率值

//************T1占空比测量处理*********************

duty_test=th1_out*256+tl1_out;//计算T1计数值

duty_test=duty_test*1000/Now;//求百分比

// if(abs(duty_test-duty_factor)>1)

// duty_test+=600;

dis_freq_futy();

// ET2=1;

}

}

void dis_freq_futy()

{

uchar j;

//*************频率显示**************************** freq_test1=(uint)freq_test;

for(j=0;j<4;j++)

{

freq_out_num[j]=freq_test1%10;

freq_test1/=10;

}

write_com(0x95);

for(j=0;j<4;j++)

{

write_data(freq_out_num[3-j]+0x30);

}

//*************占空比显示************************** duty_test1=(uint)duty_test;

write_com(0x9d);

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

{

duty_test_num[j]=duty_test1%10;

duty_test1/=10;

}

for(j=0;j<2;j++)

{

write_data(duty_test_num[2-j]+0x30);

}

write_data('.');

write_data(duty_test_num[0]+0x30);

write_data('%');

}

void init()

{

display_init();

//***************************************************

//**************定时器0初始化************************

time0=1000000/freq; //不求time0直接求高低电平,可能精度高些

time0_high=time0/100*duty_factor; //高电平时间

time0_low=time0-time0_high; //低电平

TMOD=0x91;//设置工作方式GATE1 C/T M1 M0=1001;工作方式GATE0 C/T M1 M0=0001 th0_high=(65536-time0_high)/256; // 高低电平的定时器初值

tl0_high=(65536-time0_high)%256;

th0_low=(65536-time0_low)/256;//

tl0_low=(65536-time0_low)%256;

EA=1;

ET0=1;

TR0=1;

//****************************************************

//***************定时器2初始化************************

ET2=1;//开T2中断

T2MOD=0X00;

T2CON=0x0d;//16位捕获模式,定时,外部使能

TH2=0;

TL2=0;

//****************************************************

//****************定时器1初始化***********************

// ET1=1;//不开T1中断

TR1=1;

TH1=0;

TL1=0;

}

矩阵键盘程序:文件keycode.c

#include

uchar key,keycode;

extern freq,duty_factor;

uchar num[4],freq_num[4],duty_factor_num[2],n; uint freq1;

void delay(uint z)//4.476ms

{

uint x,y;

for(y=z;y>0;y--)

for(x=110;x>0;x--);

}

unsigned char code KeyTable[4][4]={

{'1','2','3','A'},

{'4','5','6','B'},

{'7','8','9','C'},

{'0','F','E','D'}};

//***键盘扫描*********//

uchar keyscan()

{

unsigned int row=0,column=0;

uchar key=0;

// EA=0;

P2=0xf0;

key=P2;

if(key!=0xf0){

delay(10);

key=P2;

if(key!=0xf0){

P2=key|0x0f;

switch(key)

{

case 0xe0:column=0;break;//1110

case 0xd0:column=1;break;//1101

case 0xb0:column=2;break;//1011

case 0x70:column=3;break;//0111 }

key=P2&0x0f;

switch(key)

{

case 0x0e:row=0;break;//1110

case 0x0d:row=1;break;//1101

case 0x0b:row=2;break;//1011

case 0x07:row=3;break;//0111

}

}

P2=0x0f;

key=P2;

while((key&0x0f)!=0x0f){key=P2;}

EA=0;

相关主题
相关文档
最新文档