用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++;
}
}