⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tuner.c

📁 一个带收音的功放程序, VFD显示驱动用一个非常实用的方法, 稍加修改即可换成不同的VFD, 功放芯片用M61538
💻 C
📖 第 1 页 / 共 2 页
字号:
#include	"reg52.h"
#include 	"intrins.h"
#include 	"..\..\inc\globedef.h"
#include 	"..\..\inc\keydef.h"
#include    "..\..\inc\keyproc.h"
#include 	"..\..\inc\vfddef.h"
#include	"..\..\inc\delay.h"
#include	"..\..\inc\i2c.h"
#include	"..\..\inc\tuner.h"


/************************************************
 * MCU向TUNER发送一个字节数据			            *
 * 输入: ucData	要发送的无符号字节              *
 * 无返回值				                    	*
 * 注意:是低位选发送				            *
 ************************************************/
void SendByte_ToTuner(BYTE ucData)
{
	BYTE i;

	for(i=0; i<8; i++)
	{
		CLEAR_TUNER_CLK;
		if(ucData & 0x01) 
			SET_TUNER_DATA;
		else
			CLEAR_TUNER_DATA;
		Delay5US();
		SET_TUNER_CLK; //上升沿发送数据
		ucData >>= 1;
	}
}
/************************************************
 * MPU自TUNER读一个字节数据职                     *
 * 无输入值                                     *
 * 返回值读入的无符号字节                       *
 * 注意:是高位先读入                           *
 ************************************************/
BYTE ReadByte_FromTuner(void)
{
	BYTE i, ucData = 0;
	
    //TRI_TUNER_DATA;
	for(i=0; i<8; i++)
	{
		CLEAR_TUNER_CLK;
		Delay5US();
		SET_TUNER_CLK;
		Delay5US();
		ucData <<= 1;
		if(TUNER_DATA_HIGH)
			ucData++; //高电平置1
	}
	return(ucData);
}

/****************************************************
 * MCU向TUNER指定地址发送多个字节数据                 *
 * 输入: *ucData 要发送的无符号字节数据组           *
 *	unN	发送数据个数                                *
 *	unAddr	CCB地址                                 *
 * 无返回值                                         *
 * 注意:是低位先发送                               *
 ****************************************************/
void SendString_ToTuner(BYTE ucAddr, BYTE ucN, BYTE *ucData)
{
	BYTE i;

	CLEAR_TUNER_CS;       	   
	SendByte_ToTuner(ucAddr);	   
	SET_TUNER_CS;
	for(i=0; i<ucN; i++)
	   SendByte_ToTuner(ucData[i]); //发送数据
	CLEAR_TUNER_CS;			  
}

/************************************************
 * MPU自CCB指定地址读多个字节数据               *
 * 输入:	unN	要求读入数据个数                *
 *	unAddr	CCB地址	                            *
 * 返回值 *ucData所读入的无符号字节数据组       *
 * 注意:每个字节的高位先读入                   *
 ************************************************/
void ReadString_FromTuner(BYTE ucAddr, BYTE ucN, BYTE *ucData)
{
	BYTE i;

	CLEAR_TUNER_CS;			      //准备发送CCB地址
	SendByte_ToTuner(ucAddr);	      //发送CCB地址
	SET_TUNER_CS;
	for(i=0; i<ucN; i++)
	   ucData[i] = ReadByte_FromTuner(); //接收数据
	CLEAR_TUNER_CS;				  //结束
}	

/****************************************
 * 收音模块的初始化	             		*
ucRadioControl[0] 的各位代表值

ucRadioControl[0].7 = STSW;  = 0, MONO; =1, stereo
ucRadioControl[0].6 = BDSW1; = 0, AM;   =1, FM
ucRadioControl[0].5 = B02;
ucRadioControl[0].4 = IFSW;  =1, MUTED, =0 RECEIVED
ucRadioControl[0].3 = B01;
ucRadioControl[0].2 = 0;
ucRadioControl[0].1 = 1;
ucRadioControl[0].0 = 0;


*******************************************/
void RadioInit(void)
{

	if(FM_AM_Select == FM_MODE)
	{
		//FM state
		ucRadioControl[0]=0xc2;//STEREO, FM MODE
		//设置DEAD BAND WIDTH 为DZC, 检测到立体声Tuner_DATA_OUT变低
		ucRadioControl[1]=0x8c;

		//一般操做模式,设置中频计数的计算时间为32ms和等待时间为4ms左右
		ucRadioControl[2]=0x17;//
	}
	else
	{
		//AM state
		ucRadioControl[0]=0x02;//MONO, AM mode
		ucRadioControl[1]=0x8c;//81;
		ucRadioControl[2]=0x17;//12;
	}
	SendString_ToTuner(IN2_MODE,3,ucRadioControl);
}


