📄 alarm.c
字号:
#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 + -