• [交流分享] 聊聊万物互联-Wi-Fi6
    WiFi的历史从802.11的FHFS,DSSS到802.11b的DSSS,到802.11a的OFDM,802.11g的ERP(将OFDM从5G迁移到了2.4G),到802.11n的更宽频带(40MHz)的OFDM技术,到802.11ac的进一步拓宽(80, 80+80,160MHz)的OFDM技术,到802.11ax的更窄的子载波(78.125kHz)的OFDM技术,到讨论中的802.11be的320MHz的OFDM技术。OFDM技术从802.11a,大概2001年的时候,到现在,已经持续演进了20年了,它的抗多径效应,适合无线空间的复杂环境。因为802.11ax(Wi-FI 6)希望覆盖更广的空间,所以把载波宽度进一步变小了。每一代的发展,频带基本是越来越宽,似乎是可以无限的把频宽扩展下去。但是这应该是存在问题的,多样化的需求下,大频宽是可能浪费频段的。毕竟有些地方只需要小的频宽就好了。802.11ax还定义了一个仅支持20MHz的模式,也是瞄准了万物互联的趋势下,小数据,低能耗的搭配。但是802.11be(TB Wi-Fi 7)又把带宽变得更大了,每一代总是希望能更快的。但是单纯更快有什么意思呢。OFDM不止可以分频带,因为网络的特性,还可以分用户,这是Wi-Fi现在越来越看重的,希望越来越多的用户都是使用这个网络,而且还要能用。从802.11ac(2013)开始的Wi-Fi5已经引入了多用户的观念,对应的技术是MU-MIMO。它是这么样的,不同的用户用的是不同的天线。到了802.1ax(Wi-Fi6),支持上行的MU-MIMO,而且还把一个频段同时分配给了多个用户(OFDMA),每个用户最少可以只用2MHz的带宽。一下还把上行和下行都给加进去了。不止如此,还加入了BSS Coloring技术,弱化Exposed Node的问题,提升密集网络覆盖下的并行性。Wi-Fi6有这么多优势,其实它的主要着笔点在于密集用户,密集网络。想想现在Wi-Fi6的设备已经都出来1两年了,但是也并没有多改变生态。其实现在大家也觉得够用了,就像我自己,这种Wi-Fi6的理念对人这个用户来讲真的是有点超前了,哪里去找如此密集的人流和网络?办公场所,体育场?这些场合毕竟是少数。自动化生产车间也许是比较合适的,不过不是人流,而是物流。Wi-Fi7似乎要在这个道路上越走越远,越来越远…
  • [问题求助] 【XXX产品】【XXX功能】一句话描述问题
    【功能模块】【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [交流分享] 回头看var、let和const
    varvar声明的作用域是函数作用域,如果一个变量在全局用var进行了声明,那么这个变量就会作为window对象的一个属性,可以通过window.XXX来访问。如果在函数体内部声明了这个变量,则这个变量会在函数执行完后被销毁。var声明会被提升,这里要注意,被提升的是声明,而不是赋值var a = 100;这一行代码其实可以被分解成为两个部分:var a;a = 100;被提升的是var a;这一句,赋值这一句只有在代码执行到时才会执行,看个例子:function foo(){    console.log(age);    var age = 21;}foo()//输出的结果是undefined这段代码等同于:function foo(){    var age;//变量age被提升了    console.log(age);    age = 21;}foo()//输出的结果是undefined执行到console.log(age)的时候age只被声明了,但是还没被赋值,所以输出来了undefined。同时var支持多次声明同一个变量,不会报错,后面的赋值会替代前面的赋值。var a;var a = 10;var a = 20;console.log(a) //20而且a这个变量的内存地址始终是相同的,这可能会发生一些奇怪的现象,我们留到后面说。letlet相对于前面的var有一个很大的区别就是,var是函数作用域,而let是块级作用域,什么是块呢?我的理解是块就是由一对{}包括起来的代码,不严谨地说函数作用域其实也算是一种块级作用域,因为函数体地代码也是由一对{}包裹起来的。换句话说let的作用域受限的地方会比var多,如何理解这句话呢,看代码:{    let a = 10;}console.log(a);//Uncaught ReferenceError: a is not definedif (true) {     let age = 26;     console.log(age); // 26} console.log(age);// ReferenceError: age 没有定义作为对比,var是这样的if (true) {     var age = 26;     console.log(age); // 26} console.log(age); // 26console.log(window.age) //26这就是一个块级作用域例子,在块里面声明的变量在块的外部是不能访问的,出了块就会被销毁。与var不同的还有let不允许在一个块里面重复声明 一个相同变量let a;let a;//会报错var a;let a;//会报错对声明冗余报错不会因混用 let 和 var 而受影响。这两个关键字声明的并不是不同类型的变量, 它们只是指出变量在相关作用域如何存在。前面说了var的变量声明是会被提升的,但是let就不会被提升,会出现暂时性死区function foo(){    console.log(age);    let age = 21;}foo()// ReferenceError:age 没有定义如果在浏览器的环境下,用let定义一个全局变量,这个全部变量在全局任何地方都是能被访问的,但是与var不同的是,let不会让这个变量window对象的一个属性。在for中使用let的好处:先看用var 的坏处:for (var i = 0; i < 5; ++i) {     // 循环逻辑}console.log(i); // 5由于for循环不是函数作用域,是块级作用域,所以var声明的变量在for循环结束后会“泄露”,这并不是什么好事,为了避免这种情况,可以用let。for (let i = 0; i < 5; ++i) {     // 循环逻辑}console.log(i); // ReferenceError: i 没有定义其实仔细的同学已经发现了,在for里面用var进行声明a,算是多次重复声明a,这些a的内存地址都是一样的,而在for里面用let进行声明,则会在5个块里面各自声明一个a,互不影响,这些a的内存地址都是不一样的,知道了这一点,我们再来看个有意思的for (var i = 0; i < 5; ++i) {     setTimeout(() => console.log(i), 0)}// 你可能以为会输出 0、1、2、3、4// 实际上会输出 5、5、5、5、5for (let i = 0; i < 5; ++i) {     setTimeout(() => console.log(i), 0)}// 会输出 0、1、2、3、4为什么会造成这种情况?这其实需要知道一点有关于宏任务、微任务的相关知识,再结合本次讲的内容,就可以测底搞明白了。不懂的可以去翻翻我之前的博客,看不懂的可以在线问我,在能力范围内必定解答。首先setTimeOut的回调函数是一个宏任务,会在当前的宏任务,以及微任务执行完后才会执行,这里没有微任务,所以不用考虑微任务是什么。这里的宏任务就是这个for循环,这个for循环执行完后(往宏任务队列push了5个宏任务)才会按顺序执行这些setTimeOut的回调函数“() => console.log(i)”,当for里用var的时候,i在循环结束的时候等于5,而且i不会被销毁,后面开始执行5个回调函数的时候,输出来的自然是5个5,而在for里用let的时候,每个回调函数会引用不同的i,这些i在前面也说到了,是有不同的内存地址的,所以称他们为“不同的i”,输出来的就会是0,1,2,3,4了。这里有人会问了:let声明的变量除了块级作用域不就被销毁了么,这里的是for结束后再开始执行回调的,以及出了块,怎么还可以访问i的值?这要细说的话就要说到闭包和作用域链了,下次会单独写一篇来说这个。来看看红宝书的话而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。 每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循 环执行过程中每个迭代变量的值。const这里把const放到最后,因为const和let很像,唯一的不同就是let声明的变量可以修改值,而const不可以,所以const的声明和赋值必须同时完成const a = 10;//只能这样赋值当然如果const定义的变量赋值为一个对象,修改这个对象内部的属性和方法是允许的。const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量引用的是一个对象, 那么修改这个对象内部的属性并不违反 const 的限制。
  • [问题求助] 为啥单片机向电脑发送的字符串是乱码
    两台单片机分别向电脑发送含中文字符串能正常显示,电脑向单片机发送含中文字符串再返回回来也正常显示,但是一台单片机向另一台单片机发送含中文字符串再由接收的单片机向电脑发送,结果却只有中文显示乱码;如下图绿色的是发送的字符串,黑色的是接收到的字符串,有什么解决办法吗? 572221572222
  • [其他] TensorFlow-py27通用模板
    简介搭载TensorFlow1.8 AI引擎,运行环境为“python2.7”,内置输入输出模式为未定义模式,请根据模型功能或业务场景重新选择合适的输入输出模式。使用该模板导入模型时请选择到包含模型文件的model目录。模板输入存储在OBS上的TensorFlow模型包,确保您使用的OBS目录与ModelArts在同一区域。对应的输入输出模式未定义模式,可覆盖,即创建模型时支持选择其他输入输出模式。模型包规范模型包必须存储在OBS中,且必须以“model”命名。“model”文件夹下面放置模型文件、模型推理代码。模型推理代码文件不是必选文件,如果有,其文件名必须为“customize_service.py”,“model”文件夹下有且只能有1个推理代码文件使用模板导入的模型包结构如下所示:model/ │ ├── 模型文件 //必选,不同的框架,其模型文件格式不同,详细可参考模型包示例。 ├── 自定义Python包 //可选,用户自有的Python包,在模型推理代码中可以直接引用。 ├── customize_service.py //可选,模型推理代码,文件名称必须为“customize_service.py”,否则不视为推理代码。模型包示例TensorFlow模型包结构发布该模型时只需要指定到“model”目录。OBS桶/目录名 |── model 必选,文件夹名称必须为“model”,用于放置模型相关文件。 ├── <<自定义python包>> 可选,用户自有的Python包,在模型推理代码中可以直接引用。 ├── saved_model.pb 必选,protocol buffer格式文件,包含该模型的图描述。 ├── variables 对“*.pb”模型主文件而言必选。文件夹名称必须为“variables”,包含模型的权重偏差等信息。 ├── variables.index 必选 ├── variables.data-00000-of-00001 必选 ├──customize_service.py 可选,模型推理代码,文件名称必须为“customize_service.py”, 有且只有1个推理代码文件。“customize_service.py”依赖的“py”文件可以直接放“model”目录下。
  • [问题求助] 【STM32单片机】【连接云平台不给反馈】
    【功能模块】,我想问一下我发送AT+MIPLOPEN=0,86400只给我反馈了miplopen 0,1 只是开始连接到了bootstrap服务器,前面的都是正常的到这一步就卡住了,想请教一下各位是什么问题【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [技术干货] 【技术长文】物联网专业真的很坑吗?浅谈物联网的未来发展趋势和方向
    大家好,我是无际。最近几年,我基本都在从事物联网产品的开发,我做的主要是硬件端,也就是单片机开发。我见证了物联网这几年的发展,也享受了物联网真正给我们带来了便利,我也相信物联网是未来发展的趋势。这篇文章我将为大家剖析普通人如何切入物联网,耐心看完,一定能让你的认知刷新一个等级,从此不再是人云亦云的傀儡。我也是最近才知道原来有物联网工程这个专业,就去了解了一下,发现在某乎上大多数都是喷这个专业坑的。人啊,最怕就是人云亦云,有时你看到的不一定是真的,其实最好的办法就是看一下这个行业的从业者,他们混得怎么样,多找几个综合对比,比你看任何文章都要来得靠谱!我仔细看了一些回答者以及一些评论者,基本可以判断,这些人要么是在校学生,要么就是外行人。真正这个行业的资深人士都在研究怎么做产品,怎么融资,怎么闷身发财。一、电子展让我学到很多在2014年的时候,当时在一家公司做物联网产品线的项目经理兼研发,经常会参加一些展会,以便自己熟悉行业的人都在做什么产品。当时去上海参加了CES的电子展会,现在还保留着在外滩看夜景时拍的照片,真怀念当初的青春和羞涩。大家现在知道那些发展得还不错的平台和公司,其实在那个时候还是个小公司。也正是抓住了物联网这波红利,一飞冲天,特别是现在的物联网云平台。他们快速起飞的秘诀呢,就是不断路演,然后融资。其实当时的所谓物联网产品真的很鸡肋。拿当时wifi插座来说,就开关这么简单的功能,我要先花几分钟配置wifi让插座连上家里的wifi,连上以后打开app,等app连上服务器以后才能控制。有时出问题搞个10几分钟都开不了一个插座,还不如自己走过去手动打开关闭来得快,碰到这种情况你可能会崩溃想把它砸了。我记得当时做wifi插座的时候,不管是wifi模块厂家,还是云平台,都是求着一些传统硬件厂家去使用他们模块和接入他们平台的。当时传统硬件接入平台也不用license费用的,不像现在每接入一个硬件设备到他们平台都要3-10块钱不等。当时大家都在做实验,即便只是一个wifi插座,远程控制开关这么简单的功能,很多都做不稳定。我当时做得也非常痛苦,对这种产品又爱又恨,我们硬件端基本已经很成熟了,因为产品都是经过大批量验证,只不过在原来的基础上加上wifi模组给产品赋能实现远程控制而已。但是中间涉及的环节太多,坑也多,有碰到因为协议不成熟导致不稳定的,也有因为app有问题导致不稳定的。所以做物联网产品是整个体系,其中一个环节不给力,你的努力可能都会白费,这也是为什么很多所谓的远程控制产品都是鸡肋的原因。经历了这么多年的研发和产品验证,我基本上也熟悉了硬件端实现物联网整个通讯流程和协议,后面也和一家企业联合从零搭建了物联网云平台。随着后面对接的平台越来越多,发现各大平台的通讯协议,其实都是相互模仿改进的。二、为什么很多人觉得物联网专业很坑?说了这么多,如果你是物联网工程专业,你可能会觉得很懵,我说得这些怎么我都没接触过?难道我是读得假专业?你有这种问题实在太正常了,不是你学的假专业,而是学校学的太杂了。比如说C/C++、java、C#、单片机原理与应用、传感器原理与应用、ZigBee无线网络技术等等。所学这些很多完全是不同产业链,不同行业方向的知识,这样学,你根本不知道物联网专业出来是干嘛的,跟四不像似的。很多人学完出来甚至连自己找什么职位都不知道,找不到工作也是正常的,所以觉得这个专业坑。如果你单靠学校学出来找工作,未免太牵强了,物联网涉及的领域和行业太多了,要先定位好方向,然后针对性深造。想从事物联网行业,我认为嵌入式是一个不错的切入点。记得在2014年,也就是物联网开始火爆的时候,大量的人都涌去学java做app,当时需求量也确实很大。当时做产品经常要和app工程师联调,有时候一个功能怎么做都做不稳定,我都觉得他们技术很水,但是工资都比我们做单片机开发的要高几千块。那段时间让我非常郁闷,我和很多从业人员一样,一遍靠着这个行业吃饭,一遍骂着这个行业辣鸡,软硬件都要懂,工资还比做app的低这么多。不过最近两年我和一个做app的朋友对比,发现做app也没以前这么香了,反而是做嵌入式的一直处于上涨趋势,很多已经超过app。嵌入式也分很多方向的,主流的是就是单片机开发或者嵌入式linux开发。所以,如果你想从事物联网这个行业,一定把方向定得越细越好,比如说我只做单片机开发。然后用单片机技术去从事物联网的产品开发,这样你才能真正切入物联网这个行业。比如说无线通讯技术(315/433/868M、Lora、Zigbee、蓝牙、nb-iot、wifi等等).这些无线通讯技术怎么应用到我们产品上呢?比如说我们无际单片机编程带领学员做的智能防盗报警系统。传感器和主机之间采用433M实现星型拓扑的无线通讯,无线数据采用软件编码和解码的方式进行传输。主机再通过wifi模块与云平台连接,实现远程监控,这就是一套典型的物联网产品。通过这种项目切入物联网是最接地气的,只有当你做过这样的产品,你才会深刻理解自己学的东西到底有啥用。三、物联网未来发展趋势和方向从目前看的话,虽然这个行业已经发展了很多年,但是我认为依然算得上是蓝海行业。因为目前技术还没有完全成熟,很多东西,没有基础铺垫,即便你知道未来一定会这样去发展,你当下也实现不了。我举个例子,比如说美团、滴滴,包括很多线上的生意,如果线上支付没出来,这种些肯定也很难做起来,因为没有支付工具的基础铺垫。我经常说,我们未来的生活场景就是物联网技术的体现。很多人可能还不知道,物联网到底有啥用,能给我们带来什么便利。下面我还是通过大家肯定接触过的一个例子来讲解:共享单车。共享单车就是一个很典型的物联网应用,并且也确实解决了我们短途出行的效率,这个不可否认。大家想象一下,如果每个个体的出行效率提高了,那必定会提高整体的效率,其中能产生的潜在价值细思极恐。还有其他的智慧停车场之类的物联网应用就不说了,相信经常开车出行的朋友都试过自主扫码付费出停车场,真的是太方便了。所以,物联网目前的应用最大的价值在于提高效率的同时降低成本,只要能让人类更进步的技术我都认为是趋势。而现在物联网仍然处于蓝海阶段,还有很多技术瓶颈尚未解决,lora、nb-iot之类技术的出现都是为了解决物联网某个环节的痛点。等真正实现万物互联那一天,估计就没我们啥事了。当然,如果你能在红利前期布局好,不管是技术还是产品,沉淀几年,别人想超越你也是没那么容易的,这才是核心竞争力。————————————————版权声明:本文为CSDN博主「无际单片机编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_43982452/article/details/119324514
  • [技术干货] 硬件接口
    转自:https://cloud.google.com/architecture/iot-overview?hl=zh-cn 大多数硬件接口都是串行接口。 串行接口通常使用多条线来控制通过主数据线的二进制信息的流和计时。每种类型的硬件接口定义了外围设备和中央处理器之间通信的方法。 物联网硬件平台使用了许多通用接口。传感器和执行器模块可以支持一个或多个以下的接口: USB。通用串行总线通常用于各种即插即用设备。 GPIO。通用输入/输出引脚直接连接到处理器。顾名思义,这些引脚由制造商提供,以实现制造商未设计的自定义使用场景。GPIO 引脚可以设计为承载数字或模拟信号,而数字引脚只有两种状态,即 HIGH 或 LOW。 数字 GPIO 可以支持脉宽调制 (PWM)。 PWM 可让您迅速打开和关闭电源,而每个“on(开)”相位都是具有特定持续时间(或宽度)的脉冲。反映到设备中就是更低或更高的功率水平。例如,您可以使用 PWM 来改变 LED 的亮度;“on(开)”脉冲越宽,LED 就越亮。 模拟引脚可以连接板载模数转换 (ADC) 电路。ADC 电路可以定期对连续的模拟波形(如模拟音频信号)进行采样,并为每个样本提供一个相对于系统电压且介于 0 到 1 之间的数字值。 当您在代码中读取数字 I/O 引脚的值时,该值必须为 HIGH(高电平)或 LOW(低电平),其中任何给定时刻的模拟输入引脚可以是某个范围内的任何值。该范围取决于 ADC 的分辨率。例如,8 位 ADC 可以产生范围在 0 到 255 的数字值,而 10 位 ADC 可以产生更宽范围的值,从 0 到 1024。更多的值意味着更高的分辨率,因此以更可靠的数字表示任何给定的模拟信号。 ADC 采样率决定了 ADC 可以再现的频率范围。采样率越高,数字数据中的最大频率就越高。例如,在忽略典型过滤和其他处理的情况下,以 44100 Hz 采样的音频信号产生频率响应高达 22050 Hz 的数字音频文件。位精度决定了信号幅度的分辨率。 I2C。内部集成电路串行总线使用一种协议,可以在总线上为多个模块分配一个离散地址。I2C 可以读为“I two C”,“I I C”或“I squared C”。 SPI。串行外设接口总线设备采用主从架构,具有单主机和全双工通信的特点。SPI 指定了以下四个逻辑信号: SCLK:串行时钟,由主设备输出 MOSI:主输出从输入,由主设备输出 MISO:主输入从输出,由从设备输出 SS:从选择,是主机的低有效信号输出 UART。通用异步收/发器设备在处理器对数据操作的点处在串行和并行形式之间转换数据。当串行数据必须以并行方式布置在内存中时,需要使用 UART。 软件中的硬件抽象 操作系统会抽象出通用的计算资源,例如内存和文件 I/O。此外,操作系统还为不同的硬件接口提供非常低级别的支持。通常,这些抽象不易直接使用,并且操作系统通常不会为构建物联网解决方案时可能需要的各种传感器和执行器模块提供抽象。 您可以使用跨平台抽象硬件接口的库。这些库帮助您以更直接的方式使用设备(例如运动检测器)。使用库可以让您专注于收集模块为应用提供的信息,而不是直接使用硬件的低级详细信息。 一些库提供了在硬件接口之上以轻量级驱动程序的形式表示外围设备的抽象。这些库的示例包括 Johnny-Five JavaScript 框架、MRAA(支持多种语言)、EMBD Go 库、Arduino-wiring 和 Firmata。
  • [技术干货] 烧录软件对比分析
    OpenOCD(Open On-Chip Debugger)开源片上调试器,是一款开源软件,JLINK  J-Link是针对ARM设计的一个小型USB到JTAG转换盒。它通过USB连接到运行Windows的PC主机。J-Link无缝集成到IAR Embedded Workbench for ARM中,它完全兼容 PNP(即插即用ST-LINK  ST-LINK /V2指定的SWIM标准接口和JTAG / SWD标准接口,其主要功能有:  (1)编程功能:可烧写FLASH ROM、EEPROM、AFR等。  (2)仿真功能:支持全速运行、单步调试、断点调试等各种调试方法,可查看IO状态,变量数据等等。  (3)仿真性能:采用USB2.0接口进行仿真调试,单步调试,断点调试,反应速度快!  (4)编程性能:采用USB2.0接口,进行SWIM / JTAG / SWD下载,下载速度快!JTAG  JTAG(Joint Test AcTIon Group;联合测试工作组)是一种国际标准测试协议(IEEE 1149.1兼容),主要用于芯片内部测试。现在多数的高级器件都支持JTAG协议,如DSP、FPGA器件等。标准的JTAG接口是4线:TMS、TCK、TDI、TDO,分别为模式选择、时钟、数据输入和数据输出线。标准的JTAG接口是4线:TMS、TCK、TDI、TDO,分别为模式选择、时钟、数据输入和数据输出线。
  • [技术干货] RT - Thread 多线程
    什么是多线程?  在单片机上学习RT-Thread的多线程之前,要先把“进程”这个概念先放一边,因为单片机是没有多进程概念的。单片机运行操作系统,不管多少个任务,他们都是多个(或单个)线程之间进行处理这些任务,单片机一般不涉及多进程。  什么是多线程?在哪些情况下要用到多线程?先来举一个音乐播放器的例子,这个音乐播放器要做以下这些基本的工作:读取音乐文件并播放、读取歌词并显示、读取MV文件并播放。  如果这三个基本的工作不用多线程来完成,单片机使用裸机的方式去做这三个工作的话,必然会造成音乐播放卡顿,歌词显示不同步,MV视频播放与音乐不同步。  因为单片机做这三件事情的时候,是Step by Step的,必须完成一件事情之后,再去做下一件事情,这三件事情是有先后顺序的,并且不断循环重复,如下图所示。  而如果采用多线程这种方式来完成这个工作,这个过程就变得相对简单了,比如针对音乐播放器这个场景,可以设计这几个线程来处理:音乐文件读取线程,歌词文件读取线程,MV文件读取线程,音视频和歌词显示线程。  (此处只为举例描述多线程的概念,不考虑音视频编解码的复杂过程,不考虑线程同步,实际上音乐播放器的实现比此处描述更复杂)  音乐文件读取线程只负责从磁盘读取音乐文件,歌词文件读取线程和MV文件读取线程也是同样的道理,它们只做文件读取工作,而音视频和歌词显示线程,是负责把读取到的数据进行显示。这几个线程的工作过程,如下图所示。  如上图所示,这几个任务看上去是“同时”进行的,每个任务都只完成自己的事情,通过多线程,就可以把原本串行完成的任务改为并行完成,大大提高了工作效率。  所以,通俗地对多线程进行理解,就是把一个比较大型的任务,拆分为多个小型的任务,然后通过合理的调度方式,让这几个小型的任务“同时”运行,当这几个小型任务完成后,大型的任务也随之完成,这样可以大大提高任务的完成效率。多线程的几种状态  对于运行RT-Thread操作系统,线程都处于以下五种状态的其中一种(初始状态、就绪状态、运行状态、挂起状态、关闭状态),通过调用操作系统提供的接口函数,可以让线程在这五种状态中进行来回切换。  关于这五种线程状态的描述,如下表所示:多线程的API函数  如上图的状态机所示,多线程可以通过调用系统提供的函数接口,在多个状态之间进行切换。这些API函数在官方提供的参考文档里面都有详细的说明描述,以下列举一些比较常用的函数接口。多线程的应用示例  多线程的应用示例,主要是为了验证以上的多线程API接口函数,并且通过实验现象观察多线程的运行情况,主要有以下三个示例:  示例源码下载链接:https://github.com/embediot/rtthread_study_notes1、线程动态创建与静态创建、线程退出示例。  这个示例主要是通过动态方式创建线程1,,通过静态方式创建线程2,线程1的优先级比线程2的优先级低,因此可以被线程2抢占。线程2运行10次后就会主动退出,初始化代码如下图所示。2、相同优先级线程的时间片轮转调度示例。  这个示例主要是通过动态方式创建线程1和线程2,这两个线程都是相同的优先级,并且共用一个线程入口函数,主要是通过传入不同的线程参数以区分线程1和线程2。线程2运行所占用的时间片比线程1要少,因此线程2运行的时间比较短,初始化代码如下图所示。3、线程调度器的钩子函数使用示例。  这个示例主要测试了线程在进行调度时,关于钩子函数的调用情况。通过线程调度器的钩子函数,打印出线程间的切换信息,初始化的代码如下图所示。多线程应用的注意事项  在使用RT-Thread实时操作系统进行多线程应用开发的时候,应该要注意以下事项:1、RT-Thread的线程调度器是抢占式的,也就是能够保证就绪队列里面,最高优先级的任务总能获得CPU的使用权,在任务设计的时候,要充分考虑好任务的优先级。2、在硬件中断服务程序运行期间,如果有高优先级的任务就绪,那么被中断的低优先级任务将被挂起,高优先级的任务将会获得CPU的使用权。3、每个线程都有独立的线程栈,用来保存线程调度时上下文的信息,因此在创建线程分配栈空间的时候,要充分考虑栈的大小。4、在线程的循环体里面,应该要设置某些条件,在必要的时候主动让出CPU的使用权,特别对于高优先级的线程,如果程序里面有死循环操作而又不主动让出CPU使用权,那么这个线程将会一直占用CPU,并且低优先级的线程永远不会被调度执行。5、对于没有一直循环执行的线程,线程执行完毕后,资源的回收情况实际上是在空闲线程里面进行的,线程变为关闭状态后,不代表资源马上被回收。6、系统空闲线程是最低优先级且永远为就绪状态的,空闲线程是一个死循环,永远不会被挂起,但可以被其他高优先级任务抢占,空闲线程主要执行僵尸线程的资源回收工作。7、空闲线程也可以设置钩子函数,用来进行功耗管理,看门狗喂狗等工作。8、通过动态方式创建的线程,需要设置好系统堆内存的大小,而通过静态方式创建的线程,线程栈和线程句柄在程序编译的时候就已经确定,不能被动态分配,也不能被释放。9、大多数线程都是在不断循环执行的,无需进行删除,一般不推荐主动删除线程。线程运行完毕后,系统调度器将会自动把线程加入僵尸队列,资源回收工作将在空闲线程里面进行。
  • [问题求助] 【200DK】【i2c】关于I2C使用的问题
    我希望能用200DK与舵机控制板PCA9685通信从而输出PWM,在参考I2C例程https://gitee.com/ascend/samples/tree/master/cplusplus/level1_single_api/5_200dk_peripheral/i2c后遇到了几个问题:1.函数atlas_i2c_write(unsigned char slave, unsigned char reg, unsigned char data)中第二个参数reg的含义,是指从设备内部寄存器的地址吗? 如果我想向PCA9685(地址设为0x81)的MODE1寄存器(内部地址为00)中写入0x00,是不是可以直接用xxx.atlas_i2c_write(0x81,0x00,0x00)呢?2.如果我希望读取PCA9685(地址设为0x81)的MODE1寄存器(内部地址为00)的值,该怎么使用函数atlas_i2c_read(unsigned char slave, unsigned char reg, unsigned char *data)呢?
  • [技术干货] 【毕昇编译器】编译优化与软硬协同释放鲲鹏澎湃算力
    一、背景知识——编译优化与软硬协同编译器:将源程序(高级语言)转换为等价的机器语言源代码(source code)→预处理器(preprocessor)→编译器(compiler)→目标代码(object code)→链接器(Linker)→可执行程序(executables)编译优化:保留程序语义(正确性)的前提下,对程序进行等价变化,从而较少程序运行时间软硬协同:在编译优化中适配/使能诸多硬件特性      HPC( High Performance Computing,高性能计算)领域主要是解决计算密集型、海量数据处理等业务的计算需求,如科学研究、气象预报、计算模拟等。如何提高计算能力、极致化应用性能成为当前 HPC 领域各大平台最关键的课题之一,编译器在其中发挥着至关重要的作用。二、认识毕昇编译器      毕昇编译器是基于开源LLVM 10.0.1版本开发,并进行了优化和改进,同时将flang作为默认的Fortran语言前端编译器,是一种Linux下针对鲲鹏920的高性能编译器,其针对鲲鹏平台进行了深度优化的高性能编译器。除支持 LLVM 通用功能和优化外之外,对中端及后端的关键技术点进行了深度优化,对以下三个方面进行了增强,使得鲲鹏平台的强劲算力能够最大限度地得到释放。高性能编译算法:编译深度优化,内存优化增强,自动矢量化等,大幅提升指令和数据呑吐量。加速指令集:结合 NEON/SVE 等内嵌指令技术,深度优化指令编译和运行时库,发挥鲲鹏架构极致算力。AI 迭代调优:内置 AI 自学习模型,自动优化编译配置,迭代提升程序性能,完成最优编译。关键特性支持鲲鹏微架构芯片及指令优化通过软硬协同提供相较开源LLVM更高的性能集成Auto-tuner特性支持编译器自动调优运行平台:鲲鹏920硬件平台操作系统:openEuler21.03、openEuler 20.03 (LTS)、CentOS 7.6、Ubuntu 18.04、Ubuntu 20、麒麟V10、UOS 20注:详细的运行平台和操作系统对应关系请参见 兼容性查询工具部分通用信息请参考LLVM的用户指导https://llvm.org/docs/UserGuides.html相比GCC和icc,LLVM前端Clang对语法的检查更严谨,严格匹配语言标准,Clang的常见兼容性和可移植性问题,请参考开源官方文档https://clang.llvm.org/compatibility.html支持的编程语言      LLVM是一种涵盖多种编程语言和目标处理器的编译器,毕昇编译器聚焦于对C、C++、Fortran语言的支持,利用LLVM的Clang作为C和C++的编译和驱动程序,Flang作为Fortran语言的编译和驱动程序。1、C,C++程序      Clang不仅仅是可以将C, C++程序编译为LLVM中间表示的IR,它也是一个驱动程序,会调用所有以代码生成为目标的LLVM优化遍,直到生成最终的二进制文件。毕昇编译器提供了端到端编译程序所需的所有工具和库。2、Fortran程序      Flang是专为LLVM集成而设计的Fortran前端,由两个组件flang1和flang2组成。它也是一个驱动程序,将源代码转换为LLVM IR,前端驱动程序将IR传输下去进行优化和目标代码生成。毕昇编译器优化效果:Benchmark跑分、HPC典型应用性能提升      当前毕昇编译器已广泛应用于多种 HPC 典型场景,如气象、安防、流体力学等,性能优势已初步体现。毕昇编译器与鲲鹏芯片协同,充分发挥芯片的性能,提升鲲鹏硬件平台上业务的性能体验。基于鲲鹏上编译器优化,SPEC CPU 2017 benchmark 跑分平均优于 GCC 20%以上HPC 典型气象应用 WRF 优于 GCC 10%~20%三、毕昇编译器典型优化场景及其优化原理1、结构体内存布局优化——大幅提升缓存命中率,突破访存瓶颈      SPEC CPU 2017 benchmark 中的 mcf 子项是对内存要求极高的应用,它是一款叫做MCF的大规模交通规划软件的核心代码。其瓶颈代码如下图左边所示。 将结构体数组转换为数组结构体结构体可以是显式的,也可以通过检查循环中的数组使用情况来推断它们      可见在 struct 中,data1 的使用率极高,而 data2 是不使用的。然而由于源代码中,数据的排布是以结构体数组的形式排布。按照一般编译器的编译方式,拿数据时每次都会将整个结构体放到 cache 里面,导致大量不参与计算的 data2 也被加载到了 cache 中,造成高速内存空间的浪费和性能的损耗。毕昇编译器会通过用户标记的结构体声明,或者通过自动检查循环中适合优化的内存场景,确认优化点。然后通过将结构体数组变为数组结构体的方式(如上图右),将有效数据紧凑排布,从而提高 cache 命中率和应用性能。经测试,此优化可以对 mcf 子项带来50%的性能提升。2、结构体指针压缩优化——大幅降低内存使用,提升缓存命中率使编译过程更加灵活和可控细粒度编译控制,提供更多优化机会    将指针成员由8字节压缩至4字节,减小每个结构体node的内存体积。被压缩的域成员指针外提为全局结构体指针ps_head,ps变换为相对基址的偏移,将有效数据紧凑排布,从而大幅降低内存使用,提升 cache 命中率和应用性能。3、软件预取——大幅提高程序性能,提升缓存命中率(1)软件预取:通过插入预取指令提前从内存中读取所需数据(2)预取的效果取决于“提前量”数据太早到达→浪费宝贵的cache空间数据太晚到达→仍需要等待访存过程(3)如何计算“提前量"循环大小Cache line大小访存延迟(4)针对鲲鹏微架构特征调整软件预取参数4、自动矢量化—计算效率提升的秘诀使用矢量寄存器、矢量指令提高并行度理论基础:SIMD(single instruction multiple data),一条指令可以处理多个数据硬件基础:ARM NEON指令集扩展,32个128位的矢量寄存器,指令可以同时操作4*32或2*64的数据软件基础:编译器针对NEON指令的分析和优化      鲲鹏平台支持 Armv8 NEON 矢量化指令集。当前支持32个128位的矢量寄存器,指令可以同时操作4*32或2*64的数据。毕昇编译器依托这种硬件优势做了大量优化,包括 SLP(superword-level parallelism) 矢量化和循环自动矢量化。      例如在 SPEC CPU 2017 benchmark 中处理视频流格式转换的x264子项中,毕昇编译器会自动识别并使用 uabd 和 udot 这类高效向量指令完成计算来替换标量指令,增大单时钟周期的数据处理量, 从而大幅提升计算效率。对于 x264 子项,这项优化可有效提升其30%的计算效率。5、循环优化——帮助发现更多的优化机会Loop unroll:将循环体复制多遍减少分支跳转次数帮助发现更多的优化机会Loop (partial) unswitch:外提(减少)循化内条件判断Loop fusion/distribution:将循环体合成一个/拆成多个6、Autotuner—基于机器学习快速获取最优编译配置      如何获取性能最优编译选项是编译器使用中常见的问题,往往需要长时间的手动选项调优。为了减少这其中的工作量,使得用户能快速找到最优的优化选项,毕昇编译器自研了基于 ML 的自动搜索技术(ML-based Search) 的 Autotuner 工具。      一种自动化的迭代过程, 通过操作编译设置来优化给定程序,以实现最佳性能。它由两个组件配合完成,毕异编译器和Autotuner命令行工具。此功能不需要在源代码中注入pragma,而是允许用户在简单的yaml文件中指定优化配置,该文件包含优化信息及其相应的代码区域信息,包括名称和行号。此外,它还可以记录优化结果,以及可调优的代码区间并以yaml的形式导出。与毕昇编译器进行交互:根据编译器产生的可调优代码结构创建搜索空间(search space)生成编译配置并调用编译器来编译源代码操作调优参数以及应用搜索算法自带的遗传算法获取性能数据引入基于ML的自动搜索技术(ML-basedSearch)关键技术点:1、知识库(Autotuner Database):根据静动态分析信息,建立知识库,支持决策系统进行优化2、优化决策系统(Optimal configuration):根据热点和性能评估信息、知识库信息,综合考虑确定优化措施3、热点标记和性能评价:热点标记,瓶颈检测,性能评估4、查找驱动(Feedback):将优化决策系统,反馈的优化建议Autotuner 的调优流程由两个阶段组成:初始编译阶段(initial compilation)和调优阶段(tuning process),如下图所示:初始编译阶段      初始编译阶段发生在调优开始之前,Autotuner首先会让编译器对目标程序代码做一次编译,在编译的过程中,毕昇编译器会生成一些包含所有可调优结构的YAML文件, 告诉我们在这个目标程序中哪些结构可以用来调优,比如文件(module), 函数(function), 循环(loop)。 例如,循环展开是编译器中最常见的优化方法之一,它通过多次复制循环体代码,达到增大指令调度的空间,减少循环分支指令的开销等优化效果。若以循环展开次数(unroll factor)为对象进行调优,编译器会在YAML文件中生成所有可被循环展开的循环作为可调优结构。调优阶段当可调优结构顺利生成之后,调优阶段便会开始:Autotuner首先读取生成好的可调优结构的YAML 文件,从而产生对应的搜索空间,也就是生成针对每个可调优代码结构的具体的参数和范围;调优阶段会根据设定的搜索算法尝试一组参数的值,生成一个YAML格式的编译配置文件(compilation config),从而让编译器编译目标程序代码产生二进制文件;最后Autotuner将编译好的文件以用户定义的方式运行并取得性能信息作为反馈;经过一定数量的迭代之后,Autotuner将找出最终的最优配置,生成最优编译配置文件,以YAML的形式储存。      简单来说,在初始编译阶段,编译器会通过用户指定的调优方向,对可调优的代码区间进行标记。在随后的调优阶段,Autotuner 会根据搜索算法对不同的优化区间生成不同的编译配置。然后使用此配置编译运行,并根据运行性能的反馈来迭代优化配置参数。最后经过给定迭代次数后找出最优配置供用户使用。在实践过程中,通过 Autotuner 对 Coremark Benchmark 进行调优可以获取5%以上的收益。7、毕昇编译器Fortran前端:特性、架构与优化增强(1)毕昇编译器Fortran语言前端基于Classic Flang构建,通过增强Classic Flang,支持如下特性:支持F2003、F2008 (Coarray特性除外)语言标准最高支持四倍浮点精度(real16)数据类型,15维数组数据类型,支持OpenMP4.0、OpenMP4.5并行化编程模型支持DWARF4标准多种Pragma引导语支持,如软件prefetch,omp simd,unroll,vector等(2)多个Fortran内建函数的优化maxloc/minloc/nint的内联trim/lentrim采用更优算法(3)内存分配优化,栈内存替挽堆内存(4)为中后端提供更准确详细的信息来辅助优化别名分析增强过程间优化增强四、毕昇编译器:新版本1、毕昇编译器1.3.3版本已于2021.06.30正式发布,点击”毕昇编译器软件包下载”,下载后解压使用:毕昇编译器软件包下载其中包含以下新特性:支持基于Structure Peeling的特性增强及指针压缩优化完善Fortran2003/2008语言特性新增大量优化特性:支持unroll and jam,loop distribution优化增强,软件预取增强,静态分支优化改善,循环矢量化特性增强等Autotuner特性增强与完善,改善调优时间新增支持macOS 10.0及以上版本支持申请并使用鲲鹏远程云调测环境优化操作易用性新增毕昇JDK安装部署功能修复部分已知BUG2、软件包下载点击”毕昇编译器软件包下载”,下载后解压使用:毕昇编译器软件包下载点击”毕昇编译器sha256”,用于对比完整性校验结果:毕昇编译器 sha2563、参考文档毕昇编译器用户指南毕昇编译器Autotuner 特性指南4、问题讨论鲲鹏社区论坛,可发帖提问:https://bbs.huaweicloud.com/forum/forum-923-1.html五、总结针对不同的场景,不同的应用特点,使用不同的编译优化手段编译优化的代价与收益权衡,需要综合考虑性能收益,代码体积,编译时间,可调试性等多方面因素软硬件结合,通过软件及硬件的协同优化,最大化的发挥硬件算力语言生态构建的持续性,语言标准的不断演进,及新特性支持【参考】【1】鲲鹏论坛编译器版块:https://bbs.huaweicloud.com/forum/forumdisplay-fid-928-orderby-lastpost-filter-typeid-typeid-1642.html【2】鲲鹏开发套件:https://kunpeng.huawei.com/#/developer/devkit/【3】鲲鹏首页:https://kunpeng.huawei.com【4】【毕昇编译器】编译优化与软硬协同释放鲲鹏澎湃算力:https://bbs.huaweicloud.com/live/kunpeng_live/202105311500.html
  • [问题求助] 【200DK】【I2C】关于I2C使用的问题
    我希望能用200DK与舵机控制板PCA9685通信从而输出PWM,在参考I2C例程https://gitee.com/ascend/samples/tree/master/cplusplus/level1_single_api/5_200dk_peripheral/i2c后遇到了几个问题:1.函数atlas_i2c_write(unsigned char slave, unsigned char reg, unsigned char data)中第二个参数reg的含义,是指从设备内部寄存器的地址吗? 如果我想向PCA9685(地址设为0x81)的MODE1寄存器(内部地址为00)中写入0x00,是不是可以直接用xxx.atlas_i2c_write(0x81,0x00,0x00)呢?2.如果我希望读取PCA9685(地址设为0x81)的MODE1寄存器(内部地址为00)的值,该怎么使用函数atlas_i2c_read(unsigned char slave, unsigned char reg, unsigned char *data)呢?
  • [鲲鹏编译器] 【毕昇编译器】毕昇编译器,让你的代码快到飞起!
    HPC( High Performance Computing,高性能计算)领域主要是解决计算密集型、海量数据处理等业务的计算需求,如科学研究、气象预报、计算模拟等。如何提高计算能力、极致化应用性能成为当前 HPC 领域各大平台最关键的课题之一,编译器在其中发挥着至关重要的作用。毕昇编译器作为一款基于鲲鹏平台的高性能编译器,在编译算法、加速指令集、 Autotuner 等方面对应用场景进行了深度的优化,为开发者提供高效的性能加持。本期由毕昇编译器工程师卜乐为你介绍鲲鹏的性能优化利器——毕昇编译器如何释放鲲鹏的强劲算力。了解毕昇编译器毕昇编译器是基于 LLVM,针对鲲鹏平台进行了深度优化的高性能编译器。除支持 LLVM 通用功能之外,对以下三个方面进行了增强,使得鲲鹏平台的强劲算力能够最大限度地得到释放。高性能编译算法:编译深度优化,内存优化增强,自动矢量化等,大幅提升指令和数据呑吐量。加速指令集:结合 NEON/SVE 等内嵌指令技术,深度优化指令编译和运行时库,发挥鲲鹏架构极致算力。AI 迭代调优:内置 AI 自学习模型,自动优化编译配置,迭代提升程序性能,完成最优编译。毕昇编译器特性架构图当前毕昇编译器已广泛应用于多种 HPC 典型场景,如气象、安防、流体力学等,性能优势已初步体现。其中,SPEC CPU 2017 benchmark 跑分平均优于 GCC 20%以上,HPC 典型气象应用 WRF 优于 GCC 10%。毕昇编译器与开源编译器SPEC CPU 2017 跑分对比毕昇编译器典型优化场景及其优化原理1 结构体内存布局优化—大幅提升缓存命中率,突破访存瓶颈SPEC CPU 2017 benchmark 中的 mcf 子项是对内存要求极高的应用,它是一款叫做MCF的大规模交通规划软件的核心代码。其瓶颈代码如下图左边所示。结构体优化原理示意图可见在 struct 中,data1 的使用率极高,而 data2 是不使用的。然而由于源代码中,数据的排布是以结构体数组的形式排布。按照一般编译器的编译方式,拿数据时每次都会将整个结构体放到 cache 里面,导致大量不参与计算的 data2 也被加载到了 cache 中,造成高速内存空间的浪费和性能的损耗。毕昇编译器会通过用户标记的结构体声明,或者通过自动检查循环中适合优化的内存场景,确认优化点。然后通过将结构体数组变为数组结构体的方式(如上图右),将有效数据紧凑排布,从而提高 cache 命中率和应用性能。经测试,此优化可以对 mcf 子项带来50%的性能提升。2 自动矢量化—计算效率提升的秘诀鲲鹏平台支持 Armv8 NEON 矢量化指令集。当前支持32个128位的矢量寄存器,指令可以同时操作4*32或2*64的数据。毕昇编译器依托这种硬件优势做了大量优化,包括 SLP(superword-level parallelism) 矢量化和循环自动矢量化。例如在 SPEC CPU 2017 benchmark 中处理视频流格式转换的x264子项中,毕昇编译器会自动识别并使用 uabd 和 udot 这类高效向量指令完成计算来替换标量指令,增大单时钟周期的数据处理量, 从而大幅提升计算效率。对于 x264 子项,这项优化可有效提升其30%的计算效率。 矢量化优化示例 3 Autotuner—基于机器学习快速获取最优编译配置如何获取性能最优编译选项是编译器使用中常见的问题,往往需要长时间的手动选项调优。为了减少这其中的工作量,使得用户能快速找到最优的优化选项,毕昇编译器自研了基于 ML 的自动搜索技术(ML-based Search) 的 Autotuner 工具。Autotuner 的调优流程由两个阶段组成:初始编译阶段(initial compilation)和调优阶段(tuning process),如下图所示:Autotuner 使用流程简单来说,在初始编译阶段,编译器会通过用户指定的调优方向,对可调优的代码区间进行标记。在随后的调优阶段,Autotuner 会根据搜索算法对不同的优化区间生成不同的编译配置。然后使用此配置编译运行,并根据运行性能的反馈来迭代优化配置参数。最后经过给定迭代次数后找出最优配置供用户使用。在实践过程中,通过 Autotuner 对 Coremark Benchmark 进行调优可以获取5%以上的收益。 以上介绍的三个优化特性分别是毕昇编译器在中前端算法优化、后端指令优化、迭代调优中最具代表性、在各自领域对性能提升表现最佳的三个特性。除以上介绍的三个优化特性之外,毕昇编译器在软件预取、循环优化、分支预测、指针压缩等编译优化技术均有探索且取得了显著的收益,详情可点击官网获取毕昇编译器详细信息,快来试试吧! 原文转载自 华为计算-【鲲鹏DevKit黑科技揭秘】┃ 毕昇编译器,让你的代码快到飞起!
  • [交流吐槽] 【技术长文】27岁没文凭,想努力自学编程,有机会成为程序员吗?
    之前在某乎看了很多类似的回答,说实话,我只想用一张图来表达。感觉个个都是清华北大的高材生,说的无学历就只能被社会抛弃,连选择的权利都没有一样。高学历的确就像玩游戏拿了红蓝BUFF,可以肆无忌惮游走整个地图,对照现实,就是你有更多选择大厂的权利和资本。可是,人生十有九不如意,即便你有高学历,也不代表你的人生是一帆风顺的。反而,打惯逆风局的人,碰到任何事,都能以云淡风轻的心态去面对。很多时候,实际的情况并没有大家说的这么糟,毕竟不是每个人都有条件接受高等的教育。世界上也不是只有大公司,如果你到一线城市看看,你就会发现。小公司的数量多如牛毛,高学历去大厂,低学历就去小厂呗。到后面谁比谁更有钱途,拼的也不是你的大厂经历,而是你会不会做人,手里积累了什么资源。大大小小的公司我都进过,但是我还是比较喜欢待在小厂。大厂拉帮结派,勾心斗角,请个假都要3,4个人签名才能走,一天打4次卡,还有上班不能上网,查阅资料的话只能用专用电脑的。如果不是每个月按时发工资,我还以为自己在坐牢。还是小厂舒服,特别是做技术的,老板有时候都供着你,生怕你突然跑路让他擦屁股,请假啥的直接说一声就行,遇到良心的还不扣工资。不过有利必有弊,大厂和小厂各有什么优缺点?大厂优缺点:抗风险能力强,稳定,这次YQ就是最好的考验,小厂倒一片。福利待遇各方面都比较好,五险一金全安排。出去以后能装逼,我是某某大厂出来的。工作比较细分,不能接触到整个产业链,你做软件开发老板绝对不会叫你去拿快递,相对轻松。大厂要面子,要维护企业形象,所以对员工学历有比较严格的要求,宣传的时候说我们公司99%都是博士硕士,这一听就感觉这公司牛逼对吧?管理相对严格,迟到会扣钱,请假也没那么方便。其他想不到了,我只呆过小厂。小厂优缺点:一个人当3个人干,能学到的东西更多,一个写代码的,分分钟让你连产品包装设计都做了。时间相对自由,请假也没那么多屁事,适合发展副业,哈哈哈。老板一般比较抠(当然也有大方的),记得一次在一家小厂开年会,我还是玩三公赢了老板300块,就当是年终奖了。对学历基本没啥要求,毕业第一家公司,直到我离职那一天,老板都不知道我是啥学历,只要你有能力,就有舞台。小厂有更多的机会,因为你接触了产品的整个环节,也有很多挖公司客户最后成为自己客户的。最后聊下,没学历,有机会成为程序员吗?通常有这种想法的人,都是思想上的巨人,行动上的矮子。你有这时间去想这种问题,还不如直接找一些视频教程看看,看看自己是否真的适合这个行业。我也没学历,学校专业是电气工程,本身挺有前途的一专业,后面全系被学校强制被安排成电梯专业。被迫无奈,我只能奋发图强,自学转行到单片机开发,照样从事了这个行业十年,十年前的学习笔记我都还保留着。只有那些不敢尝试,随波逐流的同学还在24小时待命修电梯,每个月拿着可怜的几千块。相比技术,我觉得个人的魄力和眼光更重要,特别是男人。如果你迷茫,不知道该往哪个方向,可以考虑往单片机开发方向发展,我个人也比较看好这个行业,而且我都能学会,相信你也可以。学会以后,先找个小公司沉淀项目经验。不用担心找不到工作的问题,我第一次出来找工作的时候,也被拒绝了N多次,后面我甚至都跟公司说,前期我不要工资都行,等我能为公司赚钱了再发工资。只要想做,办法总比问题多,在前期,没有选择的资本,有人要就行了。说得更现实些,你和公司都是相互利用的关系,公司压榨你的青春,你获得你想要的经验。有了经验,你就可以有更好的选择,至于能达到什么高度,就要看个人努力的程度了。————————————————版权声明:本文为CSDN博主「无际单片机编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_43982452/article/details/117929690
总条数:248 到第
上滑加载中