OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7452|回复: 2

自己写的波形发生器+测试用的频率计

[复制链接]

1

主题

2

帖子

0

精华

新手入门

积分
26
金钱
26
注册时间
2013-7-16
在线时间
0 小时
发表于 2013-9-3 23:23:06 | 显示全部楼层 |阅读模式

简易波形发生器,可以测量输出频率,占空比可调。。。自己写来玩玩。。。


键盘设置频率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=0xf0ORTA=0xf0;//位码输出,AD输入 
  DDRB=0x0eORTB=0xff;//按键输入 蜂鸣器输出
  DDRC=0xffORTC=0xff;//段码输出
  DDRD=0xffORTD=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++;
}  

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165352
金钱
165352
注册时间
2010-12-1
在线时间
2108 小时
发表于 2013-9-4 11:32:23 | 显示全部楼层
回复 支持 反对

使用道具 举报

0

主题

16

帖子

0

精华

初级会员

Rank: 2

积分
191
金钱
191
注册时间
2012-8-27
在线时间
47 小时
发表于 2014-2-11 22:07:43 | 显示全部楼层
谢谢分享!!!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 04:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表