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

📄 alarm.c

📁 多功能MP3代码
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "COMM.H"	 
//闹钟部分代码,包括所有的脑中操作函数 					    
//正点原子@SCUT
//V1.1

//全局变量区域	
//闹钟结构体						   
typedef struct  
{																				   
	u8  Status;	//状态寄存器 bit3,ON/OFF;bit2 RING/FM;bit 1,0 ONCE/EVERY DAY/SELF DEFINE
	u8  WeekMark;//自定义标志  
	u8  Ring;	//闹铃声编号
	u8  hour;
	u8  min;
	u8  Ring_Name[9];
	u32	Ring_Addr;		 
}AlarmStruct;			 
AlarmStruct Alarm[8];	//闹钟暂存
AlarmStruct Alarm_Temp;	//零时寄存区  
  
u8  AlarmInLine=0;//在闹钟寄存器中的闹铃编号 0~7  	 
u8 *Alarm_F1[8];//时间数据缓存区   XX:XX +'\0' 用于数据显示	    
//存储铃声
//存储地址区间:300~411 总共112个字节
//type :铃声类型 0,MP3,1,FM
//Rnum :铃声编号 0~7
//RingN:铃声名字短文件名 对MP3
//RAddr:铃声地址/FM频率 	 
void Save_Ring(u8 type,u8 RNum,u8 *RingN,u32 RAddr)
{
	u8 i;
	if(type)//FM收音机	保存 103.6 (1036)之类的数据,占两个字节
	{	
		FM24C16_WriteLenByte(396+RNum*2,RAddr,2);//写入两个字节		  
	}else
	{
		for(i=0;i<8;i++)FM24C16_WriteOneByte(300+RNum*12+i,RingN[i]);//把歌曲名字保存
		FM24C16_WriteLenByte(300+RNum*12+8,RAddr,4);//写入四个字节	   
	}										   		 
}
//读取铃声
//地址区间:300~411 总共112个字节
//type :铃声类型
//Rnum :铃声编号
//RingN:铃声名字短文件名 对MP3
//RAddr:铃声地址/FM频率 
void Read_Ring(u8 type,u8 RNum,u8 *RingN,u32 *RAddr)
{
	u8 i;		 
	if(type)//FM收音机	读取 103.6 (1036)之类的数据,占两个字节
	{									    
		*RAddr=FM24C16_ReadLenByte(396+RNum*2,2);   
	}else for(i=0;i<8;i++)
	{	 
		for(i=0;i<8;i++)*RingN++=FM24C16_ReadOneByte(300+RNum*12+i);
		*RingN='\0';//添加结束符
	    *RAddr=FM24C16_ReadLenByte(300+RNum*12+8,4); 
	}
}	  
//存储闹钟数据
//存储地址区间:260~299 总共40个字节
//alx:要保存的编号 0~7,>=8,全部保存
void Save_Alarm(u8 alx)
{
	u8 i;
	if(alx<8)
	{
		FM24C16_WriteOneByte(260+alx*5,Alarm[alx].Status);
		FM24C16_WriteOneByte(261+alx*5,Alarm[alx].WeekMark);
		FM24C16_WriteOneByte(262+alx*5,Alarm[alx].Ring);
		FM24C16_WriteOneByte(263+alx*5,Alarm[alx].hour);
		FM24C16_WriteOneByte(264+alx*5,Alarm[alx].min);
		Save_Ring(Alarm[alx].Status&0x04,Alarm[alx].Ring,Alarm[alx].Ring_Name,Alarm[alx].Ring_Addr);  //保存MP3信息到相应的地址
	}else for(i=0;i<8;i++)
	{
		FM24C16_WriteOneByte(260+i*5,Alarm[i].Status);
		FM24C16_WriteOneByte(261+i*5,Alarm[i].WeekMark);
		FM24C16_WriteOneByte(262+i*5,Alarm[i].Ring);
		FM24C16_WriteOneByte(263+i*5,Alarm[i].hour);
		FM24C16_WriteOneByte(264+i*5,Alarm[i].min);
		Save_Ring(Alarm[alx].Status&0x04,Alarm[alx].Ring,Alarm[alx].Ring_Name,Alarm[alx].Ring_Addr);  //保存MP3信息到相应的地址
	}
}

