4通道方波发生器

用51单片机设计一个四通道脉冲发生器,要求每个方波频率、占空比、振幅可单独调节。
这里采用的方法是用定时器产生一个基础方波,在基础方波的基础上叠加方波上升沿下降沿从而实现频率可调。
不足之处:因为采用的是51单片机,方波的频率不会特别高。代码如下:

#include "reg52.h"
#include "absacc.h"
#include "stdio.h"
#include "math.h"
#include "intrins.h"


#define uchar unsigned char
#define unint unsigned int


/******************************/
sbit key0=P3^0;
sbit key1=P3^1;


sbit led2=P3^7;
sbit led1=P3^6;


/***********************************************************************/
//led数码管显示变量定义
/************************************************************************/

uchar digit;        //字位
uchar wordbuf[8];   //字型码缓冲区
bit showflag;        //数码管显示与否标志

/**************************************************/
//脉冲产生变量定义
/**************************************************/

sbit PWM_1 =  P1^1;
sbit PWM_2 =  P1^2;
sbit PWM_3 =  P1^2;
sbit PWM_4 =  P1^2;
sbit  PWM_out1 = P3^2;
sbit  PWM_out2 = P3^3;
sbit  PWM_out3 = P3^4;
sbit  PWM_out4 = P3^5;


int PWM_cnt1=0;
int PWM_cnt2=0;
int PWM_cnt3=0;
int PWM_cnt4=0;
int PWM_cnt=0;


unint N;
long out2_cnt=0,out4_cnt=0;
unint cnt=1;

bit ji_ou_0=0;
bit ji_ou_1=0;
bit ji_ou=0;
bit PWM_flag0=0;
bit PWM_flag1=0;
bit PWM_flag=0;
bit PWM_flag_=0;


int Zkb1=5,Zkb2=5,Delay1=5,Delay2=5;
int PWM_speed_l=1,PWM_speed_r=1;
int Timer0_val_h=0,Timer1_val_h=0,Timer0_val_l=0,Timer1_val_l=0;
bit For_Back=0,Erro_en=0;

/***********************************************************************/
//键盘扫描函数声明
/************************************************************************/

//矩阵键盘按键特征码表
uchar code KeyCodeTable[]={0x12,0x22,0x42,0x82,0x14,0x24,0x44,0x84,0x18,0x28,0x48,0x88}; 
bit k0,k1;

/***********************************************************************/
//led数码管显示函数声明
/************************************************************************/
/*根据共阴极字型编码表获取0~9,A~B字型代码*/
uchar getcode(uchar i)
{
uchar p;
switch(i)
    {

    case 0: p=0x3f;
    break;
    case 1: p=0x06;
    break;
    case 2: p=0x5B;
    break;
    case 3: p=0x4f;
    break;
    case 4: p=0x66;
    break;
    case 5: p=0x6D;
    break;
    case 6: p=0x7D;
    break;
    case 7: p=0x07;
    break;
    case 8: p=0x7f;
    break;
    case 9: p=0x67;
    break;
    case 10: p=0x77;
    break;
    case 11: p=0x7C;
    break;
    case 12: p=0x39;
    break;
    case 13: p=0x5E;
    break;
    case 14: p=0x79;
    break;
    case 15: p=0x71;
    break;
    default: break;
}
return(p);
}


/*led显示初始化子程序*/
void  Led_display_Init(void)
{
    uchar j;
    digit=0x01;                   //从第一位数码管开始动态扫描
    /*刚加电时,显示*/
    for(j=0;j<8;j++)
        wordbuf[j]=j;
    showflag=1;                               //打开数码管显示

}

/*显示函数*/
void display(void)
{
uchar i;
switch(digit)
{
    case 1: i=0;break;
    case 2: i=1;break;
    case 4: i=2;break;
    case 8: i=3;break;
    case 16: i=4;break;
    case 32: i=5;break;
    case 64: i=6;break;
    case 128: i=7;break;
    default: break;
}

P0=0x00;                     //关闭显示 
P2=~digit;                      //送字位码
P0=getcode(wordbuf[i]);          //送字型码

if(digit<0x80)                   //共8位
 digit=digit*2;                  //左移一位
else
 digit=0x01;
}




