压控PWM信号发生器

单片机的课程设计NO.4

    程序功能

    1、ADC0808采集一路0~5V的直流信号

    2、生成频率100Hz的PWM信号,占空比与采集到的直流信号电压成正比

    3、LCD1602显示当前采集到的电压值与输出PWM的占空比

    4、DAC0832输出一路0~5V正弦信号,频率值(1~9)/10Hz

    5、向上位机传输当前采集到的电压值与PWM占空比

    6、由上位机控制输出正弦信号的频率

项目代码



/*上位机操作指令*/
/*
	指令	作用
	0		单片机停止发送
	1		
	2		显示实时测量值
	3		改变DAC0832产生正弦信号的频率(在此之后输入频率)
*/

/*	----------------------------

	程序功能

	1、ADC0808采集一路0~5V的直流信号

	2、生成频率100Hz的PWM信号,占空比与采集到的直流信号电压成正比

	3、LCD1602显示当前采集到的电压值与输出PWM的占空比

	4、DAC0832输出一路0~5V正弦信号,频率值(1~9)/10Hz

	5、向上位机传输当前采集到的电压值与PWM占空比

	6、由上位机控制输出正弦信号的频率

	----------------------------*/
#include<reg52.h>
#include<intrins.h>			//包含_nop_()空函数指令的头文件
#include<string.h>
#define uchar unsigned char
#define uint unsigned int
#define out P2

sbit CS=P1^1; 				//DAC0832片选端
sbit WR1=P1^2;				//DAC0832WR1端
sbit PWM=P1^4;				//PWM信号输出端
sbit RS = P1^5;				//LCD1602寄存器选择
sbit RW = P1^6;				//LCD1602读写操作选择
sbit E = P1^7;				//LCD1602使能信号
sbit START = P3^3;			//ADC0808启动信号
sbit Clock = P3^4;		//74HC595移位信号
sbit Data = P3^5;		//74HC595数据输出
sbit Lock = P3^6;		//74HC595锁存信号
sbit OE=P3^7;		    ///ADC0808转换结果输出允许端

bit flag_timer=0;			//当flag_timer=0时,中断程序T0调用timer[0]~timer[3],change_timer函数重装timer[4]~timer[7],反之调换
bit flag_volt=0;		   	//ADC测量结束标志
bit flag_fre=0;				//DAC频率输入标志