//读取闹钟数据
//存储地址区间:260~299 总共40个字节
//alx:要读取的编号 0~7,>=8,全部读取
void Read_Alarm(u8 alx)
{
	u8 i;
	if(alx<8)
	{
		Alarm[alx].Status=FM24C16_ReadOneByte(260+alx*5);
		Alarm[alx].WeekMark=FM24C16_ReadOneByte(261+alx*5);
		Alarm[alx].Ring=FM24C16_ReadOneByte(262+alx*5);
		Alarm[alx].hour=FM24C16_ReadOneByte(263+alx*5);
		Alarm[alx].min=FM24C16_ReadOneByte(264+alx*5);
		Read_Ring(Alarm[alx].Status&0x04,Alarm[alx].Ring,Alarm[alx].Ring_Name,&Alarm[alx].Ring_Addr);//读取闹钟铃声信息	  
	}else for(i=0;i<8;i++)
	{	 
		Alarm[i].Status=FM24C16_ReadOneByte(260+i*5);
		Alarm[i].WeekMark=FM24C16_ReadOneByte(261+i*5);
		Alarm[i].Ring=FM24C16_ReadOneByte(262+i*5);
		Alarm[i].hour=FM24C16_ReadOneByte(263+i*5);
		Alarm[i].min=FM24C16_ReadOneByte(264+i*5);
		Read_Ring(Alarm[i].Status&0x04,Alarm[i].Ring,Alarm[i].Ring_Name,&Alarm[i].Ring_Addr);//读取闹钟铃声信息	   
	}
}
//初始化闹钟寄存器
//把闹钟0~7中的闹钟值取一个与当前时间最接近的放在闹钟寄存器里面
void Init_Alarm_Reg(void)
{
	u8 i;
	u8 temp;
	u32 curtime=0;
	u32 temptime=0;
	u32 destime=0XFFFFFFFF;//设定到最大
	u8 weekx;
	u8 weektemp;
	u8 t;

	rtc_get();//得到时间 
	GetWeek(timer.w_year,timer.w_month,timer.w_date,&weekx);//得到星期 0~6 代表周末到周六	    
		
	weekx=8-weekx;//与weekmark标志匹配
	if(weekx==8)weekx=1;//周末处理

	curtime=RTC->CNTH;//得到计数器中的值(秒钟数)
	curtime<<=16;
	curtime+=RTC->CNTL;
						 
	//取一个与当前时间最接近的值作为闹钟寄存器的内容
	for(i=0;i<8;i++)
	{
		temptime=curtime/86400;	//得到当前运行天数
		temptime=temptime*86400;
		temptime+=(u32)Alarm[i].hour*3600+(u32)Alarm[i].min*60;//得到秒钟数
		temp=Alarm[i].Status;
		if(temp&0x08)//闹钟开启了
		{
			temp&=0x03;
			switch(temp)
			{
				case 0://闹铃一次
				case 1:
					if(temptime<=curtime)temptime+=86400;//执行时间已过,推迟到明天
					if(temptime<destime)
					{
						destime=temptime;//更改闹钟寄存器 
						AlarmInLine=i;//记录保存在闹钟寄存器中的闹钟编号
					}
					break;  
				case 2://自定义闹钟
					temp=Alarm[i].WeekMark;//周标记	  
					if((temp&(1<<weekx))&&(temptime>curtime))//有标记当前的星期,且时间没有超过
					{									 													   
						if(temptime<destime)
						{
							destime=temptime;//更改闹钟寄存器 
							AlarmInLine=i;//记录保存在闹钟寄存器中的闹钟编号
						}
					}else
					{	  	
						weektemp=weekx;					  	
						t=0;
						while(1)
						{
							weektemp--;
							if(weektemp<1)weektemp=7;   
							t++;
							if(temp&(1<<weektemp))//有标记了
							{
								temptime+=(u32)t*86400;//更改闹钟寄存器,推后了t天
								if(temptime<destime)
								{
									destime=temptime;
									AlarmInLine=i;//记录保存在闹钟寄存器中的闹钟编号
								}
								break; 	
							}
							if(weektemp==weekx)break;//经过了一个循环
						}	
					}
					break;	 			
			}
		}   
	}
	//读取闹钟铃声信息										  																						  
	Read_Ring(Alarm[AlarmInLine].Status&0x04,Alarm[AlarmInLine].Ring,Alarm[AlarmInLine].Ring_Name,&Alarm[AlarmInLine].Ring_Addr);   
	//设置闹钟寄存器
    RCC->APB1ENR|=1<<28;//使能电源时钟
    RCC->APB1ENR|=1<<27;//使能备份时钟
	PWR->CR|=1<<8;    //取消备份区写保护
	//上面三步是必须的!
	RTC->CRL|=1<<4;   //允许配置 
	RTC->ALRL=destime&0xffff;
	RTC->ALRH=destime>>16;
	RTC->CRL&=~(1<<4);//配置更新
	while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成    
}
//显示FM频道信息
u16 Ring_Fm_Show(u8 rch)
{
	u16 freqdiv;
	BACK_COLOR=WHITE;
	POINT_COLOR=BLACK;						 

	TFT_ShowNum(136,114,rch,2,16,0x00);  //显示频道值	   	 		   
	freqdiv=FM24C16_ReadLenByte(60+rch*2,2);  			   
	if(freqdiv>=10000)TFT_ShowChar(98,146,freqdiv/10000+'0',16,0x00);//在指定位置显示一个字符
	else TFT_ShowChar(98,146,' ',16,0x00);//在指定位置显示一个字符	 
	TFT_ShowChar(104,146,(freqdiv/1000)%10+'0',16,0x00);//在指定位置显示一个字符
	TFT_ShowChar(112,146,(freqdiv/100)%10+'0',16,0x00);//在指定位置显示一个字符
	TFT_ShowChar(120,146,'.',16,0x00);//在指定位置显示一个字符
	TFT_ShowChar(128,146,(freqdiv/10)%10+'0',16,0x00);//在指定位置显示一个字符
	return freqdiv;//返回频率值
}
//设置闹铃/FM频率
void Set_Alarm_Ring(void)
{			   
	FileInfoStruct RingInfo;
	u16 index;
	u32 curdir=0;
	u8 key;
	u8 Ch_Num;//频道总数
	u8 CH_Val=0;

	Load_Gui_Bro("完成");//显示GUI界面
	if(Alarm_Temp.Status&0x04)//收音机作为铃声
	{
		Ch_Num=FM24C16_ReadOneByte(58);//保存USA频段最大电台数 sCh_Num		 
		if(Ch_Num==0)//没有频率供选择.直接退出
		{				
			Show_Str_Mid(0,114,"无任何频道供选择!",0x01,240); //叠加模式,非自动换行
 			return;
		}
		//加载GUI
 		POINT_COLOR=RED;												  
		Show_Str_Mid(0,2,"FM铃声选择",0x01,240);  //叠加模式,非自动换行    
		POINT_COLOR=BLUE;		   
		Show_Str(56,114,"频道:",0x01); //叠加模式,非自动换行
		Show_Str(56,146,"频率:     MHz",0x01); //叠加模式,非自动换行		 
		//加载操作按钮
		BACK_COLOR=WHITE;
		POINT_COLOR=BROWN;
		TFT_ShowButton(104,110,1);//<
		TFT_ShowButton(160,110,0);//>
		
		index=Ring_Fm_Show(CH_Val);//显示频率等值							   
		Pen_Point.Key_Sta=Key_Up;//释放显示期间的触发 
		key=0;
		while(1)//等待按键
		{
			if((Pen_Point.Key_Sta==Key_Down||NPEN)&&Pen_Point.Key_LSta)key=Touch_To_Num(4);//得到按键值	  
			if(PEN)//按键松开了,状态改变(状态机)
			{
				Pen_Point.Key_LSta=1;	 
				Pen_Point.Key_Sta=Key_Up;
			}   
			if(key)//有按键按下
			{  			   
				Pen_Point.Key_LSta=0;
				if(Is_In_Area(104,110,128,134))//减少键
				{
					if(CH_Val)CH_Val--;
					else CH_Val=Ch_Num-1;
					index=Ring_Fm_Show(CH_Val);
				}else if(Is_In_Area(160,110,184,134))//增加键
				{
					CH_Val++;
					if(CH_Val>=Ch_Num)CH_Val=0;	
					index=Ring_Fm_Show(CH_Val);  
				}
				if(key==9)//确认了
				{								   
				    Save_Ring(1,Alarm_Temp.Ring,&key,index);//保存FM,写入FM频率时扩大十倍	 
					return; 
				}else if(key==10)return;//返回  
				key=0;//取消按键值 											    
			}   
			delay_ms(1);	
		} 
	}else //MP3作为铃声
	{	  	
		POINT_COLOR=RED;
		Show_Str_Mid(0,2,"MP3铃声选择",0x01,240);//叠加模式,非自动换行

		curdir=Cur_Dir_Cluster;//保存上次的目录簇号
		if(FAT32_Enable)Cur_Dir_Cluster=FirstDirClust;//根目录簇号
	 	else Cur_Dir_Cluster=0;	    
		index=File_Browse(T_MP3|T_WMA|T_WAV|T_MID);//浏览文件夹 
		if(index==0)
		{
			Cur_Dir_Cluster=curdir;//恢复上次的目录簇号
			return;//按下返回按钮了 
		}
		Get_File_Info(Cur_Dir_Cluster,&RingInfo,T_MP3|T_WMA|T_WAV|T_MID,&index);//得到这首歌曲的信息	   
		Save_Ring(0,Alarm_Temp.Ring,RingInfo.F_ShortName,RingInfo.F_StartCluster);//保存MP3信息到相应的地址		 	
	
		for(index=0;index<8;index++)Alarm_Temp.Ring_Name[index]=RingInfo.F_ShortName[index];//得到新闹铃的名字
		Alarm[Alarm_Temp.Ring].Ring_Addr=RingInfo.F_StartCluster;//得到新闹铃的地址,必须分配给ALARM
				    
		Cur_Dir_Cluster=curdir;//恢复上次的目录簇号				   												 
	}  
}	    