/***********************************************************************/
//键盘扫描函数声明
/************************************************************************/


//延时
void DelayMS(unint x) 
{ 
uchar i; 
while(x--) for(i=0;i<200;i++); 
} 

//键盘扫描
uchar Keys_Scan() 
{ 
    uchar sCode,kCode,i,k; 
    //低4位置0,放入4行

    P1=0x0e;   

    //若低3位出现0,则有键按下

    if((P1&0xf0)!=0x00) 
    {   

     DelayMS(50); 
       //led2=~led2;
    if((P1&0xf0)!=0x0e) 
    { 
        sCode=0xfd; //行扫描码初值
        for(k=0;k<3;k++) //对3行分别进行扫描
            { 
            P1=sCode; 
            if((P1&0xf0)!=0xf0) 
                { 
                kCode=~P1; 


                for(i=0;i<12;i++) //查表得到按键序号并返回
                    if(kCode==KeyCodeTable[i]) 
                    return(i); 
                } 
            else 
                sCode=_crol_(sCode,1); 
            } 
    } 
    } 
    return(-1); 
}

//键盘扫描值利用
 void key_judge(uchar KeyNo)
    {
     switch(KeyNo)
     {
        //uchar Zkb1=50,Zkb2=50,Delay1=50,Delay2=50;
//uchar PWM_speed_l=5,PWM_speed_r=5;
//uchar Timer0_val_h,Timer1_val_h,Timer0_val_l,Timer1_val_l;

      case 0 : Delay1++ ;if(Delay1>=10) Delay1=1;break;
      case 1:  Delay1-- ;if(Delay1<=0) Delay1=9;break;
      case 2 :  PWM_speed_l++;if(PWM_speed_l>=100) PWM_speed_l=1 ;break;

      case 3 :  ;break;
      case 4 :  Delay2++ ;if(Delay2>=10) Delay2=1;break ;
      case 5 :  Delay2-- ;if(Delay2<=0) Delay2=9;break ;

      case 6 : PWM_speed_r++;if(PWM_speed_r>=100) PWM_speed_r=1  ;break;
      case 7 :  ;break;
      case 8 : Zkb1++;if(Zkb1>=10) Zkb1=1;break;

      case 9 : Zkb2++;if(Zkb2>=10) Zkb2=1 ;break;
      case 10 :  ;break;
      case 11:  ;break;

      default : break;
     }
    }

    void do_allkey(void)
    {

      Timer0_val_h = (1/(float)PWM_speed_l)*917*(Zkb1);//-10/(float)PWM_speed_l*Zkb1*Delay1/100;  //N=nms*1000/1.09 ; nms=1/PWM_speed*1000
      Timer0_val_l = (1/(float)PWM_speed_l)*917*((10-Zkb1));//-10/(float)PWM_speed_l*Zkb1*Delay1/100;
      Timer1_val_h = (1/(float)PWM_speed_r)*917*(Zkb2);//-10/(float)PWM_speed_r*Zkb2*Delay1/100;
      Timer1_val_l = (1/(float)PWM_speed_r)*917*((10-Zkb2));//-10/(float)PWM_speed_r*Zkb2*Delay1/100;//通过设定的每秒产生的波数来确定timer的初始值


    }


    //独立键盘扫描

     void Scan_selfkey(void)
     {
      if(key0==0)
      {
        DelayMS(5);
        if(key0==0)
        {
         k0=1;
         while(!key0);
        }
      }

      if(key1==0)
      {
        DelayMS(5);
        if(key1==0)
        {
        k1=1;
         while(!key1);
        }
      }


     }

    //独立键盘利用
     void do_selfkey(void)
     {
      if(k0==1)
      {
       k0=0;
       For_Back=~For_Back;

      }

     //
     if(k1==1)
      {
       k1=0;
       Erro_en=~Erro_en;
      }



     }
/**************************************************/
//脉冲产生函数声明
/**************************************************/