/****************************************
 *收音头静音			             	*
 ****************************************/
void RadioMute(void)
{
	if(FM_AM_Select == FM_MODE)
	{
		//FM state ucRadioControl[0].4的IFSW位控制静音
		ucRadioControl[0]=0xd2;//0a;
		ucRadioControl[1]=0x8c;//80;
		ucRadioControl[2]=0x17;//12;
	}
	else 
	{
		//AM state
		ucRadioControl[0]=0x12;//62;
		ucRadioControl[1]=0x8c;//81;
		ucRadioControl[2]=0x17;//12;
	}
	SendString_ToTuner(IN2_MODE,3,ucRadioControl);
}

/****************************************
 *STRERO/MONO                           *
 ****************************************/

void SetRadioMono(void)
{
	if(FM_AM_Select == FM_MODE)
	{
		//ucRadioControl[0].7控制立体声或者单声道
		ucRadioControl[0]=0x42;//aa;
		ucRadioControl[1]=0x8c;//80;
		ucRadioControl[2]=0x17;//12;
		SendString_ToTuner(IN2_MODE,3,ucRadioControl);
	}
}	

/****************************************
 *收音头打开声音, 其实是针对FM的操做			         	*
 ****************************************/
void RadioOpen(void)
{
	if(Mono_Stereo_Select == Tuner_MONO)
		SetRadioMono();
	else		
		RadioInit();
}

/****************************************
 * 写入收音频率值	(IN1 Mode)	      	*
 * 输入:uiFreq	要写入的频率值          *
 ****************************************/
void RadioFreq(WORD uiFreq)
{	
    if(FM_AM_Select == FM_MODE)
	{
		//设置参考频率为25KHZ, 设置PLL的divisor = P[15:0] * 2;
		//reset中频计数
		ucRadioControl[2]=0x2a;
	}
	else
	{
		//设置参考频率为 5KHZ,设置PLL的divisor = P[15:4];
		ucRadioControl[2]=0x98;
		uiFreq<<=4;//移位是因为P[3:0]是被忽略的
	}
	ucRadioControl[0]=(BYTE)(uiFreq&0x00ff);
	ucRadioControl[1]=(BYTE)((uiFreq&0xff00)>>8);
	SendString_ToTuner(IN1_MODE,3,ucRadioControl); //写入CCB总线
	DelayX1ms(60);

	//GTE = 1; START中频计数
	ucRadioControl[2]|=0x04;
	SendString_ToTuner(IN1_MODE,3,ucRadioControl);
}


/****************************************
 *读中频计数和状态		             	*
 *返回值为状态字节	            		*
 *中频计数值去后4个BIT保存在uiIFCount	*
 ****************************************/
void RadioCountIF(void)
{	
    //BYTE TEMP[3];
    ReadString_FromTuner(OUT_MODE,3,ucRadioControl); //自CCB上读3个字节
	//计算读出的中频值,忽略低4个BIT	
	//最高位STINT  =1代表立体声, =0代表单声道
	Mono_Stereo_Select = ucRadioControl[0] & 0x80;
	if(Mono_Stereo_Select != 0)
		Mono_Stereo_Select = Tuner_STEREO;
	else
		Mono_Stereo_Select = Tuner_MONO;
	Mono_Stereo_Select = ((ucRadioControl[0] & 0x80) >> 7);
	uiIFCount = (WORD)(ucRadioControl[2] >> 4) + (WORD)(ucRadioControl[1] << 4)
											   + (WORD)(ucRadioControl[0] << 12);
	
}

/****************************************
 *判断是否锁到台			         	*
 *返回:TRUE	锁到		         	*
 *     FALSE	未锁到	        		*
 ****************************************/
BYTE RadioLock(void)
{		
	if(Wait_Lock_40ms < Wait_Timer_Out)
		return 0xFF;
	else
	{		
		Wait_Lock_40ms = 0;		
		RadioCountIF();				
		if( FM_AM_Select == FM_MODE )
		{
			//FM,中频频率为10.7MHz在32ms内的计数值应为0x53980
			if((uiIFCount>=(FMIFS-FMDELTA))&&(uiIFCount<=(FMIFS+FMDELTA)))
			{
				return TRUE;
			}
			
		}
		else
		{
			//AM,中频是450KHZ,在32MS内的计数为0x3840
			if((uiIFCount>=(AMIFS-AMDELTA))&&(uiIFCount<=(AMIFS+AMDELTA)))
			{
				return TRUE;
			}
		}
		return FALSE;
	}
	
}

