小作品基于STM32的天气预报系统
以前在学校时候做的一个小作品,分享给大家。1、作品介绍
首先,看一下作品的演示视频:
视频加载中...
温馨提示:因为是进行人机对话演示,所以应打开音量观看哈。
这是本人之前的一个小作品,一个智能的天气预报系统。显示屏上显示各种天气指标及实时显示时间日期等。可以使用触摸屏输入城市名称搜索天气,也可以使用语音搜索天气。 1.1 系统功能
作品包含的的功能有:
(1)实时天气显示,温湿度显示,日历显示;
(2)收音机功能;
(3)人机对话功能。
系统框图如下:
1.2 系统GUI界面
(1)主界面
你没有看错,就是99℃,就是星期八。但这不是系统出错,而是本人故意设置的初始值,每当开机收到天气数据之后就可以看出有明显的变化。
(2)菜单界面
(3)wifi设置界面
点击文本框会进入键盘界面,输入WiFi信息之后返回,再点击 Add 按钮即可发送WiFi名称与密码给控制器,控制器控制WiFi模块连接WiFi热点。
(4)收音机界面
通过点击下方频率点跳到相应频率,再通过左右按钮调节频率至所需频率。 2、作品实现2.1 天气数据获取及解析2.1.1 天气数据从哪来?
天气数据可以从一些专门做天气预报的网站获取,如心知天气、和风天气等。本人选择的是心知天气
https://www.seniverse.com/
网站首页如下:
我们是通过其 API密钥 才能获取得到其天气数据,而只有注册的用户才拥有API密钥,所以必须得注册,可以点击右上角进行注册。2.1.2 天气数据是什么格式?
登录 心知天气 网站之后,点击菜单导航中的数据->常规数据 即可查看API文档 。在API文档页面的左侧可看到一些可查看的条目,如:
可点击 天气实况 查看其相关说明,可以看到其天气数据格式如下图所示:
这就是JSON格式的数据,不了解JSON的朋友可查看往期文章:例说嵌入式实用知识之JSON数据
2.1.3 如何解析得到有用的数据?
从上图中的JSON格式天气数据包中我们可以看出:我们需要用到的数据就是 冒号后面的字符串数据 ,这些数据是我们需要获取并显示到屏幕上的数据。
那么,我们该怎么从这一堆JSON格式数据中解析出冒号后面的字符串呢?并且,这个系统是基于单片机的天气预报系统。而单片机使用C语言进行编程开发的,所以我们得使用C语言对这些JSON天气数据包进行解析。
其实,有一个专门解析JSON数据包的第三方C语言库。我们可以使用这个库进行解析,这个CJSON库的下载链接为:
链接:https://pan.baidu.com/s/1DQynsdlNyIvsVXmf4W5b8Q 提取码:ww4z
只要把 cJSON.c 与cJSON.h 放到工程主程序所在目录,然后在主程序中包含头文件JSON.h 即可引入该库。如:
下面给出一个实例:
测试代码: /*---------------------------------------------------------------------------------------- 程序功能:解析JSON天气数据包now.json(天气实况) 微信公众号:嵌入式大杂烩 ----------------------------------------------------------------------------------------*/ //1、数据来源:心知天气(api.seniverse.com) //2、获取方法:GET https://api.seniverse.com/v3/weather/now.json?key=2owqvhhd2dd9o9f9&location=beijing&language=zh-Hans&unit=c //3、返回的数据范例见文件test.txt #include #include #include #include "cJSON.h" //函数声明 int cJSON_WeatherParse(char *JSON); /********************************************************************************* * Function Name : main主函数 * Parameter : NULL * Return Value : 0 * Function Explain : **********************************************************************************/ int main(int argc, char **argv) { FILE *fp; char *data; int len; int i; if((fp = fopen("now.txt","rb")) == NULL) { printf("Open error! "); return 1; } fseek(fp, 0, SEEK_END); // 文件指针指向文件末尾 len = ftell(fp); // 求文件长度 fseek(fp, 0, SEEK_SET); // 文件指针指向文件开头 data = (char*)malloc(len+1); fread(data, len, 1, fp); fclose(fp); //printf("read file %s complete, len=%d. ","now.txt",len); cJSON_WeatherParse(data); // 解析天气数据 free(data); system("pause"); return 0; } /********************************************************************************* * Function Name : cJSON_WeatherParse,解析天气数据 * Parameter : JSON:天气数据包 results:保存解析后得到的有用的数据 * Return Value : 0:成功 其他:错误 * Function Explain : **********************************************************************************/ int cJSON_WeatherParse(char *JSON) { cJSON *json,*arrayItem,*object,*subobject,*item; json = cJSON_Parse(JSON); if(json == NULL) { printf("Error before: [%s] ",cJSON_GetErrorPtr()); return 1; } else { if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL); // 匹配字符串"results",获取数组内容 { int size = cJSON_GetArraySize(arrayItem); // 获取数组中对象个数 //printf("cJSON_GetArraySize: size=%d ",size); if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL) // 获取父对象内容 { if((subobject = cJSON_GetObjectItem(object,"location")) != NULL) { printf(" -------------------------------location----------------------------- "); if((item = cJSON_GetObjectItem(subobject,"id")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"name")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"country")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } } if((subobject = cJSON_GetObjectItem(object,"now")) != NULL) { printf("---------------------------------now------------------------------- "); if((item = cJSON_GetObjectItem(subobject,"text")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"code")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"feels_like")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"pressure")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"humidity")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"visibility")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"wind_direction")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"wind_speed")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"wind_scale")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"clouds")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } if((item = cJSON_GetObjectItem(subobject,"dew_point")) != NULL) { printf("%s : %s ",item->string,item->valuestring); } } if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL) { printf("----------------------------last_update---------------------------- "); printf("%s : %s ",subobject->string,subobject->valuestring); } } } } cJSON_Delete(json); return 0; }
这个测试程序会去读取我们工程目录下的 now.txt 件,所以事先我们需要把JSON格式的天气预报数据复制到该文件中:
把 now.txt 里面的数据读出并保存到data 指向的动态内存中。然后再把data 中的数据传入我们事先编写好的解析天气数据的函数int cJSON_WeatherParse(char *JSON) 中进行解析,最后把解析之后的数据给到该函数的返回值即可。
解析函数里主要用到以下函数: 1、cJSON_Parse函数 cJSON*cJSON_Parse(const char *value);
该函数用来解析JSON数据包,并按照cJSON结构体的结构序列化整个数据包。
2、cJSON_GetObjectItem函数 cJSON_GetObjectItem(cJSON *object,const char *string);
该函数可从cJSON结构体中查找某个子节点名称(键名称),如果查找成功可把该子节点序列化到cJSON结构体中。
3、cJSON_GetArraySize函数 cJSON_GetArraySize(const cJSON *array);
该函数可获取数组中元素个数。
4、cJSON_GetArrayItem函数 cJSON_GetArrayItem(const cJSON *array, int index);
该函数可获取数组中的内容。
5、cJSON_Delete函数 cJSON_Delete(cJSON *c);
该函数用来释放 cJSON_Parse 函数内部申请的堆内存。
我们的解析函数主要运用多次 cJSON_GetObjectItem 来匹配各对象成员,然后取出各个键值对的值valuestring 。
该程序的运行结果如下:
可见,解析完全正确!解析结果中冒号后面的数据就是我们可以选择使用的数据。这是解析当天的天气实况数据,解析未来几天的天气数据包或是其它天气数据包的方法都是类似的。 2.2 显示部分2.2.1 几类常用的显示屏
液晶显示屏的接口较为常见的有 3 种类型: RGB 接口 ,MCU 总线接口 ,串口 HMI 。
(1)RGB 接口
RGB 接口必须用在 带有RGB驱动的ARM芯片 上,一般的 ARM9 芯片有少许支持 RGB 的,ARM9 以上的芯片多数支持 RGB.但是此类接口的驱动是最复杂 的,对硬件要求也是最高 的。
(2)MCU 总线接口
MCU 总线接口驱动比 RGB 简单一些,对硬件也基本没有任何要求,简单的 MCU 就可以驱动。但是界面的显示 驱动工作量很大 。
总线型接口的屏只提供点阵的操作。图片,字符等任何显示内容都是通过取模数据,在屏幕上相应的位置把点阵一个一个的打出来。在此基础上再来实现人机界面的逻辑。工作量很大。
(3)串口 HMI
串口HMI是一种新的显示方案。首先它跟MCU总线屏一样 对硬件没有任何要求 ,其次。它没有速度瓶颈 ,因为界面的显示是设备内部自己实现的,用户MCU只是发送指令,并不需要底层驱动。
再次,针对显示的人机界面的布局和大多数的逻辑(比如界面背景,按钮效果,文本显示等)。全部都不需要用户的 MCU 参与,使用设备提供的上位软件,在电脑上点几下鼠标就完成了。制作好资源文件以后下载到屏幕即可自动运行,剩下的就是 USART 交互了。 2.2.2 本系统的显示方案
本系统选择的是 串口HMI 这一显示方案。因为这种方案确实是可以在短时间内设计出比较漂亮的GUI界面。GUI界面设计软件如下图:
这是串口屏商家给的配套的GUI设计软件,该软件的下载链接:
链接:https://pan.baidu.com/s/1uYFhF412WVkk0FuqeOAGCg 提取码:e70r
我们可以从左侧的工具箱里往工作区里拖拽需要用到的控件,常用的控件有文本控件、文字控件、按钮控件等。可在右侧的属性窗口设置控件的属性。可以通过选择不同的字库来设置不同的字体样式。
控件、页面的切换或则触发可能会产生相应的事件,可以通过代码来控制。其中,页面、控件的背景是可以上传本地的图片的,所以可以事先通过PS或则其他作图软件设计出精美的背景图片,然后再把控件都设置为透明色,最终地显示效果就可以达到很好的效果。
总之,可以很方便很容易设计出精美的GUI界面。同时,这个GUI设计软件还具有模拟真实的屏幕的功能,可以很方便地与用户MCU进行联调。仿真界面如图所示:
进入模拟器界面,可在下方选择数据的输入方式为 用户MCU输入 ,然后设置相应的串口号和波特率即可。还可以实时查看用户MCU传给模拟器的数据。2.3 与天气服务器通信
每个问题的解决往往都不能一步到位,要把这个问题的所有关键点找出来,着手去解决这些关键点,最终问题自然会得到解决。
同样的,虽然我们最终是用单片机控制WiFi模块来获取天气数据的,但是我们首先应该确保在没有单片机的情况下能获取得到天气数据,确保能和天气服务器正常通信。只有这样,在使用单片机获取数据遇到问题时才知道出错的范围在哪,便于我们进行调试。下面,分享windows下与天气服务器通信的测试方法: 2.3.1 所需的工具
网络调试助手 。本人使用的是SocketTool ,SocketTool 是一款小巧实用且功能强大的TCP/UDP 网络通讯调试工具,可以帮助你检查网络应用软件及硬件的通讯情况,可以创建Socket服务器,如创建UDP组播地址及端口、创建UDP Client客户端、创建TCP Client、创建TCP Server。
该工具下载链接为:
链接:https://pan.baidu.com/s/1fgarl8xNb6nEAl3Ly0NQ3w 提取码:np5v 2.3.2 测试方法
(1)首先,使用 SocketTool 工具建立一个TCP Client ,对方IP设为:116.62.81.138 (这是心知天气服务器的IP地址),对方端口设为80。如:
怎么才能知道一个网站的IP呢?在cmd窗口下输入 ping+域名 即可得该域名对应的IP,如我们ping 百度:
ping 是Windows、Unix和Linux系统下的一个命令,利用ping命令可以检查网络是否连通,可以很好地帮助我们分析和判定网络故障,该命令还可以加许多参数使用,具体是键入Ping按回车即可看到详细说明。
(2)发送HTTP请求,向心知天气服务器请求天气数据。HTTP有几种请求方法,我们这里使用的是GET请求:
GET请求:从指定的资源请求数据。
具体的请求方法示例为: GET https://api.seniverse.com/v3/weather/now.json?key=2owqvhhd2dd9o9f9&location=beijing&language=zh-Hans&unit=c
其中,GET后面的URL地址可以上心知天气查看,如:
URL中的几个参数是可以设置的:
key:你的API密钥 location:所查询的地点 language:语言 unit:单位
在 SocketTool 工具中发送GET请求 (首先先得点击连接 按钮进行连接),发送格式如下:
需要注意的问题就是每个GET请求之后都需要空两行,这两个换行也是GET请求的一部分,所以在编写单片机代码时需要注意的是要在这个请求字符串后添加 r r ,表示换两行。
服务器返回的天气数据为:
看看服务器返回的数据,发现中文都是乱码。原因是获取得的天气数据是utf-8格式,必须转换为GBK格式中文才能正常显示。此处,我们只是测试与服务器是否能正常交互,测试结果显示有数据返回,说明通过以上的GET请求时可以获取到数据的。
在应用到单片机上时,还需要考虑的问题就是怎么把utf-8格式转换为GBK格式的问题,转换后中文才能正常显示在显示屏上。 2.4 语音对话功能
本系统人机对话功能采用了两个硬件模块:(1)语音识别模块:采用 LD3320 语音识别芯片;(2)语音合成模块:采用SYN6288 语音合成芯片。2.4.1 语音识别
本系统语音识别模块采用的语音芯片是LD3320。该芯片已经集成了语音识别的处理器,不需要外接其他的辅助芯片如Flash、 RAM 等,直接嵌入在现有的产品中就可以实现语音识别的功能。
语音识别的过程为: (1)先预存要识别的关键词,如: //-------------------------搜索天气----------------------------------- #define STR00 "xiao tian" // 小天 #define STR01 "sou suo fu zhou tian qi" // 搜索福州天气 #define STR02 "sou suo shang hai tian qi" // 搜索上海天气 #define STR03 "sou suo shen zhen tian qi" // 搜索深圳天气 #define STR04 "sou suo bei jing tian qi" // 搜索北京天气 #define STR05 "sou suo guang zhou tian qi" // 搜索广州天气 #define STR06 "sou suo nan ning tian qi" // 搜索南宁天气 #define STR07 "sou suo xia men tian qi" // 搜索厦门天气 #define STR08 "sou suo quan zhou tian qi" // 搜索泉州天气 #define STR09 "sou suo pu tian tian qi" // 搜索莆田天气 #define STR10 "sou suo nan ping tian qi" // 搜索南平天气
可以预存50条关键词(关键句),本人已经把关键词写死在程序里了,这显然就不能灵活的面对各种场景。其实可以通过代码编写一个学习功能,即识别之前首先进行学习一些即将要识别的关键词,然后在进行识别演示,这样就可以应对比较多的场景。
但是,这样还是不够智能,毕竟只能识别已经预存的关键词(关键句),要是没有预存就没办法识别了。所以真正的语音识别应该是在软件算法上下功夫,关于语音识别已然成为热门的一大研究专题,这就属于人工智能的范畴吧。希望以后可以有机会接触这一块,如有接触再做学习分享~
(2)开始识别,如: static void Task_ASR(void) { switch(nAsrStatus) { case LD_ASR_RUNING: case LD_ASR_ERROR: break; case LD_ASR_NONE: nAsrStatus=LD_ASR_RUNING; if (RunASR()==0) // 启动一次ASR识别流程:ASR初始化,ASR添加关键词语,启动ASR运算 { nAsrStatus = LD_ASR_ERROR; } break; case LD_ASR_FOUNDOK: nAsrRes = LD_GetResult( ); // 一次ASR识别流程结束,去取ASR识别结果 ASRSuccess_Handle(nAsrRes); nAsrStatus = LD_ASR_NONE; break; case LD_ASR_FOUNDZERO: default: nAsrStatus = LD_ASR_NONE; break; } }
nAsrStatus 是用来表示语音识别的状态,不是LD3320 芯片内部的状态寄存器。nAsrStatus 有几种情况。我们比较关注的是LD_ASR_FOUNDOK 状态。LD_ASR_FOUNDOK 状态为识别成功,识别成功后将调用ASRSuccess_Handle 函数进行识别后的操作。
(3)识别成功则执行相应操作,如 void ASRSuccess_Handle(uint8 asr_code) { printf("r 识别码:%d ",asr_code); if(0 == asr_code) { printf("我在,需要我的帮助吗? "); TTSPlay(0, "[t3][2]我在,[2]需要[2]我的[3]帮助吗"); RunFlag = TRUE; } else if(RunFlag) { RunFlag = FALSE; /* 识别码0-10为搜索天气识别码 */ if(asr_code>=0&&asr_code<=10) { switch(asr_code) { case CODE01: printf(""福州"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索福州天气"); memcpy(g_city,"fujianfuzhou",sizeof(g_place)); break; case CODE02: printf(""上海"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索上海天气"); memcpy(g_city,"shanghai",sizeof(g_place)); break; case CODE03: printf(""深圳"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索深圳天气"); memcpy(g_city,"shenzhen",sizeof(g_place)); break; case CODE04: printf(""北京"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索北京天气"); memcpy(g_city,"beijing",sizeof(g_place)); break; case CODE05: printf(""广州"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索广州天气"); memcpy(g_city,"guangzhou",sizeof(g_place)); break; case CODE06: printf(""南宁"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索南宁天气"); memcpy(g_city,"nanning",sizeof(g_place)); break; case CODE07: printf(""厦门"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索厦门天气"); memcpy(g_city,"xiamen",sizeof(g_place)); break; case CODE08: printf(""泉州"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索泉州天气"); memcpy(g_city,"quanzhou",sizeof(g_place)); break; case CODE09: printf(""莆田"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索莆田天气"); memcpy(g_city,"putian",sizeof(g_place)); break; case CODE10: printf(""南平"命令识别成功r "); TTSPlay(0, "[t3][2]小天正在为您搜索南平天气"); memcpy(g_city,"nanping",sizeof(g_place)); break; } memset(&weather_data, 0, sizeof(weather_data)); GET_NowWeather(); GET_DailyWeather(); GetWeatherTimer = TIMER1_HOUR; DisplayWeather(weather_data); DisplayWeatherIcon(weather_data); } else { switch(asr_code) { case CODE11: printf(""语音播报天气"命令识别成功r "); printf("%s ",g_WeatherText); // TTSPlay(0, (uint8_t*)g_WeatherText); break; case CODE12: printf(""今天的气温是多少"命令识别成功r "); break; default: TTSPlay(0, "语音识别失败,请对准麦克风说话!"); break; } } } }2.4.2 语音合成
本系统的语音合成模块采用SYN6288语音合成芯片,支持文本直接转化为语音。其与单片机的通信方式为串口通信。向该模块发送以下格式的数据包:
5字节帧头+文本+1字节校验,文本字节数小于等于200字节
即可合成语音。代码如: // 微信公众号:嵌入式大杂烩 void TTSPlay(uint8_t Music,uint8_t *Text) { /****************需要发送的文本**********************************/ uint8_t DataPacket[50]; // uint8_t Text_Len; uint8_t ecc = 0; //定义校验字节 uint8_t i=0; Text_Len =strlen((const char*)Text); //需要发送文本的长度 /*****************帧固定配置信息**************************************/ DataPacket[0] = 0xFD ; //构造帧头FD DataPacket[1] = 0x00 ; //构造数据区长度的高字节 DataPacket[2] = Text_Len + 3; //构造数据区长度的低字节 DataPacket[3] = 0x01 ; //构造命令字:合成播放命令 DataPacket[4] = 0x01 | Music<<4 ; //构造命令参数:背景音乐设定 /*******************校验码计算***************************************/ for(i = 0; i<5; i++) //依次发送构造好的5个帧头字节 { ecc=ecc^(DataPacket[i]); //对发送的字节进行异或校验 } for(i= 0; i
氢取第一金龙汽车集团旗下三家企业喜获省科学技术奖日前,2020年度福建省科学技术奖正式公布,金龙汽车集团旗下三家企业喜获科技进步一等奖一项三等奖两项。金龙汽车集团本次获奖的项目均和新能源密切关联。其中,获得一等奖的,是金旅客车金
华人首富赵长鹏是谁?感染了新冠的赵长鹏身穿4年前300美元买的西装,戴苹果的AppleWatch,住2000美元一晚的酒店,他去年9月在迪拜刚买了一套公寓。财富杂志说他的身价740亿美元,他发推特说没
3。31比特币持续下行,以太坊回踩试探支撑?比特币矿企Bitfarms发布Q4财报BTC持有总量或已达到4,301枚金色财经消息,比特币矿企Bitfarms发布Q4财报和全年业绩数据,该公司四季度收入达到6,000万美元,较
从亏44亿到赚18。5亿,阅文免费后怎么反而赚钱了?去年还因收购新丽巨亏44亿的大阅文,今年就用18。5亿元的净利润为自己正名。连新丽集团也不再拖后腿,一年赚了5。3亿元。看来经过一年的调试,阅文集团真正走过了低谷期。不过这并非意味
何晟铭解锁新身份,出任启牛学堂品牌体验官赋能国人成长,知识点量未来。3月30日,尔湾科技品牌升级发布会如期举行,会上,尔湾科技品牌正式升级为量子之歌。量子之歌集团创始人CEO李鹏,量子之歌集团联合创始人白柏,量子之歌集团
互联网前浪张朝阳,依然战斗在一线雷达财经出品文张凯旌编深海张朝阳的物理课真上头。最近在社交平台中搜索张朝阳,可以看到类似的评价。雷达财经注意到,这位搜狐CEO自2021年11月就开始在线上直播上物理课,不久前的3
为何超市扫码枪不用输密码就能支付?微信和支付宝有漏洞吗?为何超市扫码枪不用输密码就能支付?微信和支付宝有漏洞吗?随着移动互联网的发展,人们的生活方式也发生了很大的改变,今天我们来聊聊付款方式。如今我国已经迎来了移动支付时代,在这方面可以
网约车的路网约车的路越走越难,尤其是平台的野蛮生长,司机的野蛮生长,平台和司机的内卷格外严重,司机们心不齐,司机心奇的话所有的问题都可以迎刃而解,司机老是任人宰割,各大平台都在无底线的试探着
骁龙888Plus12GB512GB5000mAh,红米的最大竞争者众所周知,现在手机的性价比市场可以说是越来越大,也是越来越受欢迎的。要说性价比市场最具代表性的品牌,应该要非红米莫属了。作为小米的子品牌,红米的手机兼具了比较高的性能与价高的性价比
大疆Mavic3s无人机或在研发中强化长焦副摄提升续航表现去年下半年,大疆正式发布了DJIMavic3无人机,其采用43英寸的大底主摄以及加入长焦副摄的配置为消费级无人机市场带来了新的变化,不过最近有外媒透露,DJIMavic3的下一代无
iPhone14定价方案曝光14起售599914Pro起售8999按照惯例,苹果将会在今年的秋季发布会上推出iPhone14系列新品,这也是目前果粉最为期待的一款手机,虽然从现在算起来大约还有半年时间,不过按照苹果新品的研发进度来看,目前已经到了