51单片机频率可调的方波信号发生器小设计

如需要源文件可以添加qq群聊获取:662177587

概要

实际设计图:

设计内容

用单片机产生频率可调的方波信号。输出方波的频率范围为1Hz-200Hz,频率误差比小于0.5%。要求用“增加”、“减小”2个按钮改变方波给定频率,按钮每按下一次,给定频率改变的步进步长为1Hz,当按钮持续按下的时间超过2秒后,给定频率以10次/秒的速度连续增加(减少),输出方波的频率要求在数码管上显示。用输出方波控制一个发光二极管的显示,用示波器观察方波波形。开机默认输出频率为5Hz

整体架构流程

研究目标

    任务分析:方波信号的产生实质上就是在定时器溢出中断次数达到规定次数时,将输出I/O管脚的状态取反。由于频率范围最高为200Hz,即每个周期为5ms(占空比1:1,即高电平2.5ms,低电平2.5 ms),因此,定时器可以工作在8位自动装载的工作模式。

    涉及以下几个方面的问题:按键的扫描、功能键的处理、计时功能以及数码管动态扫描显示等。问题的难点在按键连续按下超过2S的计时问题,如何实现计时功能。

    系统的整体思路:主程序在初始化变量和寄存器之后,扫描按键,根据按键的情况执行相应的功能,然后在数码显示频率的值,显示完成后再回到按键扫描,如此反复执行。中断程序负责方波的产生、按键连续按下超过2S后频率值以10Hz/s递增(递减)。

选择单片机型号和所需外围器件型号,设计单片机硬件电路原理图。

 采用MCS-51系列单片机At89S51作为主控制器,外围电路器件包括数码管驱动、独立式键盘、方波脉冲输出以及发光二极管的显示等。

数码管驱动采用2个四联共阴极数码管显示,由于单片机驱动能力有限,采用74HC244作为数码管的驱动。在74HC244的7段码输出线上串联100欧姆电阻起限流作用。

独立式按键使用上提拉电路与电源连接,在没有键按下时,输出高电平。发光二极管串联500欧姆电阻再接到电源上,当输入为低电平时,发光二极管导通发光。

技术细节

  • 主函数.c
#include <STC89C5xRC.H>
#include "Timer0.h"
#include "Nexie.h"

unsigned char freq=5;									 //ƵÂÊ£¬³õʼֵΪ5
unsigned char long_flag=0,long_flag1=0;//ÓÃÓÚ¼Ó¼õ10µÄÅжϱê־λ

unsigned int comp;										//ÓÃÓÚ¶¨Ê±Æ÷µÄ±È½ÏÖµ²úÉúpwm
code unsigned int comper[201]={0,15833,7516,5668,4251,3401,2834,2429,2125,1889,1700,1545,1417,1308,1214,1133,1062,1000,944,894,850,
809,772,739,708,680,654,629,607,586,566,548,531,515,500,485,472,459,447,436,425,
414,404,395,386,377,369,361,354,346,340,333,326,320,314,309,303,298,292,288,284,
	
283,281,279,277,275,273,271,269,267,265,263,261,259,257,255,253,251,249,247,245,
243,241,239,237,235,233,231,229,227,225,223,221,219,217,215,213,211,209,207,205,
203,201,199,197,195,193,191,189,187,185,183,181,179,177,175,173,171,169,167,165,
	
164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,
144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,127,126,125,
124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,
104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85};


/**
  * @brief  °´¼üɨÃè
  * @param  ÎÞ
  * @retval ÎÞ
  */
void Key_Loop()
{
	static unsigned int count,count1;
	
	if(P30==0)
	{
		count++;
		if(count>200) //˵Ã÷³ÖÐø°´ÏÂ
		{							//Ö´ÐмӼõ10µÄ²Ù×÷
			long_flag=1;
			count--;		//ΪÁ˲»ÈüÆÊýÖµ³¬¹ý·¶Î§
		}
	}
	if(P30==1)
	{
		if(count>2) //˵Ã÷Ö»Êǵ¥»÷
		{						//Ö´ÐмӼõ1µÄ²Ù×÷
			freq++;
			if(freq>200)	//ÏÞÖÆƵÂÊ·¶Î§Îª1-200hz
			{freq=1;}
		}
		long_flag=0;
		count=0;
	}
	
	if(P31==0)
	{
		count1++;
		if(count1>200) //˵Ã÷³ÖÐø°´ÏÂ
		{							//Ö´ÐмӼõ10µÄ²Ù×÷
			long_flag1=2;
			count1--;		//ΪÁ˲»ÈüÆÊýÖµ³¬¹ý·¶Î§
		}
	}
	if(P31==1)
	{
		if(count1>2) //˵Ã÷Ö»Êǵ¥»÷
		{						 //Ö´ÐмӼõ1µÄ²Ù×÷
			freq--;
			if(freq<1)	//ÏÞÖÆƵÂÊ·¶Î§Îª1-200hz
			{freq=200;}
		}
		long_flag1=0;
		count1=0;
	}
}
/**
  * @brief  ƵÂÊÏÔʾº¯Êý
  * @param  ÎÞ
  * @retval ÎÞ
  */
void Fre_show()
{
		Nixie_SetBuf(1,freq/100%10);
		Nixie_SetBuf(2,freq/10%10);
		Nixie_SetBuf(3,freq%10);
}

void main()
{
	Timer0_Init();		//¶¨Ê±Æ÷0³õʼ»¯
	Timer1_Init();		//¶¨Ê±Æ÷1³õʼ»¯
	while(1)
	{
		Fre_show();			//Ë¢ÐÂÏÔʾƵÂÊÖµ
		comp=comper[freq];	//»ñµÃ±È½ÏÖµ1000/2/frequence=¼ÆʱºÁÃ뷭תÊý
	}
}

/**
  * @brief  ¶¨Ê±Æ÷1µÄÏà¹Ø²Ù×÷
	* @brief  ¶¨Ê±Æ÷1Ϊģʽ8λ²»×Ô¶¯ÖØÔØ,1msÖжÏ
  * @param  ÎÞ
  * @retval ÎÞ
  */
void Timer1_Routine() interrupt 3
{
	static unsigned int T1Count0;//¶¨Ê±Æ÷Ïà¹Ø±äÁ¿
	T1Count0++;
	if(T1Count0>=comp)//Êä³ö·½²¨
		{
			T1Count0=0;
			P20=!P20;
		}
	
}
/**
  * @brief  ¶¨Ê±Æ÷0µÄÏà¹Ø²Ù×÷
	* @brief  ¶¨Ê±Æ÷0Ϊģʽ1,16Ϊ²»×Ô¶¯ÖØÔØ,1msÖжÏ
  * @param  ÎÞ
  * @retval ÎÞ
  */
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count0,T0Count1,T0Count2;//¶¨Ê±Æ÷Ïà¹Ø±äÁ¿
		TL0 = 0x18;				//ÉèÖö¨Ê±³õʼֵ
		TH0 = 0xFC;				//ÉèÖö¨Ê±³õʼֵ

		T0Count0++;T0Count1++;T0Count2++;//ÿ1ms½øÐÐÒ»´Î++£»
			
		if(T0Count0>=10)//10msµ÷ÓÃÒ»´ÎKey_Loop()º¯Êý
		{
			T0Count0=0;
			Key_Loop();
		}
		if(T0Count1>=2)//2msµ÷ÓÃÒ»´ÎNixie_Loop()º¯Êý
		{
			T0Count1=0;
			Nixie_Loop();
		}
		
		if(T0Count2>=250)//µ÷½Ú¸ÃÖµ¿É¸Ä±ä¼Ó¼õ10µÄËÙ¶È
		{
			T0Count2=0;
			if(long_flag==1)
			{
				freq+=10;
				if(freq>200)	//ÏÞÖÆƵÂÊ·¶Î§Îª1-200hz
				{freq=1;}
			}
			if(long_flag1==2)
			{
				freq-=10;
				if(freq>200)	//ÏÞÖÆƵÂÊ·¶Î§Îª1-200hz
				{freq=200;}
			}
		}
		
}
  • 定时器.c
#include <STC89C5xRC.H>

/**
  * @brief  ¶¨Ê±Æ÷0³õʼ»¯
  * @param ÎÞ
  * @retval ÎÞ
  */
	void Timer0_Init(void)		//100us@12.000MHz
	{
		TMOD &= 0xF0;			//¶¨Ê±Æ÷ʱÖÓ12Tģʽ
		TMOD |= 0x01;			//ÉèÖö¨Ê±Æ÷ģʽ
		TL0 = 0x18;				//ÉèÖö¨Ê±³õʼֵ
		TH0 = 0xFC;				//ÉèÖö¨Ê±³õʼֵ
		TF0 = 0;				//Çå³ýTF0±êÖ¾
		TR0 = 1;				//¶¨Ê±Æ÷0¿ªÊ¼¼Æʱ
		ET0=1;
		EA=1;
		PT0=0;
	}
/**
  * @brief  ¶¨Ê±Æ÷1³õʼ»¯
  * @param ÎÞ
  * @retval ÎÞ
  */	
void Timer1_Init(void)		//10΢Ãë@12.000MHz
{
	TMOD &= 0x0F;			//ÉèÖö¨Ê±Æ÷ģʽ
	TMOD |= 0x20;			//ÉèÖö¨Ê±Æ÷ģʽ
	TL1 = 0xF6;				//ÉèÖö¨Ê±³õʼֵ
	TH1 = 0xF6;				//ÉèÖö¨Ê±ÖØÔØÖµ

	TF1 = 0;				//Çå³ýTF1±êÖ¾
	TR1 = 1;				//¶¨Ê±Æ÷1¿ªÊ¼¼Æʱ
	ET1=1;
	EA=1;
	
}
	
  • 定时器.h
#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);
void Timer1_Init(void);		//10΢Ãë@12.000MHz
	
#endif
  • 数码管.c
#include <STC89C5xRC.H>
#include "Delay.h"
unsigned char Nixie_Buf[4]={0,10,10,10};//0ÊÇΪÁËÕÕÓ¦loopÖÐi=1
unsigned char NixieNumb[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
													
/**
  * @brief  Íⲿµ÷ÓöÔÊý×éNixie_Buf[4]¸³Öµ
  * @brief  ʹµÃloopº¯ÊýÑ­»·¶Ôscanº¯Êý¸³ÖµÊ±¶Áµ½ÏàÓ¦Êý¾Ý
  * @brief  δ¸³ÖµµÄÊý×éλ¼´Îª10£»¶ÔÓ¦NixieNumb[]ÖеÄ0£»
  * @param Table,NumberÔÚNixie_BufÊý×éµÄÏÂ±ê ¸³µÄÖµ£¨¸ÃÖµ¼´¶ÔÓ¦NixieNumb[]ÖеÄÖµ£©
  * @retval ÎÞ
  */
void Nixie_SetBuf(unsigned char Table,Number)
{
	Nixie_Buf[Table]=Number;
}

/**
  * @brief  ÊýÂë¹ÜÏÔʾ
  * @param  Table,NumberÏÔʾµÄλÖà ÏÔʾµÄÊý×Ö
	* @param Á½²ÎÊýÓɶ¨Ê±Æ÷°´ÖÜÆÚɨÃèʱ¸ø¶¨
  * @retval ÎÞ
  */
void Nixie_Scan(unsigned char Table,Number)
	{
		P0=0x00;//ÏûÒþ
		switch(Table)
		{//     P2_4=C-4,P2_3=B-2;P2_2=A-1
			case 1:P24=1;P23=1;P22=1;break;
			case 2:P24=1;P23=1;P22=0;break;
			case 3:P24=1;P23=0;P22=1;break;
		}
		P0=NixieNumb[Number];//²»ÓÃdelayÔÙÏûÒþ£¬ÒòΪ¶¨Ê±Æ÷½øÀ´ÓÐʱ¼ä¼ä¸ô
		
	}
/**
  * @brief  ¶¨Ê±Æ÷µ÷Óõĺ¯Êý
  * @param  ÎÞ
  * @retval ÎÞ
  */
	void Nixie_Loop(void)//¶¨Ê±Æ÷ÿ½øÒ»´Î¾Íµ÷ÓÃÒ»´Îscanº¯Êý
	{										//ʹµÃ3¸öÊýÂë¹ÜÒÀ´Î¿ìËÙÏÔʾ
		static unsigned char i=1;
		Nixie_Scan(i,Nixie_Buf[i]);
		i++;
		if(i>=4)i=1;
	}
  • 数码管.h
#ifndef __NEXIE_H__
#define __NEXIE_H__

void Nixie_Scan(unsigned char Table,Number);
void Nixie_Loop(void);
void Nixie_SetBuf(unsigned char Table,Number);

#endif

小结

用单片机产生频率可调的方波信号。输出方波的频率范围为1Hz-200Hz,频率误差比小于0.5%。

如需要源文件可以添加qq群聊获取:662177587

希望对你有所帮助!

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是基于51单片机可调矩形波生成器的代码: ```c #include<reg52.h> #include<intrins.h> #define uint unsigned int #define uchar unsigned char // 定义IO口 sbit TRIG = P1^0; // 触发脉冲输出 sbit ECHO = P1^1; // 超声波接收端 sbit OUT = P1^7; // 方波输出端 // 全局变量定义 uint distance; // 超声波测距距离 uchar freq, duty; // 方波频率和占空比 // 函数声明 void Init_Timer0(); void Init_Timer1(); void Init_Timer2(); void delay(uint); void beep(); // 主函数 void main() { Init_Timer0(); // 初始化定时器0 Init_Timer1(); // 初始化定时器1 Init_Timer2(); // 初始化定时器2 while(1) { // 超声波测距 TRIG = 1; delay(10); TRIG = 0; // 发送触发脉冲 while(!ECHO); // 等待超声波接收端输出高电平 TR0 = 1; // 启动定时器0,开始计时 while(ECHO); // 等待超声波接收端输出低电平 TR0 = 0; // 关闭定时器0,停止计时 distance = TH0*256+TL0; // 计算距离 // 根据距离调整方波频率和占空比 if(distance < 10) { freq = 1; duty = 10; } // 距离小于10cm,频率1Hz,占空比10% else if(distance < 20) { freq = 2; duty = 20; } // 距离小于20cm,频率2Hz,占空比20% else if(distance < 30) { freq = 3; duty = 30; } // 距离小于30cm,频率3Hz,占空比30% else if(distance < 40) { freq = 4; duty = 40; } // 距离小于40cm,频率4Hz,占空比40% else { freq = 5; duty = 50; } // 距离大于等于40cm,频率5Hz,占空比50% // 生成方波信号 beep(); } } // 定时器0初始化函数,用于测距 void Init_Timer0() { TMOD |= 0x01; // 定时器0工作在模式1,16位定时器 TH0 = 0; // 定时器初值为0 TL0 = 0; } // 定时器1初始化函数,用于生成方波 void Init_Timer1() { TMOD &= 0x0F; // 定时器1工作在模式0,13位定时器 TMOD |= 0x10; TH1 = 0; // 定时器初值为0 TL1 = 0; } // 定时器2初始化函数,用于延时 void Init_Timer2() { T2CON = 0x04; // 定时器2工作在模式1,8位定时器 } // 延时函数,用于超声波测距 void delay(uint t) { while(t--) _nop_(); } // 生成方波信号 void beep() { uint i,j; OUT = 1; // 方波输出端置高 for(i=0; i<freq; i++) // 生成freq个方波周期 { for(j=0; j<duty; j++) // 方波占空比为duty% { TH1 = TL1 = 256-(11059200/12/500/freq); // 计算定时器初值,使方波频率为freq Hz TR1 = 1; // 启动定时器1,开始生成方波 while(TF1 == 0); // 等待定时器1溢出 TR1 = 0; // 关闭定时器1,停止生成方波 TF1 = 0; // 定时器1溢出标志清零 } for(j=0; j<100-duty; j++) // 方波占空比为100-duty% { TH1 = TL1 = 256-(11059200/12/500/freq); // 计算定时器初值,使方波频率为freq Hz TR1 = 1; // 启动定时器1,开始生成方波 while(TF1 == 0); // 等待定时器1溢出 TR1 = 0; // 关闭定时器1,停止生成方波 TF1 = 0; // 定时器1溢出标志清零 } } OUT = 0; // 方波输出端置低 } ``` 这段代码使用三个定时器,其中定时器0用于测距,定时器1用于生成方波,定时器2用于延时。当超声波测距得到距离值后,根据距离值调整方波频率和占空比,然后使用定时器1生成方波信号。其中,占空比的调整是通过在定时器1中生成两个不同占空比的方波周期来实现的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SFR-小曾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值