发动态
图文
列表
置顶
【元器件规范共建召集令】诚邀行业专家,定义行业规范新基准
当你在电子元器件选型时,是否因参数定义模糊反复试错?当你推进研发项目时,是否因标准不统一延误进度?如今,有一个能改变行业现状、为电子产业发展注入新动能的机会 —— 加入立创商城电子元器件规范共建项目,与更多行业专家携手,打造科学、完善、权威的元器件参数规范体系!立创商城深耕电子元器件电商领域多年,深知统一精准的参数规范对行业上下游的重要性。我们正启动一项开创性工程,现面向全国电子元器件行业规范制定人、电子行业从业者、电子专业教育从业者、资深领域电子爱好者等群体招募 20-50 名细分领域专家,涵盖接口芯片、时钟和定时、射频无线、传感器等 9 大核心方向,邀你成为这场 “规范革命” 的 “执笔人”。1、你将参与的核心领域(涵盖9大方向)接口芯片USB、PCIe、CAN芯片等接口芯片的设计关注核心参数范围划定及其参数名词解释时钟和定时晶振、定时器、时钟发生器等震荡器的设计关注核心参数范围划定及其参数名词解释射频无线RF芯片、天线模块、无线收发器等无线射频相关器件的的设计关注核心参数范围划定及其参数名词解释传感器温度、压力、光电等传感器的设计关注核心参数范围划定及其参数名词解释功能模块电源管理、信号调理模块等电子模块的设计关注核心参数范围划定及其参数名词解释物联网/通信模块5G、WiFi、蓝牙模块等无线通讯模块的设计关注核心参数范围划定及其参数名词解释单片机/微控制器ST、TI、STC等单片机器件的设计关注核心参数范围划定及其参数名词解释逻辑器件和数据转换ADC/DAC、逻辑门等与信号转换和数据转换相关的设计关注核心参数范围划定及其参数名词解释显示屏器件OLED、LCD等显示屏的设计关注核心参数范围划定及其参数名词解释 2、你的角色:从技术实践者到标准制定者评审与优化:针对公司内部团队起草的规范初稿(如参数定义、填写规范、案例模板),以专业视角审核逻辑严谨性,提出修改建议(例如隔离电压、CMTI等参数的单位换算、优先级规则);深度参与:基于实操经验,为芯片引脚定义、数据速率计算、温度范围界定等参数提供行业实践案例,确保规范兼具理论准确性与工程可行性;成果共创:与跨领域专家协作,构建类似“电子元器件维基百科”的公开规范网站,让技术标准真正服务行业生态。3、我们为你提供的四大价值回报「行业署名权」:每一份经你评审修改的规范,均将在最终版本中明确标注你的姓名与单位,成为个人技术生涯的权威背书;「品牌曝光度」:规范公开时,参与评审与编撰的专家名单将同步公示,通过公司官方渠道(行业媒体、技术社区)定向推送,提升行业影响力;「知识共享平台」:加入电子元器件规范维基网站建设,你的技术见解将被全球工程师查阅引用,成为领域内的“隐形标准制定者”;「多样激励体系」:任务制,每次任务均有丰厚报酬奖励,根据审核规范复杂度与贡献度可获取,包括且不限于京东E卡/采购晶/优惠券/实物奖励等,多劳多得激励形式:1、积分制每次任务,每人均可获得积分,根据每人贡献程度获得对应积分贡献程度人数获得积分皇冠125黄金315白银610青铜105 2、积分可兑换礼品积分数兑换礼品价值550E卡或50采购晶50元10100元E卡或100元采购晶100元20200元E卡或200元采购晶200元50500元E卡或500元采购晶500元1001000元E卡或1000元采购晶1000元2002000元E卡或2000元采购晶2000元 4、为什么工程师值得加入?技术价值升华:从“用标准”到“定标准”,让你的经验成为行业参照坐标; 资源链接机遇:与芯片原厂、方案商专家深度交流,拓展技术人脉圈; 职业发展加分:参与行业级规范制定的经历,是技术管理岗晋升的硬核背书。5、报名方式如果您在上述领域拥有多年以上研发/设计经验,或主导过元器件选型与参数验证项目,欢迎将个人简历(附技术专长说明)发送至:,邮件主题注明“【规范专家报名】+领域方向”。我们将在3个工作日内与您联系,共商规范共建蓝图。 电子元器件的每一个参数,都承载着工程师的智慧。现在,你就有机会成为定义行业规范的 “少数派”,让全球工程师使用你参与制定的标准。这不仅是一次技术实践,更是一段能为行业留下深刻印记、为职业增添高光的宝贵经历。立创商城期待与你携手,重塑元器件参数规范行业标杆,让你的技术印记,刻进行业未来! 注:“本次共建采用灵活协作模式,单次任务预计耗时2~4小时,全程线上进行,不影响日常工作。”
【元器件规范共建召集令】诚邀行业专家,定义行业规范新基准
立创商城
在计算机编程的世界中,C++是一门备受推崇的编程语言,它的强大之处之一就是支持面向对象编程(Object-Oriented Programming,OOP)。在C++中,类和对象是面向对象编程的核心概念,它们为程序员提供了一种结构化的方式来组织和管理代码。1. 类(Class):抽象的蓝图在C++中,类是一种用户定义的数据类型,用于封装数据和方法。可以将类看作是对象的抽象蓝图,其中包含了描述对象属性和行为的成员变量和成员函数。通过定义类,程序员可以创建自己的数据类型,从而更好地组织和管理代码。 例如我们可以把人作为一个对象,他有基本的属性:性别、身高、年龄等等 也有基本的行为:吃饭、睡觉、学习、玩游戏等等。1.1 类的基本结构一个简单的类通常包含以下几个要素:class MyClass { private: // 成员变量(属性) int myInt; double myDouble; public: // 构造函数 MyClass() { myInt = 0; myDouble = 0.0; } // 成员函数(方法) void setValues(int i, double d) { myInt = i; myDouble = d; }     ~MyClass() { } }; class + 类名 的方法创建我们的类。 类中的变量可以称作成员,他们有一些访问属性:Protect:保护,private:私密,public:公开 故名思意除了public其他的变量都不可以在类外被访问。 类中有两种特殊的函数 与类名相同的名称被称作构造函数,我们在创建类的同时会调用构造函数! 同样的还有一个特殊的函数:析构函数,和析构函数差不多,但是需要多一个~符号,这个函数会在类被释放的时候调用。1.2 类的实例化通过定义类,我们可以创建类的实例,也称为对象。对象是类的具体实体,可以调用类中定义的方法,访问和修改成员变量。int main() { // 创建类的实例 MyClass myObject; // 调用成员函数     myObject.setValues(42, 3.14); return 0; } 2. 对象(Object):实体化的具体实例对象是类的实例,是具体存在的数据单元。在C++中,通过创建对象,我们可以利用类定义的结构来存储和操作数据。2.1 对象的特性对象具有以下几个重要的特性:封装性(Encapsulation): 类的内部实现对外部是不可见的,只有通过公共接口(成员函数)才能访问类的属性和方法,确保了数据的安全性和代码的模块化。继承性(Inheritance): 类可以通过继承从其他类中获取属性和方法,实现代码的重用和扩展。多态性(Polymorphism): 不同的类可以具有相同的接口,但表现出不同的行为,提高了代码的灵活性和可维护性。2.2 对象的生命周期对象的生命周期从创建到销毁,包括对象的构造、使用和析构阶段。在C++中,构造函数和析构函数负责对象的初始化和清理工作。int main() { // 创建对象,调用构造函数 MyClass obj; // 对象在main函数结束时销毁,调用析构函数 return 0; C++中的类和对象为程序提供了一种灵活而强大的编程范式,使得代码更易理解、维护和扩展。通过合理利用类和对象,程序员可以更好地组织和管理代码,提高代码的可读性和可维护性。
C++中的类和对象:面向对象编程的基石
嘉立创PCB
随着我国无线通信和物联网技术的发展,WiFi已普及到我们的生活每一个角落。无线WiFi设备已经被带到太空,实现神舟十二号载人飞船空间站“移动WiFi”智能生活空间。为了更方便的应用与生产,WiFi也逐渐形成了模块化的形式。作为WiFi模块厂家方案商,和你一起了解高性价比无线路由方案的WiFi模块。WiFi模块是将串口或TTL电平转为符合WiFi无线网络通信标准的嵌入式模块,WiFi模块可以直接利用WiFi联入互联网,是实现无线智能家居,M2M等物联网应用的重要组成部分。现在我们聊的是WiFi模块中既可用于广域网也可以用于局域网的无线路由器方案WiFi模块,以RMS7628N模块为例。   RMS7628N无线路由器方案WiFi模块就是基于通用串行接口符合网络标准的嵌入式WiFi模块,内置TCP/IP协议栈,可实现串口,以太网,无线网(WiFi)接口之间的相互连接。是新一代802.11n Wi-Fi AP/路由器系统单芯片解决方案(SoC)。为智能家庭内的数据、语音和影像应用程序提供高数据传输率,而且耗电量低。MT7628和MT7620一样具有2T2R 300M wifi速率,接口丰富,但是它比MT7620功耗更低、芯片成本更低,专门针对物联网应用推出3个串口、PWM输出等特点,可谓是MT7620的升级产品。无线路由方案WiFi模块体积小、功耗低、发热量小,wifi、网口传输性能稳定。运行openwrt(linux)系统,可长期稳定运行。模块外围电路非常简单,仅需加上3.3V DC电源,即可让系统启动,并可通过WIFI控制。    RMS7628N无线路由方案WiFi模块可用于有线转WiFi、4G转WiFi、吸顶AP、4G路由器、无线音箱、无线存储扩容、无线图传、数据透传、智能家居、IP camera、遥控拍摄飞行器、远程视频监控系统等
物联网智能工控网关 高性价比的无线路由方案的WiFi模块RMS7628N
开源硬件平台
#嘉立创EDA#敬爱的嘉立创EDA产品与研发团队:你们好! 我是一名陪伴嘉立创EDA走过多年的忠实用户,也是一名坚定的EDA国产替代信仰者。从用EasyEDA标准版画第一块核心板,到如今创业做工业硬件研发全程以专业版为核心工具,我亲眼见证了咱们的国产EDA从“浏览器里的轻量化工具”,成长为打破海外巨头垄断、打通“设计-制造”全链路、真正实现硬件研发普惠化的行业标杆。 我始终坚信,咱们的核心竞争力,从来不是对海外EDA工具的简单复刻,而是走出了一条“云原生+制造闭环+低门槛普惠”的中国特色EDA之路。永久免费的授权模式、开箱即用的百万级国产器件库、与生产端无缝衔接的DFM体系、原生的多人协同能力,这些都是Altium、Cadence等海外厂商永远无法给中国硬件开发者的核心价值。也正因如此,我始终把嘉立创EDA作为首选工具,向身边的学生、创客、中小企业同行反复推荐,我真心希望咱们的国产EDA,能真正站到全球EDA行业的顶端。 但作为一名深度用户,我也不得不直面困扰我和身边同行多年的核心瓶颈——**性能短板,正在成为咱们向下普惠、向上突破的最大障碍**。我见过太多学生用宿舍的低配置笔记本,画一个仅几十器件的两层板,就出现画布缩放、元件拖动的肉眼可见卡顿,哪怕关掉所有实时功能也无法获得流畅体验,最后只能无奈转向盗版AD。 我深知,团队这些年从未停止过性能优化的努力:从Canvas到WebGL再到WebGPU的渲染引擎三代迭代,从增量铺铜到多线程DRC的算法优化,从V2到V3版本对工程格式、原理图引擎的全面重构,每一个版本的更新日志里,都能看到你们为解决性能痛点付出的心血。但我也必须坦诚地说:**当前Electron+Web的原生架构,从底层就给咱们的性能天花板划定了边界,局部的优化迭代,已经很难抹平与海外原生架构EDA的代际差距,更难从根源解决“低配置电脑哪怕画小PCB也卡顿”的基础体验问题**。 经过调研与深度思考,我想给团队提一个建设性建议:《基于国产Cocos Creator 3D引擎,重构咱们EDA软件的渲染与交互内核》。这个提议绝非一时兴起的空想,它既能完整保留咱们当前所有的核心产品优势,更能从底层架构上彻底突破性能瓶颈,实现对海外EDA厂商的弯道超车。以下是我完整的论证与分析,恳请团队能耐心看完。 一、基于Cocos引擎重构EDA,具备100%的技术可行性 Cocos绝非只能做游戏的娱乐向引擎,它已经是经过工业级场景验证、完全自主可控、性能与成熟度拉满的国产跨平台3D渲染引擎,其核心能力与EDA软件的底层需求高度契合,可行性已经过全维度验证:1. 渲染能力完全覆盖EDA全场景核心需求 EDA软件的核心交互载体,是**高精度2D矢量布线画布**与**工业级3D装配预览**,这两项需求恰好是Cocos引擎的核心优势,成熟度远超咱们自研的渲染引擎。 在2D布线场景,Cocos底层GFX图形框架原生支持WebGPU、Vulkan、Metal、OpenGL等全平台图形API,内置成熟的Signed Distance Fields(SDF)矢量渲染管线,可实现任意缩放级别下的线条无损、无锯齿渲染,与PCB设计“纳米级坐标精度、无限缩放无失真”的核心要求完全契合。同时它原生支持分层渲染、视口裁剪、GPU实例化、静态批处理等优化技术,我们可以针对EDA场景定制专属渲染管线:将布线层、飞线层、DRC标记层、铺铜层拆分为独立渲染单元,仅重绘变更的图层与视口内的图元,从根源解决当前画布缩放、平移卡顿的核心痛点。在3D可视化场景,Cocos引擎已经落地了车载智能座舱、ADAS 3D可视化等对精度、稳定性要求极高的工业场景,其原生支持PBR物理渲染、百万级多边形模型实时渲染、STEP/IGES标准3D模型导入、实时碰撞检测,完全满足PCB 3D预览、机电协同装配、干涉校验的全流程需求。更重要的是,这套渲染管线经过了全球20亿终端用户的验证,在显卡适配、性能优化、显存管理上的成熟度,远超EDA厂商自研方案。 2. 架构设计从底层解决当前所有核心性能瓶颈 当前咱们的核心卡顿根源,是Electron+JS单线程架构的原生缺陷,而Cocos的架构设计从底层就规避了这些问题。一方面,Cocos采用**C++底层内核+TypeScript上层API**的混合架构,底层渲染、场景管理、物理计算均由C++实现,原生支持**渲染线程、逻辑线程、物理线程、计算线程完全分离**。这套架构可以彻底解决咱们的核心卡顿痛点:将DRC规则校验、铺铜计算、交互式布线算法、仿真分析等算力密集型任务,完全剥离到独立的计算线程执行,无论计算负载多高,都不会阻塞UI主线程的画布交互,彻底告别“一计算就卡死”的顽疾。另一方面,Cocos拥有极致轻量的运行时,空工程原生客户端内存占用仅**<100MB**,冷启动时间<3秒,对比当前Electron架构空工程1-2GB的内存占用、10秒以上的启动时间,基础资源开销降低了90%以上。哪怕是4GB内存、双核CPU、入门级核显的低配置电脑,也能流畅运行小型PCB设计,真正实现咱们“让所有人都能轻松做硬件”的普惠初心。3. 跨平台能力完美匹配咱们的产品核心定位 Cocos的核心定位就是“高效、轻量、跨平台、全功能3D开发引擎”,原生支持Windows、macOS、Linux、Web、HarmonyOS Next、Android、iOS等几乎所有主流平台,一套代码可实现多端一键编译。 这套跨平台能力,既能完整保留咱们“Web端免安装、打开浏览器即可设计”的核心优势,又能通过原生编译彻底摆脱Electron架构的内存泄漏、高资源占用问题;同时借助Cocos Runtime能力,可实现PCB工程的轻量化分享——无需安装完整软件,点击链接即可打开工程完成查看、批注、校验,完美适配云协同、轻量化交付的工业场景;更重要的是,它原生适配所有国产操作系统与芯片平台,完全符合国产EDA的自主可控战略。 4. 完全自主可控的开源生态,无任何技术封锁风险 Cocos引擎采用MIT开源协议,底层核心模块完全开源,无海外技术封锁风险,我们可以根据EDA需求对引擎进行深度定制改造,这是Unity、Unreal等海外引擎永远无法比拟的优势,也完全契合咱们国产EDA的国产化核心要求。同时,Cocos拥有全球170万注册开发者,国内移动游戏市场份额达40%,生态内有大量成熟的物理引擎、网络协同模块、UI框架、插件工具,我们无需从零开发EDA的配套能力,研发成本与周期可降低50%以上,能把更多精力投入到EDA核心算法、制造闭环的优化上。5. 行业已有成熟的技术验证先例 学术界与工业界早已验证了游戏引擎用于EDA开发的可行性:学术界已有基于游戏引擎面向数据设计(DOD)理念构建的开源PCB物理设计库,大幅提升了超大工程的处理性能;工业界已有基于Unreal Engine构建的数字电路仿真系统、PCB 3D可视化平台,实现了沉浸式电路设计、实时信号流可视化、3D装配校验等功能;而Cocos引擎更是已经在车载HMI、工业数字孪生、智能装备可视化等领域实现大规模量产落地,其实时渲染、高精度交互、工业级稳定性均已通过市场验证,完全满足EDA软件的工业级要求。二、基于Cocos引擎重构,将带来碾压级的性能优势 这套架构重构,绝非简单的技术栈替换,而是能从根源上解决当前所有性能痛点,在全维度实现对现有架构、甚至海外主流EDA的性能超越,核心优势集中在五大维度:1. 基础运行开销实现数量级下降,彻底解决低配置设备适配难题 重构后,咱们的软件空工程内存占用将从1-2GB降至100MB以内,冷启动时间从8-15秒缩短至3秒以内,基础资源开销仅为当前架构的1/10。对于低配置电脑,哪怕是几十器件的小型PCB,当前架构也会因基础开销过高触发内存交换、CPU满载,而重构后的架构仅占用极少系统资源,可实现全程流畅交互,从根源解决“小PCB也明显卡顿、低配置电脑完全无法使用”的用户痛点,真正把硬件研发的普惠门槛降到最低。2. 渲染性能实现代际提升,彻底告别画布交互卡顿 重构后,10万焊盘级别的PCB工程,画布缩放、平移、元件拖动可稳定60FPS满帧运行,流畅度是当前架构的2-3倍,甚至超过Altium Designer。基于SDF的矢量渲染方案,PCB走线、焊盘在任意放大倍数下都清晰锐利,无锯齿失真,同时渲染性能不会因缩放而下降;全板飞线、DRC违规标记、网络高亮等叠加元素,可通过独立渲染层实现,不会阻塞主线程,也不会影响基础画布的交互流畅度,我们再也不用为了流畅度,被迫关闭实时DRC、隐藏飞线、关闭铺铜。3. 算力密集型场景实现架构突破,彻底解决编辑响应延迟 Cocos的多线程分离架构,让铺铜、DRC、布线算法等算力任务完全运行在独立线程,哪怕全板重铺、全量DRC校验,用户仍可正常操作画布,无任何卡顿;同时原生支持多核并行计算,可将全板DRC、铺铜三角化、等长匹配等任务拆分到多核CPU并行执行,计算速度比当前架构提升5-10倍;再加上原生支持的增量计算,仅重算设计变更的区域,而非全板重算,编辑后的响应速度比当前架构提升10倍以上,彻底告别大工程“动一下等几秒”的噩梦。4. 3D可视化与机电协同能力实现质的飞跃 重构后,包含数千个元器件的PCB 3D预览,可稳定60FPS旋转、缩放,流畅度远超当前架构与Altium;内置的Bullet工业级物理引擎,可实现实时3D碰撞检测、装配干涉校验,甚至模拟元器件插拔、散热风道、跌落测试,这些能力是海外大厂都不具备的差异化优势;同时原生支持几乎所有工业3D模型格式,导入解析速度比当前架构快数倍,显存占用降低50%以上,能让咱们的机电协同能力直接跻身行业顶尖水平。 5. 云协同与跨端体验实现全面升级 重构后的Web版EDA,页面加载时间<2秒,内存占用<200MB,对比当前网页版5秒以上的加载时间、1GB以上的内存占用,对低配置电脑、弱网环境的友好度大幅提升;原生支持的网络状态同步机制,结合OT算法实现多人实时协同,增量同步数据包更小,同步延迟更低,不会出现多人协同场景下的卡顿、冲突问题;同时原生客户端可完全离线运行,工程文件存储在本地,资源占用极低,对比当前Electron架构的离线模式,稳定性、性能、内存控制都有质的提升。 三、核心技术挑战与成熟落地方案 我深知,EDA软件的工业级属性,决定了架构重构绝非易事,我也针对大家可能顾虑的核心技术挑战,做了完整的解决方案论证,所有方案均有成熟的行业先例,不存在无法突破的技术壁垒: 第一,针对PCB设计的纳米级数学精度适配问题,我们可以采用**双精度业务内核 + 视口相对坐标渲染**的混合架构。底层EDA核心数据层全程采用double双精度浮点数,保证PCB设计的纳米级数学精度,所有电气规则校验、坐标计算均在该层完成,与渲染层完全解耦;渲染层仅处理当前视口内的相对坐标,将双精度的绝对坐标转换为单精度的视口相对坐标,再交给Cocos引擎渲染,这也是Altium等海外大厂沿用多年的成熟方案,完全不会有精度丢失的问题。 第二,针对统一数据模型与引擎节点系统的映射问题,我们可以构建**独立EDA核心数据层 + 引擎映射中间层**的解耦架构。完整保留咱们当前已经非常成熟的V3增量日志型数据模型作为整个软件的唯一可信数据源,与渲染引擎完全无关;仅做一层轻量的中间映射层,实现数据模型与Cocos场景节点的双向映射:数据层的变更实时同步到Cocos的渲染节点,用户在Cocos画布中的操作,通过中间层校验后回写到核心数据层,既保证了设计数据的一致性与严谨性,又完全不会动摇咱们多年积累的核心数据资产。 第三,针对EDA专用算法的集成与优化问题,我们可以将交互式布线、铺铜、DRC校验等核心算法,用C++/Rust独立编写,客户端编译为原生插件,Web端编译为WebAssembly(WASM),通过Cocos的原生扩展机制集成,获得接近原生的计算性能。算法执行与渲染完全解耦,所有算力任务均在独立的计算线程中运行,既保留咱们多年积累的算法优势,又能获得多核并行计算的性能提升,甚至可以复用Cocos内置的物理引擎,优化布线避障、3D碰撞检测等算法,降低自研成本。 第四,针对工业制造文件与第三方工具的兼容性问题,我们可以在底层核心数据层实现完整的导入/导出器体系,与渲染引擎完全解耦,不依赖Cocos的任何能力。所有Gerber导出、第三方工程文件导入导出、MCAD工具对接,均和当前的实现逻辑完全一致,无技术壁垒,完全不会影响咱们多年积累的兼容性优势。最后 敬爱的研发与产品团队,我写这封信,不是来挑刺吐槽的,是作为一名陪伴了你们多年的老用户,真心想和咱们团队站在一起,突破当前最大的发展瓶颈。 我从来没有因为功能缺失放弃过嘉立创EDA,却无数次因为卡顿、响应慢而焦虑;我从来没有因为海外大厂的功能更全而动摇过国产替代的信仰,却无数次因为身边同行因为性能问题放弃咱们的产品而惋惜。我真心不希望,咱们已经打通了最难的设计-制造闭环,已经打破了海外巨头的垄断,最后却被性能这个短板,拦住了走向全球顶尖的脚步。 更重要的是,用国产Cocos引擎,做国产EDA,是国产替代赛道上的强强联合,我们能打造出一套从渲染引擎到EDA工具、从设计到制造完全自主可控的硬件创新全链路,这不仅是产品体验的升级,更是中国工业软件发展史上的重要一步。 如果团队愿意考虑这个方向,我愿意无偿参与所有的内测、验证,把我这些年的深度使用体验、所有的痛点和需求,毫无保留地反馈给你们。 我始终相信,嘉立创EDA一定能成为全球顶尖的EDA工具,一定能让全球的硬件开发者,都用上咱们中国人做的EDA软件。这条路很难,但我会一直陪着你们走下去。此致敬礼一名嘉立创EDA的忠实用户国产EDA替代的坚定信仰者2026年4月24日
致嘉立创EDA产品与研发团队的一封信
嘉立创EDA
前面几期利用.NET MAUI我们开发了一个Android应用用来接收ESP32的图片数据以及制作了一个摇杆方便我们操控。 但是有一点,我们发送图片以及交流的IP都是固定的。 可是,IP地址会随着网络以及设备发生变换,那么我们怎么知道每次的IP地址呢。 本期我们将介绍ESP32如何开启AP模式来让手机进行连接并且获取所连接的设备的IP地址。 在ESP的AP模式下,设备像一个Wi-Fi网络中的路由器一样,允许其他设备通过Wi-Fi连接到它,从而建立本地网络。这种模式通常用于创建一个局域网(Local Area Network,LAN),其中ESP设备充当中心节点,其他设备可以通过该节点相互通信。 通过AP模式,ESP设备可以提供网络连接、数据传输和通信服务,使其他设备能够连接到互联网或者在局域网内进行数据交换。这对于构建物联网应用和连接智能设备非常有用。代码编写#includeesp_wifi.h#include <Wifi.h> 首先需要导入这两个库,分别用来连接WiFi和获取设备IP  WiFi.softAP(ssid, password);//AP模式开启Wifi ip = WiFi.softAPIP();//获取本机IP   Serial.println(ip);//打印IP   WiFi.onEvent(WiFiEvent);//创建一个事件用来监听事件 使用上述语句开启WiFi AP模式,ssid为Wifi的名字,password为Wifi的密码,注意这个密码至少八个字符!! 可以看到可以发现一个ESP32的Wifi.void WiFiEvent(WiFiEvent_t event) {   if(event == 13)   {    wifi_sta_list_t wifi_sta_list; tcpip_adapter_sta_list_t adapter_sta_list; memset(&wifi_sta_list, 0, sizeof(wifi_sta_list)); memset(&adapter_sta_list, 0, sizeof(adapter_sta_list)); esp_wifi_ap_get_sta_list(&wifi_sta_list); tcpip_adapter_get_sta_list(&wifi_sta_list, &adapter_sta_list); for (int i = 0; i < adapter_sta_list.num; i++) { tcpip_adapter_sta_info_t station = adapter_sta_list.sta[i]; Serial.print("station nr "); Serial.println(i + 1); Serial.print("MAC: "); for (int i = 0; i < 6; i++) { Serial.printf("%02X", station.mac[i]); if (i < 5) Serial.print(":"); } Serial.print("\nIP: "); ip4_addr_t ip_buf; memcpy((char *)&ip_buf, (char *)&station.ip, sizeof(ip4_addr)); String ipstr = ip4addr_ntoa(&(ip_buf)); Serial.println(ipstr); } } } 接着为Wifi添加事件回调。(这些设备包括:设备断开,设备连接,设备被分配到IP......) 当有Wifi事件触发时,我们打印连接设备的IP地址。 这里Wifi连接和赋予地址都会触发回调,我们只处理赋予IP地址的事件 wifi_sta_list_t 和 tcpip_adapter_sta_list_t 是结构体,用于存储STA(Station)列表的信息。 memset 函数用于将结构体初始化为零,以确保所有字段的初始值为零。 esp_wifi_ap_get_sta_list 用于获取与当前AP连接的STA列表,并将结果存储在 wifi_sta_list 中。 tcpip_adapter_get_sta_list 则用于将 wifi_sta_list 中的信息转换为 adapter_sta_list 结构体中。 接下来,通过循环遍历 adapter_sta_list 中的STA列表,逐个处理每个STA的信息。 最后是打印IP信息。 一个是本机地址,一个是我手机所连接的IP。String ipstr = ip4addr_ntoa(&(ip_buf)); if (ipstr== ("0.0.0.0")) { continue; } staIPAddresses[i] = ipstr; STANumber = i; Serial.println(ipstr); 我们比较一下,剔除掉自身的IP,然后保存所有设备的IP。if (ipstr== ("0.0.0.0")) { continue; } staIPAddresses[i] = ipstr; STANumber = i;
ESP32使用Arduino IDE开启Wifi AP模式并获取所连接设备地址
嘉立创PCB
一、方案背景在前端中经常会出现多接口并发的场景,而针对请求常规方式会一股脑发送给浏览器,浏览器中会对大量请求进行排队,但大量请求推送至浏览器就会占用内存,最后达到一定量级导致页面卡顿,甚至假死常规请求图如下二、解决思路针对此模式,我们可以创建如下序列,待发送请求池作为中间层,只作为载体,每次推送固定数量到浏览器,当浏览器主线程中存在接口执行完毕后,代表主线程中接口数量减少,在从待发送请求中取出新的接口放入主线程,从而实现控制主线程发送数量避免内存溢出创建待发送请求池控制最大并行请求数量指定接口缓存,如数据源,结合请求,响应拦截器进行处理流程图如下<<<顺手说一个:有新的技术大厂在→要人,前端/后端还有测试,一线城市及双一线城市几乎都有坑位,待遇稳定性都还成,感兴趣的可以瞅瞅~三、具体代码实现请求并发控制方案概述这是一个基于请求池(Request Pool)的并发控制方案,用于管理前端应用中的 HTTP 请求。通过双队列机制控制并发数量,避免同时发起过多请求导致的性能问题和浏览器限制。核心特性并发控制:限制同时执行的请求数量(默认 20 个)双队列设计:待执行队列(pendingQueue)+ 执行中队列(runningQueue)请求取消:支持取消单个或全部请求,基于 AbortController缓存支持:可配置的请求结果缓存机制内存优化:请求完成后自动清理引用,防止内存泄漏非阻塞调度:使用 setTimeout(0) 让出主线程,避免阻塞 UI防重复调度:通过 isProcessing 标志位避免重复调度架构设计1. 状态管理const poolState = { pendingQueue: [], // 待执行队列 runningQueue: [], // 执行中队列 cacheStore: new Map(), // 缓存存储 maxConcurrent: 20, // 最大并发数 maxPendingQueue: Infinity, // 待执行队列最大长度 isProcessing: false // 防止重复调度标志位 }; 2、核心机制防重复调度使用 isProcessing 标志位防止多次调用 scheduleExecute() 时重复创建定时器: const scheduleExecute = () => { if (poolState.isProcessing) return; // 已在处理中,直接返回 poolState.isProcessing = true; setTimeout(() => { processQueue(); poolState.isProcessing = false; // 处理完成,重置标志 }, 0); }; 批量处理每次调度时,根据可用槽位批量启动请求:const processQueue = () => { // 计算可用槽位 const slots = poolState.maxConcurrent - poolState.runningQueue.length; const count = Math.min(slots, poolState.pendingQueue.length); // 批量启动 for (let i = 0; i < count; i++) { const task = poolState.pendingQueue.shift(); if (task) { poolState.runningQueue.push(task); executeRequest(task); } } }; API 文档addRequest(config, axiosInstance)添加请求到队列参数:config (Object): axios 请求配置对象axiosInstance (Function): axios 实例返回:Promise: 请求的 Promise 对象示例:import axios from 'axios'; import { addRequest } from '@/utils/requestPool'; const config = { method: 'get', url: '/api/users', params: { page: 1 } }; addRequest(config, axios) .then(response => console.log(response.data)) .catch(error => console.error(error)); setMaxConcurrent(max)设置最大并发数参数:max (Number): 最大并发数示例:import { setMaxConcurrent } from '@/utils/requestPool'; // 设置最大并发数为 10 setMaxConcurrent(10); clearAllRequests()取消所有请求(包括待执行和执行中的请求)返回:Object: 取消的请求数量统计pending (Number): 待执行队列中取消的数量running (Number): 执行中队列中取消的数量示例:import { clearAllRequests } from '@/utils/requestPool'; const count = clearAllRequests(); console.log(`取消了 ${count.pending} 个待执行请求`); console.log(`取消了 ${count.running} 个执行中请求`); getPoolState()获取请求池当前状态(用于调试和监控)返回:Object: 请求池状态信息示例:import { getPoolState } from '@/utils/requestPool'; const state = getPoolState(); console.log('待执行:', state.pendingCount); console.log('执行中:', state.runningCount); console.log('缓存数:', state.cacheCount); getCacheKey(config)生成缓存键(预留功能)参数:config (Object): axios 配置对象,需包含 cacheParams 字段返回:String | null: 缓存键,如果未配置 cacheParams 则返回 nullgetCache(key) / setCache(key, data) / clearCache(key)缓存操作方法(预留功能)使用示例1. 基础集成 - Axios 拦截器在 axios 实例中集成请求池:// src/utils/request.js import axios from 'axios'; import { addRequest, clearAllRequests } from './requestPool'; const service = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10000 }); // 请求拦截器 service.interceptors.request.use( config => { // 标记使用请求池 config.usePool = true; return config; }, error => Promise.reject(error) ); // 响应拦截器 service.interceptors.response.use( response => response.data, error => { console.error('请求失败:', error); return Promise.reject(error); } ); // 重写 axios 请求方法,使用请求池 const originalRequest = service.request.bind(service); service.request = function(config) { if (config.usePool !== false) { // 使用请求池 return addRequest(config, originalRequest); } // 不使用请求池,直接请求 return originalRequest(config); }; export default service; export { clearAllRequests }; 2. API 调用示例 // src/api/user.js import request from '@/utils/request'; // 获取用户列表 export const getUserList = (params) => { return request({ url: '/api/users', method: 'get', params }); }; // 获取用户详情 export const getUserDetail = (id) => { return request({ url: `/api/users/${id}`, method: 'get' }); }; // 创建用户 export const createUser = (data) => { return request({ url: '/api/users', method: 'post', data }); }; 3. 组件中使用<template> <div> <button @click="loadData">加载数据</button> <button @click="cancelAll">取消所有请求</button> <div>待执行: {{ poolState.pendingCount }}</div> <div>执行中: {{ poolState.runningCount }}</div> </div> </template> <script setup> import { ref, onMounted } from 'vue'; import { getUserList } from '@/api/user'; import { clearAllRequests, getPoolState } from '@/utils/requestPool'; const poolState = ref({ pendingCount: 0, runningCount: 0 }); // 更新请求池状态 const updatePoolState = () => { const state = getPoolState(); poolState.value = state; }; // 加载数据 const loadData = async () => { try { // 同时发起 50 个请求,但只有 20 个会并发执行 const promises = Array.from({ length: 50 }, (_, i) => getUserList({ page: i + 1 }) ); // 定时更新状态 const timer = setInterval(updatePoolState, 100); const results = await Promise.all(promises); clearInterval(timer); console.log('所有请求完成:', results.length); } catch (error) { console.error('请求失败:', error); } }; // 取消所有请求 const cancelAll = () => { const count = clearAllRequests(); console.log(`已取消 ${count.pending + count.running} 个请求`); updatePoolState(); }; onMounted(() => { updatePoolState(); }); </script> 4. 路由切换时取消请求// src/router/index.js import { createRouter, createWebHistory } from 'vue-router'; import { clearAllRequests } from '@/utils/requestPool'; const router = createRouter({ history: createWebHistory(), routes: [ // 路由配置... ] }); // 路由切换前取消所有请求 router.beforeEach((to, from, next) => { if (from.path !== '/') { const count = clearAllRequests(); console.log(`路由切换,取消了 ${count.pending + count.running} 个请求`); } next(); }); export default router; 5. 批量请求示例// 批量加载用户详情 async function loadUserDetails(userIds) { const promises = userIds.map(id => getUserDetail(id)); try { const results = await Promise.all(promises); console.log('加载完成:', results); return results; } catch (error) { console.error('批量加载失败:', error); throw error; } } // 使用示例 const userIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; loadUserDetails(userIds); 6. 动态调整并发数import { setMaxConcurrent, getPoolState } from '@/utils/requestPool'; // 根据网络状况动态调整 function adjustConcurrency() { const connection = navigator.connection; if (connection) { const effectiveType = connection.effectiveType; switch (effectiveType) { case 'slow-2g': case '2g': setMaxConcurrent(5); break; case '3g': setMaxConcurrent(10); break; case '4g': default: setMaxConcurrent(20); break; } console.log('网络类型:', effectiveType); console.log('当前并发数:', getPoolState().maxConcurrent); } } // 监听网络变化 if (navigator.connection) { navigator.connection.addEventListener('change', adjustConcurrency); } 7. 请求优先级(扩展示例)如果需要实现请求优先级,可以扩展 addRequest 方法:// 扩展版本 - 支持优先级 export const addRequestWithPriority = (config, axiosInstance, priority = 0) => { return new Promise((resolve, reject) => { const abortController = new AbortController(); const task = { config: { ...config, signal: abortController.signal }, resolve, reject, axiosInstance, abortController, priority // 添加优先级字段 }; // 根据优先级插入队列 const index = poolState.pendingQueue.findIndex(t => t.priority < priority); if (index === -1) { poolState.pendingQueue.push(task); } else { poolState.pendingQueue.splice(index, 0, task); } scheduleExecute(); }); }; // 使用示例 addRequestWithPriority(config, axios, 10); // 高优先级 addRequestWithPriority(config, axios, 0); // 普通优先级 性能优化要点1. 内存管理请求完成后自动清理任务对象的引用:task.config = null; task.resolve = null; task.reject = null; task.axiosInstance = null; task.abortController = null; 2. 非阻塞调度使用 setTimeout(0) 让出主线程:setTimeout(() => { processQueue(); poolState.isProcessing = false; }, 0); 3. 批量处理一次调度处理多个请求,减少调度次数:const count = Math.min(slots, poolState.pendingQueue.length); for (let i = 0; i < count; i++) { // 批量启动 } 注意事项并发数设置:默认 20 个,可根据实际情况调整请求取消:路由切换或组件卸载时记得取消请求错误处理:已取消的请求不会触发 reject,避免重复处理缓存功能:当前代码中已预留,可根据需要启用浏览器限制:不同浏览器对同域名并发请求有限制(通常 6-8 个),但通过请求池可以更好地控制——转载自:米西米西1
前端必看!接口并发方案
开源硬件平台
上期我们利用FFImageLoad实现了图片流的显示,之前也有一期简单介绍了一下利用SkiaSharp实现绘图。 本期我们来实现一个摇杆的实现。public class DrawAble {     private readonly Rocker view; public DrawAble(Rocker view) {         this.view = view; } private void Draw_Circle(SKSurface surface, SKRect bounds) { float centerX = bounds.MidX; float centerY = bounds.MidY; Midx = centerX; Midy = centerY; // 计算圆的半径(使用ChargingRingDrawable类中的rad属性) float radius = CirCleRad; // 使用SKPaint对象定义圆的样式(颜色、线条宽度等) using (SKPaint paint = new SKPaint()) { paint.Color = SKColors.Blue; paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = 20; // 画圆 surface.Canvas.DrawCircle(centerX, centerY, radius, paint); }     } public void Draw(SKSurface surface, SKRect bounds) { surface.Canvas.Clear();         Draw_Circle(surface, bounds);//画圆轮廓     } } 首先定义两个类,一个是画板类,他必须有最基本的Draw函数用来给Sharp实现接口。 其构造函数传入我们的Rocker类,这个类我们在下面定义。 public partial class Rocker : SKCanvasView {         private readonly DrawAble drawable; public Rocker() {             this.EnableTouchEvents = true;// this.drawable = new ChargingRingDrawable(this);         } protected override void OnPaintSurface(SKPaintSurfaceEventArgs e) { this.drawable.Draw(e.Surface, e.Info.Rect); this.InvalidateSurface(); } protected override void OnTouch(SKTouchEventArgs e) {             base.OnTouch(e);         } } } 接着定义一个类,命名为Rocker,这个类抽象自SKCanvasView(SkiaSharp的控件) 定义一个画板,构造的时候传入自身。 我们要保留两个处理函数,一个是OnPaintSurface,我们的控件刷新就会调用这个函数,还有一个是OnTouch函数,这个函数用来处理我们的触摸事件。private void Draw_Circle(SKSurface surface, SKRect bounds) {     float centerX = bounds.MidX;//获得画板中心 float centerY = bounds.MidY;     Midx = centerX;//用一个参数保存画板中心 Midy = centerY; // 计算圆的半径(使用ChargingRingDrawable类中的rad属性) float radius = CirCleRad; // 使用SKPaint对象定义圆的样式(颜色、线条宽度等) using (SKPaint paint = new SKPaint()) { paint.Color = SKColors.Blue; paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = 20; // 画圆 surface.Canvas.DrawCircle(centerX, centerY, radius, paint); } } 在DrawAble类中有这样子一个函数,其作用是画一个基本的圆,我设置的大小是400像素。private void Draw_InsertCircle(SKCanvas canvas, SKPoint touchLocation, float radius) { // 控件的中心点 float centerX = Midx; float centerY = Midy; // 计算手的位置与圆的交点 SKPoint intersectionPoint = CalculateIntersectionPoint(centerX, centerY, 300, touchLocation); // 使用SKPaint对象定义圆的样式(颜色、线条宽度等) using (SKPaint paint = new SKPaint()) { paint.Color = SKColors.Red; paint.Style = SKPaintStyle.Fill; // 在交点位置绘制圆 canvas.DrawCircle(intersectionPoint.X, intersectionPoint.Y, radius, paint); LocationPoint = intersectionPoint; } } private SKPoint CalculateIntersectionPoint(float centerX, float centerY, float radius, SKPoint touchLocation) { // 计算手的位置与圆的交点 float dx = touchLocation.X - centerX; float dy = touchLocation.Y - centerY; float distance = (float)Math.Sqrt(dx * dx + dy * dy); // 如果距离超出阈值,将交点移动到圆上最近的点 if (distance > radius) { float scale = radius / distance; float intersectionX = centerX + dx * scale; float intersectionY = centerY + dy * scale; return new SKPoint(intersectionX, intersectionY); } // 如果距离未超出阈值,则返回手的位置作为交点 return touchLocation; } 接着画内部的摇杆内容,我们计算这个圆和控件中心的位置,设置一个阈值,保证我们画的圆在这个阈值之内,如果超过了阈值,就计算手的位置和圆的交点,再进行画圆。 实现这样子的效果。 接着,我们补全Rocker中触摸事件protected override void OnTouch(SKTouchEventArgs e) { base.OnTouch(e); switch (e.ActionType) { case SKTouchAction.Pressed: // 处理按下事件 break; case SKTouchAction.Moved: // 处理移动事件 SKPoint touchLocation = e.Location; drawable.InsertCirclePoint = touchLocation; OnPositionChanged(new SKPoint(drawable.LocationPoint.X-drawable.Midx,drawable.LocationPoint.Y-drawable.Midy)); break; case SKTouchAction.Released: SKPoint InsertCirclePoint = new SKPoint(drawable.Midx,drawable.Midy); drawable.InsertCirclePoint = InsertCirclePoint; // 使得画布无效,触发重绘 InvalidateSurface(); OnPositionChanged(new SKPoint(0,0)); break; case SKTouchAction.Cancelled: // 处理取消事件 break; } // 标记事件已处理 e.Handled = true; } 当移动时,将位置传给DrawAble中,DrawAble会根据手的位置绘制摇杆位置。 并且在放下的时候重新归位。 同时我们定义一个事件,向MainPage中传入位置信息。private void Rocker_PositionChanged(object sender, SKPoint newPosition) {    Label.Text = $"Position: ({newPosition.X}, {newPosition.Y})"; } MainPage中打印我们的位置信息。
.NET MAUI的Android WiFi图传开发(6)——利用SkiaSharp制作一个摇杆
嘉立创PCB
B站demo演示视频:我把传感器塞进网球避震器,测了一下发球速度【项目背景】网球发球训练缺乏即时量化反馈工具。现有方案(Zepp、Babolat Play等)体积大、数据维度有限,无法捕捉发力结构细节。做了一个避震器形态的传感器模块,目标是在不显著改变球拍挥重的前提下,采集发球过程中的关键力学参数。【迭代过程】V1(已废弃):- 直接用蓝牙模组内置MCU做开发,没有独立单片机- 想法是单IMU做完整动作轨迹重建- 实测结果:误差累计太大,加速度二次积分漂移无法在这个成本和体积下解决- 教训:没搞过固件就上蓝牙模组MCU开发,调试手段有限,效率极低V2(当前版本):- 砍掉了"全动作记录"需求,聚焦发球训练——单次重复动作,每次击球间可归零,回避积分漂移问题- 加了独立STM32单片机,开发调试效率大幅提升- 换了高量程陀螺仪——发球动作核心是旋转发力(内旋),陀螺仪数据能覆盖主要需求,不再依赖加速度积分【当前方案概述】MCU:STM32C011F6P6IMU:LSM6DSVTR蓝牙模组:PB-03f供电:软包锂电核心模块重量:5.2g(不含外壳,未做工程优化)算法输出指标:- 拍头速度(发球瞬间)- 掉拍头幅度- 发力速度- 手臂内旋发力占比【当前进展】V2硬件完成并验证- 算法和数据链路跑通- 与手机App的BLE通信稳定- 已完成多次球场实测验证,四项指标实时输出【下阶段目标】做工程样机,小型化、外壳优化、电池选型及充电设计。发工程样机给网球爱好者、教练、运动员测试,吸收反馈迭代产品功能。【期望交流】希望能与做过类似消费电子/穿戴设备的,有工程化经验的朋友交流。我的邮箱:nospoon@qq.com小红书(记录了开发的部分过程):there is no spoon#DIY设计#
DIY网球发球训练数据采集模块,希望能与感兴趣的朋友交流
开源硬件平台
前言如果你点的椰果奶茶被做成了珍珠奶茶,虽然也能喝,但就是完全不是你想要的,至少对于我这种有点强迫症的人。那么 JavaScript 就是这样一个 “随性” 的奶茶店老板,而 TypeScript 就是那个拿着订单反复跟你确认 “少糖少冰” 的靠谱店员,从根源上避免了 “错单” 的尴尬。用一句话来说其实就是:TypeScript 是更严谨的 JavaScript。一、有了 JavaScript 为什么还要有 TypeScript ?写 JavaScript 就像开盲盒,你永远不知道下一个变量里装的是 数字、字符串还是 薛定谔的 undefined。我统称它们为 盲盒变量。比如这段代码:let n = 1, m = 0; n = 'hello'; // 数字秒变字符串,JS 主打一个“灵活” function add(a, b) { if (typeof a === 'number' && typeof b === 'number') { return a + b; } } // 传入字符串,函数直接返回 undefined,Bug 这不就来了 console.log(add(1, '2')); 你以为你在写 “动态灵活” 的代码,其实是在给未来的自己 埋雷。比如上面这段代码,可能你知道等会要传 2个number类型,但是如果别人直接拿来Ctrl + cv 用你封装的函数,传了一个 string类型 那就坏了。直到 TypeScript 出现,让变量从 “盲盒” 变成了 “明码标价的商品”。二、弱类型:自由过了火就是混乱在上面代码中有这样一个情况:let n = 1; n = 'hello'; // 在 JavaScript里面不报错 如果你是 C++、Java或者Go的工程师,你肯定会觉得这人怕不是敲代码敲疯了吧。在C++、Java或者Golang里面这代码直接就报错了。这就是因为 JavaScript 是典型的弱类型语言,变量不需要提前声明类型,随时可以 “变身”。打印结果为 hello:你可以让数字 a 一秒变成字符串,编辑器连个警告都没有。这种 “自由” 在小项目里或许能跑,但项目一复杂,就会出现 add(1, '2') 这种隐蔽 Bug,排查起来堪比大海捞针。三、强类型:给变量上 “户口”TypeScript 作为 JavaScript 的超集,核心就是给变量加上了类型声明。首先要用 TypeScript,我们需要去下载它:npm install -g typescript # 全局安装 TypeScript tsc -v # 查看 TypeScript的版本 tsc project.ts # project 是你的文件名,编译 TypeScript文件 当编译完你会发现编译器给你编译出了一份对等的JavaScript文件:这个时候你就可以用Node.js去跑这份文件,因为 TypeScript 本身不能直接运行,需要先编译成 JavaScript 再运行。不过现在有一些工具可以简化这个过程,比如 ts-node、deno 等。我这里简要介绍下 ts-node的使用:ls package.json # 首先检查项目是否有 package.json 文件 npm init -y # 如果没有,初始化一个 npm install -g ts-node # 然后安装 ts-node npm install --save-dev ts-node # 或本地安装 # 运行 TypeScript文件 ts-node 2.ts # 全局安装时 npx ts-node 2.ts # 本地安装时 一般 TypeScript 都是在 React项目 等环境下运行,所以直接运行一个文件的比较少见,这里我们主要看 TypeScript 语法的使用和基础知识。同样的代码,在 TypeScript 里面就会报错:let a: number = 1; a = 'hello'; // 编辑器直接标红:不能将类型 “string” 分配给类型 “number” console.log(a); 细心的你很快就发现了猫腻:TypeScript 相较于 JavaScript 不同的地方就在于 TypeScript 的写法中明确标注了变量是什么类型。就比如这里 a 被明确声明为 number 类型,如果你想把它改成字符串,TypeScript 会立刻报错,把问题扼杀在编码阶段。这样就使得文件更加严谨。<<<顺便说句,技术大厂,前后端-测试机会,一线双一线城市坑位充足,感兴趣可以看看这个~四、TypeScript 数据类型全家桶在之前我写过几篇 JavaScript数据类型 的文章,那我们现在来看看 TypeScript 类型全家桶,他们并不完全一样,但还是有很高的相似度。比如这段代码:let isDone: boolean = false; // boolean类型 let count: number = 123; // number类型 let str: string = 'Trae'; // string类型 const symbol: symbol = Symbol(); // symbol类型 let obj: object = { [symbol]: 'Trae' // object类型(对象) }; let list: number[] = [1, 2, 3]; // array类型(数组) enum Color { Red, Green, // 类似于结构体 Blue } let color: Color = Color.Red; let notSure: any = 10; // any类型 notSure = '123'; // any 类型可以随便变,是 TypeScript 里的 “漏网之鱼” let value: unknown = 10; // unknown类型 value = '123'; let abc: string = 'hello'; // unknown 类型不能直接赋值给其他类型,比 any 更安全 // abc = value; // 报错 abc = notSure; // 不报错 let tuple: [number, string] = [10, 'hello']; // 元组:固定长度和类型的数组 function user1(): number { return 123; } function user2(): Function { return function fn(): number { return 123; } } // 报错 // function user2(): string { // return 123; // } function user3(): void {} // void 表示没有返回值 let u: undefined = undefined; // undefined类型 let n: null = null; // null类型 基本上都与 JavaScript 相似,可以去看我之前写的 JavaScript数据类型。从基础的 boolean、number、string,到复杂的 enum、tuple、unknown,TypeScript 让每个变量都有了明确的 “身份”。这里有一个注意的点就是 unknown 类型 和 any类型。unknown 类型不能直接赋值给其他类型,而 any 类型可以随便变,所以下次报错的时候看看,是不是这个原因。五、对象与类型:不是所有空对象都一样TypeScript 对对象的类型约束更严格:const obj: object = {}; const obj2: Object = {}; const obj3: {} = {}; // 错误 // obj.a = 1; // 编译错误 // obj3.a = 1; // 编译错误 // 正确(类型断言) (obj2 as any).a = 1; console.log(obj2); // 输出: { a: 1 } const hello = 'hello'; const a: 'hello' = 'hello'; object、Object 和 {} 看似相似,实际约束力度不同;字面量类型更是把变量锁死在特定值上,杜绝了 “意外变身”。六、类型守卫🛡️:给你的代码装上 “火眼金睛”TypeScript 的类型守卫,就像给你的代码配上了一个智能安检员,能在运行时精准识别变量类型。// 类型守卫 interface Person { name: string; age: number; sex?: unknown; // 可选属性,不是每个人都需要填写 } const person: Person = { name: 'henry', age: 18, sex: '男' // 可选属性,写不写都不会报错 }; // 举个类型守卫的例子:判断一个值是不是 Person 类型 function isPerson(value: unknown): value is Person { return ( typeof value === 'object' && value !== null && 'name' in value && 'age' in value ); } function printUserInfo(value: unknown) { if (isPerson(value)) { // 进入这个分支后,TypeScript 就知道 value 是 Person 类型了 console.log(`姓名:${value.name},年龄:${value.age}`); if (value.sex) { console.log(`性别:${value.sex}`); } } else { console.log('这不是一个合法的 Person 对象'); } } printUserInfo(person); // 输出:姓名:henry,年龄:18 printUserInfo({ name: 'lucy' }); // 输出:这不是一个合法的 Person 对象 七、类型转换与组合:灵活不代表放纵如果遇到类型不确定的场景,TypeScript 提供了类型断言来 “手动担保”:let someValue: any = '123'; let strLength = (someValue as string).length; // 写法一 let strLength2 = (someValue).length; // 写法二 还可以用 type 定义联合类型和交叉类型:type Person = string | number | boolean; const a: Person = 'hello'; const b: Person = 123; const c: Person = true; type PartialX = {x: number} type Point = PartialX & {y: number} // 交叉类型:合并多个类型 const p: Point = { x: 10, y: 20 } 八、泛型:写一次,适配所有类型泛型是 TypeScript 的 “秘密武器”,让函数和组件更通用。function identity(value: T) { return value; } identity (100); // 指定 T 为 number 类型 function identity2 (value: T, msg: U): T { console.log(msg); return value; } identity2 (100, 'hello'); // 多泛型参数 let arr: Array = [1, 2, 3]; let arr2: Array = [1, 2, 3, 'hello']; 泛型让 identity 函数既能处理数字,也能处理字符串,不用写多个重复函数,代码复用性直接拉满。结语从 JavaScript 的 “盲盒变量” 到 TypeScript 的 “精准类型”,本质是从 “靠运气写代码” 到 “靠逻辑写代码” 的转变。写的代码都不严谨,那还写什么代码呢😄。TypeScript 不是给你套枷锁,而是给你装护栏 —— 它不会限制你的创造力,只会帮你提前避开那些低级 Bug。所以,不要害怕红色的报错,而是试着去解决它。——转载自:风止何安啊
为什么要有 TypeScript?让 JS 告别 “薛定谔的 Bug”
开源硬件平台
#技术干货# 【摘要】一款基于表格的研发项目管理工具,覆盖概念、系统设计、开发、测试、验收全流程,帮助研发团队规范过程管理、沉淀项目数据、实现需求追溯。适用于汽车电子 ECU 及其他嵌入式系统研发。 在研发项目管理中,你是否遇到过这些问题: 需求、设计、测试数据分散在多个 Excel 文件中,版本难以统一管理 项目成员各自维护自己的表格,信息不同步 需要追溯需求时,要在多个文件之间来回查找关联 项目结项后,经验教训没有系统沉淀,下一个项目继续踩坑 这些问题的核心在于:缺乏一个统一的数据管理平台。 零绪研发项目管理工具,正是为了解决这些问题而设计。 ## 零绪是什么? 零绪是一款基于表格的研发项目管理工具。 它提供标准化的表格模板,覆盖研发项目的完整生命周期:概念阶段、系统设计阶段、开发阶段、测试阶段、验收阶段。 每个阶段包含若干张专业设计的表格,用户通过填写表格完成项目数据的录入和管理。所有数据集中存储,团队成员访问同一份数据,避免多版本混乱。 ### 核心特点 类 Excel 操作体验   如果你熟悉 Excel,就能快速上手零绪。工具采用表格形式呈现,支持单元格编辑、数据筛选等常见操作。 标准化字段设计   每张表格的字段基于 ASPICE、ISO 26262 等行业标准设计,确保数据规范性和完整性。 集中化数据存储   所有项目数据存储在统一平台,支持跨阶段查询和统计,方便团队协作和知识沉淀。 可追溯的数据结构   通过 ID 引用建立需求、设计、测试之间的关联关系,支持追溯查询和覆盖率统计。 ## 零绪能管理什么? 零绪覆盖研发项目的五个核心阶段,每个阶段提供相应的表格模板: 概念阶段——收集客户 SOR 需求,进行可行性评估,定义系统需求,完成 HARA 分析和功能安全目标设定。 系统设计阶段——进行系统架构设计,分解硬件和软件需求,完成关键元器件选型,输出 DFMEA/PFMEA 分析,管理工作进度。 开发阶段——管理软件和硬件的架构设计、详细设计、单元测试用例及执行记录,支持线束定义。 测试阶段——管理集成测试、系统测试(功能/性能/环境/诊断/工况)、功能安全确认测试,覆盖测试计划、用例设计、执行记录全流程。 验收阶段——规划验收测试,记录测试结果和客户意见,生成交付物清单和验收报告,完成项目结项和经验总结。 此外,每个阶段还包含输入评审、输出评审、问题记录、变更管理四张公共表格,用于过程管理和质量控制。 项目信息查询模块提供跨阶段的数据总览,包括需求跟踪矩阵、评审汇总、问题分布统计、变更趋势分析等。 ##零绪如何使用?### 基本操作流程 创建项目:新建项目,填写项目基本信息 选择阶段:根据项目进展进入对应阶段 填写表格:按照字段定义逐项录入数据 建立关联:在关联字段中填写对应 ID,建立追溯关系 评审确认:组织评审并记录结论 问题跟踪:发现问题及时登记并跟踪解决 变更管理:变更时填写变更表,评估影响并实施 ### 数据录入方式 零绪中的数据需要手动录入,这是为了保证数据的准确性和责任明确: 需求描述由系统工程师根据客户 SOR 手工转化 设计内容由开发工程师根据设计方案填写 测试结果由测试工程师根据实际测试情况记录 评审结论由评审参与人员讨论后填写 工具的价值在于提供标准化模板、统一字段定义、集中存储管理、建立ID 引用,让数据录入更规范、查询更便捷、追溯更清晰。 ### 统计与查询 零绪支持多种数据统计和查询: 需求覆盖率统计 问题状态分布 变更趋势分析 进度可视化(甘特图) 追溯链查询 ## 谁适合使用零绪? 适用行业 汽车行业 ECU 研发(发动机控制器、变速箱控制器、车身控制器、网关、BMS、VCU、MCU 等) 其他嵌入式系统研发(工业控制、医疗设备、航空航天、轨道交通等) 团队规模 小型团队(5-10 人):快速建立规范化流程 中型团队(10-30 人):提升协同效率 大型团队(30 人以上):统一工作语言和模板 适用角色 项目经理、系统工程师、硬件工程师、软件工程师、测试工程师、质量工程师。 ## 为什么选择零绪? 专业设计——表格字段基于行业标准设计,符合车规级研发要求。 易于上手——类 Excel 的操作方式,无需复杂培训即可使用。 灵活适配——可根据团队实际需求调整,不强制绑定特定方法论。 持续沉淀——项目数据集中存储,形成组织过程资产。 合规支持——完整的评审记录、追溯关系、问题跟踪,为审核提供证据支持。 更多内容
01_零绪研发项目管理工具
硬创社
最近圈子炸了两次。第一次是Claude Code源码泄露事件。有人把Anthropic的核心代码扔到了GitHub上,虽然官方火速处理,但技术圈已经炸开了锅——大家突然发现,原来AI编程已经进化到了这个程度。第二次更刺激:豆包9块9。对,你没看错,9块9就能用上一个完整的AI编程工具。这价格,连一杯奶茶都买不到,但它已经开始抢程序员的饭碗了。然后就出现了两种声音:1.AI要把程序员干掉了2.AI最终不靠谱,锅还是要人来背的我专门花了三个月研究这件事,结论是——AI确实在抢饭碗,但抢的是另一群程序员的。什么意思?你会发现,现在最慌的不是那些真正写核心逻辑、做架构设计的人,而是那些每天写CRUD、做简单前端页面的"代码搬运工"。AI工具对这部分工作的替代效率,高得可怕。但反过来,那些真正能解决问题、能设计系统、能理解业务的人,AI不是来抢你饭碗的,它是来给你装上火箭助推器的。说白了,AI淘汰的不是程序员,而是低效的编程方式。你还在一个字母一个字母敲代码,别人已经在用AI生成框架、自动写测试、一键优化性能了。差距不是一点半点。(((顺便吆喝一句,技术大厂,前后端-测试机会,全国一线及双一线城市均有坑位坑位,待遇和稳定性还不错,感兴趣可以试试~所以问题来了:你和AI之间,是竞争关系,还是协作关系?这个问题的答案,决定了你是在2026年被淘汰,还是在2026年起飞。#嘉立创PCB#
AI 9块9抢程序员饭碗?我专门研究了三个月,结论可能和你想的不一样
开源硬件平台
这几天折磨死我了,因为这玩意我也是自己在琢磨,然后资料也没有多少,简直就是自己慢慢摸索。 本期介绍如何利用TCP接收图片信息并显示。 首先我们先新建一个类,将我们想要的内容全部写到这个类上(类的代码会放在最后面) cpListener用来创建监听,tcpClient用以发送。public AndroidWifiService() { } ~AndroidWifiService() { tcpClient?.Close(); tcpClient = null; tcpListener = null; MessageReceived = null; } public AndroidWifiService(IPAddress address,int Port) { StartListening(address, Port); } public AndroidWifiService(string address, int Port) { StartListening(IPAddress.Parse(address), Port); } 提供三种类型的构造函数和析构函数。protected virtual void OnMessageReceived(byte[] buffer) { // 触发事件 MessageReceived?.Invoke(this, buffer); } 设置一个事件,用以传递监听到的图片信息。public async void StartListening(IPAddress IP,int Port) { tcpListener = new TcpListener(IP, Port); tcpListener.Start(); while (true) { tcpClient = await tcpListener.AcceptTcpClientAsync(); Task.Run(() => HandleClient(tcpClient)); } } private void HandleClient(TcpClient client) { try { NetworkStream stream = client.GetStream(); byte[] buffer = new byte[1024]; // 使用固定大小的缓冲区 using (MemoryStream ms = new MemoryStream()) { int bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, bytesRead); } if (ms.Length > 0) { // 在主线程上更新 UI MainThread.BeginInvokeOnMainThread(() => { OnMessageReceived(ms.ToArray()); }); } } } catch (Exception ex) { Console.WriteLine($"Exception in HandleClient: {ex.Message}"); } } 创建一个监听函数,注意的是,我们是接受完一次完整的流再传递信息,而不是边接收边传递。private void OnMessageReceived(object sender, byte[] message) { MainThread.BeginInvokeOnMainThread(async () => { try { using (MemoryStream ms = new MemoryStream(message)) { SKBitmap bitmap = SKBitmap.Decode(ms); AndroidSaveClass save = new AndroidSaveClass(); string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MAUI_Picture_Save"); if (!save.DoesFolderExist(folderPath)) { Directory.CreateDirectory(folderPath); } // 生成文件路径 string uniqueFileName = $"sample_{DateTime.Now:yyyyMMddHHmmssfff}.png"; string filePath = Path.Combine(folderPath, uniqueFileName); // 将 SKBitmap 编码并保存为 PNG 文件 using (var image = SKImage.FromBitmap(bitmap)) using (var data = image.Encode(SKEncodedImageFormat.Png, 100)) using (var stream = File.OpenWrite(filePath)) { data.SaveTo(stream); } Picture.Source = filePath; } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }); } 再MainPage.xmal.cs中,我们新建一个这个类的变量,监听我们的窗口。并且设置回调函数用来处理事件。 事件中,我们将图片的字节数组转为图片,之后保存到程序的文件目录中,并且使用时间戳防止图片重复。 之后用Image控件来绑定图片源显示图片。
.NET MAUI的Android WiFi图传开发(3)——Android设备接收TCP信息并显示
嘉立创PCB
01|什么是 Claude Code一句话:👉 Claude Code = 终端里的 AI 执行助手你可以用一句人话,让它帮你:写代码改文件整理资料分析数据自动完成任务📌 和普通 AI 最大区别:ChatGPT:告诉你怎么做 Claude Code:直接帮你做02|快速安装核心只有一句话:👉 先装 Node → 再装 Claude Code安装 Node.jsnodejs.org选择 LTS 版本验证:node -v npm -v安装 Claude Code npm install -g [@anthropic](https://x.com/@anthropic) -ai/claude-code 验证 claude --version 不废话,技术大厂捞人:前端/后端/测试,全国多地可选,待遇和稳定度都在线。→试试试试不吃亏 03|连接国内大模型一、编辑或新增 settings.json 文件MacOS 在.claude文件夹下创建settings.json, ~/.claude/settings.jsonWindows 为用户目录/.claude/settings.json #新增或修改里面的env字段# 注意替换里面的 `your_deepseek_key` 为您上一步获取到的 API Key { "env": { "ANTHROPIC_AUTH_TOKEN": "your_deepseek_key", "ANTHROPIC_BASE_URL":"https://api.deepseek.com/anthropic", "API_TIMEOUT_MS": "3000000", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1, "ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.5-air", "ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-4.7", "ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-4.7" } } 二、再编辑或新增 .claude.json 文件用去跳过MacOS & Linux 为 ~/.claude.jsonWindows 为用户目录/.claude.json #再编辑或新增`.claude.json`文件# 新增 `hasCompletedOnboarding` 参数 { "hasCompletedOnboarding": true } 三、进入ClaudeCode确认首先确认系统默认的模型名称然后输入/status命令查看baseUrl和模型名称,输入命令 /status ——转载自:想不到一个好的ID
Claude Code 初学者必看指南
开源硬件平台
各位工程师、采购和电子爱好者,你是否遇到过这样的问题——选型时拿不准器件的稳定性?量产之后才发现可靠性隐患?其实,民品也一样需要“高可靠”的底气。 这一次,我们邀请了一位“硬核”原厂——火炬电子,用航天同源的可靠性,降维解决民品顽疾,为电子工程师与爱好者提供专业、可靠的选型方案,再也不用为“莫名炸机”和批次不稳头疼! 4月15日 ,立创商城 × 火炬电子开启专场技术直播,深度拆解高可靠电容与功率器件,从航天级标准到工业民用落地,一站式解决选型、可靠性、失效分析等核心难题!现在扫码预约直播后,保存预约截图,点击链接参与互动还有机会得20采购晶!(采购晶可用于抵扣一定比例的现货商品金额,以及兑换采购晶专区的礼品) 直播全程福利狂撒,2000元现金红包、小炬玩偶礼盒、运动毛巾、冷感速干巾、样品册等实物礼品开送!  直播时间4月15日(周三)19:30 直播主题火炬电子电容器功率器件产品推介 直播嘉宾刘芳演 高级应用工程师黄倩萍 高级市场工程师 关于火炬电子 火炬电子始创于1989年,是国家高新技术企业,产品覆盖MLCC、钽电容、超级电容器、功率器件等品类,以高稳定性、高可靠性和长期服役能力著称,广泛应用于航空、航天、船舶、电力、轨道交通、新能源等重点领域与重大工程,为关键核心系统提供安全、稳定的基础支撑。 直播核心亮点 航天级电容解析:MLCC、钽电容、超级电容的高可靠设计与选型标准;功率器件硬核科普:MOS/SiC MOS等高可靠方案与工业/新能源应用;可靠性实战指南:电容失效、压电效应、金脆效应等问题一站式解决; 在线实时答疑:火炬电子嘉宾解答高可靠元器件选型、测试、应用疑问,若你的问题被嘉宾挑中回答,还可以获得立创送出的采购晶! 无论您在做电源、工控、汽车还是消费类产品,这场直播将帮您选对器件、提升产品可靠性。 立即预约,4月15日19:30,立创商城视频号见!
原厂揭秘:火炬电子高可靠产品推介,预约锁定专属福利
立创商城
社区数据
今日帖子
-
今日互动量
-
在线人数
-
帖子总量
-
用户总量
-
功能讨论
()
主题
打赏记录
服务时间:周一至周六 9::00-18:00 · 联系地址:中国·深圳(福田区商报路奥林匹克大厦27楼) · 媒体沟通:pr@jlc.com · 集团介绍
移动社区