uchar code seg[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
uchar const code await_f[]="Please enter frequency(n/10Hz):(1~9)\n";
uchar Sin[]="sin:0.00V ",Pwm[]="PWM:00%",measure[20];
uchar send_mode=0;
uchar ac_data=0;	   	//数字量
uint ac_volt=0;		//电压值
uchar Fre = 1;		//DA正弦频率
uchar timer[8];	//timer[0]=HighTH0,timer[1]=HighTL0
				//timer[2]=LowTH0,timer[3]=LowTL0
				//timer[4]=HighTH1,timer[5]=HighTL1
				//timer[6]=LowTH1,timer[7]=LowTL1
				//上述TH0/TL0和TH1/TL1均为计时器T0的预装载值,两组预装载值交替使用,一组使用时另一组进行计算和重装
uchar const code sin_tab[256]={
0x80,0x83,0x86,0x89,0x8C,0x8F,0x92,0x95,0x98,0x9B,
0x9E,0xA1,0xA4,0xA7,0xAA,0xAD,0xB0,0xB3,0xB6,0xB9,
0xBC,0xBE,0xC1,0xC4,0xC6,0xC9,0xCB,0xCE,0xD0,0xD3,
0xD5,0xD7,0xDA,0xDC,0xDE,0xE0,0xE2,0xE4,0xE6,0xE8,
0xE9,0xEB,0xED,0xEE,0xF0,0xF1,0xF3,0xF4,0xF5,0xF6,
0xF8,0xF9,0xF9,0xFA,0xFB,0xFC,0xFD,0xFD,0xFE,0xFE,
0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,
0xFE,0xFD,0xFD,0xFC,0xFB,0xFA,0xFA,0xF9,0xF8,0xF7,
0xF5,0xF4,0xF3,0xF1,0xF0,0xEF,0xED,0xEB,0xEA,0xE8,
0xE6,0xE4,0xE2,0xE0,0xDE,0xDC,0xDA,0xD8,0xD5,0xD3,
0xD1,0xCE,0xCC,0xC9,0xC6,0xC4,0xC1,0xBE,0xBC,0xB9,
0xB6,0xB3,0xB0,0xAE,0xAB,0xA8,0xA5,0xA2,0x9F,0x9C,
0x99,0x95,0x92,0x8F,0x8C,0x89,0x86,0x83,0x80,0x7D,
0x79,0x76,0x73,0x70,0x6D,0x6A,0x67,0x64,0x61,0x5E,
0x5B,0x58,0x55,0x52,0x4F,0x4C,0x49,0x46,0x44,0x41,
0x3E,0x3B,0x39,0x36,0x34,0x31,0x2F,0x2C,0x2A,0x28,
0x26,0x23,0x21,0x1F,0x1D,0x1B,0x19,0x17,0x16,0x14,
0x12,0x11,0x0F,0x0E,0x0C,0x0B,0x0A,0x09,0x08,0x07,
0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x02,
0x02,0x03,0x04,0x05,0x05,0x06,0x07,0x08,0x0A,0x0B,
0x0C,0x0D,0x0F,0x10,0x12,0x14,0x15,0x17,0x19,0x1B,
0x1D,0x1F,0x21,0x23,0x25,0x27,0x2A,0x2C,0x2E,0x31,
0x33,0x36,0x38,0x3B,0x3E,0x40,0x43,0x46,0x49,0x4B,
0x4E,0x51,0x54,0x57,0x5A,0x5D,0x60,0x63,0x66,0x69,
0x6C,0x6F,0x73,0x76,0x79,0x7C};


void change_timer(uchar dc);	//刷新计时器预装值函数
void lcd_initial(void);		//LCD初始化函数
void check_busy(void);		//检查忙标志函数
void write_command(uchar com);		//写命令函数
void write_data(uchar dat);			//写数据函数
void string(uchar ad,uchar *s);		//显示字符串函数
void delay(uint j);
void S_to_P(uchar message);		//串转并函数
void send(uchar *s);		//串口通信发送函数
void dacSIN();					//正弦波函数
void init_DAC0832();	 //DAC0832初始化
void main_initial(); //主函数初始化
void show_LCD();
void main(void)
{
  	uchar dc,i=0;
	main_initial();

	while(1)
	{
		if(flag_volt)
		{
			
			dc = ac_data*0.39;			 	//将采集到的二进制数转换成百分比
			ac_volt=ac_data*1.96;			//将采得的二进制数转换成可读的电压值

			change_timer(dc);				//依据占空比改变PWM占空比	
						
			Sin[4]=ac_volt/100+'0';
			Sin[6]=ac_volt/10%10+'0';
			Sin[7]=ac_volt%10+'0';
			Pwm[4]= dc/10+'0';			
			Pwm[5]= dc%10+'0';
										
			
			string(0x84,&Sin[4]);					 	//显示到LCD管上
			string(0xc4,&Pwm[4]);
			i++;
			if(i==5)
			{
				strcpy(measure,Sin);		  //发送给上位机
				strcat(measure,Pwm);
				strcat(measure,"\n");
				TI = 1;	
				i=0;
			}	
			
				
			flag_volt = 0;
		}
	}
}

/* ---------------------------

	 主函数初始化函数

----------------------------*/
void main_initial()
{
	init_DAC0832();	    
	lcd_initial();
	string(0x80,Sin);					 	//显示到LCD管上
	string(0xc0,Pwm);
	TMOD = 0X21;	   	//设置T0、T1的工作方式
	CP_RL2=0;EXEN2=0;	//设置T2为16位自动重装载定时器工作方式	
	change_timer(50);	//为timer赋初值(占空比50)
	flag_timer=!flag_timer;
	TH0 = timer[0+flag_timer*4];
	TL0 = timer[1+flag_timer*4];
	TH1 = 0XFD;			//波特率9600
	TL1 = 0XFD;
	TH2 = RCAP2H = (65536-3906)/256;
	TL2 = RCAP2L = (65536-3906)%256;
	SCON = 0X50;	
	PCON = 0X00;
	EA = 1;			//中断总允许
	ES = 1;			//收发中断源允许
	ET0 = 1;		//T0中断允许 	
	ET2 = 1;		//T2中断允许
	EX0 = 1;		//INT0中断允许
	IT0 = 1; 		//INT0中断下跳沿触发
	TR0 = 1;		//T0计时器开启
	TR1 = 1;		//T1计时器开启
	TR2 = 1;		//T2计时器开启
	START = 0;
 	START = 1;	 	//启动模数转换
	START = 0;
	send_mode=1;

}

/* ---------------------------

	PWM占空比预装载函数

----------------------------*/
void change_timer(uchar dc)		//对timer[]进行重装
{
	uint temp;
	static uint freq = 100;	  	//PWM频率为100Hz
	temp=65535 - 12000000/12/freq*dc/100;	
	timer[0+!flag_timer*4]=(uchar)(temp>>8);
	timer[1+!flag_timer*4]=(uchar)temp;
	temp=65535 - 12000000/12/freq*(100-dc)/100;
	timer[2+!flag_timer*4]=(uchar)(temp>>8);
	timer[3+!flag_timer*4]=(uchar)temp;
}

/* ---------------------------

   	 PWM生成函数	

----------------------------*/
void TO_Interrupt()		interrupt 1		//生成PWM波
{
	if(PWM==0)
	{
		PWM = 1;
		flag_timer=!flag_timer;			//交换timer[]读写区域
		TH0 = timer[0+flag_timer*4];
		TL0 = timer[1+flag_timer*4];
 		START = 1;	
		START = 0;						//PWM上升沿启动模数转换
	}
	else
	{
		PWM = 0;
		TH0 = timer[2+flag_timer*4];
		TL0 = timer[3+flag_timer*4];
	}
	
}
/* ---------------------------

   	ADC0808电压采集函数

----------------------------*/
void INTO_Interrupt()		interrupt 0		//采集电压
{
	OE = 1;
	ac_data = P0;
	flag_volt = 1;
	OE = 0;			
}
/* ---------------------------

   	DAC0832正弦信号生成函数

----------------------------*/
void T2_INT(void)	interrupt 5
{
	TF2 = 0;		//复位中断标志位TF2
	dacSIN();
}


 
 
void dacSIN()		//正弦波函数
{
	static uchar i=0;
	S_to_P(sin_tab[i]);
	i++;			//自动溢出
}
void S_to_P(uchar message)		//串转并			
{
	uchar i,temp = 0x80;
	for(i = 0;i<8;i++)				
	{
		if( message&(temp>>i) )	//按位分解
			Data = 1;
		else
			Data = 0;
		Clock = 0;
		Clock = 1;		//移位
	}
	Lock = 0;
	Lock = 1;		//锁存
}

void init_DAC0832()	 //DAC0832初始化
{
	CS=0;
	WR1=0;
}

/* ---------------------------

   	上下位机通信函数

----------------------------*/
void TRX_Interrupt() interrupt 4				//串口中断 
{
	static uchar temp=0;
	if(RI)				 //接收程序	  	
	{
	 	RI = 0;	
		temp = SBUF;
		if((temp>='0')&&(temp<='9'))
		{
			if(!flag_fre)
			{			
				send_mode=temp-'0';
				if(send_mode==3)
					flag_fre=1;
			}
			else
			{
				Fre=temp-'0';
				RCAP2H=(65536-1000000/256/Fre*10)/256;
				RCAP2L=(65536-1000000/256/Fre*10)%256;
				flag_fre=0;
				send_mode=2;
			}
		}			  																
    }

	if(TI)				//发送程序	
	{
		TI = 0;
		if(send_mode==2)
			send(measure);						 
		else if(send_mode==3)
			send(await_f);

	}
}

void send(uchar *s)		//串口发送函数
{
	static uchar i=0;
	if(*(s+i))
	{
		SBUF=*(s+i);
		i++;
	}
	else 	   //当一个字符串发送完毕后会进入这里
	{
		i=0;
		if(send_mode==2);
		else
			send_mode=0;
	}			 	
}





/* ---------------------------

   	LCD1602显示函数

----------------------------*/
void delay(uint j)				//延时函数
{
	uchar i = 250;
	for(;j>0;j--)
	{
		while(--i);
		i=249;
		while(--i);
		i=250;
	}
}


void check_busy(void)		//检查忙标志函数
{
	uchar dt;
	do
	{
		dt = 0xff;
		E = 0;
		RS = 0;
		RW = 1;
		E = 1;
		dt = out;
	}while(dt&0x80);
	E = 0;
}

void write_command(uchar com)			//写命令函数
{
	check_busy();
	E = 0;
	RS = 0;
	RW = 0;
	out = com;
	E = 1;
	_nop_();
	E = 0;
	delay(1);
}

void write_data(uchar dat)			//写显示数据函数
{
	check_busy();
	E = 0;
	RS = 1;
	RW = 0;
	out = dat;
	E = 1;
	_nop_();
	E = 0;
}

void lcd_initial(void)		//LCD初始化函数
{
	write_command(0x38);			//写入命令0x38:8位两行显示,5*7点阵字符
	write_command(0x0c);			//写入命令0xc:开整体显示,光标关,无闪烁
	write_command(0x06);			//写入命令0x06:光标右移
	write_command(0x01);			//写入命令0x01:清屏
	delay(1);
}

void string (uchar ad,uchar *s)				//输出显示字符串的函数
{
	write_command(ad);
	while(*s>0)
	{
		write_data(*s++);
	}
}

 电路原理图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值