/********************************************
 * 频率加1,如果超过范围,则自动从最小开始	*
 * 返回当前频率值		            		*
 ********************************************/
void RadioUp(void)
{
	//WORD idata uiFreqTemp;
	
    //当前频率加1个步长
	if(FM_AM_Select == FM_MODE )
	{
		//加50KHz
		if(DeltFMFreq >= (FMFREQMAX - FMFREQSTEP))
		{
			DeltFMFreq = 0;
			if(Auto_Scan_Enable == 1)
				Auto_Is_Reach = 1;				
		}
		else
			DeltFMFreq += FMFREQSTEP;  //
		Current_Freq=(WORD)DeltFMFreq+(WORD)FMFREQMIN;
	}
	else
	{		
		if(DeltAMFreq >= (AMFREQMAX-AMFREQSTEP))
		{
			DeltAMFreq = 0;
			if(Auto_Scan_Enable == 1)
				Auto_Is_Reach = 1;
		}
		else
			DeltAMFreq += AMFREQSTEP;
		Current_Freq=(WORD)DeltAMFreq+AMFREQMIN;
	}
	//RadioFreq(Current_Freq);
	//return Current_Freq;
}

/********************************************
 * 频率减1,如果超过范围,则自动从最大开始	*
 * 返回当前频率			                	*
 ********************************************/
void RadioDown(void)
{
	//WORD uiFreq;	
    //当前频率减1个步长
	if(FM_AM_Select == FM_MODE)
	{		
		if(DeltFMFreq < FMFREQSTEP) //如果当前的偏差小于步长, 那么设置最大值
			DeltFMFreq = FMFREQMAX;
		else
			DeltFMFreq -= FMFREQSTEP;
		Current_Freq=FMFREQMIN+DeltFMFreq;
	}
	else
	{		
		if(DeltAMFreq < AMFREQSTEP)
			DeltAMFreq = AMFREQMAX;
		else
			DeltAMFreq -= AMFREQSTEP;
		Current_Freq=AMFREQMIN+(WORD)DeltAMFreq;
	}
	
}
/*****************************************************************
 * TUNER 处理函数 *
 包括全自动扫描, 手动向下扫描, 手动向上扫描, 记忆存储
 数字键的处理,  			                	
****************************************************************/
void	Tuner_Proc(void)
{
	BYTE Lock_Flag;
	BYTE TEMP1;	
	BYTE TEMP2;
	if(Auto_Scan_Enable == Auto_Scan_Go)
	{
		//刚开始第一次自动扫描扫描
		if(Auto_Scan_Start == 0)
		{
			if(FM_AM_Select == FM_MODE)
				Current_Freq = FMFREQMIN;  //在FM模式,置FM的频率为最小值
			else
				Current_Freq = AMFREQMIN; //AM模式的频率最小值
			
			DeltFMFreq = 0; //FM的增量为0
			DeltAMFreq = 0; //AM的增量为0			
			RadioMute();    //RADIO静音
			RadioFreq(Current_Freq); //送当前频率到TUNER PLL
			Auto_Scan_Start = 1;     //自动扫描起始标志位置位
			Scan_Channel = 0;
			Wait_Lock_40ms = Wait_Timer_Start;      //
		}
		else
		{
			Lock_Flag = RadioLock(); //看是否到达中频锁定时间
			if( Lock_Flag != Timer_Not_Reach)
			{
				if(Lock_Flag == TRUE)
				{
					//如果有台锁定,那么保存台值,继续下一个扫描
					//Scan_Channel,扫描的台的频率					
					if(FM_AM_Select == FM_MODE)
					{
						TEMP1 = FM_Start + (Scan_Channel * 2);
						I2C_PutByte(A24C02, TEMP1, DeltFMFreq & 0xFF );
						DelayX1ms(2);
						TEMP2 = (DeltFMFreq & 0xFF00) >> 8;
						I2C_PutByte(A24C02, TEMP1 + 1, TEMP2);
					}
					else
					{
						I2C_PutByte(A24C02, (AM_Start + Scan_Channel - 1), (BYTE)(DeltAMFreq & 0xFF) );					
					}
					Scan_Channel++;
				}

				//如果还没有到频率的最大值和存储的台没有超过30,那么继续扫描
				if((Auto_Is_Reach == 0)&& (Scan_Channel < 30))
				{
					RadioMute();   //中频静音
					RadioUp();     //频率加加
					RadioFreq(Current_Freq); //设置改变后的频率
					Wait_Lock_40ms = Wait_Timer_Start;
				}
				else
				{
					//假如已经搜索到最大频率或者存储的台超过30
					if(FM_AM_Select == FM_MODE)
					{
						//从24C02中取出第一个存储的频率

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -