移远4G模组拨号+socket获取天气数据

嵌入式大杂烩 2020-06-26 00:00

点击上方「嵌入式大杂烩」,选择「置顶公众号」第一时间查看嵌入式笔记!

上一篇分享了《基于4G Cat.1的内网穿透实践》,这一篇笔记我们直接使用4G开发板访问天气服务器获取天气数据。

我们要使用移远4G模块进行网络通信,要经历 3 个主要过程:网络注册网络激活socket 创建

网络注册是自动完成的,无需用户代码干预(网络注册前,请确认 SIM 卡是否正常识别且 SIM 卡无欠费等业务异常)。

只有在网络注册成功以后,才可进行网络激活,即本文所述的拨号(下文皆称为拨号)。只有拨号成功后,才可进行 socket 网络通信。

拨号+socket 通信基本流程


确保拨号成功的必要条件:SIM 卡没欠费;硬件良好,天线匹配;拨号前,调用 ql_network_register_wait 等待网络注册成功;拨号时,向 ql_start_data_call 传递正确的参数。

Socket 通信流程


EC100 模块 Socket 通信基本流程如上图:

1、在进行 socket 通信之前,必须确保拨号已经成功,可以通过 ql_get_data_call_info()查询需要进行 socket 通信的网络通道是否拨号成功。

2、拨号成功后进行 socket 通信时,必须对需要通信的网络通道进行 bind 操作。不管是 UDP 还是 TCP,都必须执行 Bind 操作之后才可以正常进行 socket 通信。

sdk中给我们提供了一个tcp_client的demo,这个demo的设计思路完全按照上面两张图流程图来设计。我们在这个demo进行修改,获取天气数据。

我们修改后的example_tcp_weather_client.c代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ql_type.h"
#include "ql_rtos.h"
#include "ql_application.h"
#include "ql_data_call.h"
#include "sockets.h"
#include "netdb.h"
#include "cJSON.h"

#define  DEBUG   0  

/* 心知天气(www.seniverse.com)IP及端口 */
#define  WEATHER_IP_ADDR   "116.62.81.138"
#define  WEATHER_PORT    80

#define TCP_CONNECT_TIMEOUT_S 10
#define TCP_RECV_TIMEOUT_S 10
#define TCP_CLOSE_LINGER_TIME_S 10
#define TCP_CLIENT_SEND_STR "tcp client send string"
#define PROFILE_IDX 1
#define PROFILE_IDX 1

#define  KEY    "2owqvhhd2dd9o9f9"  // 每个用户自己的一个key

/* GET请求包 */
#define  GET_REQUEST_PACKAGE     \
         "GET https://api.seniverse.com/v3/weather/%s.json?key=%s&location=%s&language=zh-Hans&unit=c\r\n\r\n"

 
/* JSON数据包 */ 
#define  NOW_JSON     "now"
//....还用更多其他的天气数据包可查阅心知天气

/* 天气数据结构体 */
typedef struct
{

 /* 实况天气数据 */
 char id[32];     //id
 char name[32];     //地名
 char country[32];    //国家
 char path[32];     //完整地名路径
 char timezone[32];    //时区
 char timezone_offset[32];  //时差
 char text[32];     //天气预报文字
 char code[32];     //天气预报代码
 char temperature[32];      //气温
 char last_update[32];   //最后一次更新的时间
}Weather;

// 全局变量
static struct in_addr ip4_addr = {0};

// 函数声明
static void GetWeather(char *weather_json, char *location, Weather *result);
static int cJSON_NowWeatherParse(char *JSON, Weather *result);
static void DisplayWeather(Weather *weather_data);
static void ql_nw_status_callback(int profile_idx, int nw_status);
static void datacall_satrt(void);

/*******************************************************************************************************
** 函数: sockets_weather_test
**------------------------------------------------------------------------------------------------------
** 参数: void
** 返回: void
********************************************************************************************************/