void Timer_0_1_Init(void)
{
 TMOD = 0x11;                      //工作在方式1,16位定时器  ,默认优先级0高

//TH0=-2000/256;              //重置2ms定时
//TL0=-2000%256;
 TH0 = (65536-(50*1000))/256;       //1
 TL0 = (65536-(50*1000))%256;

 //TH0 = 0xD8;        //10us
// TL0 = 0xF0;

 TH1 = (65536-(50*1000))/256;       //10us
 TL1 = (65536-(50*1000))%256;


 ET0 = 1;        //定时器0中断允许
 ET1 = 1;        //定时器1中断允许位     


}

void Timer_2_Init(void)
{
 T2MOD = 0x00;                      //工作在方式1,
 T2CON = 0X00;
 RCAP2H = (65536-2000)/256;
 RCAP2L = (65536-2000)%256;
 ET2 = 1;        //定时器2中断允许

}

void EXint_0_1_Init(void)
{

IE=0x8F; 
PT2=1; //中断优先
PT1=1; //中断优先
PT0=1; //中断优先

IT0=0; 
IT1=0;//低电平触发 

}





void Timer0(void) interrupt 1 
{

    TH0=(uchar)((65536-4587)/256);            //重置2ms定时
    TL0=(uchar)((65536-4587)%256);


     PWM_cnt1++;  
 if(ji_ou_0==0)
    {
        if(PWM_cnt1>=(20*Zkb1/PWM_speed_l))
        {
            PWM_out1=~PWM_out1;
            PWM_cnt1=0;

            PWM_flag0=1;

            ji_ou_0=1;
        }


    }

  if(ji_ou_0==1)
    {
        if(PWM_cnt1>=(20*(10-Zkb1)/PWM_speed_l))
        {
            PWM_out1=~PWM_out1;
            PWM_cnt1=0;  

            ji_ou_0=0;
        }                   

    }



    if(PWM_flag0==1)
        PWM_cnt2++;

 if(ji_ou_0==0)
    {
    if(PWM_cnt2>=(20*Zkb1*Delay1/PWM_speed_l)/10)
      {

       PWM_out2=~PWM_out2;   
       PWM_cnt2=0;

      // PWM_flag0=0;

       PWM_flag=1;  

          ji_ou_0=1;
      }

    }

  if(ji_ou_0==1)
    {
    if(PWM_cnt2>=(20*(10-Zkb1)*Delay1/PWM_speed_l)/10)
      {

       PWM_out2=~PWM_out2;   
       PWM_cnt2=0;
       PWM_flag0=0;
        ji_ou_0=0;
      }

    }

    if(PWM_flag==1)
        PWM_cnt++;


    if(PWM_cnt>=(20*Zkb1*Delay2/PWM_speed_l)/10);//+(200>>(PWM_speed_r-1))*Zkb2/10)
    {  
      PWM_flag_=1;
      PWM_cnt=0;
      PWM_flag=0;

        led1=~led1; 
    }


}


void Timer1(void) interrupt 3 
{

 TH1=(uchar)((65536-4587)/256);           //重置2ms定时
 TL1=(uchar)((65536-4587)%256);
    if(PWM_flag_==1)
      PWM_cnt3++;

    if(ji_ou_1==0)
           {
           if(PWM_flag_==1&&PWM_cnt3>=(20*(10-Zkb2)/PWM_speed_r))
           {
            PWM_out3=~PWM_out3;
            PWM_cnt3=0;

            PWM_flag_=0;
        //  PWM_flag=0;


            PWM_flag1=1;

            ji_ou_1=1;
          }
          }

    if(ji_ou_1==1)
           {
           if(PWM_flag_==1&&PWM_cnt3>=(20*Zkb2/PWM_speed_r))
           {
            PWM_out3=~PWM_out3;
            PWM_cnt3=0;            
          ji_ou_1=0;
          }
        }

  if(PWM_flag1==1)
        PWM_cnt4++;
    if(ji_ou_1==0)
    {
    if(PWM_flag1==1&&PWM_cnt4==(20*Zkb2*Delay1/PWM_speed_r)/10)
      {

       PWM_out4=~PWM_out4;   
       PWM_cnt4=0;
       PWM_flag1=0;

      }
      ji_ou_1=1;
    }

    if(ji_ou_1==1)
    {
    if(PWM_flag1==1&&PWM_cnt4==(20*(10-Zkb2)*Delay1/PWM_speed_r)/10)
      {

       PWM_out4=~PWM_out4;   
       PWM_cnt4=0;
       PWM_flag1=0;

      }
      ji_ou_1=0;
    }
  }







