简易波形发生器,可以测量输出频率,占空比可调。。。自己写来玩玩。。。
键盘设置频率0~9999。。。
ad用来大幅度调节占空比。键盘可以步进调节占空比
#define F_CPU 16000000UL //16M晶振
#include <ioavr.h>
#include <intrinsics.h>
#define uchar unsigned char
#define uint unsigned int
static uchar flag=0;//模式标志位
static uint fre_out=0;//测量频率
static uint duty=50;//设置占空比
static uint cnt=0;//溢出累加值
static uchar choose_setduty=0;//选择占空比设置方式标记
//数码管0-9的数字编码
const uchar SEG_CODE[] =
{ 0xD7, //0
0x11, //1
0xCD, //2
0x5D, //3
0x1B, //4
0x5E, //5
0xDE, //6
0x15, //7
0xDF, //8
0x5F //9
};
uchar FRQ_DATA[]={5,0,0,0};//分解后的待显示输出频率数位
uchar FRQ_OUT[]={0,0,0,0};//分解后的待显示测量频率数位
uchar DUTY[]={0,0,5,0};//分解后的待显示占空比数位
//-----------------------------------------------------------------
// 数码管显示
//-----------------------------------------------------------------
void Show_DSY(uchar *x)
{
PORTC=0xff;
PORTA=0x00;
PORTA=0xef;
PORTC=~SEG_CODE[x[3]];
__delay_cycles(10000);
PORTC=0xff;
PORTA=0x00;
PORTA=0xdf;
PORTC=~SEG_CODE[x[2]];
__delay_cycles(10000);
PORTC=0xff;
PORTA=0x00;
PORTA=0xbf;
PORTC=~SEG_CODE[x[1]];
__delay_cycles(10000);
PORTC=0xff;
PORTA=0x00;
PORTA=0x7f;
PORTC=~SEG_CODE[x[0]];
__delay_cycles(10000);
}
//-----------------------------------------------------------------
// AD转换
//-----------------------------------------------------------------
uint AD_convert()
{
int i=0;
ADMUX=0xc0;//选择ADC0
i=(int)(ADC);//获得AD值
return i;
}
//------------------------------------------------------------------
// 占空比设置
//------------------------------------------------------------------
void AD_Set_Duty(uint i)
{
static uint pre_AD=0;
if(i!=pre_AD)
{
pre_AD=i;
if(i==1023) i=0;
else if(i==0) i=1023;
}
OCR1A=(uint)(ICR1/1023.0*i);//更新占空比
duty=(uint)(i/1023.0*100);
DUTY[0]=0;
DUTY[1]=0;
DUTY[2]=(duty-DUTY[0]*1000-DUTY[1]*100)/10;
DUTY[3]=duty%10;//分解设置的占空比得到数位
}
void Set_Duty(uint x)
{
DUTY[0]=0;
DUTY[1]=0;
DUTY[2]=(x-DUTY[0]*1000-DUTY[1]*100)/10;
DUTY[3]=x%10;//分解设置的占空比得到数位
OCR1A=(uint)(ICR1/100*x);//设置占空比
}
//------------------------------------------------------------------
// 频率设置
//------------------------------------------------------------------
void Set_Frequency()
{
uint fre=0;
fre=FRQ_DATA[0]*1000+FRQ_DATA[1]*100+FRQ_DATA[2]*10+FRQ_DATA[3];
if(fre<=500&&fre>30)
{
TCCR1B=0x13;//64分频
ICR1=F_CPU/(2*fre*64);
}
else if(fre>500)
{
TCCR1B=0x11;//无分频
ICR1=F_CPU/(2*fre);
}
else
{
TCCR1B=0x15;//1024分频
ICR1=F_CPU/(2*fre*1024);
}
}
//------------------------------------------------------------------
// 测量频率
//------------------------------------------------------------------
void Get_Frequency(uint x)
{
FRQ_OUT[0]=x/1000;
FRQ_OUT[1]=(x-FRQ_OUT[0]*1000)/100;
FRQ_OUT[2]=(x-FRQ_OUT[0]*1000-FRQ_OUT[1]*100)/10;
FRQ_OUT[3]=x%10;
}
//------------------------------------------------------------------
// 按键扫描
//------------------------------------------------------------------
void key()
{
static uchar i=0;
static uchar state=0xff;
if((PINB|0x0f)!=0xff)//判断PB高4位状态
{
state=(PINB|0x0f);//保存键值
while((PINB|0x0f)==state)
{
PORTB_Bit2=0;//按下响一下蜂鸣器
__delay_cycles(3000);
PORTB_Bit2=1;
}
switch(state)
{
case 0x7f:i=0;break;
case 0xbf:i=1;if(flag==1)
{
choose_setduty=~choose_setduty;//选择占空比设置方式
}break;
case 0xdf:i=2;break;
case 0xef:i=3;break;
case 0x3f:flag++;i=5;
if(flag==3)
{
flag=0;//一共三种模式
}break;
}
if(flag==0)//输出频率数位设置
{
FRQ_DATA=(FRQ_DATA+1)%10;
}
else if((flag==1) && (choose_setduty!=0))//输出占空比步进设置
{
if(i==2)
{
if(duty<100)
duty++;
}
if(i==3)
{
if(duty>0)
duty--;
}
}
}
}
//------------------------------------------------------------------
// 主程序
//------------------------------------------------------------------
int main()
{
uint x;
DDRA=0xf0 ORTA=0xf0;//位码输出,AD输入
DDRB=0x0e ORTB=0xff;//按键输入 蜂鸣器输出
DDRC=0xff ORTC=0xff;//段码输出
DDRD=0xff ORTD=0xff;//波形输出
ADCSRA=0xE6;//ADC转换置位,启动转换,64分频
__delay_cycles(3000);//延时等待系统稳定
TCCR1B=0x00;//停止定时器
TCNT1=0;//初始值
OCR1A=800;//占空比50%
ICR1=1600;//频率 16*10^6/(2*1*5000)=1600
TCCR1A=0x80;//相位与频率修正PWM TOP=ICR1
TCCR1B=0x11;//无分频
TCCR0=0x00;//停止定时器
TCNT0=0;
//TCCR0=0x07;//计脉冲数 上升沿触发
TCCR2=0x00;//停止定时器
TCNT2=131;//定时8ms
//TCCR2=0x07;//1024分频
TIMSK=0x41;//中断允许
SREG|=(1<<7); //使能全局中断
while(1)
{
key();
if(flag==0)
{
Set_Frequency();// 设置频率
Show_DSY(FRQ_DATA);//显示设置的频率
OCR1A=(uint)(ICR1/2);//保持占空比50%
}
else if(flag==1)//调节占空比
{
if(choose_setduty==0)//AD调节占空比
{
x=AD_convert();//AD转换
AD_Set_Duty(x); //AD设置占空比
}
else//按键调节占空比
{
Set_Duty(duty);//步进设置占空比
}
Show_DSY(DUTY);//显示设置的占空比
}
else if(flag==2)//开启测频模式
{
TCCR0=0x07;//计脉冲数 上升沿触发
TCCR2=0x07;//1024分频
Get_Frequency(fre_out);//分解测得频率数位给FRQ_OUT[4]
if(fre_out>9999)//频率超过9999报警
{
PORTB_Bit2=0;
__delay_cycles(3000);
PORTB_Bit2=1;
}
Show_DSY(FRQ_OUT);//显示测得频率
}
}
}
//-----------------------------------------------------------------
// TIM0计脉冲
//-----------------------------------------------------------------
#pragma vector = TIMER0_OVF_vect
__interrupt void TOver0_isr( void )
{
cnt++;//溢出累计
}
//-----------------------------------------------------------------
// TIM2定时1s
//-----------------------------------------------------------------
#pragma vector = TIMER2_OVF_vect
__interrupt void TOver2_isr( void )
{
static uint s=0;
uint sum=0;;
if(s==125)//计时1s 125*8ms=1s
{
s=0;
sum=cnt*256+TCNT0;//1s测到的脉冲
fre_out=sum;
cnt=0;//溢出清零
TCNT0=0;//计数器0清零
TCCR0=0x00;//关TIM0
TCCR2=0x00;//关TIM2
}
TCNT2=131;//计数器2重新赋值 8ms
s++;
}
|