static void sockets_weather_test(void * argv)
{
 struct ql_data_call_info info = {0};
 char ip4_addr_str[16] = {0};
 Weather weather_data = {0};
 char *location = "shenzhen";

 printf("========== sockets tcp test will start ...\r\n");

 /* 拨号开始 */
 datacall_satrt();

 /* 获取拨号信息 */
 ql_get_data_call_info(10, &info);

 printf("info.profile_idx: %d\r\n", info.profile_idx);
 printf("info.ip_version: %d\r\n", info.ip_version);
 printf("info.v4.state: %d\r\n", info.v4.state);
 printf("info.v4.reconnect: %d\r\n", info.v4.reconnect);

 inet_ntop(AF_INET, &info.v4.addr.ip, ip4_addr_str, sizeof(ip4_addr_str));
 printf("info.v4.addr.ip: %s\r\n", ip4_addr_str);

 inet_ntop(AF_INET, &info.v4.addr.pri_dns, ip4_addr_str, sizeof(ip4_addr_str));
 printf("info.v4.addr.pri_dns: %s\r\n", ip4_addr_str);

 inet_ntop(AF_INET, &info.v4.addr.sec_dns, ip4_addr_str, sizeof(ip4_addr_str));
 printf("info.v4.addr.sec_dns: %s\r\n", ip4_addr_str);

 ip4_addr = info.v4.addr.ip;

 if(info.v4.state)
 {
  memset(&weather_data, 0sizeof(weather_data));  // weather_data清零 
  GetWeather(NOW_JSON, location, &weather_data);   // GET 并解析实况天气数据
  DisplayWeather(&weather_data);      // 显示天气结果
 }

 printf("========== sockets tcp test finished\r\n");
 
 return 0;
}
 
static void ql_nw_status_callback(int profile_idx, int nw_status)
{
 printf("profile(%d) status: %d\r\n", profile_idx, nw_status);
}

static void datacall_satrt(void)
{
 printf("wait for network register done\r\n");

 /* 等待网络注册结果 */
 if(ql_network_register_wait(120) != 0)
 {
  printf("*** network register fail ***\r\n");
 }
 else
 {
  printf("doing network activing ...\r\n");
  
  ql_wan_start(ql_nw_status_callback);   /* 拨号初始化:注册拨号回调函数 */
  ql_set_auto_connect(1, TRUE);     /* 设置拨号掉线是否自动重连 */
  ql_start_data_call(10NULLNULLNULL0);  /* 开始拨号 */
 }
}

static void GetWeather(char *weather_json, char *location, Weather *result)
{
 int    sock_nbio = 1;
 int    ret   = 0;
 int    sock_fd     = -1;
 int    sock_error  = 0;
 socklen_t  optlen = 0;
 fd_set    read_fds, write_fds;
 struct timeval t;
 struct addrinfo  * reshints;
 struct sockaddr_in * ip4_svr_addr;
 struct sockaddr_in ip4_local_addr = {0};
 u8 dns_success = 0;
 u8 recv_buf[128] = {0};
 u8 GetRequestBuf[256] = {0};
 u8 WeatherRecvBuf[2*1024] = {0};

 /*  */
 memset(&hints, 0sizeof(struct addrinfo));
 hints.ai_family = AF_INET;
 hints.ai_socktype = SOCK_STREAM;
 if(getaddrinfo_with_pcid(WEATHER_IP_ADDR, NULL, &hints, &res, PROFILE_IDX) != 0)
 {
  printf("*** DNS fail ***\r\n");
  goto exit;
 }

 dns_success = 1;
 
 ret = socket(AF_INET, SOCK_STREAM, 0);
 if(ret < 0)
 {
  printf("*** socket create fail ***\r\n");
  goto exit;
 }

 sock_fd = ret;

 ioctl(sock_fd, FIONBIO, &sock_nbio);

 ip4_local_addr.sin_family = AF_INET;
 ip4_local_addr.sin_port = htons(ql_soc_generate_port());
 ip4_local_addr.sin_addr = ip4_addr;
 
 ret = bind(sock_fd, (struct sockaddr *)&ip4_local_addr, sizeof(ip4_local_addr));
 if(ret < 0)
 {
  printf("*** bind fail ***\r\n");
  goto exit;
 }
 
 ip4_svr_addr = (struct sockaddr_in *)res->ai_addr;
 ip4_svr_addr->sin_port = htons(WEATHER_PORT);

 ret = connect(sock_fd, (struct sockaddr *)ip4_svr_addr, sizeof(struct sockaddr));

 printf("connect ret: %d, errno: %u\r\n", ret, errno);

 if(ret == -1 && errno != EINPROGRESS)
 {
  printf("*** connect fail ***\r\n");
  goto exit;
 }

 t.tv_sec = TCP_CONNECT_TIMEOUT_S;
 t.tv_usec = 0;

 FD_ZERO(&read_fds);
 FD_ZERO(&write_fds);

 FD_SET(sock_fd, &read_fds);
 FD_SET(sock_fd, &write_fds);

 ret = select(sock_fd + 1, &read_fds, &write_fds, NULL, &t);

 printf("select ret: %d\r\n", ret);

 if(ret <= 0)
 {
  printf("*** select timeout or error ***\r\n");
  goto exit;
 }

 if(!FD_ISSET(sock_fd, &read_fds) && !FD_ISSET(sock_fd, &write_fds))
 {
  printf("*** connect fail ***\r\n");
  goto exit;
 }
 else if(FD_ISSET(sock_fd, &read_fds) && FD_ISSET(sock_fd, &write_fds))
 {
  optlen = sizeof(sock_error);
  ret = getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &sock_error, &optlen);
  if(ret == 0 && sock_error == 0)
  {
   printf("connect success\r\n");
  }
  else
  {
   printf("*** connect fail, sock_err = %d, errno = %u ***\r\n", sock_error, errno);
   goto exit;
  }
 }
 else if(!FD_ISSET(sock_fd, &read_fds) && FD_ISSET(sock_fd, &write_fds))
 {
  printf("connect success\r\n");
 }
 else if(FD_ISSET(sock_fd, &read_fds) && !FD_ISSET(sock_fd, &write_fds))
 {
  printf("*** connect fail ***\r\n");
  goto exit;
 }
 else
 {
  printf("*** connect fail ***\r\n");
  goto exit;
 }

 /* 组合GET请求包 */
 sprintf(GetRequestBuf, GET_REQUEST_PACKAGE, weather_json, KEY, location);

 /* 发送数据到服务端 */
 ret = send(sock_fd, (const void*)GetRequestBuf, strlen(GetRequestBuf), 0);
 if(ret < 0)
 {
  printf("*** send fail ***\r\n");
  goto exit;
 }

_recv_:
 t.tv_sec = TCP_RECV_TIMEOUT_S;
 t.tv_usec = 0;

 FD_ZERO(&read_fds);
 FD_SET(sock_fd, &read_fds);

 ret = select(sock_fd + 1, &read_fds, NULLNULL, &t);

 printf("select ret: %d\r\n", ret);

 if(ret <= 0)
 {
  printf("*** select timeout or error ***\r\n");
  goto exit;
 }

 if(FD_ISSET(sock_fd, &read_fds))
 {
  ret = recv(sock_fd, WeatherRecvBuf, sizeof(WeatherRecvBuf), 0);
  if(ret > 0)
  {
   printf("recv data: [%d]%s\r\n", ret, WeatherRecvBuf);
   /* 解析天气数据并保存到结构体变量weather_data中 */
   if (0 == strcmp(weather_json, NOW_JSON))  // 天气实况
   {
    cJSON_NowWeatherParse(WeatherRecvBuf, result); 
   }
  }
  else if(ret == 0)
  {
   printf("*** peer closed ***\r\n");
   goto exit;
  }
  else
  {
   if(!(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN))
   {
    printf("*** error occurs ***\r\n");
    goto exit;
   }
   else
   {
    printf("wait for a while\r\n");
    ql_rtos_task_sleep_ms(20);
    goto _recv_;
   }
  }

 }

exit:
 if(dns_success) freeaddrinfo(res);

 if(sock_fd >= 0)
 {
  struct linger linger = {0};

  linger.l_onoff = 1;
  linger.l_linger = TCP_CLOSE_LINGER_TIME_S;

  setsockopt(sock_fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
  setsockopt(sock_fd, IPPROTO_TCP, TCP_CLOSE_TIMEROUT, &linger.l_linger, sizeof(linger.l_linger));

  /* 清空缓冲区 */
  memset(GetRequestBuf, 0256);   
  memset(WeatherRecvBuf, 02*1024);    
  close(sock_fd);
 }
}

/*******************************************************************************************************
** 函数: cJSON_NowWeatherParse,解析天气实况数据
**------------------------------------------------------------------------------------------------------
** 参数: JSON:天气数据包   result:数据解析的结果
** 返回: void
********************************************************************************************************/

static int cJSON_NowWeatherParse(char *JSON, Weather *result)
{
 cJSON *json,*arrayItem,*object,*subobject,*item;
 
 json = cJSON_Parse(JSON); //解析JSON数据包
 if(json == NULL)    //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
 {
  printf("Error before: [%s]\n",cJSON_GetErrorPtr()); //打印数据包语法错误的位置
  return 1;
 }
 else
 {
  if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL); //匹配字符串"results",获取数组内容
  {
   int size = cJSON_GetArraySize(arrayItem);     //获取数组中对象个数
#if DEBUG
   printf("cJSON_GetArraySize: size=%d\n",size); 
#endif
   if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
   {
    /* 匹配子对象1:城市地区相关 */
    if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
    {
     // 匹配id
     if((item = cJSON_GetObjectItem(subobject,"id")) != NULL)   
     {
      memcpy(result->id, item->valuestring,strlen(item->valuestring));   // 保存数据供外部调用
     }
     // 匹配城市名
     if((item = cJSON_GetObjectItem(subobject,"name")) != NULL
     {
      memcpy(result->name, item->valuestring,strlen(item->valuestring));   // 保存数据供外部调用
     }
     // 匹配城市所在的国家
     if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)
     {
      memcpy(result->country, item->valuestring,strlen(item->valuestring));  // 保存数据供外部调用
     }
     // 匹配完整地名路径
     if((item = cJSON_GetObjectItem(subobject,"path")) != NULL)  
     {
      memcpy(result->path, item->valuestring,strlen(item->valuestring));   // 保存数据供外部调用 
     }
     // 匹配时区
     if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)
     {
      memcpy(result->timezone, item->valuestring,strlen(item->valuestring));  // 保存数据供外部调用 
     }
     // 匹配时差
     if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)
     {
      memcpy(result->timezone_offset, item->valuestring,strlen(item->valuestring));  // 保存数据供外部调用
     }
    }
    /* 匹配子对象2:今天的天气情况 */
    if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
    {
     // 匹配天气现象文字
     if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)
     {
      memcpy(result->text, item->valuestring,strlen(item->valuestring));  // 保存数据供外部调用
     }
     // 匹配天气现象代码
     if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)
     {
      memcpy(result->code, item->valuestring,strlen(item->valuestring));  // 保存数据供外部调用
     }
     // 匹配气温
     if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL
     {
      memcpy(result->temperature, item->valuestring,strlen(item->valuestring));   // 保存数据供外部调用
     } 
    }
    /* 匹配子对象3:数据更新时间(该城市的本地时间) */
    if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
    {
     memcpy(result->last_update, subobject->valuestring,strlen(subobject->valuestring));   // 保存数据供外部调用
    }
   } 
  }
 }
 
 cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
 
 return 0;
}

/*******************************************************************************************************
** 函数: DisplayWeather,显示天气数据
**------------------------------------------------------------------------------------------------------
** 参数: weather_data:天气数据
** 返回: void
********************************************************************************************************/

static void DisplayWeather(Weather *weather_data)
{
 printf("============%s today weather===========\n", weather_data->name);
 printf("weather_data->text: %s\n", weather_data->text);  
 printf("weather_data->temperature: %s\n", weather_data->temperature); 
 printf("weather_data->timezone: %s\n", weather_data->timezone); 
 printf("weather_data->timezone_offset: %s\n", weather_data->timezone_offset);
 printf("weather_data->last_update: %s\n", weather_data->last_update);
}

application_init(sockets_weather_test, "sockets_weather_test"84);


测试结果:


关于天气获取、解析代码以及乱码数据之前已经有详细分享过,这里不再解释。相关文章:【socket应用】基于C语言的天气客户端的实现

猜你喜欢

C语言、嵌入式应用:TCP通信实例分析

一些不可不知的计算机网络基础

AT指令测试ESP8266通信模组并获取天气数据

基于RT-Thread的智慧路灯案例实验分享

基于GUILite的简易万年历

基于LiteOS的智慧农业案例实验分享



免责声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

嵌入式大杂烩 专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!
评论 (0)
  • 浪潮之上:智能时代的觉醒    近日参加了一场课题的答辩,这是医疗人工智能揭榜挂帅的国家项目的地区考场,参与者众多,围绕着医疗健康的主题,八仙过海各显神通,百花齐放。   中国大地正在发生着激动人心的场景:深圳前海深港人工智能算力中心高速运转的液冷服务器,武汉马路上自动驾驶出租车穿行的智慧道路,机器人参与北京的马拉松竞赛。从中央到地方,人工智能相关政策和消息如雨后春笋般不断出台,数字中国的建设图景正在智能浪潮中徐徐展开,战略布局如同围棋
    广州铁金刚 2025-04-30 15:24 169浏览
  • 4月22日下午,备受瞩目的飞凌嵌入式「2025嵌入式及边缘AI技术论坛」在深圳深铁皇冠假日酒店盛大举行,此次活动邀请到了200余位嵌入式技术领域的技术专家、企业代表和工程师用户,共享嵌入式及边缘AI技术的盛宴!1、精彩纷呈的展区产品及方案展区是本场活动的第一场重头戏,从硬件产品到软件系统,从企业级应用到高校教学应用,都吸引了现场来宾的驻足观看和交流讨论。全产品矩阵展区展示了飞凌嵌入式丰富的产品线,从嵌入式板卡到工控机,从进口芯片平台到全国产平台,无不体现出飞凌嵌入式在嵌入式主控设备研发设计方面的
    飞凌嵌入式 2025-04-28 14:43 140浏览
  • 随着电子元器件的快速发展,导致各种常见的贴片电阻元器件也越来越小,给我们分辨也就变得越来越难,下面就由smt贴片加工厂_安徽英特丽就来告诉大家如何分辨的SMT贴片元器件。先来看看贴片电感和贴片电容的区分:(1)看颜色(黑色)——一般黑色都是贴片电感。贴片电容只有勇于精密设备中的贴片钽电容才是黑色的,其他普通贴片电容基本都不是黑色的。(2)看型号标码——贴片电感以L开头,贴片电容以C开头。从外形是圆形初步判断应为电感,测量两端电阻为零点几欧,则为电感。(3)检测——贴片电感一般阻值小,更没有“充放
    贴片加工小安 2025-04-29 14:59 195浏览
  • 在CAN总线分析软件领域,当CANoe不再是唯一选择时,虹科PCAN-Explorer 6软件成为了一个有竞争力的解决方案。在现代工业控制和汽车领域,CAN总线分析软件的重要性不言而喻。随着技术的进步和市场需求的多样化,单一的解决方案已无法满足所有用户的需求。正是在这样的背景下,虹科PCAN-Explorer 6软件以其独特的模块化设计和灵活的功能扩展,为CAN总线分析领域带来了新的选择和可能性。本文将深入探讨虹科PCAN-Explorer 6软件如何以其创新的模块化插件策略,提供定制化的功能选
    虹科汽车智能互联 2025-04-28 16:00 174浏览
  • 你是不是也有在公共场合被偷看手机或笔电的经验呢?科技时代下,不少现代人的各式机密数据都在手机、平板或是笔电等可携式的3C产品上处理,若是经常性地需要在公共场合使用,不管是工作上的机密文件,或是重要的个人信息等,民众都有防窃防盗意识,为了避免他人窥探内容,都会选择使用「防窥保护贴片」,以防止数据外泄。现今市面上「防窥保护贴」、「防窥片」、「屏幕防窥膜」等产品就是这种目的下产物 (以下简称防窥片)!防窥片功能与常见问题解析首先,防窥片最主要的功能就是用来防止他人窥视屏幕上的隐私信息,它是利用百叶窗的
    百佳泰测试实验室 2025-04-30 13:28 239浏览
  • 文/郭楚妤编辑/cc孙聪颖‍越来越多的企业开始蚕食动力电池市场,行业“去宁王化”态势逐渐明显。随着这种趋势的加强,打开新的市场对于宁德时代而言至关重要。“我们不希望被定义为电池的制造者,而是希望把自己称作新能源产业的开拓者。”4月21日,在宁德时代举行的“超级科技日”发布会上,宁德时代掌门人曾毓群如是说。随着宁德时代核心新品骁遥双核电池的发布,其搭载的“电电增程”技术也走进业界视野。除此之外,经过近3年试水,宁德时代在换电业务上重资加码。曾毓群认为换电是一个重资产、高投入、长周期的产业,涉及的利
    华尔街科技眼 2025-04-28 21:55 147浏览
  • 贞光科技代理品牌紫光国芯的车规级LPDDR4内存正成为智能驾驶舱的核心选择。在汽车电子国产化浪潮中,其产品以宽温域稳定工作能力、优异电磁兼容性和超长使用寿命赢得市场认可。紫光国芯不仅确保供应链安全可控,还提供专业本地技术支持。面向未来,紫光国芯正研发LPDDR5车规级产品,将以更高带宽、更低功耗支持汽车智能化发展。随着智能网联汽车的迅猛发展,智能驾驶舱作为人机交互的核心载体,对处理器和存储器的性能与可靠性提出了更高要求。在汽车电子国产化浪潮中,贞光科技代理品牌紫光国芯的车规级LPDDR4内存凭借
    贞光科技 2025-04-28 16:52 233浏览
  • 文/Leon编辑/cc孙聪颖‍2023年,厨电行业在相对平稳的市场环境中迎来温和复苏,看似为行业增长积蓄势能。带着对市场向好的预期,2024 年初,老板电器副董事长兼总经理任富佳为企业定下双位数增长目标。然而现实与预期相悖,过去一年,这家老牌厨电企业不仅未能达成业绩目标,曾提出的“三年再造一个老板电器”愿景,也因市场下行压力面临落空风险。作为“企二代”管理者,任富佳在掌舵企业穿越市场周期的过程中,正面临着前所未有的挑战。4月29日,老板电器(002508.SZ)发布了2024年年度报告及2025
    华尔街科技眼 2025-04-30 12:40 184浏览
  • 一、gao效冷却与控温机制‌1、‌冷媒流动设计‌采用低压液氮(或液氦)通过毛细管路导入蒸发器,蒸汽喷射至样品腔实现快速冷却,冷却效率高(室温至80K约20分钟,至4.2K约30分钟)。通过控温仪动态调节蒸发器加热功率,结合温度传感器(如PT100铂电阻或Cernox磁场不敏感传感器),实现±0.01K的高精度温度稳定性。2、‌宽温区覆盖与扩展性‌标准温区为80K-325K,通过降压选件可将下限延伸至65K(液氮模式)或4K(液氦模式)。可选配475K高温模块,满足材料在ji端温度下的性能测试需求
    锦正茂科技 2025-04-30 13:08 178浏览
  • 网约车,真的“饱和”了?近日,网约车市场的 “饱和” 话题再度引发热议。多地陆续发布网约车风险预警,提醒从业者谨慎入局,这背后究竟隐藏着怎样的市场现状呢?从数据来看,网约车市场的“过剩”现象已愈发明显。以东莞为例,截至2024年12月底,全市网约车数量超过5.77万辆,考取网约车驾驶员证的人数更是超过13.48万人。随着司机数量的不断攀升,订单量却未能同步增长,导致单车日均接单量和营收双双下降。2024年下半年,东莞网约出租车单车日均订单量约10.5单,而单车日均营收也不容乐
    用户1742991715177 2025-04-29 18:28 201浏览
  • 在智能硬件设备趋向微型化的背景下,语音芯片方案厂商针对小体积设备开发了多款超小型语音芯片方案,其中WTV系列和WT2003H系列凭借其QFN封装设计、高性能与高集成度,成为微型设备语音方案的理想选择。以下从封装特性、功能优势及典型应用场景三个方面进行详细介绍。一、超小体积封装:QFN技术的核心优势WTV系列与WT2003H系列均提供QFN封装(如QFN32,尺寸为4×4mm),这种封装形式具有以下特点:体积紧凑:QFN封装通过减少引脚间距和优化内部结构,显著缩小芯片体积,适用于智能门铃、穿戴设备
    广州唯创电子 2025-04-30 09:02 205浏览
我要评论
0
1
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