基于STM32电子钟语音报时

1.硬件平台

  • CPU:STM32F103ZE
  • 屏幕:3.5寸TFTLCD屏
  • 语音播报: VS1053
  • SD卡、外扩Sram

2.功能实现

  本示例主要设计两个界面:时间显示界面和日历界面
  1.通过按键切换界面;
  2.时间界面包含:时间表盘绘制、数字时间和日期显示、闹钟设置;支持按键校时和闹钟时间设置;
  3.日历界面支持查看日期;
  4.上电自动检测字库是否正常、报时语音包是否正常;支持SD卡字库和语音包更新;

3.示例效果

基于STM32电子钟语音播报

4.软件设计

4.1 VS1053初始化及播放音频

/**************硬件接口*****************
**VS_MISO -- PA6 主机输入
**VS_MOSI -- PA7 主机输出
**VS_SCK  -- PA5 时钟
**VS_XCS  -- PF7 命令片选(低电平有效)
**VS_XDCS -- PF6 数据片选(低电平有效)
**VS_DREQ -- PC13 数据请求线(高电平表示可以接收数据)
**VS_RST  -- PE6 复位脚(低电平复位)
**
*****************************************/void VS1053_Init(void)
{/*1. 开时钟*/RCC->APB2ENR|=1<<2;//PARCC->APB2ENR|=1<<4;//PCRCC->APB2ENR|=1<<6;//PERCC->APB2ENR|=1<<7;//PFGPIOA->CRL&=0x000FFFFF;GPIOA->CRL|=0x38300000;GPIOF->CRL&=0x00FFFFFF;GPIOF->CRL|=0x33000000;GPIOC->CRH&=0xFF0FFFFF;GPIOC->CRH|=0x00800000;GPIOE->CRL&=0xF0FFFFFF;GPIOE->CRL|=0x03000000;VS_XCS=1;VS_XDCS=1;VS1053_RST();VS1053_SetVoice(255,255);/*2.配置时钟寄存器*/VS1053_WriteRegDat(VS1053_CLOCKF,0x9800);
}
/*SPI收发一个字节*/
u8 VS1053_SPI_ReadWriteData(u8 data_tx)
{u8 data_rx=0;u8 i=0;for(i=0;i<8;i++){VS_SCK=0;if(data_tx&0x80)VS_MOSI=1;else VS_MOSI=0;VS_SCK=1;data_tx<<=1;data_rx<<=1;if(VS_MISO)data_rx|=0x01;}return data_rx;
}
/********************往寄存器中写入数据******************
**
**形参:u8 addr --地址
**          u16 data  -- 写入的数据
**********************************************************/
void VS1053_WriteRegDat(u8 addr,u16 data)
{while(VS_DREQ==0){}//等待数据线空闲VS_XDCS=1;//数据片选拉高VS_XCS=0;//命令片选拉低VS1053_SPI_ReadWriteData(0x02);//写指令VS1053_SPI_ReadWriteData(addr);   //寄存器地址VS1053_SPI_ReadWriteData(data>>8);VS1053_SPI_ReadWriteData(data>>0);//写入数据VS_XCS=1;
}
/*******************从寄存器中读取数据*******************/
u16 VS1053_ReadRegDat(u8 addr)
{u16 data=0;while(VS_DREQ==0){}//等待数据线空闲VS_XDCS=1;//数据片选拉高VS_XCS=0;//命令片选拉低VS1053_SPI_ReadWriteData(0x03);//读指令VS1053_SPI_ReadWriteData(addr);   //寄存器地址data=VS1053_SPI_ReadWriteData(0xff)<<8;data|=VS1053_SPI_ReadWriteData(0xff);VS_XCS=1;return data;
}
/****************音量调节*****************
**
**形参:u8 vol_l -- 左声道 0~254
**      u8 vol_r -- 右声道 0~254
**每个增量表示0.5db的衰减,值越大,音量越小
**注意:如果设置 VOL 的值为 0xFFFF,将使芯片进入掉电模式。
**右声道是高 8 位 左声道是低 8 位
*******************************************/
void VS1053_SetVoice(u8 vol_l,u8 vol_r)
{u16 temp=vol_r<<8|vol_l;VS1053_WriteRegDat(VS1053_VOL,temp);
}
/***************VS1053硬件复位**************/
void VS1053_RST(void)
{//硬件复位VS_RST=0;Delay_Ms(20);VS_XDCS=1;//取消数据传输VS_XCS=1;//取消命令传输VS_RST=1;//完成复位//软件复位while(VS_DREQ==0){}//等待数据线空闲VS1053_WriteRegDat(VS1053_MODE,0x0804);//设置为新模式,进行软件复位Delay_Ms(2);    while(VS_DREQ==0){}//等待数据线空闲,复位完成
}
/****获取解码时间******/
u16 VS1053_Get_Time(void)
{u16 time=0;time=VS1053_ReadRegDat(VS1053_DECODE_TIME);return time;
}
/****清除解码时间******/
void VS1053_Clear_Time(void)
{VS1053_WriteRegDat(VS1053_DECODE_TIME,0);
}
/**************播放音乐****************************/
u8 VS1053_PlayOneMusic(const char *data,u32 data_size)
{u32 i=0;/*3.设置音量*/VS1053_SetVoice(50,50);for(i=0;i;i++)>

4.2 表盘和日历

/*绘制表盘*/
void LCD_DrawClockDial(void)
{u8 buff[20];/*画表盘*/LCD_Circle(160,160,150,BLACK);//画圆LCD_Circle(160,160,151,BLACK);//画圆LCD_Circle(160,160,152,BLACK);//画圆/*画刻度*/u16 i;for(i=0;i<360;i+=6){LCD_DrawAngleLine(160,160,i,151,15,BLUE);//画任意角度直线}for(i=0;i<360;i+=30){LCD_DrawAngleLine(160,160,i,151,25,RED);//画任意角度直线}/*显示时间数据*/LCD_Display_Str(160-8,10+30,16,(u8 *)"12",BLACK);LCD_Display_Str(160-4,160+150-45,16,(u8 *)"6",BLACK);LCD_Display_Str(160+150-35,160-8,16,(u8 *)"3",BLACK);LCD_Display_Str(10+35,160-8,16,(u8 *)"9",BLACK);/*闹钟*/snprintf((char *)buff,sizeof(buff),"闹钟1:%s",alarm_clock1);LCD_Display_Str(Timeinfo.alarm1_x,Timeinfo.alarm1_y,24,(u8 *)buff,BLACK);snprintf((char *)buff,sizeof(buff),"闹钟2:%s",alarm_clock2);LCD_Display_Str(Timeinfo.alarm2_x,Timeinfo.alarm2_y,24,(u8 *)buff,BLACK);
}
/*绘制指针*/
static const char *celen_week[]={"一","二","三","四","五","六","日"};
void LCD_DrawTime(void)
{char buff[100];int time_sec=RTC_Time.sec;int time_min=RTC_Time.min;int time_h=RTC_Time.hour;static u8 stat=0;/*清除秒针*/LCD_DrawAngleLine(160,160,270+(time_sec-1)*6.0,110,110,WHITE);//清除上一秒/*处理时针*/LCD_DrawAngleLine(160,160,270+time_h*30.0+(time_min-1)*0.5,60,60,WHITE);//清除上次时针LCD_DrawAngleLine(160,160,270+time_h*30.0+time_min*0.5,60,60,BLACK);//画当前分位置/*处理分指针*/LCD_DrawAngleLine(160,160,270+(time_min-1)*6.0,90,90,WHITE);//清除上一分LCD_DrawAngleLine(160,160,270+time_min*6.0,90,90,BLACK);//画当前分位置//画秒针LCD_DrawAngleLine(160,160,270+time_sec*6.0,110,110,RED);//画当前秒位置/*数字时间显示*/stat=!stat;if(stat){snprintf(buff,sizeof(buff),"%02d:%02d",time_h,time_min);}else {snprintf(buff,sizeof(buff),"%02d %02d",time_h,time_min);}LCD_Display_Str(Timeinfo.time_x,330,24,(u8 *)buff,BLACK);snprintf(buff,sizeof(buff),"%04d/%02d/%02d 周 %s",RTC_Time.year,RTC_Time.month,RTC_Time.day,celen_week[RTC_Time.week-1]);LCD_Display_Str(Timeinfo.date_x,Timeinfo.date_y,24,(u8 *)buff,BLACK);LCD_Refresh();if(time_sec==0 && time_min==0){Voice_ReadData(voice_addr[time_h]);LCD_DrawAngleLine(160,160,270+(time_sec)*6.0,110,110,WHITE);//清除上一秒}snprintf(buff,sizeof(buff),"%02d:%02d",time_h,time_min);if((!strcmp(buff,(char *)alarm_clock1) || !strcmp(buff,(char *)alarm_clock2)) &&  time_sec==0){LCD_Display_Str(LCD_WIDTH-24*3-30,Timeinfo.alarm1_y+12,24,(u8 *)"时间到!",RED);LCD_Refresh();Voice_ReadData(voice_addr[24]);LCD_Display_Str(LCD_WIDTH-24*3-30,Timeinfo.alarm1_y+12,24,(u8 *)"       ",RED);LCD_Refresh();LCD_DrawAngleLine(160,160,270+(time_sec)*6.0,110,110,WHITE);//清除上一秒}
}

4.3 整点报时语音获取

  文字转语音网址:https://uutool.cn/text2voice/

4.4 字库加载、语音包加载

  res=f_mount(&fs,"",1);if(res){printf("磁盘挂载失败ret=%d\n",res);snprintf(buff,sizeof(buff),"err%d",res);LCD_Display_Str(20+strlen("SD卡状态")*12+20,20,16,(u8 *)buff,RED);LCD_Display_Str(20,50,16,(u8 *)"请检查SD卡是否插入!",RED);LCD_Refresh();Delay_Ms(1000);goto AA;}else LCD_Display_Str(20+strlen("SD卡状态")*12+20,20,16,(u8 *)"OK",RED);/*字库检测*/LCD_Display_Str(LCD_WIDTH/2-strlen("字库检测")/2*16,40,16,(u8 *)"字库检测",RED);LCD_Refresh();
GBK_16:W25Q64_ReadData(GBK_16_ADDR-10,(u8*)buff,9);//GBK16_OKif(strstr(buff,"GBK16_OK")){LCD_Display_Str(20,60,16,(u8 *)"GBK16    OK",RED);LCD_Refresh();}else {LCD_Display_Str(20,60,16,(u8 *)"GBK16    NO",RED);LCD_Display_Str(LCD_WIDTH/2-strlen("更新GBK16字库")/2*16,80,16,(u8 *)"更新GBK16字库",RED);LCD_Refresh();if(SDcard_DownFont("0:/font/GBK_16.DZK",GBK_16_ADDR,16))//字库更新{LCD_Display_Str(LCD_WIDTH/2-strlen("                 ")/2*16,80,16,(u8 *)"                 ",WHITE);LCD_Display_Str(10,80,16,(u8 *)"请将GBK_16.DZK放到/font/目录下,重启!",BLACK);LCD_Refresh();}else {LCD_Display_Str(LCD_WIDTH/2-strlen("                 ")/2*16,80,16,(u8 *)"                 ",WHITE);LCD_Display_Str(20,100,16,(u8 *)"                   ",WHITE);LCD_Refresh();goto GBK_16;}}  /*GBK24_OK*/
GBK_24:W25Q64_ReadData(GBK_24_ADDR-10,(u8*)buff,9);if(strstr(buff,"GBK24_OK")){LCD_Display_Str(20,100,16,(u8 *)"GBK24    OK",RED);LCD_Refresh();}else {LCD_Display_Str(20,100,16,(u8 *)"GBK24    NO",RED);LCD_Display_Str(LCD_WIDTH/2-strlen("更新GBK24字库")/2*16,120,16,(u8 *)"更新GBK24字库",RED);LCD_Refresh();if(SDcard_DownFont("0:/font/GBK_24.DZK",GBK_24_ADDR,24))//字库更新{LCD_Display_Str(LCD_WIDTH/2-strlen("                 ")/2*16,120,16,(u8 *)"                 ",WHITE);LCD_Display_Str(10,120,16,(u8 *)"请将GBK_24.DZK放到/font/目录下,重启!",BLACK);LCD_Refresh();}else {LCD_Display_Str(LCD_WIDTH/2-strlen("                 ")/2*16,120,16,(u8 *)"                 ",WHITE);LCD_Display_Str(20,140,16,(u8 *)"                   ",WHITE);LCD_Refresh();goto GBK_24;}}  /*语音包检测*/LCD_Display_Str(LCD_WIDTH/2-strlen("语音包检测")/2*16,140,16,(u8 *)"语音包检测",RED);LCD_Refresh();
VOICE_STAT:Voice_ReadAddr(voice_addr);//获取每个音频文件存放位置for(i=0;i<25;i++){if(voice_addr[i]==0)break;}if(i!=25){LCD_Display_Str(20,140+20,16,(u8 *)"语音包    ERR",RED);LCD_Display_Str(LCD_WIDTH/2-strlen("更新语音包")/2*16,140+40,16,(u8 *)"更新语音包",RED);LCD_Refresh();if(Voice_Download_W25Q64("voice"))//将语音包数据写入到W25Q64中{LCD_Display_Str(LCD_WIDTH/2-strlen("                 ")/2*16,160+60,16,(u8 *)"                 ",WHITE);LCD_Display_Str(10,140+60,16,(u8 *)"请将语音MP3放到/voice/目录下,重启!",BLACK);LCD_Refresh();goto VOICE_STAT;}else {LCD_Display_Str(10,160+60,16,(u8 *)"语音包更新完成",RED);LCD_Refresh();}}else {LCD_Display_Str(20,160+60,16,(u8 *)"语音包 OK",RED);LCD_Refresh();}f_unmount("");//取消SD卡挂载LCD_Display_Str(10,160+100,16,(u8 *)"系统文件自检完成,请移除SD卡!",RED);LCD_Display_Str(55,160+130,24,(u8 *)"欢迎使用电子时钟!",RED);LCD_Display_Str(75,160+165,24,(u8 *)"正在启动中",RED);

4.5 主函数

VS1053_Init();//VS1053初始化LCD_DrawClockDial();RTC_Init();//RTC初始化rtc_stat=1;u8 touch_stat=0;u16 x1,x2,y;while(1){if(usart1_flag){usart1_rx_buff[usart1_cnt]='\0';printf("rx:%s\r\n",usart1_rx_buff);//rx:*20210609115254
//        printf("usart1_rx_cnt=%d\n",usart1_cnt);if(usart1_rx_buff[0]=='*' && usart1_cnt == 15){RTC_Time.year=(usart1_rx_buff[1]-'0')*1000+(usart1_rx_buff[2]-'0')*100+(usart1_rx_buff[3]-'0')*10+(usart1_rx_buff[4]-'0')*1;RTC_Time.month=(usart1_rx_buff[5]-'0')*10+(usart1_rx_buff[6]-'0')*1;RTC_Time.day=(usart1_rx_buff[7]-'0')*10+(usart1_rx_buff[8]-'0')*1;RTC_Time.hour=(usart1_rx_buff[9]-'0')*10+(usart1_rx_buff[10]-'0')*1;RTC_Time.min=(usart1_rx_buff[11]-'0')*10+(usart1_rx_buff[12]-'0')*1;RTC_Time.sec=(usart1_rx_buff[13]-'0')*10+(usart1_rx_buff[14]-'0')*1;printf("%d/%d/%d -- %d:%d:%d\r\n",RTC_Time.year,RTC_Time.month,RTC_Time.day,RTC_Time.hour,RTC_Time.min,RTC_Time.sec);//RTC时间校准Time_Conversion_Sec(RTC_Time.year, RTC_Time.month,RTC_Time.day,RTC_Time.hour,RTC_Time.min,RTC_Time.sec); LCD_Clear(WHITE);LCD_DrawClockDial();}      usart1_flag=0;usart1_cnt=0;}if((key_val&1<<0) && rtc_stat!=1)//时钟界面{key_val&=~(1<<0);rtc_stat=1;LCD_Clear(WHITE);LCD_DrawClockDial();}else if(key_val&1<<1)//日历界面{key_val&=~(1<<1);rtc_stat=2;LcdDrawcalen(RTC_Time.year,RTC_Time.month,RTC_Time.day);u16 year=RTC_Time.year;u8 month=RTC_Time.month;u8 day=RTC_Time.day;while(1){if(key_val)break;touch_stat=XPT2046_ReadXY();if(touch_stat){x1=touch_info.x;while(T_PEN==0)//等待松开{XPT2046_ReadXY();x2=touch_info.x;}if(x1-x2>20){if(month>=12){month=1;year++; }else month++;LcdDrawcalen(year,month,day);}else if(x2-x1>20){if(month<=1){month=12;year--; }else month--;LcdDrawcalen(year,month,day);}}}}touch_stat=XPT2046_ReadXY();if(touch_stat && rtc_stat==1)进入时间设置{y=touch_info.y;if(y<=Timeinfo.time_y+24 && y>=Timeinfo.time_y){u16 hour=RTC_Time.hour;u8 min=RTC_Time.min;u16 year=RTC_Time.year;u16 month=RTC_Time.month;u16 day=RTC_Time.day;Time_Calibration(year,month,day,hour,min);//printf("设置时间\r\n");}else if(y<=Timeinfo.alarm1_y+24 && y>=Timeinfo.alarm1_y)//设置闹钟时间1{u8 hour,min;sscanf((char *)alarm_clock1,"%02d:%02d",(int *)&hour,(int *)&min);//printf("hour=%d,min=%d\n",hour,min);Time_SetAlarm(hour,min,1);}else if(y<=Timeinfo.alarm2_y+24 && y>=Timeinfo.alarm2_y)//设置闹钟时间2{u8 hour,min;sscanf((char *)alarm_clock2,"%02d:%02d",(int *)&hour,(int *)&min);//printf("hour=%d,min=%d\n",hour,min);Time_SetAlarm(hour,min,2);}}}
}


  示例链接:https://download.csdn.net/download/weixin_44453694/85456736

基于STM32电子钟语音报时相关推荐

  1. 基于STM32智能语音台灯的设计与实现

    本项目设计的是一款基于STM32的智能语音台灯,主要利用了自动语音识别技术(非特定人语音识别)以及STM32F103C8T6主控单片机内的按键中断机制,通过语音和按键来控制定时器的参数影响PWM波的占 ...

  2. 基于stm32智能语音电梯消毒系统

    这次来分享个最近做的项目,stm32智能语音电梯消毒系统 功能说明:在电梯,房间,客道区域内,检测到人,则执行相关动作!例如继电器开关灯,喷洒酒精等行为.手机app/微信小程序可以控制需要执行的动作 ...

  3. 基于STM32 + SYN6288语音播报

    重要的懒人提醒:代码下载方式,躺在最底那儿~~ 一.接线示例: 二.模块重点: 1:5V供电 ,功耗约120mA (带图中小喇叭): 2:最少接3根线:5V,  GND,  RXD,TXD-可不接,B ...

  4. STM32单片机语音声控智能台灯可调光冷暖光人检测锂电池供电太阳能和USB充电

    实践制作DIY- GC0022-语音声控智能台灯 一.功能说明: 基于STM32单片机设计-语音声控智能台灯 功能介绍: 硬件:STM32F103C最小系统+语音识别模块+18650锂电池+太阳能充电 ...

  5. 基于STM32的esp8266WIFI自动校时+语音报时可调时钟(附源代码)

    基于STM32WIFI自动校时+语音报时可调时钟(附源代码) 概述 STM32f103C8T6最小系统 共阴数码管 74HC595芯片 JQ5600语音模块 ESP8266-01SWIFI模块 ds1 ...

  6. 基于STM32设计的指针式电子钟与万年历

    1. 项目简介 这是基于STM32设计的一个指针式电子钟+万年历小项目,采用3.5寸的LCD屏显示时钟,日历.温度.天气,支持触摸屏调整设置时间,设置闹钟,查看日历等等.整体项目主要是技术点就是LCD ...

  7. stm32舵机控制程序_免费开源基于STM32的lt;智能垃圾桶gt;之语音播报

    大家好,我是『芯知识学堂』的SingleYork,前面给大家简单介绍了和,今天笔者将要给大家介绍我们这个DIY智能垃圾桶套件中"语音播报模块"的详细使用. 这个"语音播报 ...

  8. 基于STM32单片机的电子钟(Proteus仿真+程序)

    编号:12 基于STM32单片机的电子钟 功能描述: 本设计由STM32单片机+液晶1602+按键+RTC时钟组成. 1.采用STM32F103最小系统板. 2.利用STM32内部自带RTC时钟提供时 ...

  9. 智能垃圾桶c语言程序,『免费开源』基于STM32的智能垃圾桶之语音播报

    大家好,我是『芯知识学堂』的SingleYork,前面给大家简单介绍了<基于STM32的智能垃圾桶之成员简介>和<基于STM32的智能垃圾桶之语音识别>,今天笔者将要给大家介绍 ...

最新文章

  1. Nature子刊:遗传发育所白洋组发表高通量分离培养和鉴定根系细菌的方法
  2. Apache rewrite
  3. 复杂数据权限设计方案
  4. 3.以太坊之秘钥文件
  5. cvpr 2015 2016论文地址
  6. UA MATH563 概率论的数学基础 中心极限定理4 独立一元随机变量的性质
  7. 关于小程序取data- 的值的问题
  8. 在Nginx服务器上用Jenkins发布Vue/React代码的步骤
  9. 因果推断理论框架 Potenial Outcomes Framework
  10. 高速列车横向17自由度模型
  11. 国产数据库及厂商介绍
  12. Python绘制多维度专题地图
  13. 生成对抗网络(GAN)论文原文详解
  14. 眼科赛道的“觉醒年代”,清晰医疗赴港能否具备后发优势?
  15. 五百亿!又一大型平台崩了!85后女老板跑路!
  16. 且行且走 (8月24,25日)
  17. pikachu靶场-5 远程命令,代码执行漏洞(RCE)
  18. 七大IT业界顶尖认证证书
  19. 一文读懂Kubernetes Scheduler扩展功能
  20. 微型计算机的典型结构式,试卷正文1新.doc

热门文章

  1. 国产元宇宙电影要来了? 《元宇宙2086》影视动漫首批概念图曝光
  2. Description 一个笼子里关了若干鸡和兔子,鸡有2只脚,兔子有4只脚,没有例外。已知笼子里脚的 总数a,问笼子里至少有多少只动物,至多有多少只动物? Input 第一行是测试数据的组数n,后面
  3. 【莫言语录】莫言说过的经典语录摘记
  4. Markdown - 做好看的笔记
  5. 青云霍秉杰:一文读懂Prometheus长期存储主流方案
  6. 赵小楼《天道》深度解析(69)不要执著于豆豆和书,或寻找高人。更多的是要在意内容、内容、内容。你掌握之后,你也是高人
  7. 200行纯C++代码构建一个捕鱼游戏「源码已打包」
  8. 用免费OA办公系统打造统一移动办公系统
  9. 公开密钥基础设施PKI
  10. Nine Knights