//在中断里面执行
//必须要用到独立的RAM,否则可能影响其他程序的运行
u8 ALARMPLAYBUFFER[512];
//播放闹钟
void Play_Alarm_Ring(void)
{
	u32 bfactor;
	u32 bcluster;
	u16 count;
	u8 key,n;
	u16 i;
	u8 audioch;//音频音源暂存器	  
	FileInfoStruct RingInfo;  
	
	audioch=Audio_Ch;//记录闹钟时的音源  
	read_dsp();	
	if(Alarm[AlarmInLine].Status&0x04)//收音机作为铃声
	{						  									 
		if(Alarm[AlarmInLine].Ring_Addr>10800||Alarm[AlarmInLine].Ring_Addr<8750)return; 	  
	  	init_pt2314(FM_Audio);//设置声音  
		bfactor=frequency_set; //保留先前的频率	
		n=JPUS;//保存先前的频段
		JPUS=USA;//设置到USA频段

		set_frequency(Alarm[AlarmInLine].Ring_Addr*10);//开启收音机,到指定频率

		key=0;
		Pen_Point.Key_Sta=Key_Up;
		while(1)
		{
			if((Pen_Point.Key_Sta==Key_Down||NPEN)&&Pen_Point.Key_LSta)key=Touch_To_Num(6);//不使用扩展按钮;	  
			if(PEN)//按键松开了,状态改变(状态机)
			{
				Pen_Point.Key_LSta=1;	 
				Pen_Point.Key_Sta=Key_Up;
			}   
			if(key)
			{
				Pen_Point.Key_LSta=0;
				if(key==1)break;//按中有效区域,退出播放	  		    
				key=0;
			}
		}
		JPUS=n;                //恢复到原先的频段
		set_frequency(bfactor);//把收音机恢复到先前的频率		
	}else //MP3作为铃声,播放歌曲
	{				 
		RingInfo.F_StartCluster=Alarm[AlarmInLine].Ring_Addr;  
		if(RingInfo.F_StartCluster<2)return;//没有铃声		    
		init_pt2314(MP3_Audio);//设置声音 	   
		delay_ms(20);  	 		 	 
		Vs1003SoftReset();//软复位VS1003 	 
		 	 
	    bfactor=fatClustToSect(RingInfo.F_StartCluster);//得到开始簇对应的扇区
		bcluster=RingInfo.F_StartCluster;				 //得到文件开始簇号	 			  
		key=0;	
		count=0;	 	    
		Pen_Point.Key_Sta=Key_Up;//释放按键			
		while(1)   //播放音乐的主循环
	    {
	        if(SD_ReadSingleBlock(bfactor,ALARMPLAYBUFFER))break;//读取一个扇区的数据   
	        count++;//扇区计数器 
			i=0;
			do      //主播放循环
	        {  	    
				if((GPIOC->IDR&MP3_DREQ)!=0)  //非暂停,送数据给VS1003
				{			   	 
		            for(n=0;n<32;n++)Vs1003_DATA_Write(ALARMPLAYBUFFER[i++]);//发送音乐数据    
				} 
				if((Pen_Point.Key_Sta==Key_Down||NPEN)&&Pen_Point.Key_LSta)key=Touch_To_Num(6);//不使用扩展按钮;	  
				if(PEN)//按键松开了,状态改变(状态机)
				{
					Pen_Point.Key_LSta=1;	 
					Pen_Point.Key_Sta=Key_Up;
				}   
				if(key)
				{
					Pen_Point.Key_LSta=0;   
					if(key==1)goto PLAYOVER;//按中有效区域,退出播放
					key=0;	  
				}
			}while(i<511);//循环发送512个字节    
	        bfactor++; //扇区加				  
	        if(count>=SectorsPerClust)//一个簇结束,换簇
	        {									  
	            count=0;  					 	   
	            bcluster=FAT_NextCluster(bcluster);
				//文件结束 
				if((FAT32_Enable==0&&bcluster==0xffff)||bcluster==0x0ffffff8||bcluster==0x0fffffff)break;//error	
	            bfactor=fatClustToSect(bcluster);
		    } 
		}
PLAYOVER:					  		 	  
		Vs1003SoftReset();//软复位	  
		LoadPatch();      //加载频谱分析代码
		Pen_Point.Key_LSta=0;
		Pen_Point.Key_Sta=Key_Up;	    
	}  
	init_pt2314(audioch);//恢复音源  
}

//处理闹钟中断后的进程
//执行中断里面闹钟的处理
//重新把下一个最近的闹钟值写入闹钟寄存器
void Alarm_Process(void)
{		   		    
	u16 cbcolor;
	u16 cpcolor;
	cbcolor=BACK_COLOR;	//保存先前的画笔状态
	cpcolor=POINT_COLOR;
	//对于只要闹铃一次的闹钟,在执行之后关闭闹钟					 

⌨️ 快捷键说明

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