STC89C52制作可程控低频信号发生器

准备工作

由于51单片机本身并不自带DAC的功能,因此需要借助外置模块实现DAC的功能,在选型上,看重仅需要两只引脚驱动的一款DA/AD模块,PCF8591模块,带有一路DA输出且内部自带晶振,可以配合STC89C52RC的定时器实现小频率的信号发生器。

操作流程

有了一定构思之后就需要确认操作流程!

关于PCF8591

PCF8591是一个8位分辨率的DA/AD模块,并且使用IIC通信,可以很方便的使用51单片机模拟IIC通信,使用过程中需要注意的一个点就是PCF8591的手册中有说明,IIC速率最大不超过100K,因此需要搭配合适的延时。
在这里插入图片描述

实现构思

结合手册和DA的实现我们可以发现,所谓的DA其实就是,数字量转换为模拟电压,其中又构成线性比例关系,而我们使用的PCF8591模块的基准电压源接到了,供电电源上,因此存在一下关系:
X:2^8 = N:VCC:X为写入PCF8591的数据,N为输出电压
可以通过这个计算我们可以通过编程实现N跟随X的变化而变化!,而实现一个正弦波,我们该怎么操作?正弦波参数有 : 频率,周期,就够了,幅度我们不用考虑,PCF最大输出不会超过VREF的电压,例如实现一个10HZ的正弦波:
freq = 10 ,T = 1/10 = 0.1S=100000us 那么一个周期内不断的向PCF发送电压数字量是不是可以实现呢!这个时候我们可以借助一些软件直接生成正弦波所需相关数据:如下图64个数据,则意味一个周期内需要向64此数据,这个时候我们可以借助定时器实现!!
在这里插入图片描述

相关代码

定时器相关代码

因为串口用到定时器1作为波特率发生器,串口数据中的数据帧头用到定时器0作为超时判断,只能用STC89C52RC的额外的定时器2,实现定时发送相关数据到PCF8591!

u16 timer2val = 287;   //配置定时器初始值    :频率得出周期,周期内64个点,得出每个点之间的时间就是定时器中断时间
u8 TL2BUFF;
u8 TH2BUFF;
/************************
*     定时器2初始化函数
*     T2工作在16位自动重装 开定时器中断
*************************/
void Timer2_Init(void)		//10毫秒@11.0592MHz
{
    
    
	T2MOD = 0;				//初始化模式寄存器
	T2CON = 0;				//初始化控制寄存器
	TL2BUFF = (65535-timer2val)%256;  //设置定时初始值
	TH2BUFF = (65535-timer2val)/256;  //设置定时初始值
	TL2 = TL2BUFF;				//设置定时初始值
	TH2 = TH2BUFF;				//设置定时初始值
	RCAP2L = TL2BUFF;			//设置定时重载值
	RCAP2H = TH2BUFF;			//设置定时重载值
	TR2 = 1;				//定时器2开始计时
	ET2 = 1;				//使能定时器2中断
}
/************************
*     定时器2中断服务函数
*     T0工作在方式1.开定时器中断
*************************/
void Timer2_Isr(void) interrupt 5
{
    
    
	TF2 = 0;
	timer2flag = 1;
}

串口控制频率和LCD显示函数

发送相关对应的判断指令即可控制输出不同频率的正弦波:原理通过改变定时器2的初值实现周期的改变从而实现频率的改变!!因为STC89C52RC定时器2只有16位自动重装模式,所以不能在主函数循环前开启初始化!

void Uart_service(u8 *buf)
{
    
    
	  u8 recv_move_index;
    if(recv_flag)
		 {
    
    
		    recv_flag = 0; //清除接受标志位
			  start_timer = 0;//关掉软件计时器
			  Send_Str(buf);//处理数据
			  while((recv_cnt >= 5) && (recv_move_index <= recv_cnt))
				{
    
    
				     if((buf[recv_move_index+0]) == 0x55 && (buf[recv_move_index+1]) == 0xAA && (buf[recv_move_index+2]) == 0x55)
						 {
    
    
						     if((buf[recv_move_index+3] == 0x01) && (buf[recv_move_index+4] == 0x02))
								 {
    
    
								    timer2val = 287;   //配置定时器初始值    :频率得出周期,周期内32个点,得出每个点之间的时间就是定时器中断时间
									 Timer2_Init();
									 Send_Byte_uart(0x10);
									 LcdShowStr(3,1,"Freq:");
									 LcdShowStr(9,0,"50HZ");
								 }
								 if((buf[recv_move_index+3] == 0x02) && (buf[recv_move_index+4] == 0x01))
								 {
    
    
								     timer2val = 1435;   //配置定时器初始值    :频率得出周期,周期内32个点,得出每个点之间的时间就是定时器中断时间
									 Timer2_Init();
									 Send_Byte_uart(0x50);
									 LcdShowStr(3,1,"Freq:");
									 LcdShowStr(9,0,"10HZ");
								 }
								 break;
						 }
						 recv_move_index++;
				}
			  clr_recvbuffer(buf);//清除缓冲BUF
			  recv_cnt = 0;
		 }
}

相关功能现象

串口控制实现改变便频率且LCD1602显示频率
在这里插入图片描述
在这里插入图片描述

总结

在平时的小型实验中,用不上专用的信号发生器,用这么个小模块实现小频率的正弦波用来学习还是很不错的,其实也还可作为方波发生器或者三角波,原理都跟上面说的类似,博文中仅贴出相关功能代码,需要源代码的可以留言邮箱获取哦,长期发布电子相关文章,喜欢的点个关注吧~~

猜你喜欢

转载自blog.csdn.net/qq_42250136/article/details/129811678
今日推荐