void Timer2(void) interrupt 5
{
 /*定时器0中断服务,2ms定时动态扫描显示  */
 TF2=0;
if(showflag==1)  //注意初值的设定******
        display();               //调用显示函数


}


void EX_INT0() interrupt 0 

{ 

 ET0=0;
 // DelayMS(10); 
 //led1 =~led1;



 ET0=1;

}

void EX_INT1() interrupt 2
{ 

 ET1=0;
 //DelayMS(10); 
 //led2 =~led2;

 ET1=1;
}




int main(void)
{
/*****局部变量*****/
 uchar P3_LED=0xFF; 
uchar KeyNo=-1; //按键序号,-1表示无按键


/*****寄存器变量*****/

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

 Timer_0_1_Init();
 //EXint_0_1_Init();
 Led_display_Init();
 Timer_2_Init();

 TR0 = 1;        //启动定时器0
 TR1 = 1;        //启动定时器1

 TR2 = 1;        //启动定时器2

 EA = 1;         //打开中断

 led2=1;
 led1=1;

 PWM_out1 = 1;
 PWM_out2 = 1;
 PWM_out3 = 0;
 PWM_out4 = 0;


 while(1)
 {
 /****键盘扫描*****/ 

    KeyNo=Keys_Scan(); //扫描键盘获取按键序号KeyNo    

    if(KeyNo!=-1)  
     { 
          key_judge(KeyNo);   //使用键盘扫描

    }   
     do_allkey();

  /********/

  /******显示使用******/
     wordbuf[7]= PWM_speed_l/10;
     wordbuf[6]= PWM_speed_l%10;
     wordbuf[5]= PWM_speed_r/10;
     wordbuf[4]= PWM_speed_r%10;
     wordbuf[3]= Zkb1;
     wordbuf[2]= Zkb2;  
     wordbuf[1]= Delay1; 
     wordbuf[0]= Delay2;       
  /****独立键盘扫描****/ 
  Scan_selfkey();
  do_selfkey();
   out2_cnt++;
   out4_cnt++;

  }


 }

































  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
