PWM信号脉宽测量

单片机课程设计NO.2

程序功能

测量PWM信号脉宽,并用1602显示

程序代码

IIC.C



/*********************IIC.c*************************************/
#include<reg51.h>
#include<IIC.h>

//延时:10us
void I2C_Delay10us()
{
	uchar a, b;
	for(b=1; b>0; b--)
	{
		for(a=2; a>0; a--);
	}
}

// 起始信号:在I2C_SCL时钟信号在高电平期间I2C_SDA信号产生一个下降沿
void I2C_Start()
{
	I2C_SDA = 1;
	I2C_Delay10us();
	I2C_SCL = 1;
	I2C_Delay10us();//建立时间是I2C_SDA保持时间>4.7us
	I2C_SDA = 0;
	I2C_Delay10us();//保持时间是>4us
	I2C_SCL = 0;			
	I2C_Delay10us();		
}

//终止信号:在I2C_SCL时钟信号高电平期间I2C_SDA信号产生一个上升沿
void I2C_Stop()
{
	I2C_SDA = 0;
	I2C_Delay10us();
	I2C_SCL = 1;
	I2C_Delay10us();//建立时间大于4.7us
	I2C_SDA = 1;
	I2C_Delay10us();		
}

//通过I2C发送一个字节。在I2C_SCL时钟信号高电平期间, 保持发送信号I2C_SDA保持稳定
uchar I2C_SendByte(uchar dat)
{
	uchar a = 0,b = 0;//最大255,一个机器周期为1us,最大延时255us。			
	for(a=0; a<8; a++)//要发送8位,从最高位开始
	{
		I2C_SDA = dat >> 7;	 //起始信号之后I2C_SCL=0,所以可以直接改变I2C_SDA信号
		dat = dat << 1;
		I2C_Delay10us();
		I2C_SCL = 1;
		I2C_Delay10us();//建立时间>4.7us
		I2C_SCL = 0;
		I2C_Delay10us();//时间大于4us		
	}
	I2C_SDA = 1;
	I2C_Delay10us();
	I2C_SCL = 1;
	while(I2C_SDA)//等待应答,也就是等待从设备把I2C_SDA拉低
	{
		b++;
		if(b > 200)	 //如果超过200us没有应答发送失败,或者为非应答,表示接收结束
		{
			I2C_SCL = 0;
			I2C_Delay10us();
			return 0;
		}
	}
	I2C_SCL = 0;
	I2C_Delay10us();
 	return 1;		
}

// 使用I2c读取一个字节
uchar I2C_ReadByte(uchar ack)
{
	uchar a = 0,dat = 0;
	I2C_SDA = 1;			//起始和发送一个字节之后I2C_SCL都是0
	I2C_Delay10us();
	for(a=0; a<8; a++)//接收8个字节
	{
		I2C_SCL = 1;
		I2C_Delay10us();
		dat <<= 1;
		dat |= I2C_SDA;
		I2C_Delay10us();
		I2C_SCL = 0;
		I2C_Delay10us();
	}
	if(ack)		//回复A
	{
		I2C_SDA=0;		
		I2C_SCL = 1;
		I2C_Delay10us();
		I2C_SCL = 0;
		I2C_SDA=1;
		I2C_Delay10us();
	}
	else		//回复N
	{
		I2C_SDA=1;		
		I2C_SCL = 1;
		I2C_Delay10us();
		I2C_SCL = 0;
		I2C_Delay10us();
	}

	return dat;		
}


//通过IIC读取一个字符串
void ReadString(uchar ads,uchar *s,uchar num)	//读取地址(0x00),目的字符串指针,读取个数
{
	I2C_Start();
	I2C_SendByte(0xa0);
	I2C_SendByte(ads);
	I2C_Start();
	I2C_SendByte(0xa1);
	for(;num>0;num--)
		*s++=I2C_ReadByte(num);
	I2C_Stop();			 //读取	
}


//发送一个字符串到IIC
void SendString(uchar ads,uchar *s,uchar num)
{
	I2C_Start();
	I2C_SendByte(0xa0);
	I2C_SendByte(ads);
	for(;num>0;num--)
	{
		I2C_SendByte(*s++);
	}
	I2C_Stop();						  //存储

}

 IIC.H



/*********************IIC.h*************************************/
#define uchar unsigned char
#define uint unsigned int
//--定义使用的IO口--//
sbit I2C_SCL = P1^3;
sbit I2C_SDA = P1^4;

//--声明全局变量--//
void I2C_Delay10us();
void I2C_Start();           //起始信号:在I2C_SCL时钟信号在高电平期间I2C_SDA信号产生一个下降沿
void I2C_Stop();            //终止信号:在I2C_SCL时钟信号高电平期间I2C_SDA信号产生一个上升沿
uchar I2C_SendByte(uchar dat);	  //通过I2C发送一个字节。在I2C_SCL时钟信号高电平期间,保持发送信号I2C_SDA保持稳定
uchar I2C_ReadByte(uchar ack);     	 //使用I2c读取一个字节
//通过IIC读取和发送一个字符串
void ReadString(uchar ads,uchar *s,uchar num);	//读取地址(0x00),目的字符串指针,读取个数
void SendString(uchar ads,uchar *s,uchar num);

1602.C



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

   	LCD1602显示函数

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

#include<reg51.h>
#include<intrins.h>
#include<LCD1602.H>
#define uchar unsigned char
#define uint unsigned int




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);			//写入命令0x0c:开整体显示,光标关,无闪烁
	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++);
	}
}




1602.H



