• Silicon Labs的Secure Vault物联网安全解决方案,率先获得全球PSA 3级认证

    Silicon Labs的Secure Vault物联网安全解决方案,率先获得全球PSA 3级认证

    中国,北京 - 2021年3月18日 - 致力于建立更智能、更互联世界的领先芯片、软件和解决方案供应商Silicon Labs(亦称“芯科科技”),正式成为全球率先获得高级别物联网(IoT)软硬件安全保护PSA认证的硅芯片创新者。由Arm联合创立的PSA认证是备受推崇的物联网软硬件及设备安全项目,其为Silicon Labs集成Secure Vault的EFR32MG21无线SoC授予了PSA 3级认证。 这项里程碑成就巩固了Silicon Labs在保护物联网免受不良行为者侵害方面的领先地位。Secure Vault符合PSA 3级认证所定义的严格的安全软件和物理不可克隆功能(PUF)硬件要求,从而大幅降低物联网生态系统安全漏洞所带来的风险,并减轻了知识产权方面的损害或者假冒产品造成的收入损失。具体来说,Secure Vault技术具备以下特性: · 对可扩展的本地和远程软件攻击进行防护; · 抵御本地硬件攻击,尽管在历史上硬件攻击比软件攻击更少,但由于价格低廉且易于访问的工具激增,这种攻击正在增加; · 通过独立的第三方实验室测试,可有效防止尝试使用精密的设备在特定时间内侵犯安全功能的行为。 Arm首席系统架构师兼研究员Andy Rose表示:“随着对物联网应用的攻击不断增加且变得越来越复杂,为设备提供芯片级保护显得至关重要。Silicon Labs是率先获得PSA 3级认证的硅芯片供应商,可以提供经过验证的PSA信任根,以及针对各种复杂软硬件攻击的强大防护解决方案。” Silicon Labs物联网高级副总裁Matt Johnson表示:“物联网的持续增长要依靠设备在加入生态系统时有值得信赖的真实性和安全性。PSA 3级认证为物联网设备制造商和最终用户提供了其所需的保证,使他们知道自己的物联网应用能有效保护用于身份验证的私密信息,并防止假冒或流氓设备进入其供应链,从而避免对品牌和收入造成不可挽回的损害。Silicon Labs致力于芯片、软件和解决方案的创新,以确保我们服务的物联网消费者、企业和行业得到安全可靠的发展。我们已经进行了战略投资,成为安全物联网无线解决方案的领先供应商,并成为全球率先获得PSA最高安全级别认证的芯片创新者,这是我们取得成功的有力证明。” 2020年推出的Secure Vault是屡获殊荣的先进功能套件,旨在帮助联网设备制造商应对不断升级、不断发展的物联网安全威胁和监管压力。Secure Vault包括了自己的安全内核以及ROM、RAM和Flash,其中包含核心加密算法和真随机数发生器(TRNG)功能,安全密钥管理与存储和物理篡改保护功能,以及在芯片制造时创建的、由Silicon Labs根证书链保护的安全身份。2020年,Secure Vault取得了PSA 2级认证,并荣获2020年LEAP连接类金奖。Secure Vault还因其强大的物联网安全保护功能而获得了ioXt联盟的SmartCert认证。2020年10月,ioXt联盟在其认证项目中选择PSA认证作为基础的信任根方案。 PSA认证项目是Arm在2017年联合创立的,旨在提供一个清晰的框架来保护联网设备的安全,从分析到安全评估和认证均有涵盖。该框架提供了标准化资源来解决日益增长的物联网需求碎片化问题,并消除了产品开发中的安全性障碍。PSA认证提供3个级别的安全保证,其中PSA 3级认证表明了对设备安全性的重大承诺。在PSA 3级认证标准下,芯片供应商需要满足复杂的保护配置要求,这涵盖了对一系列复杂的软件和物理性物联网攻击方式的强大防护功能。

    Silicon Labs 物联网 PSA SoC

  • 物联网的“315”,打假在路上

    本文来源:物联传媒 本文作者:Vior.Liu 每年的3.15对于企业来说都是提心吊胆的一天,在昨天的315晚会上,我们看到了隐藏在暗处的劣质、假冒伪劣产品。伴随着物联网技术的进一步成熟, 物联网行业,乃至整个科技行业也将进入打击伪劣行列中。 智能家居久“治”不愈 早在2016年,央视315就已经点名了智能家居的安全漏洞、不智能的问题,目前这个问题依旧存在。从安全性的角度来看,家庭安装的智能家庭摄像头、扫地机器人这些带有镜头的硬件设备都被爆出隐私安全问题,不仅如此,隐私被侵犯的范围也在逐渐扩大。 在过去几年内,包括智能吸尘器、扫地机器人在内的智能家居单品都被查出安全性不达标。马里兰大学曾经做过实验,可以通过扫地机器人配备的激光雷达了解用户家庭房屋的具体布局,同时通过吸尘器和智能音箱,可以对用户进行语音窃听,包括亚马逊Echo、天猫精灵等等这些产品都有此类情况。 在隐私和安全问题外,智能家居本身追求的本质是智能化需求,很多智能家居产品所呈现的智能化更多的是伪需求,浮于表面的智能。如果只是将物理开关换成触屏的方式打开某类产品,或者是在体验智能家居之前需要先连接上Wi-Fi,再打开APP进行操作的话,那这种所谓的智能真的是智能吗? 正如“计算机之父”艾伦·图灵说“如果一台机器能骗过人,使人相信它是人而不是机器,那么它就应当被称作有智能的。” 所以,我们有理由认为,安全性和智能化是智能家居依然存在的问题。 自动驾驶尚未到来 其实这一块笔者主要是想聊聊关于特斯拉,不论是我还是其他媒体都没少diss特斯拉的自动驾驶。 当然,有一些特斯拉的韭菜会不乐意听,但是事实就是如此,特斯拉的自动驾驶功能一直都能够登上315晚会,并且不局限于自动驾驶系统,还有其做工。 首先,我们来看自动驾驶,在整个自动驾驶发展的阶段下,我们将其分为L0-L5,L5是完全自动驾驶,也就是我们对于汽车智能驾驶的最理想化状态。目前还没有任何一家企业能够做到这种程度,但是从马斯克的嘴里,我们仿佛感觉,自动驾驶似乎明天就要实现了。但是我们能看到的事故,似乎已经让我们麻木不仁了。 2016年5月,处于自动辅助驾驶模式下的Model S撞上了前方正在低速左拐的大货车; 2018年1月,还是处于自动辅助驾驶系统的Model S撞上了路边停放的消防车; 2019年8月,Model 3在自动辅助驾驶系统开启的情况下莫斯科高速公路上撞上了路边停放的拖车; 2019年12月,Model 3同样在自动辅助驾驶系统开启的情况下,撞上了静止的警车。 2020年6月1日,中国台湾省高速公路上一辆行驶中的特斯拉Model 3径直撞上已侧翻在路的白色货车。据了解,事发时该车处于Autopilot辅助驾驶系统开启状态。 终于,在上周五,特斯拉向美国加州监管机构明确表示,特斯拉FSD不能够,在不久的将来,让汽车实现完全自动驾驶功能。 什么意思呢?就是特斯拉的自动驾驶吹的成分过大。所以,对特斯拉短期实现自动驾驶功能还抱有期望的韭菜们可以清醒清醒了。 除此之外,3月14日,海南Model3“刹车失灵”, 特斯拉回应称,初步判断事故的主要原因是路面湿滑和车主踩下制动踏板时幅度较轻,导致刹车距离变长,意思就是和特斯拉品质没有任何关系。 虽然特斯拉后续的刹车系统检测合格,但是这样的说法,也并不能说服车主。更多知乎博主和微博大V都认为可能是特斯拉的软件控制问题,二是特斯拉对博世刹车系统的二次开发经验不足。 前两天,关于特斯拉上315的段子愈发热烈,有网友表示“想看特斯拉上315,像想看村上春树得诺奖”。 科技企业上市打假 年后,关于科技企业撤销上市的消息不绝于耳。 数据显示,1-2月科创板和创业板指共有53家IPO企业申请终止,其中绝大多数企业属于撤回申报材料的类型。根据证监会和交易所的回应来看,这些企业带“病”上市的不在少数。 证监会表示,IPO既没有收紧也没有放松,在对企业进行上市现场检查前,很多企业都选择撤回,不得不让人怀疑是否存在财务造假、虚假陈述等违法违规问题。 激光雷达制造商禾赛科技、柔性屏生产商柔宇科技、智能语音提供商云知声等也在名单中。 由于激光雷达分为机械式激光雷达、半固态式激光雷达以及固态式激光雷达几种,其中固态式、半固态式激光雷达相比机械式激光雷达,在成本、可靠性、体积等和量产可行性等方面都更具优势,以至于目前市场明显对这两种技术路线更为“友好”。禾赛科技生产的机械式激光雷达在未来量产上存疑,上市时存在未弥补亏损。 柔宇科技的柔性屏号称已量产多年,而实际并未用于任何一家主流手机厂商的产品,只是在柔宇科技自有品牌手机(柔派)中使用。几年以来,柔宇科技亏损持续扩大。招股书显示,柔宇科技在2017年-2019年和2020年上半年分别亏损3.6亿元、8.0亿元、10.7亿元、9.6亿元。 而云知声似乎是被科大讯飞打假了,2020年12月,科大讯飞在深交所互动易平台上直言,云知声关于其语音病历市场占有率高达70%的表述严重失实,有造假现象。另外,云知声同样面临着营收较少、业绩亏损的压力。3年半来,云知声亏损高达7.9亿元,且成立8年,云知声经历了智能语音方案、物联网芯片、人工智能综合服务商等多次业务转变。 同时,由于监管风暴的严查以及3月1日起开始正式施行的刑法修正案(十一)提出的对于律师、会计师等中介机构人员在证券发行出具虚假证明文件的,最高十年有期徒刑,而欺诈发行最高判刑15年,这也让很多企业打了退堂鼓。 在物联网的发展阶段,我们能够看到众多创新产品和技术的诞生,也会看到许多伪劣产品搅乱市场。包括,豪恩的物联网传感器、霍尼韦尔的物联网产品、物联网卡被造假等等,也有企业借助政策和科技风口力图带“病”上市,无论如何,作为行业和企业,都不允许这类搅屎棍影响物联网的健康发展。 ~END~

    物联传媒 智能家居 自动驾驶 物联网

  • 量子芯片上场,光刻机跌落神坛?

    本文来源:5G通信 英特尔创始人之一戈登·科曼(GordonKemen)在1965年发现的一个发展趋势,即单个处理芯片上可以容纳的晶体管数量每18-24个月就会翻倍,CPU的特性也会翻倍。 本来呢,大家也可以不当真,听他吹牛逼就完事儿了。但是好死不死,大家都当真了。 1、工业皇冠上的明珠——ASML光刻机 在消费者和下游生产商对于更强大计算机性能的需求驱使下,芯片行业的人真的是按照摩尔定律18到24个月性能要翻倍在要求自己,你跟不上就会被淘汰。 ASML光刻机 于是在芯片生产的核心环节出现了像ASML光刻机这样集成人类目前为止最高科技的怪物。 翻开ASML的供应链列表,我们会发现它的所有供应商都是业内最顶尖的。 ASML的供应链列表: 光刻机的工艺精度很大程度上取决于其光源的波长,ASML用的13.5nm波长极紫外EUV光源,来自于美国的Cymer公司。 它的实现原理是用13.5nm波长的深紫外光精准打击直径20微米的液态金属锡,而且要在它掉落过程中连续击打两次,第一次把锡液滴打平,第二次才能激发出足够强度的13.5nm波长极紫外光。 通过光源绘制电路的曝光制程 ASML的镜片供应商是德国的老牌镜片供应商卡尔蔡司,他们提供一种极其极其光滑的,只反射13.5nm波长光的反光镜。 有多光滑呢?如果把直径30cm的镜片放大到地球那么大,最多只有一个头发丝这样高度的凸起。这应该是人类制造的最光滑的物体。 ASML的磁悬浮双工件台系统是自研的,可以做到两个工作台同步运动,误差不超过2nm。 可以看出ASML光刻机是人类内卷极致的产物,是真正工业皇冠上的明珠。 2、新型光量子芯片问世,光刻机不必再需? 新华社2月28日消息,由中国科研人员主导的国际团队在美国《科学进展》期刊上发表了一篇论文,论文中提到团队已经研发出了一种新型可编程光量子芯片,可实现多种图论问题的量子算法求解,有望应用在数据搜索、模式识别等领域。 这种新型可编程的光量子芯片,被外界看做是绕开光刻机的办法之一。据悉,光量子芯片的主导团队是国防科技大学计算机学院QUANTA团队联合军事科学院、中山大学等国内外单位。该芯片采用硅基集成光学技术,通过微纳加工工艺在单个芯片上集成大量光量子器件,对实现量子信息的编码和量子算法的映射,具有高集成度、高稳定性、高精确度等优势。 这种新型光量子芯片虽然也是采用微纳加工工艺,但主要是在单个芯片上集成大量光量子器件,由于生产原理上的不同,所以可以绕开光刻机的限制。 一旦量子芯片成功商用,诸如7nm、5nm等制程工艺的研究将失去原有的意义,芯片制造领域也将迈进一个新的里程,而过去让无数芯片制造企业趋之若鹜的高端光刻机也将跌落神坛,我们在芯片制造上也将告别过去被卡脖子的境况。 3、集成电路芯片,已经达到极限 我们知道,现在的芯片的精度就是最小的晶体管的直径,采用了半导体技术和光刻机之后,我们可以把一个晶体管的径长降低到5纳米之内,从而大大增加集成度,达成了更丰富的功能。 可是理论上来说,采用激光刻录的芯片,最小的径长取决于原子的直径,就是采用一个原子来做晶体管的时候,它的径长,决定了芯片的极限精度。 这个精度是多少? 台积电公布大约是0.1nm!氢原子大小的极限芯片,就是光刻机的物理极限。 先不说光刻机的波长问题,学过器件的人就知道,稳定、性能可控的界面态需要十个~数十个原子排排坐,从这个角度来说,传统的硅平面器件已经到顶了。 随着摩尔定律的逐步失效,单个处理芯片上晶体管数量的增加已经接近物理的极限,大数据时代对计算系统功耗和速度要求的却不断提高。 戈登分子发现的“规律性”可能无法持续,除非有技术创新。 4、光量子芯片可能使“摩尔定律”得以持续 “技术创新”可能的方向之一是用光量子代替传统集成电路芯片中的电子器件来传输数据信号和进行计算。也就是说,“光代替电”,“光量子处理芯片”用来代替传统的集成电路芯片处理芯片。 不同于集成电路芯片处理芯片,许多微电子电子器件(晶体管、电阻、电容等)必须放在塑料底座上才能生产集成电路芯片。硅光量子处理芯片由硅制成。利用硅强大的光路由器工作能力,根据释放的工作电压创建连续的激光驱动硅光量子组件,完成光信息含量的传输和计算。“以光代电”有三个明显的优势。 第一,光的网络带宽远大于电子设备; 第二,与电相比,光不易受影响; 第三,光本身可以做一些计算。 这样,光量子处理芯片就有可能大大提高处理芯片的特性,使摩尔定律得以持续。 5、十年磨一剑,要“商用”仍需努力 纵观世界上硅光量子的发展趋势,英国是硅光量子最开始流行的国家,也是现阶段发展趋势最先进的国家。早在20年前,就利用CMOS生产技术开启了对硅光量子的探索和深入分析。 现阶段,英国硅量子刚刚在Facebook、Google等企业开始量产,加工芯片发光级已经完成演示级,将很快进入量产。 谷歌的72 位量子比特的量子处理器 Bristlecone 而在中国,硅光量子的大规模科研是在2010年左右开始的。过去以学术研究为主的科研比较普遍,导致中国在硅光量子的实际过程中不如英国。而中国在硅光量子技术研发上的大规模人才和资产投入,却推动了发展趋势不晚于英国十年。 中国在硅量子产业的积累就像十年磨一剑。据专家预测,在2022年至2025年大规模生产的情况下,凭借优秀的人才、加工芯片的驱动力、加工技术、资产和销售市场,中国的硅量子技术应该有很好的机会跟上英国。 但是,说句实在话,就我国目前的缺芯现状,光量子芯片对于我们来讲是比火星还远的存在,是“远水解不了近渴”。等光量子芯片解决一个又一个技术难题,然后再量产商用时,也不知道会等到哪个猴年马月。 所以,听到我国这方面的科研成果,心里有个数就行了。虽然还没有实际地走入寻常百姓家,惠及每家每户,但是我国近年来一直瞄准世界科技前沿,将其作为重要强国战略之一,未雨绸缪,正是为了未来进入新时代的时候,不再走在别人后面,像今天一样处处受人制肘。 6、结语 中国芯壮大要经历的种种磨炼,可能还要再以十年为单位来计算,背后消耗的财力、人力、时间,可能会是一个又一个新时代的“范弗利特弹药”。但每一个中华儿女都有决心,也有定力,在这场持久战中,把我们的行业“短板”扎扎实实补齐,一步一个脚印地做下去。 罗马不是一天建成的,中国“芯”之路,没有捷径可走。 ~END~

    物联传媒 集成电路 量子芯片 光刻机

  • 每天都能见到的 extern

    前言 本文详细解析extern "C"的底层原理与实际应用。 你说的没错,如果你的头文件从来没有被任何C++程序引用过的话。 所以,如果上述代码被C语言程序引用的话,它的内容就等价于下列代码。 在这种情况下,既然extern "C" { }经过预处理之后根本就不存在,那么它和#include指令之间的关系问题自然也就是无中生有。 extern "C"的前世今生 之所以在C++的世界里存在这样一个怪物,是因为C++允许对一个名字给予不同的定义,只要在语义上没有二义性就好。比如,你可以让两个函数是同名的,只要它们的参数列表不同即可,这就是函数重载(function overloading);甚至,你可以让两个函数的原型声明是完全相同的,只要它们所处的名字空间(namespace)不一样即可。事实上,当处于不同的名字空间时,所有的名字都是可以重复的,无论是函数名,变量名,还是类型名。 编译和链接是两个阶段的事情;事实上,编译器和链接器是两个完全独立的工具。编译器可以通过语义分析知道那些同名的符号之间的差别;而链接器却只能通过目标文件符号表中保存的名字来识别对象。 但 C语言却是一门单一名字空间的语言,也不允许函数重载,也就是说,在一个编译和链接的范围之内,C语言不允许存在同名对象。比如,在一个编译单元内部,不允许存在同名的函数,无论这个函数是否用static修饰;在一个可执行程序对应的所有目标文件里,不允许存在同名对象,无论它代表一个全局变量,还是一个函数。所以,C语言编译器不需要对任何名字进行复杂的处理(或者仅仅对名字进行简单一致的修饰(decoration),比如在名字前面统一的加上单下划线_)。 例如,现有一个名为my_handle.h的头文件,内容如下: 然后使用C语言编译器编译my_handle.c,生成目标文件my_handle.o。由于C语言编译器不对名字进行粉碎,所以在my_handle.o的符号表里,这三个函数的名字和源代码文件中的声明是一致的。 随后,我们想让一个C++程序调用这些函数,所以,它也包含了头文件my_handle.h。假设这个C++源代码文件的名字叫my_handle_client.cpp,其内容如下: 其中,粗体的部分就是那三个函数的名字被粉碎后的样子。 链接规范的作用是告诉C++编译:对于所有使用了链接规范进行修饰的声明或定义,应该按照指定语言的方式来处理,比如名字,调用习惯(calling convention)等等。 1.单个声明的链接规范,比如: extern "C" void foo(); 对我们之前的例子而言,如果我们把头文件my_handle.h的内容改成: 然后使用C++编译器重新编译my_handle_client.cpp,所生成目标文件my_handle_client.o中的符号表就变为: 从中我们可以看出,此时,用extern "C" 修饰了的声明,其生成的符号和C语言编译器生成的符号保持了一致。这样,当你再次把my_handle.o和my_handle_client.o放在一起链接的时候,就不会再有之前的“符号未定义”错误了。 在我们清楚了 extern "C" 的来历和用途之后,回到我们本来的话题上,为什么不能把#include 指令放置在 extern "C" { ... } 里面? 把 #include 指令放置在extern "C" { }里面的另外一个重大风险是,你可能会无意中改变一个函数声明的链接规范。比如:有两个头文件a.h,b.h,其中b.h包含a.h,如下: 按照a.h作者的本意,函数foo是一个C++自由函数,其链接规范为"C++"。但在b.h中,由于#include "a.h"被放到了extern "C" { }的内部,函数foo的链接规范被不正确地更改了。 Q: 难道任何# i n c l u d e指令都不能放在e x t e r n "C"里面吗? 有时候,你可能利用头文件机制“巧妙”的解决一些问题。比如,#pragma pack的问题。这些头文件和常规的头文件作用是不一样的,它们里面不会放置C的函数声明或者变量定义,链接规范不会对它们的内容产生影响。这种情况下,你可以不必遵守这些规则。 Q: 你只说了不应该放入e x t e r n "C"的,但什么可以放入呢? 但,你把C语言的其它元素,比如非函数类型定义(结构体,枚举等)放入extern "C"内部,也不会带来任何影响。更不用说宏定义预处理指令了。 Q: 如果一个带有函数/变量声明的C头文件里没有e x t e r n "C"声明怎么办? 但现实是,大多数情况下,你无法准确的推测未来。你在现在就加上这个extern "C",这花不了你多少成本,但如果你现在没有加,等到将来这个头文件无意中被别人的C++程序包含的时候,别人很可能需要更高的成本来定位错误和修复问题。 A: 在a.h里面加上它。 这是一个邪恶的方案,原因在之前我们已经阐述。但值得探讨的是,这种方案这背后却可能隐含着一个假设,即我们不能修改a.h。不能修改的原因可能来自两个方面: 2. 虽然你拥有修改代码的权限,但由于这个头文件属于遗留系统,冒然修改可能会带来不可预知的问题。 在 第二种情况下,你需要抛弃掉这种不必要的安全意识。因为,首先,对于大多数头文件而言,这种修改都不是一种复杂的,高风险的修改,一切都在可控的范围之 内;其次,如果某个头文件混乱而复杂,虽然对于遗留系统的哲学应该是:“在它还没有带来麻烦之前不要动它”,但现在麻烦已经来了,逃避不如正视,所以上策 是,将其视作一个可以整理到干净合理状态的良好机会。 按照C++的规范定义,__cplusplus 的值应该被定义为199711L,这是一个非零的值;尽管某些编译器并没有按照规范来实现,但仍然能够保证__cplusplus的值为非零——至少我到目前为止还没有看到哪款编译器将其实现为0。这种情况下,#if __cplusplus ... #endif完全是冗余的。 只有在这种情况下:即某个厂商的C语言和C++语言编译器都预先定义了__cplusplus ,但通过其值为0和非零来进行区分,使用#if __cplusplus ... #endif才是正确且必要的。 但如果你的产品是一个雄心勃勃的,试图兼容各种编译器的(包括未知的)跨平台产品, 我们可能不得不使用下述方法来应对各种情况 ,其中__ALIEN_C_LINKAGE__是为了标识那些在C和C++编译中都定义了__cplusplus宏的编译器。 这应该可以工作,但在每个头文件中都写这么一大串,不仅有碍观瞻,还会造成一旦策略进行修改,就会到处修改的状况。违反了DRY(Don't Repeat Yourself)原则,你总要为之付出额外的代价。解决它的一个简单方案是,定义一个特定的头文件——比如clinkage.h,在其中增加这样的定义: 以下举例中c的函数声明和定义分别在cfun.h 和 cfun.c 中,函数打印字符串 “this is c fun call”,c++函数声明和定义分别在cppfun.h 和 cppfun.cpp中,函数打印字符串 "this is cpp fun call", 编译环境vc2010 (1) cfun.h如下: #ifndef _C_FUN_H_#define _C_FUN_H_ void cfun(); #endif (2)cfun.h同上 (3)cfun.h如下: #ifndef _C_FUN_H_#define _C_FUN_H_ #ifdef __cplusplusextern "C"{#endif void cfun(); #ifdef __cplusplus}#endif #endif c调用c++(关键是C++ 提供一个符合 C 调用惯例的函数) cppfun.h如下: #ifndef _CPP_FUN_H_#define _CPP_FUN_H_ extern "C" void cppfun(); #endif - EOF -

    嵌入式大杂烩 extern 底层原理

  • 不按套路出牌,这么来写IIC驱动?

    前言 前面分享了:干货 | C语言实现面向对象编程(附代码),分享了一些概念及基础例子。这不,给大家找来了嵌入式中的编程实例:C语言使用面向对象实现IIC驱动。 一.简述 使用面向对象的编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备时只需要实例化一个IIC对象即可,本文是基于STM32和HAL库做进一步封装的。 底层驱动方法不重要,封装的思想很重要。在完成对IIC驱动的封装之后借助继承特性实现AT24C64存储器的驱动开发,仍使用面向对象的思想封装AT24C64驱动。 二.IIC驱动面向对象封装 iic.h头文件主要是类模板的定义,具体如下: //定义IIC类 typedef struct IIC_Type { //属性 GPIO_TypeDef  *GPIOx_SCL; //GPIO_SCL所属的GPIO组(如:GPIOA) GPIO_TypeDef  *GPIOx_SDA; //GPIO_SDA所属的GPIO组(如:GPIOA) uint32_t GPIO_SCL; //GPIO_SCL的IO引脚(如:GPIO_PIN_0) uint32_t GPIO_SDA; //GPIO_SDA的IO引脚(如:GPIO_PIN_0) //操作 void (*IIC_Init)(const struct IIC_Type*); //IIC_Init void (*IIC_Start)(const struct IIC_Type*); //IIC_Start void (*IIC_Stop)(const struct IIC_Type*); //IIC_Stop uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*); //IIC_Wait_ack,返回wait失败或是成功 void (*IIC_Ack)(const struct IIC_Type*); //IIC_Ack,IIC发送ACK信号 void (*IIC_NAck)(const struct IIC_Type*); //IIC_NAck,IIC发送NACK信号 void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t); //IIC_Send_Byte,入口参数为要发送的字节 uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t); //IIC_Send_Byte,入口参数为是否要发送ACK信号 void (*delay_us)(uint32_t); //us延时 }IIC_TypeDef; iic.c源文件主要是类模板具体操作函数的实现,具体如下: //设置SDA为输入模式 static void SDA_IN(const struct IIC_Type* IIC_Type_t) { uint8_t io_num = 0; //定义io Num号 switch(IIC_Type_t->GPIO_SDA)   { case GPIO_PIN_0:     io_num = 0; break; case GPIO_PIN_1:     io_num = 1; break; case GPIO_PIN_2:     io_num = 2; break; case GPIO_PIN_3:     io_num = 3; break; case GPIO_PIN_4:     io_num = 4; break; case GPIO_PIN_5:     io_num = 5; break; case GPIO_PIN_6:     io_num = 6; break; case GPIO_PIN_7:     io_num = 7; break; case GPIO_PIN_8:     io_num = 8; break; case GPIO_PIN_9:     io_num = 9; break; case GPIO_PIN_10:     io_num = 10; break; case GPIO_PIN_11:     io_num = 11; break; case GPIO_PIN_12:     io_num = 12; break; case GPIO_PIN_13:     io_num = 13; break; case GPIO_PIN_14:     io_num = 14; break; case GPIO_PIN_15:     io_num = 15; break;   }   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零 IIC_Type_t->GPIOx_SDA->MODER|=0<<(io_num*2); //将GPIOx_SDA->GPIO_SDA设置为输入模式 } //设置SDA为输出模式 static void SDA_OUT(const struct IIC_Type* IIC_Type_t) { uint8_t io_num = 0; //定义io Num号 switch(IIC_Type_t->GPIO_SDA)   { case GPIO_PIN_0:     io_num = 0; break; case GPIO_PIN_1:     io_num = 1; break; case GPIO_PIN_2:     io_num = 2; break; case GPIO_PIN_3:     io_num = 3; break; case GPIO_PIN_4:     io_num = 4; break; case GPIO_PIN_5:     io_num = 5; break; case GPIO_PIN_6:     io_num = 6; break; case GPIO_PIN_7:     io_num = 7; break; case GPIO_PIN_8:     io_num = 8; break; case GPIO_PIN_9:     io_num = 9; break; case GPIO_PIN_10:     io_num = 10; break; case GPIO_PIN_11:     io_num = 11; break; case GPIO_PIN_12:     io_num = 12; break; case GPIO_PIN_13:     io_num = 13; break; case GPIO_PIN_14:     io_num = 14; break; case GPIO_PIN_15:     io_num = 15; break;   }   IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零 IIC_Type_t->GPIOx_SDA->MODER|=1<<(io_num*2); //将GPIOx_SDA->GPIO_SDA设置为输出模式 } //设置SCL电平 static void IIC_SCL(const struct IIC_Type* IIC_Type_t,int n) { if(n == 1)   {     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_SET); //设置SCL为高电平 } else{     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET); //设置SCL为低电平 } } //设置SDA电平 static void IIC_SDA(const struct IIC_Type* IIC_Type_t,int n) { if(n == 1)   {     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_SET); //设置SDA为高电平 } else{     HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET); //设置SDA为低电平 } } //读取SDA电平 static uint8_t READ_SDA(const struct IIC_Type* IIC_Type_t) { return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA); //读取SDA电平 } //IIC初始化 static void IIC_Init_t(const struct IIC_Type* IIC_Type_t) {       GPIO_InitTypeDef GPIO_Initure; //根据GPIO组初始化GPIO时钟 if(IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)    {      __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟 } if(IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)    {      __HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟 } if(IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)    {      __HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC时钟 } if(IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)    {      __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟 } if(IIC_Type_t->GPIOx_SCL == GPIOE || IIC_Type_t->GPIOx_SDA == GPIOE)    {      __HAL_RCC_GPIOE_CLK_ENABLE(); //使能GPIOE时钟 } if(IIC_Type_t->GPIOx_SCL == GPIOH || IIC_Type_t->GPIOx_SDA == GPIOH)    {      __HAL_RCC_GPIOH_CLK_ENABLE(); //使能GPIOH时钟 } //GPIO_SCL初始化设置 GPIO_Initure.Pin=IIC_Type_t->GPIO_SCL;      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //快速 HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL,&GPIO_Initure); //GPIO_SDA初始化设置 GPIO_Initure.Pin=IIC_Type_t->GPIO_SDA;      GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //快速 HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA,&GPIO_Initure); //SCL与SDA的初始化均为高电平 IIC_SCL(IIC_Type_t,1);        IIC_SDA(IIC_Type_t,1); } //IIC Start static void IIC_Start_t(const struct IIC_Type* IIC_Type_t) {   SDA_OUT(IIC_Type_t); //sda线输出 IIC_SDA(IIC_Type_t,1);         IIC_SCL(IIC_Type_t,1);   IIC_Type_t->delay_us(4);    IIC_SDA(IIC_Type_t,0); //START:when CLK is high,DATA change form high to low IIC_Type_t->delay_us(4);   IIC_SCL(IIC_Type_t,0); //钳住I2C总线,准备发送或接收数据 } //IIC Stop static void IIC_Stop_t(const struct IIC_Type* IIC_Type_t) {   SDA_OUT(IIC_Type_t); //sda线输出 IIC_SCL(IIC_Type_t,0);   IIC_SDA(IIC_Type_t,0); //STOP:when CLK is high DATA change form low to high IIC_Type_t->delay_us(4);   IIC_SCL(IIC_Type_t,1);    IIC_SDA(IIC_Type_t,1); //发送I2C总线结束信号 IIC_Type_t->delay_us(4);  } //IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败 static uint8_t IIC_Wait_Ack_t(const struct IIC_Type* IIC_Type_t) //IIC_Wait_ack,返回wait失败或是成功 { uint8_t ucErrTime = 0;   SDA_IN(IIC_Type_t); //SDA设置为输入 IIC_SDA(IIC_Type_t,1);IIC_Type_t->delay_us(1);      IIC_SCL(IIC_Type_t,1);IIC_Type_t->delay_us(1); while(READ_SDA(IIC_Type_t))   {     ucErrTime++; if(ucErrTime>250)     {       IIC_Type_t->IIC_Stop(IIC_Type_t); return HAL_ERROR;     }   }   IIC_SCL(IIC_Type_t,0);//时钟输出0 return HAL_OK;   } //产生ACK应答 static void IIC_Ack_t(const struct IIC_Type* IIC_Type_t) {   IIC_SCL(IIC_Type_t,0);   SDA_OUT(IIC_Type_t);   IIC_SDA(IIC_Type_t,0);   IIC_Type_t->delay_us(2);     IIC_SCL(IIC_Type_t,1);   IIC_Type_t->delay_us(2);     IIC_SCL(IIC_Type_t,0); } //产生NACK应答 static void IIC_NAck_t(const struct IIC_Type* IIC_Type_t) {   IIC_SCL(IIC_Type_t,0);   SDA_OUT(IIC_Type_t);   IIC_SDA(IIC_Type_t,1);   IIC_Type_t->delay_us(2);     IIC_SCL(IIC_Type_t,1);   IIC_Type_t->delay_us(2);     IIC_SCL(IIC_Type_t,0); } //IIC_Send_Byte,入口参数为要发送的字节 static void IIC_Send_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t txd) { uint8_t t = 0;         SDA_OUT(IIC_Type_t);            IIC_SCL(IIC_Type_t,0);//拉低时钟开始数据传输 for(t=0;t<8;t++)      {                         IIC_SDA(IIC_Type_t,(txd&0x80)>>7);           txd <<= 1;            IIC_Type_t->delay_us(2); //对TEA5767这三个延时都是必须的 IIC_SCL(IIC_Type_t,1);        IIC_Type_t->delay_us(2);          IIC_SCL(IIC_Type_t,0);         IIC_Type_t->delay_us(2);        }   } //IIC_Send_Byte,入口参数为是否要发送ACK信号 static uint8_t IIC_Read_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t ack) { uint8_t i,receive = 0;    SDA_IN(IIC_Type_t);//SDA设置为输入 for(i=0;i<8;i++ )    {       IIC_SCL(IIC_Type_t,0);        IIC_Type_t->delay_us(2);       IIC_SCL(IIC_Type_t,1);       receive<<=1; if(READ_SDA(IIC_Type_t))receive++;          IIC_Type_t->delay_us(1);    } if (!ack)          IIC_Type_t->IIC_NAck(IIC_Type_t);//发送nACK else IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK return receive; } //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用 IIC_TypeDef IIC1 = {   .GPIOx_SCL = GPIOA, //GPIO组为GPIOA .GPIOx_SDA = GPIOA, //GPIO组为GPIOA .GPIO_SCL = GPIO_PIN_5, //GPIO为PIN5 .GPIO_SDA = GPIO_PIN_6, //GPIO为PIN6 .IIC_Init = IIC_Init_t,   .IIC_Start = IIC_Start_t,   .IIC_Stop = IIC_Stop_t,   .IIC_Wait_Ack = IIC_Wait_Ack_t,   .IIC_Ack = IIC_Ack_t,   .IIC_NAck = IIC_NAck_t,   .IIC_Send_Byte = IIC_Send_Byte_t,   .IIC_Read_Byte = IIC_Read_Byte_t,   .delay_us = delay_us //需自己外部实现delay_us函数 }; 上述就是IIC驱动的封装,由于没有应用场景暂不测试其实用性,待下面ATC64的驱动缝缝扎黄写完之后一起测试使用。 三.ATC64XX驱动封装实现 at24cxx.h头文件主要是类模板的定义,具体如下: // 以下是共定义个具体容量存储器的容量 #define AT24C01  127 #define AT24C02  255 #define AT24C04  511 #define AT24C08  1023 #define AT24C16  2047 #define AT24C32  4095 #define AT24C64   8191 //8KBytes #define AT24C128 16383 #define AT24C256 32767 //定义AT24CXX类 typedef struct AT24CXX_Type { //属性 u32 EEP_TYPE; //存储器类型(存储器容量) //操作 IIC_TypeDef IIC; //IIC驱动 uint8_t (*AT24CXX_ReadOneByte)(const struct AT24CXX_Type*,uint16_t); //指定地址读取一个字节 void (*AT24CXX_WriteOneByte)(const struct AT24CXX_Type*,uint16_t,uint8_t); //指定地址写入一个字节 void (*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t); //指定地址开始写入指定长度的数据 uint32_t (*AT24CXX_ReadLenByte)(uint16_t,uint8_t); //指定地址开始读取指定长度数据 void (*AT24CXX_Write)(uint16_t,uint8_t *,uint16_t); //指定地址开始写入指定长度的数据 void (*AT24CXX_Read)(uint16_t,uint8_t *,uint16_t); //指定地址开始写入指定长度的数据 void (*AT24CXX_Init)(const struct AT24CXX_Type*); //初始化IIC uint8_t (*AT24CXX_Check)(const struct AT24CXX_Type*); //检查器件 }AT24CXX_TypeDef; extern AT24CXX_TypeDef AT24C_64; //外部声明实例化AT24CXX对象 at24cxx.c源文件主要是类模板具体操作函数的实现,具体如下: //在AT24CXX指定地址读出一个数据 //ReadAddr:开始读数的地址 //返回值  :读到的数据 static uint8_t AT24CXX_ReadOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t ReadAddr) { uint8_t temp=0;                             AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC); //根据AT的型号发送不同的地址 if(AT24CXX_Type_t->EEP_TYPE > AT24C16)   {     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0); //发送写命令 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//发送高地址 }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);    AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256); //发送低地址 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);        AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);           AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA1); //进入接收模式 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     temp=AT24CXX_Type_t->IIC.IIC_Read_Byte(&AT24CXX_Type_t->IIC,0);        AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件 return temp; } //在AT24CXX指定地址写入一个数据 //WriteAddr  :写入数据的目的地址 //DataToWrite:要写入的数据 static void AT24CXX_WriteOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t WriteAddr,uint8_t DataToWrite) {                                    AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC); if(AT24CXX_Type_t->EEP_TYPE > AT24C16)   {     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0); //发送写命令 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//发送高地址 }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);     AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256); //发送低地址 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);                  AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite); //发送字节 AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);                AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件 AT24CXX_Type_t->IIC.delay_us(10000);   } //在AT24CXX里面的指定地址开始写入长度为Len的数据 //该函数用于写入16bit或者32bit的数据. //WriteAddr  :开始写入的地址 //DataToWrite:数据数组首地址 //Len        :要写入数据的长度2,4 static void AT24CXX_WriteLenByte_t(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len) { uint8_t t; for(t=0;t>(8*t))&0xff);   }                 } //在AT24CXX里面的指定地址开始读出长度为Len的数据 //该函数用于读出16bit或者32bit的数据. //ReadAddr   :开始读出的地址 //返回值     :数据 //Len        :要读出数据的长度2,4 static uint32_t AT24CXX_ReadLenByte_t(uint16_t ReadAddr,uint8_t Len) { uint8_t t; uint32_t temp=0; for(t=0;t

    嵌入式大杂烩 C语言 IIC驱动

  • 5G行业终端起航!519款5G终端,303款已商用

    本文来源:物联传媒 本文作者:市大妈 对于每一代移动通信技术的发展,一个简单且直观的印象是:1G、2G解决了在移动过程中打电话的问题,3G、4G着重解决了快速上网和看视频的问题,而5G则第一次把重点转向了对垂直行业市场需求的支持。 在面对差异化和碎片化的业务需求时,5G通过全新的空口能力(低时延、高可靠等)、服务化的网络架构、端到端的网络切片和移动边缘计算,将进一步深度赋能垂直行业应用。如今,随着5G终端产业链在基带芯片、射频存储等关键领域的突破,5G行业终端处于产业生态变革的一个战略机遇期。 5G行业发展进度条已拉开 2020年堪称5G商用元年,5G相关建设如火如荼,产业链上各环节的企业也紧跟行业步伐。产业链上游的发展给5G行业终端打下了基础,因此在分析5G行业终端之前,我们先从5G芯片、基站 、模组以及行业应用等层面,来看看当前5G发展进度: 芯片方面:5G设备中所有相关的5G通信芯片都可以称为5G芯片。在4G时代,芯片有六大玩家:高通、MediaTek、三星、华为海思、紫光展锐、intel。而到了5G时代,intel终于发现自己不是搞基带芯片的料,忍痛把基带芯片业务出售给了苹果,因此,目前的格局变成了:高通、MediaTek、三星、华为海思、紫光展锐、苹果。 注:由于麒麟芯片已经停产,因此在此不列出。 基站方面:据近期工信部统计数据,我国已经建设了超过71.8万个5G基站,约占全球的70%,5G的投资额超过了几千亿元,5G网络已基本覆盖全国所有的地级及以上城市,独立组网模式规模部署。 从运营商的角度看5G基站建设,中国移动和中国广电两家运营商计划到2021年底完成40万个700MHz 5G基站建设,中国电信方面也透露将在今年建设32万座5G基站。 从全国各省市5G基站建设的角度看,各省市也在紧锣密鼓地推进5G基站建设,截止2020年年底5G基站建设情况如下: 注:部分省市缺乏相关数据暂未列出 模组方面: 5G模组作为承载5G终端接入网络的关键部件,其较高的开发难度、过长的开发周期和多样化的行业需求成为了制约5G在行业规模应用的瓶颈。针对目前国内市场上认知度较高的5G模组如下: 应用方面:5G行业上游的飞速发展促进了5G终端及产业融合应用生态的完善,而随着5G赋能垂直行业领域的增多,多样化、差异化的垂直行业融合应用需求又反过来推动5G网络技术的演进和发展。截止目前,5G已在港口、机械、汽车、钢铁、矿业和能源等行业和领域的应用领先发展,在物流运输、工业互联网、车联网、医疗、教育、公共安全等重点领域的应用正加速推进。 5G终端生态呈现百花齐放格局,多形态终端类型不断涌现 随着5G产业上游打下了坚实的基础,VR/AR眼镜等5G智能穿戴、5G Pad、5G热点、5G路由器、5G适配器、5G机器人、5G电视机等智能家居类个人终端创新产品层出不穷。2020年5G终端连接数突破2亿,面对泛5G终端的快速发展,工信部表示,将提升应用创新能力,培育5G+增强现实、5G+虚拟现实、沉浸式游戏等新兴消费模式。 从下图可以看出,截止到2020年12月,全球厂商总共发布了519款5G终端,303款已经实现商用。其中5G手机占5G终端将近一半,达到48.4%。 各类5G终端所占比例 而智能手机以外,固定接入的CPE成为5G出货量最大的终端。在中国移动2021年终端产品策略发布暨中国广电-中国移动共建700MHz终端生态启动仪式上了解到,2021年个人类泛终端产品长足发展,品类不断丰富,市场规模进一步提升。 从上图来看,5G CPE虽然整体规模仍较小,但是确实是实实在在存在的。2021年国内市场预计5G CPE销量为50万。同时,今年行业终端市场逐渐放量,终端丰富度持续提升,价格进一步下探,5G CPE、网关类预计将降至1000元左右。 此外,随着5G模组向通用化、模块化发展,5G泛终端必将全面提速与发展。值得一提的是,具有健康监测功能和运动数据分析的可穿戴设备逐渐走俏。 深度赋能垂直行业,5G行业终端探索起航 根据IHS Markit的报告显示,到2035年,5G在全球将创造13.2万亿美元的经济产出,为汽车、制造、健康医疗、教育、娱乐等众多行业带来积极变革。 想来5G已经超越了移动通信范畴,成为全面构筑经济社会数字化转型的关键基础设施,将促进垂直行业转型和升级。与之前相比,5G行业终端呈现了一些新的特点: 一是,三大应用场景让5G能够覆盖更多的行业,行业应用的多样性需要终端以多种形态去承载,这意味着5G行业终端不可能“千人一面”,行业终端碎片化的情况将大量存在。 二是,和5G消费类终端用户相比,行业终端用户专业化程度高,因此终端的定制化也相应水涨船高。 三是,垂直行业终端相对消费类终端而言,对性能的稳定性、可靠性、安全性也提出了更高的要求。例如,在消费类终端上,一毫秒的延迟可能不易被察觉,但在工业智能网关上就可能因此引发生产事故导致行业损失。 如今,5G行业终端的软、硬件还有很多细节需要不断打磨,行业整体需求也较小,终端的每一个应用场景都需要不停地更新解决方案,除智能手机以外,其他行业终端规模性出货确实仍有很大发展空间。 产业界对5G终端仍有美好的希冀,期待今年5G行业终端发货量能够实现大大提升,哪怕是一款模组发货量能达到百万级也是不错的! ~END~ 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

    物联传媒 通信 芯片 5G

  • 起因222个摄像头,特斯拉工厂教会IoT行业的事

    本文来源:物联传媒 本文作者:飞鸟 3月10日,特斯拉一天内产生了两条微博热搜。  一是车主反馈刹车失灵而坐车顶维权,属于客户纠纷类的;  二是媒体爆料称特斯拉上海工厂内部的监控视频被泄露,造成场内生产状况被曝光,原因是某国际黑客组织入侵了特斯拉合作伙伴——安防系统初创公司Verkada的数据库,获得了15万个摄像头视频内容,其中就包括了在特斯拉工厂和仓库的222个摄像头数据。   V erkada摄像头下的特斯拉工厂,图源彭博社 对此,特斯拉立即回应称:此次黑客的入侵范围仅涉及河南一处特斯拉供应商生产现场,此工厂使用了少数Verkada品牌摄像机用作远程质量管理,其他如上海超级工厂与此并不关联,且其他摄像设备均接入公司内网而非互联网。目前,特斯拉已停止了这些摄像头的联网,并将进一步提升各环节的安全把控。  Verkada 亦在官网表示,攻击者在2021年3月7日开始获得服务器的访问权限、摄像头的访问权限和客户名单,并一直持续到3月9日中午左右。此后,公司已经禁用了所有内部管理员账户,安全团队正在展开深入调查,并通知了美国执法部门。  而在所有公司做出事后反应时,对该事件负责的黑客组织成员蒂莉·科特曼(Tillie Kottmann)接受采访表示,入侵Verkada摄像头的方法并不复杂,仅仅是在互联网上发现了一个公开的管理员账户的用户名和密码就进入了Verkada网络内部,甚至他们还能获得摄像头的root权限,可以利用摄像头执行自己的代码。据悉,此次事件中被曝光的企业、机构不仅有上海的特斯拉工厂,还覆盖了多国的医院、诊所、公司、监狱、学校等场所,甚至还有厂家Verkada本身办公室内的视频资料。  科特曼表示,此举的目的是向大众展示视频监控的普及程度以及系统是如何被轻松入侵,目前并未给波及单位造成明显商业损失。但把话题扩大拉长,我们理应对物联网安全保持应有的关注与慎重。  一方面是各类隐私泄露事件不断发生,首先就造成消费者对使用网络摄像头的顾虑逐渐增多,以及怀疑像Amazon Echo那样的智能音箱设备是否会监听“我”的所有对话;另一方面,就像去年12月Forescout的安全研究人员披露了四个开源TCP/IP库中的33个安全漏洞,表示其影响了150多家供应商的超过100万个智能设备和工业互联网产品,这证明在企业层面也存在无法忽视的安全隐患。 矛盾点是: 部署安全防范与广铺业务赚钱,鱼与熊掌不可兼得?  在科特曼的采访陈述中提到一句非常具有个人感情色彩的话: “安全摄像头公司只追求利益,疏忽了对网络安全的防护。”  实际上,Verkada成立于2016年,主营安全摄像头业务,产品亮点包含了使本地安全摄像头迁移到云端,支持客户通过网络进行访问和管理;以及支持AI视觉技术,能分辨出视频中的人脸和车辆并对其进行检测和识别。2020年1月,公司获得8000万美元的融资,投后估值达16亿美元,其客户范围也发展到了千家以上,涵盖学校、企业、零售、酒店、医疗保险等行业。  在物联传媒早前的文章中提到,智能网络摄像头是一个很庞大的存量市场,具有产业基础扎实、产业需求明确、产品容易做出来、市场空间大、具有良好的场景延伸能力五大特点,涉及到交通、安防、社区、商场、民用等场景都可以做挖掘深入。  在早期IHS Markit视频监控情报服务提供的一份数据中,全球视频监控市场收入2019年将达到199亿美元,高于2018年的182亿美元,增长率达9%。此外,2017年增长率为9.3%,2018年增长率为8.7%。这是继2016年和2015年分别取得3.9%和1.9%的小幅增长后,全球视频监控市场连续三年迎来大幅增长。 Verkada也是踩着关键的窗口期成立的,并且在刚成立到发展得还不错这段时间里,Verkada首席执行官Filip Kaliszan曾说,他看到了许多因快速发展的消费者市场而诞生的摄像头,但其中很大一部分的技术都已经过时了,包括他们的安全理念,仅仅为了确保没有人可以未经授权就接触到监视系统的磁带和监视器实体。  虽然世界上从来没有绝对的安全,但对于早已认知并了解安全问题的Verkada公司,在2021年暴露出那样一个简单的漏洞给外界可乘之机,这终归是让人有些遗憾。  而其中的缘由,并不是一家企业的问题,甚至是整个行业都不甚清楚应该抱着何种态度对待事前的安全防护。在弄清楚之前,以业务增长为优先无可厚非。  而且,实现网络安全其实并没有什么一劳永逸的办法。及时对危害事件作出回应,持续查杀漏洞并更新补丁和固件,对网络安全投入应有的资金与人力是必要之举。Verkada是如此,海康大华也是如此。  每一次网络安全事件都应是一条学习经验  2016年“美国东部大断网”事件,是利用了数十万台受到僵尸网络感染的联网设备,比如路由器、摄像头,通过持续的扫描漏洞,操纵肉鸡的方式,向目标发送合理的服务请求,就此占用过多的服务资源,使服务器拥塞而无法对外提供正常服务。 2018年台积电的病毒感染事件,导致重要的高端产能厂区停产停线,其实是台积电犯了3个错误:1)进入产线的新设备带有病毒,且未被查杀;2)负责关键生产设施的电脑搭载的是老旧的Windows 7系统,且没有打补丁;3)没有关闭设备445端口,使病毒轻易入侵。 2019年德国杜塞尔多夫医院遭受勒索软件攻击之后,德国网络安全机构BSI向外界发出的警告是——要求德国公司和机构针对CVE-2019-19871漏洞(勒索软件的已知入口点)更新其Citrix网络网关。 2020年富士康在墨西哥的工厂遭遇勒索软件攻击之后,促使其内部资安团队加紧完成软件以及作业系统安全性更新,同时提高资安防护层级。 从这一路跟踪的情况来看,网络安全事件一直在发生,甚至一些厂商也能用被动防护的态度降低损失至最小。但一旦发生像台积电那样影响公司营收的情况,却又是追悔莫及。 有一句话说了很多次,现如今黑客或病毒所攻击的对象,已经从个人PC、防护能力较弱的传统企业、政府、学校网站等,扩散到万物互联时代的工厂、工业设备、智能摄像头、路由器等众多类型上。 也许现在,我们并没有办法光靠口号就让全行业都对安全有足够充分的认识,但回顾这几年陆续发生的事件,总当是可以吸取经验教训,逐步提升安防能力和意识的。 有望从政策标准方面给予推动  2019年1月,日本总务省对《电气通信事业法》进行修正,要求自2020年4月起要求联网终端设备须具有防非法登录功能,例如能切断外部控制、要求变更初期默认ID和密码、可时常更新软件等,且唯有满足标准、获得认定的设备才能在日本上市。  2020年1月,英国国家网络安全中心指定举措,要求消费物联网的制造商必须采用独一无二的密码,而非默认的出厂设置;并提供一个公开的接入点来报告漏洞;以及说明设备获得安全更新的最短时长。  2020年9月,澳大利亚政府发布《实践准则:为消费者保护物联网》,以13项原则为基础, 鼓励制造商提高物联网设备的安全性,以及鼓励消费者在购买智能设备时考虑安全功能。  同年9月,美国众议院通过了《2020年物联网网络安全改进法案》,要求联邦政府购买的所有与互联网连接设备(包括计算机、移动设备和其他具有互联网连接能力的产品)必须符合美国国家标准与技术研究院(NIST)发布的最低安全标准。  2020年11月,欧盟网络安全局(ENISA)发布了《物联网安全准则》,旨在帮助物联网制造商、开发商、集成商及所有物联网供应链的利益相关者在构建、部署或评估物联网技术时做出更好的安全决策。  所有的迹象都表明,全球范围内,从政府采购、消费者购买到制造商本身,都处于一个物联网安全意识增长的阶段。  其实有理由相信,未来相关主管部门将持续推动并完善安全标准,物联网安全产业终将有更明朗的未来。  参考资料: 智东西,高歌,《黑客入侵15万个摄像头,偶然曝光特斯拉上海工厂实况!》

    物联传媒 摄像头 特斯拉 IoT 物联网

  • 科技公司入场造车,是一种必然

    本文来源:极客公园 造车这件事,变了。 从2014年开始,造车成为了创业者们最希望做的事。不仅有成功创业者倾力开启第二次、第三次创业,无数“草根”团队也开始蠢蠢欲动,仿佛造车这件事的门槛一下子被拉到不存在。 但事实证明,造车的确存在门槛,并且限制了大多数玩家。蔚来汽车创始人、董事长李斌曾说过,一家电动车企业走到量产至少需要 200 亿元,小鹏汽车董事长何小鹏也感叹:以前看别人做车觉得 100 亿太夸张了,现在自己跳进来,才知道 200 亿都不够花。 最终,造车新势力跑出三个第一梯队玩家,但同时也让人们认识到一家新公司造出汽车是多么困难,人们对新玩家的态度逐渐趋于冷淡,大型企业也只是多次尝试投资产业内的公司,曲线布局汽车行业。 现在的情况正在发生变化。汽车产业发生大变革的时候,造车事项再一次被提起。只不过主角已经从创业公司,变成了互联网科技巨头。 百度已经成立了名为“集度”的汽车公司,任命前摩拜联合创始人夏一平为新公司的 CEO;小米被曝出确定造车,官方回应的态度比较暧昧:等等再看,暂时没有;连智能手机时代的王者——苹果,也开始紧锣密鼓地筹备造车事宜。 似乎在一夜之间,造车成为了科技巨头的标配,而如果沿着这个趋势下去,未来会有更多的玩家下场,进入造车这个大市场。 为什么会发生这样的状况?科技公司到底看中汽车的哪部分?更重要的是,在 21 世纪的第二个十年开始的时候,大家似乎都瞄准了这个时间点,时间对于他们意味着什么? 造车的成本,越来越低 一个大环境的变化是,造车的硬件成本似乎越来越低了。 这里提到的成本并不单纯指资金的问题。事实上,电动汽车比燃油汽车的成本要更高。过去的汽车市场中,一辆燃油车内核心零部件是发动机与动力总成,峰瑞资本创始合伙人李丰表示,发动机和动力总成在一辆燃油车里的成本占比大概是 15~20%。而在一辆新能源汽车内,核心零部件变成了电池、电控和电机,也就是所谓的“三电”,成本占比达到了 60% 以上,其中电池能占到整车成本的 40-50%。 ”这些占新能源车成本比最高的关键技术,中国已经实现了较好的自主创新,并且达到了世界先进水平。”李丰说到。对比燃油车来看,经过 30 年的努力,在中高端的燃油发动机的自主创新上,还没有达到国际最好的水平。这也是为什么新能源汽车被认为是中国可以弯道超车的机会所在。 回到科技公司入场造车的原因,在汽车向电气化转型过程中,造车新势力们需要解决的问题不仅是钱,还有与零部件厂商的博弈。 一家造车新势力内部人员曾告诉记者,一方面造车新势力与传统车企对比,对汽车的理解更加关注智能化,如人机交互、智能座舱等等,因此为了独特的体验,对于零部件的要求也更高。但相对应的是,由于造车新势力们前期销量很少或者没有任何销量,零部件厂商的开发成本也更高。 比如电动汽车的底盘、内外饰关键零部件需要重新设计开发,生产数量也不会太高。一家零部件厂商就曾透露,为了控制投资风险,他们会向造车新势力们收取一定的开发费用,风险共担。 国际最大的汽车零部件供应商之一博世,是蔚来最重要的合作伙伴。在蔚来前期的造车过程中,也给予了很大的支持。博世执行副总裁徐大全曾接受记者采访时表示,与造车新势力们的合作确实比较难盈利,尤其是主机厂定制的零部件,如果要收回前期的投入成本是比较困难的事,这时就要判断是否有决心与这家公司继续合作下去。 在经历前几年的阵痛之后,造车新势力得到了行业认可,他们背后的供应链也完成了进一步的升级。以特斯拉为例,特斯拉在上海生产汽车,在一定程度上带动了中国新能源汽车产业链成熟。据了解,目前在上海工厂生产的特斯拉零部件国产化率达到了 100%,而此时距离特斯拉上海工厂开始运转,仅一年时间。 特斯拉零部件国产化率达到了 100% “特斯拉等公司很值得人尊重,因为他们开拓了一个电动化的时代,真正推动了电动汽车的普及。正是因为很多硬件技术、平台技术标准化了之后,才让之后的智能化变得更加合理。” 百度汽车公司集度 CEO 夏一平在接受记者采访时说到,特斯拉、蔚来等造车新势力完成了第一阶段,即推动了整个行业上下游的标准化。“比如百度这样的玩家这时候进入市场,我们不会再遇到特斯拉等企业早期遇到的问题。” 如果把蔚来、小鹏、理想等造车新势力看作新造车 1.0,他们在早期拼出来的资源导致成本与制造复杂度明显比传统车企更高,那么在供应链逐渐成熟的当下,百度、苹果、小米等科技公司的入场就显得更加合理,甚至可以看作为新造车 2.0。 造车时机,软件定义 另一个环境的变化是,车企对科技公司敞开了怀抱。 百度进入造车的形式是与吉利成立合资公司,苹果在与包括起亚在内的多家汽车制造商的合作展开讨论……如果算上此前滴滴出行主导一些设计、针对网约车领域推出的 D1,背后也是由比亚迪代工完成的。 如果仅仅以代工厂来形容这些车企,恐怕不完全准确。因为在车企与科技公司的合作当中,可能创造的模式充满想象空间。 已经明确的案例是百度与吉利的合作。夏一平称,百度是集度公司的实际主导方,吉利所处的位置是战略合作伙伴和投资方。但选择吉利很重要的一点在于,在国内汽车市场里,吉利可能是目前最早提供开放的电动汽车纯电平台的公司。 这个平台名为SEA 浩瀚架构,首款搭载 SEA 平台的车型为领克品牌的纯电动车型 ZERO concept。在吉利的官方说法中,这款架构代表着从汽车制造商到智慧出行服务商的升级。 SEA 平台作为汽车的基础架构,实现了硬件可插拔,软件可升级。用一位业内人士的话说,它就像是一块主板,车企可以根据需求在这块主板上定义车辆,包括电子系统架构,以及车辆总线对于车辆控制权限接口的开放。 吉利官方宣称,SEA 平台是吉利历时 4 年,投资超过 180 亿元做出的产品。「这是吉利花了很多学费做出的一款相对成熟,真正承接电动化和智能化的平台。」一位汽车产业的产品经理告诉极客公园,一般而言,车企不会将自家的平台开放出来,而吉利对待外界是保持开放态度的,并且希望将 SEA 横向推给其他品牌或车型使用。 另一方面,吉利本身也在寻求向电动与智能化的转型。「从 2015 年到现在,吉利一直在寻求转型,但过往的尝试都没能获得真正意义上的成功。而百度在智能驾驶的优势、数字化方面的经验是吉利本身需要学习的地方。」该产品经理分析,双方的合作都是看中了对方身上自己需要补足的东西。这也是不能单纯地将车企看作代工厂的原因。 对于科技公司来说,从 0 开始造一辆车所耗费的人力、财力和时间都太过巨大。拿蔚来举例,其第一代平台的开发周期为三年时间。而与车企合作,能将造车进程大大缩短,从 4-5 年变成 2-3 年,从时间角度来说有了足够的吸引力。 软件在汽车中的占比越来越高 没错,说到底,时间成为科技公司入局造车很重要的一部分原因。供应链端的逐渐成熟与底层平台的开放,让造车的硬件成本与时间成本进一步降低,相对应地,软件在其中的占比进一步加大,也就是所谓的软件定义汽车。 本就以软件为主营业务的科技公司,在其中看到了绝佳的机会。 商业模式带来的时间窗口 看到了机会之后,带给科技公司造车的紧迫感来自于哪里? 《晚点 LatePost》对小米造车的报道中提到,2019 年第三季度,小米决策层在董事会上再提造车,称 2019 年底到 2020 年初,是小米入局造车的时机。 可以猜到,对于未来的判断让科技公司们看到了极大可能性,并且窗口期的开启,是众多科技公司已经或即将下场的关键因素。 首先是汽车的巨大市场。此前曾多次提到,汽车很可能是手机之后,体量和变化最大,也是最具有潜力的市场,手机市场在触及到天花板之后,汽车产业的红利才刚刚开始,吸引了包括手机厂商在内的众多科技公司。 其次,在软件定义汽车成为人们一致看法之后,软件带来的想象力更加引人注目。 为汽车软件付费很可能成为未来的必需品 小编曾介绍过基于自动驾驶构建的商业模式,特斯拉 CEO 埃隆·马斯克也在近日接受相关采访时印证了这一说法。他表示,特斯拉将在 2021 年第二季度推出自动驾驶(FSD)的订阅服务。 加上蔚来随 ET7 一起发布的 NAD(NIO Autonomous Driving)系统,在标配硬件上采用了服务订阅模式,每月服务费 680 元;加上特斯拉推出的 9.9 元高级车载娱乐服务包,在硬件基础之上构建的软件付费模式已经具备了雏形。 不难想象,与智能手机有一些类似,付费订阅汽车软件可以成为未来车企的很大一部分利润来源。这与过去的汽车销售一锤子买卖从根本上发生了变化。 试想,如果进入到自动驾驶付费订阅的时代,刨除硬件和部分人工成本,软件订阅的边际成本非常低,相应车企在软件的利润率上可以做到很高。有业内人士算过一笔账,按照过去三年特斯拉对 FSD 的投入,如果特斯拉 FSD 软件的订阅率在 50% 的时候,一台车的净利润能达到 2 万人民币;如果特斯拉一年卖 100 万辆汽车,在自动驾驶软件上的利润就是 200 亿人民币。 自动驾驶在未来的想象空间巨大 按照这个标准测算,特斯拉一家车企就能做到百亿市场,并且还有更大的议价空间,因为自动驾驶软件包的议价权完全掌握在车企手中。随着销量越来越大,车辆获取的数据越来越多,体验越来越好,意味着有更多人愿意付费购买产品体验。如同互联网产品一样,雪球会越滚越大。 在窗口期已经开启的情况下,科技公司应该已经看到了软件在未来的汽车上可能达到的成就,以及由此产生可观的利润率。前期有企业开始有所行动的当下,或许是科技公司们决定入局的思考之一。如果再不赶上的话,未来的机会会变得越来越小。 暂不论结局如何,新造车 2.0也许在此时,就正式拉开序幕了。 ~END~ 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

    物联传媒 电动车 自动驾驶

  • 干货 | 如何写一个高效的串口接收程序?

    导读:学单片机的大概最先、最常写的通信程序应该就是串口程序了,但是如何写出一个健壮且高效的串口接收程序呢?接下来鱼鹰将根据多年的开发经验教你如何编写串口接收程序。 本篇文章包含以下内容,很长,但干货满满,就看你能吸收多少了: 传入参数指针 互斥锁释放顺序 数据帧检查 串口空闲 通信吞吐量 内容很多,鱼鹰慢慢写,道友您也请慢慢看。 为了更好的理解接下来的知识点,鱼鹰将设计一个串口框架,让道友心中有一个参考方向。 本篇重点在于解决如何写一个健壮、高效的串口接收数据,发送与接收处理过程略讲。 帧格式 先聊聊帧格式,一般来说,一个数据帧有以下几部分内容: 帧头 帧头用于分辨一个数据帧的起始,这个帧头必须足够特殊才行,因为它是分辨一个帧的起始,那么什么样的帧头是足够特殊的数据呢?保证这个数据在一个帧内最好只出现一次的数据,那就是帧头,比如0x55、0xAA之类的。而且最好有两个字节以上,这样帧头才更加独一无二。 但是数据域内的数据你是没办法保障不包含和帧头一样的数据。 那么如果不凑巧,除了帧头外其他部分也有这样的两个字节的帧头,那会出现什么问题? 几乎不会出现问题。因为一般来说数据都是一帧一帧发送的,只要你前面的数据帧传输正确,那么即使下一帧的数据中有和帧头一样的数据(包括帧头)也没有问题,因为帧头判断已经在开始就判断成功了,就不会继续判断后面的数据是否是帧头了。 那么为什么说是几乎,因为如果上一帧数据接收错误,那么程序必须再找一次帧头才行(单字节接收时是如此,采用空闲中断的话就不需要这么麻烦),这就导致找帧头的时候在帧头数据之外寻找了,很可能这些数据就有帧头。 但是即使帧头数据之外的假帧头真的存在,也没关系,还有第二重保障,那就是校验,即使找到了一个错误的帧头,那么数据校验这一关也很难过去,所以放宽心。 如果校验也凑巧通过了,那还有第三重保障:帧尾。应该到不了这里吧,毕竟这比中彩票还难。 又要上一帧数据接收错误,还要当前帧除了帧头之外还有帧头,另外你还能跳过校验的检查(还有功能字、长度信息的检查),太难了。所以只要通过了这些检查,你就可以认为这个数据帧是可用的了。所以一帧数据接收错误,导致的问题最多只是丢失了这帧数据,对后续接收是不会有影响的(前提是你这个接收程序设计的足够好),发送端在发送超时后再发送一次即可,所以重发机制很重要。 事实上,如果你采用串口空闲中断,帧头、帧尾都可以不用,但一般来说,帧头都会保留,帧尾可以不需要,这是为了当单片机没有串口空闲中断时考虑,当然也可能有其他考虑,所以帧头得保留。 功能字 功能字主要用于说明该数据帧的功能,当然也可以作为函数指针的索引,一个索引值代表了一个具体功能,据此可找到对应的功能函数。 比如,设计一个函数指针数组,通过功能字进行索引,进而跳转到对应的功能函数中处理。 特别注意的是,设计功能字的时候,要考虑兼容性,对数据帧的功能进行划分,不要想到一个算一个,功能字也不要随便安排,不然在以后增加数据帧的时候会很麻烦。 比如说,只有一个字节的功能字,前四位作为一个大类,后四位作为大类中具体类。这样就可以将系统数据通信帧分为16个大类,每个大类下有16个可用的具体类,当你增加功能字的时候,就可以根据你的设计来确定属于哪个大类了,然后再插入进去。这样在管理、维护这些通信数据时你会发现很方便。 这个思想其实在ARM内核的中断系统和设计 uCOS II 任务优先级的时候都有,而鱼鹰在设计项目的通信协议的时候就是运用了这些思想。 (图片来源于《权威指南》) 长度 长度信息也是一个非常关键的数据,别小看了它,因为它,鱼鹰用了将近一个星期的时间才把一个HardFaul问题解决了,虽然这个程序bug不是我写的(鱼鹰一直用的是串口空闲接收方式,这个bug自然而然就跳过了),但确实很容易出错。 因为它是决定了你这个数据域长度的关键信息(一般长度信息代表数据域的长度,而不包含其它部分长度),也是这个数据帧的长度信息(加上固定字节长度就是帧长度了),更是接收程序还要接收多少数据的关键信息(对于空闲中断接收方式不算关键,这里的不关键是指不会造成程序异常问题)。 比如说你的程序刚好将帧头、帧尾、功能字判断完毕,然后中断程序因为种种原因导致没有及时接收串口数据,那么你可能得到的就是错误的数据,然后这个错误的长度数据就可能导致你的栈帧或者全局变量被破坏(单字节接收情况下就可能出现,因为鱼鹰碰到过),这是很严重的事情。所以在接收数据域的数据之前一定一定要判断这个长度信息(空闲中断除外)是否合法,不合法的话及时扔掉这帧数据,开始下一帧的数据检查。 所以为了保证及时接收数据,最好采用DMA传输。 数据域 这个没啥好说的,就是整个帧你真正需要发送的数据。而为了让你的发送函数能接收各种类型的数据,那么把参数类型设置为 void * 会是不错的选择。 校验 一个数据在接收过程中可能会被干扰,导致接收到错误的数据,那么如何保证这帧数据的完整与准确性呢,就在校验这一关了。 校验有很多方式,和校验、CRC校验等(奇偶校验是针对一个字节的,不是数据帧)。 和校验算法简单,CPU运算量小,累加最后只取最低字节即可(注意不是高字节,想想为什么),或者保存累加和的变量就是一个字节空间,这样就不需要额外操作了。 CRC校验,这个算法复杂,理解起来比较困难,但一般来说可以直接拿来用,因为它是对每一位(bit)进行校验,所以纠错率很高,几乎不存在发现不了的数据错误,但正因为对每一位进行检查,所以CPU运算量较大,但是有的单片机是可以硬件计算CRC校验值的(比如stm32)。不过现在CPU运算速度都挺快的,软件运算也是可以接受的。 那么该怎么校验呢?是从帧头开始到数据域部分,还是说直接校验数据部分?其实都可以,区别就是运算量问题,不过问题不大(最好是从头开始校验,以保证整帧数据的准确性)。 帧尾 前面说了,帧尾在空闲中断中可以不用,RXNE中断接收时其实也可以不用,当然也可以加上,好处就是当你用串口助手查看数据流时,可以观察出一帧数据是否发送完整了。 最后再说说为什么在数据域前面设计四个字节大小,除了协议本身需要外,还有一个原因就是强制类型转化需要,我们知道,一般来说,赋值时都有字节对齐的限制(实际上有的CPU可以不对齐进行赋值),stm32是32位的,那么四字节对齐是最合适的,这样就可以直接将我们收到的数据转化为需要的数据类型了。 传输过程 聊完了帧格式,再从大的方向看串口的传输过程: 当发送端发送第一帧数据包时,接收端通过某种方式接收(串口接收非空RXNE中断、串口空闲IDLE中断),为了让串口能够触发空闲中断,必须在发送端两个发送帧之间插入一段空闲时间(就是在此时间内不发数据,红色部分),保证空闲中断的准确触发。 同理,为了让发送端也能正常接收接收端的数据,也需要控制接收端的发送,不能在返回一帧数据时立马发送下一帧数据,不然触发不了发送端的空闲中断。 事实上,有些程序员设计的发送、接收过程比这个简单一些。即只有当接收端接收到一帧数据并返回一帧数据之后,发送端才能继续发送数据,这样一来,我们只需要控制好接收端的频率,就可以控制整个通信过程,也能控制通信频率。 但为什么还要设计成第一种传输情况呢?这是为了充分利用串口,增大数据吞吐率(这个后面再说)。 另外,不知道你是否观察到图中的每个数据帧占用的时间是不一样的,这是因为每个数据帧不可能都是一样长的,它们是不定长的数据包,所以你的定时不能从发送开始定时,而是从发送完成后开始定时控制空闲时间。 软件设计 上面所有的内容都是设定一些条件、需求,那么该如何实现软件设计呢?毕竟说的再多,如果不能实现这些,又有什么用呢?talk is cheap, show me the code。 下图设计了三个数据帧:GetVision(),GetSN(),GetMsg()。 GetVision()用于获取硬件版本号、软件版本号。 GetSN()用于获取产品序列号,用于识别唯一设备。 GetMsg()用于获取消息,可以获取各种传感器数据,事实上,如果数据量多的话,根据传感器的不同,会根据需要设计各种不同的数据帧(功能字不同)。 在软件设计上一般都会对这些函数设计一个统一的函数类型,用函数指针数组统一管理。 既要统一,又要体现差异性,函数参数就显得很有必要了。 这里设计了两个参数,一个是void* (无类型指针),一个是length(长度)。 无类型指针主要是用于传递数据域的数据地址,而数据域的数据可能是整型、浮点型、结构体、枚举、联合体等,为了保证传入的各种数据类型在不通过强制转化情况下都能兼容,设计为 void * 就显得很有必要了。 实际上为了显得更专业性,加上 const 修饰会是不错的选择,因为这可以保证缓存数据不被修改(事实上只能保证不被程序员修改,而不能保证程序本身,这个后面会解释)。 长度,长度参数是一个很关键的参数,为了保证长度的准确性,建议使用sizeof 获取。 有人觉得sizeof 好像一个函数,会不会导致效率低下啊,毕竟每次通信都要计算一次长度,那你就大特大错了。事实上,只要你的类型定义定义好了(不管是内置的类型定义还是自定义的结构体、枚举、联合体),编译器都能确定 sizeof 最终的数据长度,根本不存在计算过程。 用 sizeof 的两个好处: 1、可以忽略字节对齐问题(不同平台不能忽略,比如window和单片机通信)。因为编译器为了数据读写效率更高,一般会对数据进行地址对齐,这样一来手工计算一个数据类型的长度变得麻烦(当然你可以说使用某些手段让数据不进行对齐,这个另说),而 sizeof 将智能且准确计算数据大小。 2、当你使用 sizeof 时,兼容性更强,也显得更专业。程序修修改改很正常,一个数据结构改来改去也很正常,特别是开发初期更是如此。但是不管你怎么改,只要在编译器看来是固定长度的数据类型,那么 sizeof 就能在链接程序前计算出来;并且即使你后来加了数据不对齐的限制(加了这个限制后,很可能数据大小变小),也能准确计算。别问为什么,就是这么任性。 所以为了减小出错的可能性、减少劳动量,sizeof 是不错的选择。 当接收到数据地址和长度信息后,就可以进行发送了。 因为只有数据域的数据,为了组成一帧完整的数据,就必须加入打包过程。加上数据帧头、功能字、数据长度、校验等数据。 当一帧数据打包好之后,就可以进行发送了,发送可以采用循环查询发送,也可使用发送空TXE中断,当然还是建议使用DMA发送,这样你可以还没等它发送完就可处理其它事情了。 以上就是发送过程,接收过程也是同理,根据功能字来调用相应的函数进行回复。 事实上,如果只是数据的传输过程,完全可以使用一个发送函数实现数据的特异性传输,这样就可以减少一层数据传递,但是有些通信帧不只是数据的传输,可能在接收、发送时作一些其他处理(比如清除、设置某些标志位),所以需要再增加一层,用于进行差异性处理。 以上就是本篇内容的基础内容了,你以为快完了?你错了,现在只是刚开始而已,鱼鹰写本篇笔记的最终目的还在后面。 这只是前菜,正文才刚开始。 串口接收遇到的那些问题 以下内容不会用太多的笔墨描述如何写发送、接收函数,而是重点关注串口接收过程中可能遇到的一些问题,如果说描述到了发送、接收函数,别会错意,顺带的。 以下大部分问题都是因为采用RXNE(接收不为空)中断方式导致的问题,只有一个问题是鱼鹰从前没有考虑到,也是IDLE + DMA方式不可忽略的问题。 这就是为什么鱼鹰建议采用IDLE + DMA 的原因,不仅是因为效率问题,更因为它能避免很多问题,当然水平足够高的话,采用RXNE也是完全(“完全”就未必,里面有一个问题是RXNE方式难以避免的问题)没有问题。 事实上,即使鱼鹰采用RXNE方式接收数据,也能避免以下大部分的问题,因为鱼鹰的基础足够扎实,会在一开始编写代码的时候自然而然避免一些问题的出现。 但是看完以下内容后,相信各位道友写出一个高效且健壮的串口接收程序根本不是问题,因为这就是所谓的经验啊。 传入参数指针 前面鱼鹰已经提到了需要一个指针作为函数的参数,这里说说这个指针问题。 我们知道,为了维护方便,也是为了节省空间,一般都会将类似的功能整合成一个函数,比如串口经常要用的发送、接收功能,但是所发送的数据内存空间可能就处于五湖四海了,他们通过指针来指向将要发送的数据。 为了节省 RAM 空间或者其它不为人知的原因,传递给发送函数的指针就是实际发送数据的地址,并且在计算校验值的时候也是直接使用这个地址进行校验计算,然后采用循环查询的方式发送数据,这样一来,就不必拷贝一个数据的副本进行发送,而是直接从数据源的地址进行发送,节省了部分 RAM 空间。 但是这样真的好吗? 你是否考虑过在计算数据帧校验值的时候,数据源改变了的问题呢? 比如说你采用和校验,数据一开始是0x55,计算数据帧的校验和值为tx_sum,然后被中断程序或者DMA修改了这个数据源,变成了 0xAA,此时你再使用这个数据地址进行发送,接收端接收到了0xAA,接收端计算校验和的时候是 rx_sum,那么rx_sum 必然不等于 tx_sum,然后接收端就认为该数据帧是错误的,然后丢失这帧数据,而这种情况是比较少见的,但确实是会偶尔出现接收错误的情况(当时发现这个问题时始终不得其解,明明我发送的是这个校验值,为什么你计算的校验值是另一个?开始怀疑是校验函数的问题,但其他数据帧计算时没有问题,只有一种数据帧会出现问题,然后鱼鹰怀疑是数据源的问题,是的,鱼鹰很快就怀疑数据源的问题,但当时验证时,只改了校验那部分地址,发送时的地址还是使用源地址,导致问题还是没解决,过了好久之后才发现这个发送地址没改,囧。所以说,即使你的思路是对的,但如果你解决时错了,问题也很严重)。 如果说接收端(从机)具有重发机制,那么问题不是很大,丢失一帧数据而已,再重发就是,但事实是,一般串口设计成主从模式,主机会在没有接收到从机的应答数据时会进行重发,但是从机一般不会主动重发数据的,它无法判断主机是否成功接收,而从机一般会在成功发送完数据后开始清除一些标志位(比如键盘按键数据清空,不然主机下次获取按键信息时还是同一个按键数据),事实上这个动作必须在对方成功接收才能进行(否则这次按键信息就丢失了),从这个角度来看,我们必须设计一个机制用于判断主机是否成功接收。 I2C、CAN总线都有应答信号,但这是这些是总线自带的特性,我们不可能在接收到一个字节后发送一个应答信号给主机,那么是否有其他办法呢。 人们很容易想到的一个办法就是在主机收到正确数据后,主动发送一帧专用数据帧用于清除这个标志(这个帧和普通帧一样,所以可以确保主机数据能准确送达从机,因为如果超时没有送达,会触发重发机制)。这样只要在获取完这帧数据后,再额外的发送一帧数据用于对方确认即可,从机接收到后,即可开始着手清除一些标志位。 但这样会有一个问题,因为这种特殊的需要从机确认的数据包(其他类型数据不需要确认是因为如果主机没有正确收到数据还可以继续获取,获取的数据是一样并没有关系,但这种需要从机确认,一旦从机认为发送成功了,数据就被清除了这种情况就需要确认,典型的就是按键信息了),我们需要额外处理并占用发送带宽。这是鱼鹰不愿忍受的。 那么是否有更好的办法? 或许我们可以从 USB 协议中获得启发(这是在写这篇笔记的时候想到的,当时写按键板代码的时候没有想到过,但因为当时测试时传输成功率100%,所以就放弃处理这种情况了)。 USB协议是典型的主从机制,主机不主动获取数据,从机是无法主动发送数据的。那么从机是如何确定对方成功接收数据了呢? 一个bit的翻转位。 每当主机成功发送一帧数据后再发送下一帧数据时,就会翻转这个位,从机就可以根据这个位判断主机是属于重发数据(重发数据表示主机接收失败了)还是新数据了,这样从机就能从下一帧数据确定上一帧数据是否成功发送了。 而主机发送的数据是由从机发送应答包确定的,和上面的串口协议类似,所以这个方向的数据是没有问题的。 那么我们该如何重新设计这个协议呢?可以尽可能的不改变原来协议的情况下实现吗? 或许可以从功能字出发。 为了保证对功能字的原有定义保持基本不变,使用最高 bit 作为这个特殊的位,这个 bit 开始是 0,之后主机每接收一个从机应答数据就进行翻转,如果因为没有接收到从机的应答数据,就会使用相同的翻转位重复发送;而从机也根据这个bit来确定自己的上一帧数据对方是否接收(对比上一帧数据的翻转位),如果主机没有成功接收,就不清除标志位(之后主机会重发数据再次获取),否则清除标志位,。 因为是鱼鹰刚想到的,就不多说了,仅提供一个思路。 现在回到指针那块的问题。 现在已经知道,如果你在计算校验和与发送的过程中出现源数据改变的情况,就会导致数据帧校验失败,那么有什么解决办法? 如果说你坚持使用查询方式发送来节省部分空间,那么只要在计算校验值之前拷贝一份源数据,然后用这份数据计算并发送即可。 另一种方法就是,直接把整帧数据拷贝到一个数据缓存中,使用DMA发送。 现在还有一个问题,那就是如果我想发送一个数据域为空的数据该怎么发送? 一般来说,在使用指针的时候,不会使用 NULL 空指针,但是在数据为空的情况下,就需要使用 NULL 指针了,并长度设置为 0,这个时候在检查指针的时候,不能看到空指针就退出函数,还要判断长度信息,当长度为0时在打包时就不拷贝源数据,但最终还是要发送数据帧的(当时别人写的代码将指针和长度判断同时放到了 for 循环的条件里面,鱼鹰觉得效率太低,导致修改代码是没考虑指针为空的情况,所以导致了一个小bug)。 互斥锁释放顺序 现在考虑第二个问题:互斥锁释放顺序问题。 如果没有采用队列方式接收数据,而是主机发送完成后等待接收从机数据后再发送下一帧数据,那么该如何处理互斥锁的问题? 我们知道为了保证数据的同步,保证在接收到一帧数据进行处理时,不能被新的数据帧冲掉,这时就要加入一个互斥锁,表示我正在处理数据,下面的数据我接收不了,这样就能保证你正在处理的数据不会被新来的数据修改掉,从而进行正确的处理。 那么这个标志位(互斥锁)该什么时候清掉(释放掉)呢? 一般来说标志位,一般越早清掉越好,比如外部中断标志位,进入中断后,一般首先会清理标志位,这样即使你正在处理本次中断的程序,那么即使这时再来了中断,也不会丢失中断信息(有悬起标志位),这样就可以在处理完这次中断后,立马进行下一次中断的处理了(前提是优先级足够高)。 但是如果你清理太早或者清理太晚会怎样? 比如说你在接收到一帧数据后(数据帧所有检查完成),开始设置标志位,当主程序查询到这个标志时(一般数据处理不会放在中断中),如果马上开始清除这个标志……嗯,一般来说不会有问题。 那么什么时候会出现问题?当你的主程序查询到这这个标志时开始清除标志,然后处理、返回数据给主机,如果此时主机超时重发数据时,,因为这个时候你虽然在处理数据,但是因为你的标志位已经被清除了,所以接收程序就会开始往接收缓存区存数据了,当你存完之后再回到数据处理那里,你的缓存区可能就不是你想要的数据了。 可能你会说,既然是重发,那么数据应该是相同的吧?好吧,你赢了,鱼鹰编不下去了,这种情况(有重发机制)下清理太早好像是不会出现问题,但你怎么知道对方是采用副本进行重发数据的呢,如果重发时它又从源数据中拷贝后再进行重发会出现什么问题?比如时间信息,开始第一帧数据是11:59,CPU刚把11拷贝到用户空间,被串口中断程序打断,导致下一帧接收的数据是12:00,此时回到主程序继续拷贝,拷贝00,数据的完整性被破坏,这样导致的结果就是11:00,而实际上时间是12:00,这就是你打断数据处理过程的后果。 现在再说说清理太晚会怎么样。 当你的主程序查询到这个标志后,暂时不清除,而是等到从机发送完应答数据之后再清除标志,此时因为从机采用查询方式(查询方式表明从机发送完最后一个字节后后开始清除标志位,也就代表了主机就差最后一个字节没有接收了,这样发送和清除之间间隔时间较短,而采用 DMA 方式的话,发送和清除的间隔时间更短,因为可能DMA还没开始发送第一帧数据,清除工作就已经完成了),或者因为其他原因(比如中断处理)导致发送和清除之间的时间很长这种特殊情况,这样可能主机已经开始下发下一帧数据了,但是因为此时标志还没有清除,不能接收数据,所以主机这一帧数据就这样丢失了。 那么这个清除标志位最合适的时机是什么时候? 你锁定资源利用完的时候。 现在来看看,这个互斥锁锁定的是什么资源?对,就是接收缓存,那么接收缓存什么时候用完?当然是在数据处理完成之时。也就是说在数据处理完之前、发送数据之前清除最合适。 这样就不会因为处理其他事情而导致清除操作过晚而丢失下一帧数据了,因为此时主机还没收到从机上传的数据,也就不会马上开始下一帧数据的传输了。 说到清除,你觉得,需要把整个缓冲区进行清零操作吗?这个问题在以往的文章解释过,就看你是否看完了。 数据帧检查 你是否会对接收的数据进行检查?如果不进行检查会发生什么? 我们知道一帧数据中,每个部分都有各自的含义,甚至有些部分可能在某些数据帧中不存在,比如数据域部分,我们需要根据长度信息来判断数据域部分是否存在。 但是你能保证你所接收的数据都是准确的吗?你能确保在工作环境下不会因为各种干扰导致数据长度信息由0x05变成0x85(最高位翻转)吗?,如果出现了会导致什么后果? 假设你采用RXNE中断方式来一个、一个字节的接收数据,分析如下: 因为是单字节接收数据,所以你需要把所有接收的数据当成数据流,根据帧头信息来确定帧的开始,一旦确定帧头信息之后,你就可以根据接下来的一系列数据保证一帧数据的结束,同时开始新帧的接收…… 初看这个接收流程没有问题,但是真的如此吗? 但是就像前面所说,你能保证你的数据没有问题吗?如果说你接收到一个长度信息,本来是0x05,但是最终接收的数据是0x85,这就意味着你接下来的数据域的长度是0x85,根据你的接收流程,你需要再接收0x85个字节之后,才能判断校验字节是否正确。 可能你会说,虽然你的长度信息由0x05变成了0x85,之后接收校验过程肯定是失败的,那么这帧数据就会被接收程序丢弃,从而导致接收程序进入重新寻找帧头的流程,这个过程不是挺正常的吗?按理说上述异常情况是能被接收流程处理掉的。 那么首先确认一点,上述异常能被接收流程处理吗? 答案是能! 既然上述异常是能被接收状态机处理的,那么还会有什么问题? 问题就出在这个错误数据本身! 因为你是根据错误数据来决定接下来需要接收多少数据,而一般来说,接收缓存大小设置为最大帧的长度,那么就出现一个问题,你的缓存够你接收0x85个字节吗? 如果说你开辟的接收缓存空间很大,足够接收这么多数据,那么就算遇上以上情况,也是没有任何问题,但是万一你比较节省资源,缓存不够大会出现什么情况? 这就涉及到内存分配问题: 你的串口缓存一般在 Data区域,一旦你接收的数据超出了你开辟的空间,那么必然导致缓存空间溢出! 那么缓存空间溢出会导致什么危害? 我们通过上图可以知道,一旦缓存溢出,必然导致该缓存周围的数据出现异常(数据被篡改),如果你的其它代码刚好需要这个数据作为重要参考,而你在使用的时候又没有对这个数据的有效性进行检查,那么可能导致另一个灾难性后果,而这个后果又导致了其他后果,从而导致雪崩效应。 而你修复这个bug时,你以为修复了,但你只修复了表面,真正内在bug还存在! 所以,千万别太相信内存中的数据,每一个数据的输入都要进行严格检查,这个数据可以错误,但是不能导致程序崩溃! 所以千万别写能篡改别人数据的代码,这是很危险的事情,也是很难解决的bug,因为你不知道它会在什么时候篡改哪里的数据! 再假如你的接收缓存放在栈中了呢(稍微有C语言常识的程序员都不会把串口接收缓存放在栈中,但鱼鹰偏偏遇到过这种代码,而为了解决这个bug整整花了一星期,这还是在bug复现率高的情况下)? 根据前面的图可知,栈一般存放在高地址,并且一般栈生长方向为向低地址生长。如果出现上述情况(接收的数据大于开辟的栈缓存空间)会发生什么? 栈帧被破坏! 灰色部分因为接收的数据太多,导致原本存在的栈数据被串口的接收的数据修改了(注意篡改的数据可能不是连续的,因为每一次进入时,开辟的那部分栈空间可能都不在同一个地址),假如这个数据是保存返回寄存器LR的,那么必然导致返回错误,极可能触发HardFault中断! 那么有什么办法解决栈被破坏的问题? 最有效的方式鱼鹰觉得是使用ITM,如果无法在线调试,可以尝试DMA循环传输PC指针值(但是如何得到这个值?毕竟这个寄存器本身是没有地址概念的)到一块内存中,这样就可以得到最后正常执行的代码地址,从而定位错误代码的位置。 如果单片机不支持这些功能呢?鱼鹰现有的知识体系好像无法解决,只能佛系调bug了(看和bug之间的缘分),囧。 前面说了由于外部工作环境导致数据长度信息错误从而出现数组溢出这种情况,如果说你保证工作环境非常好,不可能出现这种干扰,是否还会出现问题? 当然会! 前面分析了外在原因,现在分析内在原因,你的接收程序能保证及时接收发送端发送过来的数据吗?如果不及时接收数据会出现什么问题? 我们知道,一个系统一般都有很多中断需要处理,如果说你的接收程序的中断优先级不是最高的,那么很可能出现接收程序无法及时接收的情况,即RXNE中断来临时,因更高优先级中断需要处理,而且处理时间较长,那么就会出现当前接收的字节因为没有接收完成而被后续的数据冲掉,即出现ORE(溢出错误)。 这样会导致什么问题? 数据域信息(也可能是校验值等数据)当成了长度信息(为什么只讨论长度,而不讨论功能字之类的数据,难道他们不会出现ORE的情况吗?),这样一来,如果这个数据很大,接收程序就会以为接下来还需要接收很多数据才能完成一帧的接收,导致后果和前面分析的数据干扰一样严重。 那么采用RXNE接收方式时该怎么解决这种问题? 检查长度信息的合理性,只要长度信息不会导致缓存溢出即可。 但是上面的解决方案会导致什么问题? 因为你的程序设计问题(采用RXNE接收导致不能及时处理),使得原本能接收的数据无法及时处理(DMA可以及时处理),最终使得当前这一帧数据无法正常接收(如果错误的长度信息够大的话,还有可能接下来很多帧数据都无法接收),这你能接受吗? 但是采用DMA为什么就不会有上述问题,除了DMA能自动接收数据提高效率之外,还有一点就是它不根据接收的数据来判断接下来还需要接收多少数据,而是根据设定的接收数据长度来接收的(如果加入IDLE中断,可以提前结束接收工作),这就避免了上述的缓存溢出和接收不及时问题。 最后再分析上述接收的另一个问题,那就是一帧数据中可能出现没有数据域的情况,这种情况该怎么处理? 只要根据长度信息分开处理即可。如果不对没有数据域的情况分开处理,那么你接收的下一个数据直接就是校验值,而你的接收流程却认为这是数据域的数据,必然导致校验失败。 现在总结使用RXNE方式接收的几个问题: 1、缓存溢出。 缓存溢出有两种可能,第一种就是环境干扰导致长度信息出错,从而出现缓存溢出情况;第二种情况就是因为接收不及时,导致数据错位,如果刚好是长度信息错误,并且这个长度信息太大,而你的代码未对长度进行检查,那么也会出现缓存溢出bug,而这种bug一旦出现,很难发现。所以在代码中对数据的合理性检查是非常有必要的一件事。 2、中断及时处理。 如果中断不及时处理,会导致数据错位,轻则丢失至少一帧数据,重则缓存溢出! 3、状态机是否需要接收数据部分。 由于数据帧有可能没有数据域的情况,所以必须区别处理,保证代码接收的准确性,否则有可能把校验值当成数据了,这样必然无法通过校验,这一帧数据必然会丢失! 串口空闲 前面一直提到串口空闲,也大概明白串口的作用,但是一些细节问题还是需要好好说一下的。 第一个问题,如何清除串口空闲中断标志位? 很多人会使用USART_ClearFlag标准库函数进行清除,但是当你跳转到该函数原型时,你会看到如下说明: 你会看到很多标志位是无法通过该函数清除的。 那么该如何清除IDLE标志呢?其实上面的注释已经进行了说明。 PE、FE、NE、ORE、IDLE标志位的清除是通过一个软件序列进行清除的:首先通过USART_GetFlagStatus读取USART_SR寄存器的值,然后通过USART_ReceiveData函数读取USART_DR的值即可。 那么这里就有一个问题,是否这些标志问题的清除都要单独编写清除序列呢? 答案是否定的。 因为这些标志位都是由同一种序列进行清除的,所以只要一个清除序列就会把所有的标志位都进行清除了(同样一旦执行了这个序列,也就意味着你无法再通过USART_SR寄存器获得标志位了)。 为了保证获取标志位,我们可以在清除序列之前把USART_SR寄存器的值保存到副本中,然后再读取USART_DR寄存器的值保存到副本来实现清除功能,注意该序列应该无条件执行(不在某个判断语句中)。这样后续我们就可以使用这个 USART_SR 的副本判断哪一个标志置位了,同样也可以使用 USART_DR 的副本获取串口数据,而为了实现以上效果,USART_GetFlagStatus这个函数就不合适了,只能直接操作寄存器去实现。 第二个问题,在线调试时对空闲中断会有影响吗? 我们知道,KEIL能够将一个结构体的数据全部读取出来,而库函数将串口模块的所有寄存器都封装在一个结构体中,这样就会出现一个问题,如果你的窗口是实时刷新的,当你使用KEIL读取串口模块寄存器的时候(不管是使用peripheral窗口还是Watch窗口),就会出现先读取SR再读取DR的情况, 这样就有可能出现KEIL和单片机CPU读取这两个寄存器冲突的情况。 如果全速运行时,KEIL 先执行了这个序列(通过调试器读取这两个寄存器的值),单片机CPU再读取SR寄存值,必然是无法读取到正确标志位的,因为这些标志位已经被KEIL的读取序列清除了(这个情况鱼鹰确实碰到过,当时明明下发了数据,但是单片机无法获取标志位),所以在调试串口时,注意不要让 KEIL 去读取这些寄存器(即关闭这些窗口,只有在必须的情况下才开启),防止出现莫名其妙的情况。 第三个问题,空闲中断能准确触发吗? 如果从接收端考虑的话,如果触发了空闲中断,那么必然满足了条件才触发的,而不是意外触发的(嗯,我们要相信STM32),但从发送端考虑的话,有可能出现一帧数据断续发送,导致一帧数据触发多次空闲中断,所以如果是简单的DMA+空闲中断方式接收是很有问题的(空闲出现就认为一帧结束了,就会把一帧数据当成两帧处理,这样肯定无法通过数据检查的)。 那么先来分析为什么会出现一帧数据多次触发空闲中断情况。我们知道linux、windows系统并不是实时系统,当应用程序需要发送一帧数据时,可能并没有连续发送,而是发送完一个字节后去处理其他事情后才发送下一个字节,这样一来,如果耽误的时间够长,就会触发串口的空闲中断,从而一帧数据当成两帧处理了。 那有什么方法可以解决呢?鱼鹰提供两种解决思路。 第一种,使用两个缓存空间,一个缓存空间专门用于接收串口数据,将接收到的数据存放到另一个缓存,这个缓存采用字节队列的方式进行管理,应用程序从缓存队列中一个字节一个字节的取出数据进行处理(注意检查数据有效性),这样就能保证及时处理。但是因为空闲中断不再可靠,所以空闲中断不再作为判断一帧数据结束的依据(根据长度信息判断),而是只在空闲中断中将已接收数据复制到字节队列缓存中,这样就可以处理意外的空闲中断。 第二种,还是一个缓存空间,还是DMA+空闲方式处理,但是需要增加额外的条件。就是当进入空闲中断后,不再直接处理,而是获取当前接收时刻,然后在处理数据的时候根据这个时刻来判断是否达到足够的空闲时间,只有在进入空闲中断后并达到一定延时之后才认为一帧数据结束了,这样可以避免一些非常短的空闲时间(鱼鹰公众号提供过的代码使用这种方式)。 以上问题是就是鱼鹰以前使用空闲中断从未考虑的问题,鱼鹰并不知道使用空闲中断还可能出现误触发的情况,但是既然知道了,就要想办法解决。但是为什么以前使用空闲中断时没有出现通信问题呢? 事实上不是没有问题,而是有可能把分散的一帧数据的两部分直接丢弃了而已,因为有重发机制,所以即使丢弃一帧数据,也能通信正常,而且这种一帧数据分散成两部分的概率还是挺低的,ubuntu(linux系统)下大概千分之三左右的样子。 第四个问题,如果单片机没有空闲中断又该如何做? 当我们使用 RXNE 的同时其实我们也可以使用空闲中断,这样也能确定一帧数据的结束(但是要注意前面的误触发问题)。但是如果有些低端单片机(如 51 )没有空闲中断又该怎么办? 其实我们可以从 stm32 的空闲中断得到相应的启发。 所谓空闲中断,就是当串口接收到数据后,在应该接收数据的时刻,发送方并没有发送数据,所以串口模块置位空闲标志位,从而引起空闲中断。 那么我们是否可以软件模拟串口模块的这个功能,从而确定一帧数据的结束呢? 答案是肯定的(前提是每一帧数据之间有空闲时间)。 我们可以使用一个定时器,定时器向上计数。当接收到一个字节数据后,初始化计数器并启动定时器,这样一旦有一段时间没有接收到串口数据(也就不再初始化计数器),那么定时器溢出,进入溢出中断,而这个溢出中断就类似于串口的空闲中断(在溢出中断中关闭定时器以达到清除空闲中断标志的作用),这样就达到了串口空闲中断的效果(和前面问题的第二种解决方案类似)。 通信吞吐量 在以上分析过程中,都是采用主机发送,从机接收后再回复主机的方式进行通信,虽然通信正常,但实际上效率比较低下,单位时间传输的数据量较少,如下图所示: 红色部分就是必要的空闲时间,可以看到左右两张图的通信频率是有差异的,右图中从机必须等待前一帧数据发送完毕才能处理数据,而左图可以在接收当前帧时处理上一帧数据,类似CPU的指令执行流水线。 (图片来源于《权威指南》) 我们也可以将串口接收分为二级流水线:接收、处理,如此一来,我们最少需要两个缓存空间,当一个缓存在接收时,另一个缓存就进行数据处理。发送端可能不等接收端发送完应答数据,它就已经开始发送下一帧数据了,只要相邻两帧数据保证一定发送间隔,就能正常触发中断。 同理,因为接收端也不再慢悠悠的等待接收数据,而是可能有好几帧数据等着它处理,所以为了确保发送端能正常触发空闲中断,也需要控制发送间隔。 为了最大程度利用串口,我们可以使用队列管理很多缓存空间(当只有两个缓存时,可以直接使用异或运算进行缓存切换),比如 uCOS II 中我们可以利用系统的内存管理服务和队列服务实现有效管理,并且当有非常紧急的通信任务时,还可以插入到队头优先处理。 但是增大吞吐量时,比如对重发机制和从机数据的确认有一定影响,需要考虑清楚。 对于如何提高通信量,鱼鹰经验不多,就不多说了(或许可以从网络通信过程中得到答案)。 如果要用一句话总结本篇笔记内容,那就是使用 空闲中断+DMA+队列+内存管理+定时控制 方式接收串口数据会是不错的选择。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

    嵌入式大杂烩 通信程序 串口程序 串口接收程序

  • 全球缺芯真相:是什么打乱了运转半世纪的半导体产业链?

    本文来源:财经十一人汽车产业的缺芯焦虑,似乎并没有随着时间减弱。有业内人士估计,缺芯困局将从2021年上半年继续延续到下半年,不仅如此,缺芯行业的波及面正扩散得越来越广。今年1月,本田、大众、福特等车企纷纷宣布由于芯片供应不足而减产或关停部分工厂,随后,手机、面板等消费电子行业也面临缺芯的情况,整个半导体供应链的上中下游都受到影响。全球缺芯情况究竟如何?问题卡在哪?何以解忧?受到芯片供应不足影响,根据第三方信息服务提供商IHS Markit预测,2021年第一季度,汽车产量将会比最初预期少67.2万辆。在一位通用汽车中国区高管的记忆里,这一轮全球性缺芯的情况前所未有。车企缺芯传导给芯片代工厂,全球芯片代工厂都在满产运转,在半导体行业追赶摩尔定律的将近半个世纪中,周期性产能紧张是该行业长期发生的情况。以往,都能依靠例如代工厂的提前布局,或反周期建设等措施降低矛盾,但这一次这个产业中的每个环节似乎都“失算”了。代工厂的满产转移给再上游的设备厂商,再由设备厂商传导给其上游的零部件厂商,一些零部件的交期甚至从原来的1-2个月延长至半年。上游的供应不足,又反过来传递给下游,加剧了消费电子行业缺货的状况。2月4日,在高通公司(QCOM:NASDAQ )2021年一季度财报会上,总裁克里斯蒂亚诺·安蒙(Cristiano Amon)表示,产能紧缺是全面的,预计供不应求的局面会在下半年恢复正常。2月24日,小米副总裁卢伟冰在个人微博中说,“今年芯片太缺了,不是缺,是极缺。”运转半个世纪的半导体产业链为何如此不堪一击?波及全球的缺芯是如何发生并传导至各环节?缺芯的情况什么时候能够缓解?01车企缺芯如何发生受到去年年初开始在全球发酵的新冠疫情的影响,汽车厂商去年调整了销售预测,向代工厂提出减产要求。代工厂不可能坐以待毙,一个好的办法是去找到其他生意。代工厂确实也有新的机会。疫情催化了居家办公的需求,所有与其相关的信息产品生意都很好,例如云计算、摄像头、PC等,这些厂商成为了代工厂的新客户,承接了汽车厂砍单多出来的产能。但大家没有想到的是,疫情得到一定程度的控制后,尤其到了去年下半年,中国汽车销量出现反弹。根据乘用车市场信息联席会统计,2020年全年中国市场汽车销量约为2012.37万辆,中国成为世界汽车第一大市场。这种变化让车企、代工厂都始料未及。在雷克萨斯公布的2020年全球销量上,中国成为唯一一个销量正增长的地区。以往,芯片代工厂的常规做法是统筹管理客户需求。例如优先保证长期客户生产,按照2018年和2019年两年的生产数量统计来优先排期。他们也会通过反周期建设提前布局,以确保刚建好的工厂能够赶上产能紧张的时机。这种变化传导到芯片代工厂的压力是:原本已经排好的消费电子订单显然无法取消,生产汽车芯片又显得很着急很必要。“两相矛盾之下,芯片代工厂的反应时间存在延迟。”前述设备企业从业人士告诉《财经》记者,从建厂到形成产能的周期是以年计的,成熟工艺改造少则一年,先进工艺要两年时间以上,当现有产能被云计算和消费电子挤占之后,要把已经签好的订单砍掉,再回来生产车用芯片,几乎是不可能的事情。寻找空出的产线进行转产,是否可能?对于汽车芯片来说,随意更换任意一个生产环节都会带来很大的技术和财力上的不确定性。汽车芯片本身的性质也决定了其很难进行转产。与消费电子不同,汽车芯片对其外部工作环境,如温度、湿度、粉尘、寿命、稳定度等承受度极高。汽车电子元件的规格标准,业内称车规级,车规级的电子元件售价高,要求也高。这增加了汽车芯片的制造难度。以寿命举例,车规级芯片的寿命要求至少15年,与此相比的消费电子芯片寿命为1年-3年。在温度上,车规级芯片需要承受最低约零下40摄氏度到最高约155摄氏度的温差。但消费电子一般在零摄氏度到零上40摄氏度即可。而且,汽车芯片需要花很长时间进行研发和验证,对于很多汽车芯片来说,研发的时间可能超过一年。如果要从开始研发到推向市场,至少三年。还有一些车规芯片,需要在通过了车规认证的产线才能生产。久好电子创始人刘卫东告诉记者,他已经很长一段时间“吃不好,睡不好。”这是一家专注于传感器用的信号调理芯片开发的集成电路创业设计企业。芯片设计公司将订单交给芯片代工厂生产芯片,再供应给下游的零部件供应商,然后再交给车企。久好电子的产品中,有几款汽车传感器芯片,前有需求巨大的客户,后面芯片代工厂满产运行,下单需要排队,唯一能做的,是等待。刘卫东并没有转产的计划,一是因为转产需要成本,二是汽车芯片的特殊性使得其不能随意更换任意生产环节,他需要为客户负责,保证产品的质量。此前,世界领先的汽车配套产品供应商大陆集团就官方回应记者称,尽管昼夜不停开展各项工作,但仍无法满足客户需求,使部分客户需要调整其生产计划或产品组合。大陆集团主要产品为轮胎,制动系统,车身稳定控制系统,发动机喷射系统,转速表,以及其他汽车和运输行业零部件。芯片代工厂是他们的上游。通用汽车中国区的一位高管告诉记者,缺货带来的最大感受是销售指标可能无法完成。为保证最盈利的车型顺利生产,他们会将销量不高的车型生产往后排。产能紧张从下游向上游传导,世界最大半导体设备供应商之一应用材料(NASDAQ:AMAT)公布的2021年一季度财报显示,当季营收创下新高,同比增长24%。净利润为11.3亿美元,同比增长了27%。亮眼的财报之下,设备企业的压力也不小。近半年来,国际物流运力下降,集装箱船运价格暴涨,零部件船运不过来,前述设备企业从业者告诉记者,一些零部件的交期从原来的1-2个月延长到了半年甚至更久。这也反过来加剧了缺货的情况。目前看来,下游的需求还在不断增大,只能通过供应链的调节和等待芯片代工厂扩产来解决。不少芯片代工厂,如台积电、三星、联电、中芯国际等都在通过扩产以应对旺盛的需求。02更深层次的原因除了疫情所导致的供需失衡,前所未有的全球缺芯是多重因素叠加的结果。此时回顾,车企的大规模缺芯消息频频爆出是在去年下半年,行业内其实在更早半年就感知到紧张情况。记者多方调查结果显示,芯片设计企业、车企,消费电子行业以及上游制造以及设备企业,发现芯片产能紧缺加剧,在2020年年初就有苗头。一位设备企业资深从业人士告诉记者,2020年年初,在美国疫情严重时,他们甚至要自己招聘工人来进行设备的组装,以此来保证生产,而这些工作原本是由外包工厂的工人来做的。产能紧张时,一些下游设计厂商以及应用厂商甚至直接和设备厂商接触。去年11月,芯片设计公司联发科(2454.TW)宣布斥资3.72亿人民币向泛林半导体(LRCX:NASDAQ)、佳能株式会社以及东京威力科创等设备厂商购买芯片制造设备,租给代工厂力积电(台湾力晶积成电子制造股份有限公司)使用。这是芯片行业中罕见的做法,一般来说,都是芯片设计公司将订单交给代工厂,由代工厂进行芯片制造。更深层次的原因是近年来8寸晶圆厂的陆续关闭。而大部分汽车芯片、物联网信息设备所使用的芯片,都是采用8寸晶圆制造的。例如5G射频芯片、PC端、指纹识别芯片、汽车控制芯片、传感器芯片等,并且,这些需求在未来几年会继续增加。但8寸晶圆的产能却远跟不上需求增长的速度,甚至8寸晶圆厂在逐年关闭。在中国大陆来说,芯片项目在技术先进性上的导向以及盈利,很多项目在落地时就瞄准了12寸产线,还有一些8寸产线转成12寸产线。根据第三方数据机构IC Insights统计,三星电子2020年底月产能为306.0万片8寸晶圆,位居第一大厂,其次为台积电。世界半导体8寸产能公司排名数据来源:IC Insights根据国际半导体产业协会的数据,全球8寸晶圆产线数量在2007年达到200条,随后开始下降,到2016年下降到188条。如果8寸的晶圆不足,为何不转而使用12寸晶圆生产?这是因为经济效益。8寸晶圆产线固定成本低、技术成熟,因此仍是许多信息设备的首选。久好电子的汽车传感器芯片由台积电和中芯国际代工,前两年,尽管8寸产能吃紧,等一等还是可以排上队,到了2020年3月,芯片代工厂的产能就变得非常紧张,只有抗击疫情相关的产品才能排到产能,到2020年9月,几乎所有产品都很难排上了。与之相对应的是,8寸晶圆产线所需的设备同样面临缺货的情况,记者了解到,现在8寸产线的二手设备都在涨价。根据第三方数据机构Surplus Global测算,目前市场约有700台二手8英寸晶圆制造设备出售,但是8英寸晶圆制造设备需求至少在1000台以上。设备短缺限制了相关厂商短期的扩产进度。设备企业的从业人士告诉记者,他们也收到了很多8寸产线设备的需求。既然如此,当生意来时,8寸晶圆厂是否会在未来大量增加?多位业内人士都向记者表示,会,但扩张有限。“半导体行业的核心就是一个字,‘量’。”上述设备企业从业人员说。对设备公司和代工厂来说,除非量足够大,涨价到设备企业也能挣钱,这时候,设备企业才愿意生产8寸产线所需的设备。除了8寸晶圆厂的数量减少,动荡的政治环境也是造成供需紧张的原因,一些大型公司加大囤芯力度,备货量大幅增加。这使得芯片需求市场更加紧张。手机厂商在2020年芯片采购支出上的金额上涨,根据第三方市场调研机构Gartner的数据,2020年全球芯片采购支出达4498亿美元,较2019年增长7.3%。支出金额排名前五的厂商分别是苹果、三星电子、华为、联想、戴尔科技。华为公司在2020年的芯片采购支出下降了23.5%。2019、2020年全球芯片采购金额公司排名数据来源:Gartner除了这些非长期因素,科技产业的快速发展也是一个重要因素。近两年,中国芯片产业大力度倍增,尤其是中国芯片设计企业大幅增多、需要芯片的产品也越来越多,势头迅猛,这也是致使产业链供需失衡的一个重要因素。03涨价、等待、重塑供应链产能紧张之后,涨价看起来顺理成章。新一轮涨价开启了半导体行业的2021年。年初,封测厂、芯片代工厂、芯片设计企业等纷纷宣布涨价。对中小型芯片设计公司来说,这是被迫之举。在产能紧张的情况下,他们并没有与芯片代工厂议价的能力,只能是求着工厂安排生产。刘卫东了解到,大型芯片设计公司也同样面临产能紧张的情况,不过,大型设计公司有转产到其他芯片代工厂的能力,例如人力、财力和在其他芯片代工厂的认可度。他采取的办法是,与芯片代工厂坦诚交流,取得他们的认可和了解,耐心等待。如果代工厂认可一家设计企业的可持续发展能力和未来的竞争力,即便对方是创业公司,也会给予生产能力。这反过来,对设计企业来说,也是一个大浪淘沙的过程。涨价看起来是一个结果,重塑供应链,保证供应链安全则是更加长远的需求。“如果没有新冠疫情,动荡的国际政治环境影响下,重塑供应链这件事也同样会发生,只是被疫情加速了。”多位芯片产业从业人士告诉记者。为了缓解供应链压力,一些企业加快了全球布局。一位外资设备企业高层人士向记者透露,他所在的公司在亚洲扩建产能的进程在去年被大大加速。一来考虑到亚洲疫情相对缓和,二来则是靠近主要的芯片代工厂客户。除此之外,他们在下游通过投资、并购的方式,保证供应链安全,塑造一个更灵活的产业链。为了能够及时在技术生命周期发展过程中使产品跟得上需求,设备厂商需要比其下游企业更超前地判断可能发生的技术趋势和市场变化,以此为依据进行布局,这对设备厂商来说是一个很大的挑战。另一个挑战则是,很多关键的环节很难找到第二家、第三家可替代的厂商,如何浪里淘金,是极大考验。去年12月7日,欧洲17国发表联合声明,提出将从两个方面加强欧洲的电子和嵌入式系统价值链。一是强化处理器和半导体生态系统,二是在整个供应链中扩大工业影响力,以此应对来自关键技术、安全和社会方面的挑战。今年2月24日,美国总统拜登也签署行政令,要求联邦机构对半导体芯片、电动汽车大容量电池、稀土矿物质、药品这四种关键产品的供应链进行为期100天的审查,增加国内产能,分析指,此举或为摆脱对海外供应商特别是中国供应商的依赖。在中国,本土供应链将会越来越得到重视,进口替代将加速。此前一位投资人就告诉记者,他和很多企业聊的时候,大家都会考虑在国内的备份,或者把订单转移到国内。这场缺芯潮什么时候可以结束?业内人士的判断是,2021年下半年或许会有所缓解。3月初,中国最大的芯片制造公司中芯国际(00981.HK/688981.SH)拿到美国政府的批文,可以进口成熟制程的设备。3月3日,中芯国际发公告称,该公司与荷兰半导体设备供应商阿斯麦(ASML)签订了一份高达约12亿美元的购买单,购买深紫外光刻机(DUV)。根据经修订和重述的批量采购协议,期限延长一年,至2021年12月31日。这有利于中芯国际在成熟制程上的扩产,能够解决一部分产能紧张的问题。另外,中芯国际创始人张汝京在青岛芯恩的项目,已有进展,8寸芯片厂的动力厂房、研发、设计、办公楼六栋单体完成主体施工,即将投产。当有限新增的8寸产线运转起来,产能紧张也能够有很大的缓解。现在,在这条半导体产业链的每一个企业都在重新思考自己抗击风险的能力。“新冠疫情和地缘政治这两件事叠加在一起,可以说是我们所想到的最坏的一种情况。”多位从业者对记者表示,重塑一个更加皮实的供应链,将是未来很长一段时间一项重要的事。~END~免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

    物联传媒 芯片 半导体产业链

  • 未来5年这些行业值得关注:“两会”中这些领域被提及

    本文来源:@人民日报 3月5日,“十四五”规划和2035年远景目标纲要草案提请十三届全国人大四次会议审查。新一代人工智能、集成电路、教育、养老……未来5年,哪些行业出现重大机遇? 规划纲要草案为你指明方向↓↓转给需要的TA! ~END~ 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

    物联传媒 人工智能 量子计算

  • “中国智造”成为必然选择

    本文来源:中制智库第四次工业革命的作用已经显现,在机械逐步替代人类作业的基础之上,制造业在未来10年内终将步入“分散化”生产的新时代。为深度参与世界市场的竞争,利用数字化转型实现国内制造业由“中国制造”到“中国智造”的升级和转型,变成了一种必然的选择。01中国制造面临大变局过去30年,中国制造业的规模增长了18倍,达到了26.9万亿美元。这组数字反映在具体的产品中,就是全球80%的空调、90%的个人计算机、75%的太阳能电池板、70%的手机和63%的鞋子产自中国,为数众多的中国企业参与到每一个制造领域的竞争之中。然而,面对“雁阵模式”带来的劳动密集型产业转移,以及因全球制造业价值链“缩短”而带来的高端制造企业回流,中国制造业却正面临一个前所未有的大变局。并且,背负着40%的GDP,直接提供了1.3亿个工作岗位的中国制造业,面对这场变局所能选择的只能是负重前行。02“中国智造”的升级和转型麦肯锡全球研究院的相关研究显示:几乎所有商品生产价值链中的贸易强度(即总出口与总产出的比率)都有所下降。全球制造业价值链正在呈现出“缩短”的态势,这让“逆全球化”趋势暗流涌动,一些国家也借此推动高端制造业“回流”。同时,“雁阵模式”让劳动密集型产业从发达国家向欠发达国家和最不发达国家梯次转移。而随着我国人口红利的消失,以及劳动力工资水平提升,越来越多的劳动密集型产业开始迁出国内,或者由沿海发达地区向中西部地区迁移。另一方面,在制造产业内部,越来越多的年轻人觉得进工厂是一个“没追求”的职业,为了赚取微薄的收入,在流水线上站十多个小时是90后、00后无法接受的。此外,第四次工业革命的作用已经显现,在机械逐步替代人类作业的基础之上,制造业在未来10年内终将步入“分散化”生产的新时代。这样,为深度参与世界市场的竞争,利用数字化转型实现国内制造业由“中国制造”到“中国智造”的升级和转型,变成了一种必然的选择。中国制造企业的这种转型和升级需求,把“新IT(Intelligent Transformation,智能化转型)”变成了一个风口。与传统IT不同,作为推动企业在智能化时代发展的核心动力,“新IT”的内涵更为广泛:企业智能化转型需要的不再仅是硬件设备,而是包括物联网设备、基础设施和智能应用在内的全套解决方案。因此,一个成熟的制造业转型方案,就不可避免涉及到“端-边-云-网-智”五个方面,以及对应的顾问、实施、运维在内的全方位服务。曾经,当整个欧洲深陷债务危机之时,德国却凭借“工业4.0”的技术创新,通过极具竞争力的制造业让经济一枝独秀。今天,新“IT”将成为中国制造业的破局关键。我国“十四五”布局中,已经明确将推动产业数字化转型做为一项重要战略,推动以数字技术为核心的新型基础设施建设,支持制造业企业的数字化改造。同时,鼓励数字科技企业与制造业企业开展合作。中国制造业的奇点已经到来。~END~免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

    物联传媒 中国制造 工业4.0

  • 干货 | C语言实现面向对象编程(附代码)

    前言 GOF的《设计模式》一书的副标题叫做“可复用面向对象软件的基础”,从标题就能看出面向对象是设计模式基本思想。 由于C语言并不是面向对象的语言,C语言没有直接提供封装、继承、组合、多态等面向对象的功能,但C语言有struct和函数指针。我们可以用struct中的数据和函数指针,以此来模拟对象和类的行为。 所以在正式开始设计模式前,先看看如何用C语言实现面向对象编程。 本章针对面向对象的封装、继承、组合、多态给出C语言的实现方法。 封装 封装是指对象仅暴露必要的对外接口(这里指public方法)来和其它对象进行交互,其它的属性和行为都无需暴露,这使得对象的内部实现可以自由修改。 这也要求对象包含它能进行操作所需要的所有信息,不必依赖其它对象来完成自己的操作。 以下以电力公司的例子演示封装。 电力公司生产并提供电力。为了汇聚各种发电厂的电力并让用户获得电力,电力公司提供了两个统一接口: 1、电力公司汇聚各种发电厂的电力,无论是火力发电厂、水力发电厂、原子能发电厂等都使用一个接口。如果什么时候一家火力发电厂改造成了风力发电厂,发电厂的实现完全不一样了,但接口不变,所以电力公司感觉不到发电厂变了,不需要为了发电厂实现升级而改造电力公司的系统。 2、电力公司向用户提供电力,无论用户用电的设备是烤面包机还是洗衣机,电力公司和用户之间都使用一个接口(电源插座)。用户的用电设备可以千变万化,但接口(电源插座)不变。所以电力公司不用关系用户的什么设备在用电。 代码: #include struct PowerCompany { int powerReserve; void (*PowerPlant)(struct PowerCompany *this, int power); void (*PowerUser)(struct PowerCompany *this, int power); }; void PowerPlant(struct PowerCompany *this, int power) { this->powerReserve += power; printf("默认发电厂,发电%d瓦\n", power); return;   } void PowerUser(struct PowerCompany *this, int power) { if (this->powerReserve >= power) { printf("用电%d瓦\n", power); this->powerReserve -= power;     } else { printf("电力不足,用电失败\n");     } return; } /* struct PowerCompany 的构造函数 */ void PowerCompany(struct PowerCompany *this) { this->powerReserve = 0; this->PowerPlant = PowerPlant; this->PowerUser = PowerUser; return; } /* struct PowerCompany 的析构函数 */ void _PowerCompany(struct PowerCompany *this) { } int main(void) { struct PowerCompany myPowerCompany; PowerCompany(&myPowerCompany); /* 发电 */ myPowerCompany.PowerPlant(&myPowerCompany, 1000); /* 用电 */ myPowerCompany.PowerUser(&myPowerCompany, 800);     myPowerCompany.PowerUser(&myPowerCompany, 800);          _PowerCompany(&myPowerCompany); return 0; } 从电力公司的例子中可以看出,良好的封装可以有效减少耦合性,封装内部实现可以自由修改,对系统的其它部分没有影响。 继承 面向对象编程最强大的功能之一就是代码重用,而继承就是实现代码重用的主要手段之一。继承允许一个类继承另一个类的属性和方法。 我们可以通过识别事物之间的共性,通过抽象公共属性和行为来构造父类,而通过继承父类来构造各子类。父类,即公共属性和行为,就得到了复用。 以下哺乳动物的例子演示继承。 猫和狗都是哺乳动物,它们具有公共的属性和行为。比如,猫和狗都有眼睛,且它们都会叫。 我们把眼睛的颜色、会叫抽象出来,作为哺乳动物父类的属性,让猫类、狗类都继承哺乳动物父类,可实现对”眼睛的颜色“、”会叫“实现的复用。 UML: 代码: #include struct Mammal { int eyeColor; void (*ShowEyeColor)(struct Mammal *this); int callNum; void (*Call)(struct Mammal *this); }; void ShowEyeColor(struct Mammal *this) { if (this->eyeColor == 1) { printf("眼睛是绿色\n");     } else { printf("眼睛是蓝色\n");     } return; } void Call(struct Mammal *this) { printf("叫%d声\n", this->callNum); return; } // struct Mammal 的构造函数 void Mammal(struct Mammal *this, int eyeColor, int callNum) { this->eyeColor = eyeColor; this->ShowEyeColor = ShowEyeColor; this->callNum = callNum; this->Call = Call; return;   } struct Dog { struct Mammal mammal; }; // struct Dog 的构造函数 void Dog(struct Dog *this, int eyeColor, int callNum) {     Mammal(this, eyeColor, callNum); // 狗类的其它属性,略 return; } // struct Dog 的析构函数 void _Dog(struct Dog *this) { } struct Cat { struct Mammal mammal; // 猫类的其它属性,略 }; // struct Cat 的构造函数 void Cat(struct Cat *this, int eyeColor, int callNum) {     Mammal(this, eyeColor, callNum); return; } // struct Cat 的析构函数 void _Cat(struct Cat *this) { } int main(void) { struct Dog myDog; Dog(&myDog, 1, 3);     myDog.mammal.ShowEyeColor(&myDog);     myDog.mammal.Call(&myDog);     _Dog(&myDog); struct Cat myCat; Cat(&myCat, 2, 5);     myCat.mammal.ShowEyeColor(&myCat);     myCat.mammal.Call(&myCat);     _Cat(&myCat); return 0; } 多态 多态与继承是紧耦合的关系,但它通常作为面向对象技术中最强大的优点之一。 子类从继承父类的接口,每个子类是单独的实体,每个子类需要对同一消息有单独的应答。 每个子类对同一消息的应答采用继承的相同接口,但每个子类可以有不同的实现,这就是多态。 在猫和狗的例子中,猫类、狗类都继承了哺乳动物父类的“叫”的方法,但猫类、狗类的叫声并不一样,所以猫类、狗类可以采用不同的“叫”的实现。 以下代码演示了多态。 代码: #include struct Mammal { int eyeColor; void (*ShowEyeColor)(struct Mammal *this); int callNum; void (*Call)(struct Mammal *this); }; void ShowEyeColor(struct Mammal *this) { if (this->eyeColor == 1) { printf("眼睛是绿色\n");     } else { printf("眼睛是蓝色\n");     } return; } void Call(struct Mammal *this) { printf("叫%d声\n", this->callNum); return; } /* struct Mammal 的构造函数 */ void Mammal(struct Mammal *this, int eyeColor, int callNum) { this->eyeColor = eyeColor; this->ShowEyeColor = ShowEyeColor; this->callNum = callNum; this->Call = Call; return;   } struct Dog { struct Mammal mammal; }; void Bark(struct Dog *this) { int i; for (i = 0; i < this->mammal.callNum; i++) { printf("汪 ");     } printf("\n"); return; } /* struct Dog 的构造函数 */ void Dog(struct Dog *this, int eyeColor, int callNum) {     Mammal(this, eyeColor, callNum); this->mammal.Call = Bark; return; } // struct Dog 的析构函数 void _Dog(struct Dog *this) { } struct Cat { struct Mammal mammal; }; void Meow(struct Cat *this) { int i; for (i = 0; i < this->mammal.callNum; i++) { printf("喵 ");     } printf("\n"); return; } /* struct Cat 的构造函数 */ void Cat(struct Cat *this, int eyeColor, int callNum) {     Mammal(this, eyeColor, callNum); this->mammal.Call = Meow; return; } // struct Cat 的析构函数 void _Cat(struct Cat *this) { } int main(void) { struct Dog myDog; Dog(&myDog, 1, 3); struct Cat myCat; Cat(&myCat, 2, 5); struct Mammal *myMammal; myMammal = &myDog;     myMammal->Call(myMammal);     myMammal = &myCat;     myMammal->Call(myMammal);     _Dog(&myDog);     _Cat(&myCat); return 0; } 组合 组合与继承都是面向对象中代码复用的方式,也只有通过组合和继承两种方式能够实现使用其他类构建新类。 在前面讲的继承关系中,我们把通用属性和行为抽象出来作为父类。 例如:猫、狗都是哺乳动物,它们具有哺乳动物通用的属性和行为。猫、狗与哺乳动物的关系是“is-a”,即猫、狗(is-a)哺乳动物。而组合关系体现的是“has-a”。以房子和窗户的关系举例。 我们可以单独构建窗户类,然后把窗户类应用到各种房子类上。此时房子(has-a)窗户,但绝不是窗户(is-a)房子。 以下UML和代码演示了组合。 UML: 代码 #include struct Window { int length; int width; void (*ShowWindow)(struct Window *this); }; void ShowWindow(struct Window *this) { printf("这是长%d厘米、宽%d厘米的窗户\n", this->length, this->width); return; } void Window(struct Window *this, int length, int width) { this->length = length; this->width = width; this->ShowWindow = ShowWindow; return; } void _Window(struct Window *this) { } struct House { struct Window *window; int livingRoomNum; int bedRoomNum; int bathRoomNum; void (*ShowHouse)(struct House *this); }; void ShowHouse(struct House *this) { printf("这是%d室%d厅%d卫的房子\n", this->bedRoomNum, this->livingRoomNum, this->bathRoomNum); return; } void House(struct House *this, int livingRoomNum, int bedRoomNum, int bathRoomNum) { this->livingRoomNum = livingRoomNum; this->bedRoomNum = bedRoomNum; this->bathRoomNum = bathRoomNum; this->ShowHouse = ShowHouse; return; } void _House(struct House *this) { } void main() { struct House myHouse; House(&myHouse, 2, 3, 2); /* 组合是一种低耦合,如果不初始化,子类只是存放了一个空指针来占位关联。        此处是与继承关系的区别。继承是一种强耦合,在继承关系中,无论如何子类拥有父类全部的信息。*/ struct Window myWindow1; myHouse.window = &myWindow1;     Window(myHouse.window, 100, 50); /* 通过获得其它对象的引用而在“运行时”动态定义 */ myHouse.ShowHouse(&myHouse);     myHouse.window->ShowWindow(myHouse.window);     _Window();     _House(); return; } 组合和继承的区别有以下几点: 组合关系体现的是“has-a”。继承关系体现的是“is-a”。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

    嵌入式大杂烩 C语言 设计模式 面向过程

  • 70%靠进口,中国工业机器人该如何避免芯片式悲剧?

    本文来源:华商韬略 机器人,工业之魂。 然而,很少有人知道,日本,这个与我们一衣带水的国家,竟把持着全球工业机器人市场20年之久,卡住了无数工业制造的脖子。一旦日本断供,大批工业制造将陷入停摆危机。 1、称霸全球的日本机器人 机器人领域最顶尖的四大企业,素有业内“四大家族”之称:它们分别是日本的发那科(FANUC)、安川电机(Yaskawa)、瑞士的ABB、德国的库卡(KUKA)。 这四大家族加起来,以碾压式的优势占据了我国超过70%的工业机器人市场,以及全球近一半的工业机器人市场。 ▲2020年中国市场工业机器人品牌销量排名 在部分高端工业机器人领域——比如应用在高端汽车、芯片、电子领域的六轴多关节机器人——四大家族甚至直接霸占了超过90%的中国市场,国产玩家几乎毫无抗争之力。 这其中,仅日本一个国家,就占去了四大家族的一半席位。日本发那科(FANUC)则更是早在2008年就成为了世界第一个突破20万台机器人的厂家,市场份额稳居全球第一。 从2000年开始,日本凭借着强大的工业机器人研发生产能力,成为全球第一大工业机器人生产和出口国。 2019年,即便在贸易摩擦与疫情形势严峻的双重影响下,日本工业机器人出口额仍达到了159.2亿美元,远超欧美其他国家,是机器人产业领域名副其实的“超级国家”。 反观我国,目前每万名产业工人所拥有的工业机器人数量仅为140台,远低于日本的327台。 更为可怕的是,日本还垄断着工业机器人上游生产的核心零部件。 以精密减速器为例,它是机器人关节的主要组成部分,占机器人整机成本近40%,是最核心的零件之一,被称为“机器人皇冠上的明珠”。 在这一领域,日本企业也具有压倒性的优势。 全球减速器方面,则被日本纳博特斯克(Nabtesco)、哈默纳科(Harmonic)、住友(SUMITOMO)、新宝(SHIMPO)等企业垄断。日系企业一家独大,连“四大家族”也要向日本采购。 ▲日本机器人核心零部件产业优势,图源:《日本工业机器人崛起之路》戴荣荣 减速器是精密机械工艺的巅峰之作,其技术门槛非常高,是材料科学、精密加工设备、装配技术等学科的集大成之作,需要长期的经验积累,几乎完全不存在弯道超车的可能性。 而作为“工业之魂”,工业机器人的崛起与日本强大的工业制造息息相关。 日本是继美国、德国之后,第三个在世界上建立起机床工业的制造业强国。二战之后,日本政府大力扶持本土工业制造,在战略上提出贸易立国、科技立国,在战术上重点扶持钢铁、汽车、电力、半导体、核能等重工业,并自1982年以后长期雄踞世界工业强国一线阵营。 1970年代末期,日本汽车产业开始试用工业机器人,80年代进入大规模普及阶段。统一的机器流水线生产让日本车企的规模迅速扩大,同时成本持续下降。 如今,日系车企的世界霸主地位有目共睹,仅丰田、本田、日产几家车企的营收之和就超过了1000亿美元。2018年,汽车产业在日本的工业产值中占比达到了40%。 在1970年代后期,日本的半导体产业强势崛起,其全球份额从10%狂飙到40%,甚至引来了美国的疯狂打压。 在芯片半导体的上游设备与材料领域,日本企业有着绝对的话语权。在整个半导体产业的19种关键材料中,日本产业垄断全球过半市场的有14种。 四大家族之一的日本安川电机(Yaskawa)也是世界上最早将工业机器人应用到半导体生产的机器人公司。 高速增长的生产制造业与老龄化严重的日本社会形成了鲜明的对比,在不断激化的劳动力供需矛盾之下,日本工业机器人迅速崛起,走上了称霸之路。 2、40年前的国家战略 1970年,随着战后婴儿潮的逐渐结束,65岁以上的老龄人口占比突破7%红线,日本步入老龄化社会。 然而此时,日本社会却正经历着史上前所未有的高光时刻——战后经济奇迹。 在第二次世界大战结束后,日本国民经济受到致命打击,全国四成财富毁于战火,经济严重崩溃,社会持续动荡。 然而,日本政府抓住了战后国际贸易激增的机会窗口,在本国掀起了前所未有的工业化浪潮,国民的小康阶层开始迅速崛起,在短短二十多年间实现了经济腾飞。 在1965年到1970年期间,日本经济步入了超级繁荣期,工业生产总值年平均增速高达16%、GDP增长超过11%,并在1968年超过德国,成为仅次于美国与前苏联的世界第三大国。 这轮神话般的经济繁荣,被日本国民冠以了神的名字,称为“伊奘诺景气”。 然而,老龄化却如附骨之疽,阴魂不散地缠绕着日本工业。 ▲1954-1984年日本GDP与劳动力人数反差,图源:中国银河证券研究院 1970年,日本的造船、电视、半导体收音机都已占世界第一位;钢铁、汽车、化肥、合成纤维等产量仅次于美国。 然而,此时日本的适龄劳动人口数仅为5153万人,年同比增长甚至不足1%。 激增的工业需求与日益加重的老龄化社会形成了巨大的劳动力缺口,致使日本制造业人力资源持续短缺,成本快速飙升。 与此同时,随着日本工业的迅速崛起,美国“经济老大哥”的地位开始受到威胁,日美之间贸易摩擦不断升级。 ▲尼克松当选 1968年,尼克松在总统大选中承诺将打压日本的纺织品产业,正式拉开了日美第一次贸易保护战的大幕。 大量的贸易顺差、日益不友好的贸易环境、以及日元的过快升值,种种原因迫使日本政府重新审视国家定位,正式从“贸易立国”转向“技术立国”,将技术创新的重要性提到了前所未有的高度。 此时,日本开始大力引进国外先进技术,这些技术经历了从山寨到创新、从模仿到超越的历程,最终被日本社会逐渐内化,成为日本工业创新的基石。 大洋彼岸,美国Unimation公司在1959年开发了世界上第一台工业机器人,它的创始人约瑟夫·恩格尔伯格(Joseph Engelberger)被业内尊称为“机器人之父”。 1969年,通过引进Unimation公司的技术,日本川崎重工率先造出了日本史上第一台工业机器人Unimate,开创了日本工业机器人的先河。 ▲Unimation最早的工业机器人 图源:川崎重工 当时的机器人还在发展初期,庞大而笨重,只能完成很简单的任务,各项指标都不成熟。 但在日本人力极度短缺的背景下,机器人迅速进入了实用阶段,并最先应用在汽车制造领域——Unimation公司的发家之本——并迅速拓展到机械、电子等制造业中。 日本政府也没有闲着,除了出台一系列针对工业机器人的鼓励政策之外,在1971年与1978年,日本政府迅速跟进颁布了《机电法》和《机情法》,率先制定并完善了机器人产业的行业标准,为机器人的大规模应用铺好了道路。 与此同时,日本并没有止步于技术引进,他们大力投入技术研发,不仅成立了世界上第一个国家机器人协会,还自研开发出了世界第一台弧焊机器人、第一台SCARA工业机器人、第一台电机驱动机器人等等。 ▲1980年川崎重工工业机器人在汽车产线上  图源:川崎重工 1980年,日本更是接连颁布两部刺激企业租赁工业机器人的制度法案,并由日本财政省、日本开发银行、牵头24家工业机器人企业成立“日本机器人租赁公司”,向中小企业提供机器人租赁和贷款,将机器人带到了产业链各大中小企业的工厂中。 在一系列疯狂的减税、补贴、贷款优惠、制度倾斜的扶持下,日本工业机器人迎来了第一波蓬勃发展的浪潮。1970年,日本工业机器人年产量约1350台,1980年暴增至19843台,年均增长率超过30%。 在“技术立国”的浪潮下,日本社会如饥似渴地吸收着机器人技术,川崎重工、安川机电、发那科等一大批工业机器人崛地而起,迅速占领了国内市场。 自此,日本机器人产业彻底摆脱了“技术进口”的限制,产业迎来爆发式增长的黄金二十年。 1982年,日本机器人保有量突破10万大关,高级机器人保有量超过全球的56%,远远超过机器人技术发源地——美国。 90年代后,发那科、安川机电更是崛起成为世界一流工业机器人厂商。随着日本国内市场趋于饱和,在政府的积极引导下,日本机器人厂商开始大举进军海外市场。 日本国内市场与全球市场的空间不可同日而语,很快,物美价廉、精准可控的日本工业机器人受到了来自世界各地的认可,订单如雪片般飞至。 2012年,日本机器人出口额已经占据产业总销售额的70%以上,而幅员广阔、不断崛起的亚洲市场,则成了日本机器人的最大买家。 2000年以后,日本已经成长为全球机器人第一大国,不仅稳坐机器人产销王牌位置,还把控着包括减速器、伺服电机在内的上游核心零部件,可谓笑傲机器人江湖。 3、中国的赶超之路 随着中国经济的不断崛起,中美贸易形势开始恶化,国内生育率下滑,人口红利逐渐消失,企业用工成本不断攀升…… 一切的一切,与曾经的日本市场何其相似。 事实上,中国正面临着与日本20世纪80年代类似的,工业机器人需求暴涨阶段。 从2013年开始,中国就是全球工业机器人第一大市场。2016年中国的机器人安装总量更是达到了惊人的世界第一,发展速度史无前例。 然而,我国工业机器人的生产制造能力却十分落后,不仅在核心技术、核心零部件上被人“卡着脖子”,高端机器人市场更是接近全面失守。 而这背后的原因,则同样要追溯到40年以前。 1977年,在日本社会积极拥抱机器人时,海湾彼岸的中国尚未迈出产业探索的第一步。 而此时,中国机器人产业界最关键的人物之一,未来的院士与“中国机器人之父”——蒋新松,步入了人们的视野。 ▲蒋新松院士 1977年,多国重金投入机器人产业,凭借着在东北工业自动化研究所多年的研究经验,蒋新松敏锐地察觉到,机器人必将成为国家科技实力与工业水平的象征。 在这一年的中科院自然科学规划大会上,蒋新松首次提出了发展机器人和人工智能的设想,并在此后陆续提出了“智能机器人在海洋应用”等重要课题。 然而,“十年动乱”让中国科技界元气大伤。大批科学家遭受迫害,科研工作全面陷于停顿,缺人、缺钱、缺技术,想要追上国际先进水平,谈何容易。 一直到1985年,在总设计师蒋新松的带领下,中国才拿出了第一台可正常运作的水下机器人“海人一号”。 ▲“海人一号”机器人 图源:央视 历经艰难,八载春秋,“海人一号”的成功不仅标志着中国机器人产业研究进入新阶段,更是大大鼓舞了蒋新松与其他科学家们的信心。 1986年3月,机器人项目被列入我国“863计划”(国家高技术研究发展计划)中,开启了迈向世界科技前沿的攻坚战。 在此后的日子里,蒋新松不仅连任四届“863计划”自动化领域首席科学家,还带领团队攻克了我国CIMS、特种机器人、智能机器人等多个领域的空白;主编撰写了《机器人学导论》;并创办了中国自动化学会刊物《信息与控制》和《机器人》杂志,全面推进着我国机器人产业的发展。 1994年,蒋新松当选为中国工程院首批院士,1997年因突发心脏病逝世,年仅66岁。 为了纪念蒋新松,目前国内最大、国际一流的新松机器人公司就是以他的名字命名的。 如今,我国工业机器人产业已经走过了四十载,虽然在部分领域有所突破,但是整体发展始终处于落后地位。 随着中国改革开放的不断深入,我国的工业制造能力持续提高,工业机器人需求不断增长,从2013年开始就是全球工业机器人第一大市场。 而根据华创证券数据,当前我国工业机器人国产化率不足30%,国产龙头企业市占率不足3%。 在核心零部件方面,目前国内约85%的减速器、70%的伺服电机、超过80%的控制器市场都被国外品牌占据,高端产品线更是全面失守,多处空白。 中国工业经济联合会会长、工业和信息化部原部长李毅中曾感叹,“我国现在是工业大国,还不是工业强国;是制造大国,还不是制造强国。我们要清醒地看到差距和短板。” 和80年代的日本相比,我们有着太多的相似之处:美国打压、人口老化、用工成本增加、工业需求增长、长期依赖技术引进…… ▲我国制造业用人成本不断攀升图源:德邦研究所 不同的是,中国广袤的市场空间给予了国内机器人厂商更多发展机会。 在“国产替代”的巨浪之下,伴随着新能源汽车、芯片半导体、高新电子等新兴产业所催生的市场需求,国内2020年工业机器人产量累计达到23万台,同比飙升19.1%;12月单月更是突破了2.9万台,创下历史新高。 后疫情时代,中国更是作为少数管控得当、顺利复工复产的国家,迎来了一轮制造业需求的暴增。 据中投产业研究院《2021-2025年中国机器人产业投资分析及前景预测报告》,未来五年我国机器人市场年均复合增长率约为15.80%,2025年市场规模将达到1463亿元。 广阔天地,大有作为。 参考资料: 1.《从日德韩发展历史看中国工业机器人的未来》中国银河证券研究院 2.《景气持续,制造升级,国产崛起》华创证券 3.《2018年中国搬运码垛机器人行业分析报告-市场深度分析与投资前景预测》观研天下 4.《日美贸易摩擦的历史启示》广发证券 5.《日本工业机器人产业崛起之路》戴荣荣 6.《忆中国机器人之父——蒋新松》光明日报

    物联传媒 芯片 机器人 智能制造 AI

  • 5G网络要“省钱”,得靠这四大关键技术!

    本文来源:网优雇佣军 大家都知道,对于运营商而言,要实现5G商业成功,既要拓展新业务增加收入来源,也要勒紧腰带尽可能节省TCO成本,否则,谈什么持续发展啊? 那么,5G时代有哪些关键“省钱”技术呢? 虚拟化 传统专用电信设备功能单一,软硬件封闭式垂直一体化,运营商每一次网络升级后,各种新老专用设备堆叠,使得网络越来越复杂,机房空间越来越紧张,CAPEX和OPEX成本不断上升。 而NFV(网络功能虚拟化)将网络功能从传统专用硬件设备解耦,并将虚拟化网络功能(软件)运行于通用的服务器之上,从而不必像过去那样将特定的网络功能与专用硬件一对一绑定,而是可以将各种网络功能灵活部署于统一的通用硬件资源上,这样就可以利用通用硬件的规模效应来降低成本,并提升网络部署的灵活性。 简单的理解,传统专用电信设备就好比是过去的计算器、相机、游戏机等专用电子设备,它们功能单一;而NFV就好比是今天的智能手机+APP时代,相机、游戏等各种APP共享运行于统一的智能手机硬件平台上。 云化 尽管NFV打破了传统电信设备软硬件垂直一体化的烟囱式架构,实现了软件与硬件分离,但解耦出的VNF软件依然是“大块头”的,依然不够灵活。 于是,VNF进一步被拆分为粒度更小的、模块化的微服务(网络功能服务),并部署于容器中,从而可进一步提升软件开发的灵活性和敏捷性。这就是所谓的“云原生设计”。5G核心网正是基于这样的设计。同时,无状态设计是云原生的另一大功能,其意味着将传统网元的上下文信息与网络功能软件分离,使得软件可以在容器之间灵活迁移,从而提升弹性和扩展性。云原生设计可加速新业务上线,敏捷应对变幻莫测的市场,也为灵活定制网络切片奠定了基础。 网络切片 过去2/3/4G时代,网络服务类型很少,主要提供语音、数据和视频业务。过去的网络也是以“一刀切”的方式提供这些有限的服务。而5G时代的网络切片技术将一张物理网络切成多个相互隔离的虚拟子网络来满足VR/AR、智能工厂、智慧城市、自动驾驶等不同用例的服务需求。一方面,网络切片可灵活高效的共享利用网络物理资源,从而可最大化网络价值;另一方面,网络切片具有确定性的SLA保障,可使能大量的5G创新应用,从而可增加收入来源。未来5G创新应用越多,切片越多,网络资源利用率越高,运营商收入越高。 自动化 一方面,5G时代网络越来越复杂,需要自动化来降低运维成本;另一方面,5G网络切片要敏捷开通,并能在开通后保障SLA,靠人力无法完成,也需要网络自动化。 比如,某工厂向运营商提出了通过5G网络来实现自动化机械臂、AGV、资产追踪等应用的需求,运营商需能迅速根据这些应用所需的网速、时延、可靠性等网络能力来完成资源分配、切片配置和切片开通,这个过程可能要求在几小时甚至几分钟内完成,要是依靠传统人工模式根本不可能实现;同时,开通后还需实时监控和保障切片性能,若切片网络发生故障甚至中断,系统需迅速通过编排管理重新分配资源,或者将连接切换到备用链路,否则,就可能给企业带来经济损失,这同样是传统人工运维模式无法完成的,也需要网络自动化。 事实上,5G大带宽、大规模连接网络产生的海量数据与不断进步的AI技术相结合,使得5G时代基于数据驱动的智能化、自动化网络成为可能:AI可以从海量数据中分析和学习,并根据数据做出更好的决策。比如,在RAN网络中,通过AI预测流量模式,预估某个小区在某个时间段没有流量或流量很低,从而可自主通过载波关断来节省设备功耗,降低越来越受到关注的5G网络电费成本。 在5G自动化网络中,主要包含两个闭环:一个是编排,一个是服务保障。编排的作用是根据定制化服务分配网络资源;服务保障的作用是保障始终如一的网络SLA。两个闭环都基于从端到端收集全域数据,以及基于AI分析引擎来实现。 ~END~

    物联传媒 网络 5G

发布文章