方波/三角/正弦信号发生器(ICL8038) 该信号发生器采用了精密形发生器单片集成电路ICL8038。该电路能够产生高精度正弦方波,三角,所需外部元件少。频率可通过外部元件调节。ICL8038的正弦形失真=1%,三角线性失真=0.1%,占空比调节范围为2%~98%。 ICL8038的第10脚外接定时电容,该电容的容值决定了输出形的频率,电路中的定时电容从C1至C8决定了信号频率的十个倍频程,从500μF开始,依次减小十倍,直到5500pF,频率范围对应为0.05Hz~0.5 Hz~5Hz~50Hz~500Hz~5kHz~50kHz~500kHz。电路中的V1、R7、R8构成缓冲放大器,R9 为电位器,用于改变输出形的幅度。 附:基于ICL8038函数信号发生器的设计 本设计是以ICL8038 和AT89C2051 为核心设计的数控及扫频函数信号发生器。ICL8038 作为函数信号源 结合外围电路产生占空比和幅度可调的正弦方波、三角; 该函数信号发生器的频率可调范围为1~100kHz, 步进为0.1kHz, 形稳定, 无明显失真。 1.系统设计框图 如图1 为系统设计框图。本设计是利用键盘设置相应的频率值, 根据所设置频率段选择相应电容, 经计算获得相应数字量送数字电位器实现D/A 转换, 同时与参考电压( 本例为5.5V) 相加后形成数控调压去控制ICL8038 第8 脚, 这样即可由ICL8038 实现对应频率值的矩形、三角和正弦方波幅度经衰减后送单片机可测得信号源频率并由数码管显示。 2.电路原理图 图2 为电路原理图。其中AT89C2051 是8 位单片机, 其中: P1.4~P1.7、P1.2、P1.3、P3.0、P3.1 作为数 码显示; P3.3、P3.5 、P3.7 作为键盘输入口; P3.4 作为计数口, 用于测量信号源频率;P3.0~P3.2 作为数字电位器的SPI总线; P1.1、P1.0 可根据需要扩展继电器或模拟开关选择ICL8038第10 脚( CAP) 与第11 脚间的电容C。 MCP41010 是8 位字长的数字电位器, 采用三总线SPI 接口。/CS: 片选信号, 低电平有效; SCK:时钟信号输入端; SI: 串行数据输入端, 用于寄存器的选择及数据输入。MCP41010 可作为数字电位器, 也可以作为D/A 转换器, 本设计是将MCP41010 接成8 位字长的D/A 转换器, MCP41010 根据输入的串行数据, 对基准电压进行分压后由中间抽头输出模拟电压, 即VPWO =DN/256VREF ( 式中VREF=5V) 。 函数发生电路ICL8038, 图2所示是一个占空比和一个频率连续可调的函数发生电路。ICL8038是一种函数发生器集成块, 通过外围电路的设计, 可以产生高精密度的正弦方波、三角信号, 选择不同参数的外电阻和电容等器件, 可以获得频率在0.01Hz~300kHz 范围内的信号。通过调节RW2 可使占空比在2%~98%可调。第10 脚( CAP) 与第11 脚间的电容C 起到很重要的作用, 它的大小决定了输出信号频率的大小, 当C 确定后, 调节ICL8038 第8 脚的电压可改变信号源的输出频率。从ICL8038 引脚9(要接上拉电阻)输出的形经衰减后送单片机P3.4 进行频率测量。 正弦函数信号由三角函数信号经过非线性变换而获得。利用二极管的非线性特性, 可以将三角信号的上升和下降斜率逐次逼近正弦的斜率。ICL8038 中的非线性网络是由4 级击穿点的非线性逼近网络构成。一般说来, 逼近点越多得到的正弦效果越好, 失真度也越小, 在本芯片中N= 4, 失真度可以小于1。在实测中得到正弦信号的失真度可达0.5 左右。其精度效果相当满意。为了进一步减小正弦的失真度, 可采用图2 所示电路中两个电位器RW3 和RW4 所组成的电路, 调整它们可使正弦失真度减小。当然, 如果矩形的占空比不是50% , 矩形不再是方波, 引脚2 输出也就不再是正弦了。 图2 电路原理图 经实验发现, 在电路设计中接10 脚和11 脚的电容值和性能是整个电路的关键器件, 电容值的确定也就确定电路能产生的频率范围, 电容性能的好坏直接影响信号频率的稳定性、形的失真度, 由于该芯片是通过恒流源 对C 充放电来产生振荡的, 故振荡频率的稳定性就受到外接电容及恒流源电流的影响, 若要使输出频率稳定, 必须采用以下措施:外接电阻、电容的温度特性要好; 外部电源应稳定; 电容应选用漏电小、质量好的非极化电容器。 3.实验结果 当±12V 工作电源时, 输出频率如下表: 失真度情况, 实验数据如下表: 4.软件流程图 图3 为软件流程图。T0 设为计数器,T1 设为定时器(初值为5ms)。5ms 启动主循环, 主要用于键盘扫描及扫描显示, 图2 中K0 作为控制键, K1 作为调整键, K2 作为增加键; 上电时程序进入频率设置模式, 按一下K0 键程序进入数控模式, 按二下K0 键程序进入扫频模式, 按三下K0 键程序进入频率设置模式, 周而复始。在频率设置模式, 由K1 键和K2 键完成频率设置。 图3 软件流程图

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值