/*********************LCD1602.h*************************************/
#define uchar unsigned char
#define uint unsigned int
//--定义使用的IO口--//
#define out P2
sbit RS = P1^5;				//LCD1602寄存器选择
sbit RW = P1^6;				//LCD1602读写操作选择
sbit E = P1^7;				//LCD1602使能信号

//--声明全局变量--//
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);

 主函数


	/*
		项目名:PWM信号脉宽测量

		程序设计思路:
		INT0:
			1.利用INT0的高电平作为T0计时开启的条件(硬件实现);
			2.在INT0中断中读取计时时间;
		T0:
			用于脉宽计时;
		T1:
			用于产生PWM信号;
		T2:
			用于串口通信;
		
		脉宽计每50次测量刷新一次显示值,	
	*/		
				//进度:T2计时器无法手动装载,欲将其作为波特率发生器,与T1进行调换
#include<reg52.h>
#include<intrins.h>
#include<string.h>
#include<IIC.H>
#include<LCD1602.H>
#define FOSC 12000000	// 12000000      //System frequency
#define BAUD 9600       //UART baudrate


sbit TEXT = P1^0;
sbit PWM = P1^2;
uchar timeh,timel;	//用于提取脉宽计时器T0的数值
uchar GT1H;GT1L;DT1H;DT1L;	//定时器T1的预装值:高T1高位,高T1低位,低T1高位,低T1低位
uchar ideal_duty[2];		//理想的占空比,用于:1.接收上位机的占空比 2.发送给C02存储芯片 3.计算T1预装值
												
					    								  //0123456789012345678
uchar mark[]="Duty cycle:",Duty_cycle[]="00.00%",journal[]="100Hz 0000us 00.00% ";
uint pulse_width;	 //测量得外部信号的脉宽
bit renovate_flag,duty_flag;						 

void update_T1();

/*串口发送函数*/
void send(uchar *s);


void main( )
{
	lcd_initial(); 		//LCD初始化
	T2CON=0X34;	  	//设置T2为波特率发生器,开启T2计时器
	TMOD= 0X19;

	TL2 = RCAP2L = (65536-(FOSC/32/BAUD)); //Set auto-reload vaule
	TH2 = RCAP2H = (65536-(FOSC/32/BAUD)) >> 8;
  
	SCON = 0X50;	

	EA = 1;				//总中断开			
	ES = 1;				//串口中断开			

	TR0 = 1;			//计时器T0开启
	ET1 = 1;			//T1中断开启
	EX0 = 1;			//外部中断0开
	IT0 = 1;			//外部中断0下降沿触发

	ReadString(0x40,ideal_duty,2);

	update_T1();
	TR1 = 1;			//T1计时器开启

	while(1)
	{
		if(duty_flag)		 //刷新输出占空比
		{
			update_T1();
				   	
			SendString(0x40,ideal_duty,2);

			duty_flag=0;			
		}
		if(renovate_flag)				//刷新测量显示数值
		{	 
			pulse_width=timel+256*timeh;

			Duty_cycle[0]=(pulse_width/1000)%10+'0';
			Duty_cycle[1]=(pulse_width/100)%10+'0';
			Duty_cycle[3]=(pulse_width/10)%10+'0';
			Duty_cycle[4]=pulse_width%10+'0'-1;

			write_command(0x01);		//清屏
			string(0x80,mark);
			string(0xc0,Duty_cycle);
			 
			strncpy(&journal[6],Duty_cycle,2);
			journal[8]=Duty_cycle[3];
			journal[9]=Duty_cycle[4];
			strcpy(&journal[13],Duty_cycle); //书写日志
			TI=1;

			renovate_flag=0;
			
		}							
	}
}

void INT0_Interrupt()	 interrupt 0	//外部中断0,统计待测信号的脉冲宽度
{
	static uchar time=0;
	timel=TL0;
	timeh=TH0;	
	TH0=0;
	TL0=0;
	time++;
	if(time==50)
	{	
		time=0;	
		renovate_flag=1;
	}	
	
}
/* ---------------------------

   		PWM信号生成函数

----------------------------*/
void T1_INT(void)	interrupt 3
{
	if(PWM==0)
	{
		PWM = 1;
		TH1 = GT1H;
		TL1 = GT1L;
	}
	else
	{
		PWM = 0;
		TH1 = DT1H;
		TL1 = DT1L;
	}
}

void update_T1()
{
	static uchar duty;
	static uint temp,freq = 100;	  	//PWM频率为100Hz
	duty = (ideal_duty[0]-'0')*10+ideal_duty[1]-'0';	//计算占空比
	if(duty<1||duty>99)
	{
		duty = 20;
	}
	temp=65535 - FOSC/12/freq*duty/100+12;	 //高电平持续时间
	GT1H=(uchar)(temp>>8);
	GT1L=(uchar)temp;
	temp=65535 - FOSC/12/freq*(100-duty)/100;	  //低电平持续时间
	DT1H=(uchar)(temp>>8);
	DT1L=(uchar)temp;		
}


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

   	上下位机通信函数

----------------------------*/
void TRX_Interrupt() interrupt 4		//串口通信
{
	static temp=0;
	if(RI)				
	{
	 	RI = 0;	
		if(temp==0)
		{
			ideal_duty[0]=SBUF;
			temp++;
		}
		else if(temp==1)
		{
			ideal_duty[1]=SBUF;
			temp=0;	
			duty_flag=1;
		}
					  																
    }

	if(TI)				
	{
		TI = 0;
		send(journal);
	}
}


void send(uchar *s)		//串口发送函数
{
	static uchar i=0;
	if(i<strlen(s))
	{
		SBUF=*(s+i);
		i++;
	}
	else if(i==strlen(s))
	{
		SBUF='\n';
		i++;
	}
	else
	{
		i=0;
	}			 	
}

 电路仿真

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值