发帖数

50

原创数

50

关注者

12

阅读数

9297

点赞数

4

蔡琰

  • 女工程师跟你分享和嵌入式的不解之缘

    ①邂逅

    女汉子是从小挂在我身上的标签,身体好,性格直。然而报志愿也是听亲戚推荐然后选择了计算机,话说计算机是没有嵌入式以及单片机的,只会学些计算机的语言(偏上位机),大学的所有懒惰的美好(通宵打游戏,谈恋爱等等)都体验了一番才发现是要毕业了,突然意识到自己能去干点啥,就在这个时候学校有合作的嵌入式培训,起初也是想着就业去的,而且当时看到师兄做了个机器人,又会唱歌又会跳舞,太好玩了,这个真的是激起了我的兴趣。就这样开启了学习嵌入式以及单片机的路程~

    图片1.png 

    ②笨手笨脚的第一次

    单片机,ARM一系列课程,当时感觉真的可以收获颇丰,也不会很难的吧。兴趣满满的去上课,认识元器件,画原理图,看程序。简直眼花缭乱啊,自信被打去了一大半,开始怀疑人生了,不知道自己是否能学会,就这样结束了学习的第一课。

    图片2.png 

    ③越挫越勇,继续奋斗

    当一个人想认真做一件事的时候,你会发现潜力无限啊,韧劲也是无限的呢。认真起来的样子也是很可爱的,每天充实的生活,学习,什么都不想了。当你坚持下来之后,回头看看那些坚持是收获了太多。单片机就这样在曲折的道路上学完了,有时候学了会自信满满,有时候会在崩溃的边缘,然鹅这都被我强大的内心压下去了。

    想来学完单片机真的自己会设计东西吗,记得第一次做交通灯的时候那个兴奋劲,从原理图设计,到PCB,再到程序设计,虽然做出来了,其实现在想想当时并没有完全理解了。

    从此开始对各种电子小产品有了兴趣,拆拆装装,虽然不是每次都能完全对上,但总归让自己觉得一只脚踏入了智能社会了。哇,那个心情啊~

    其实每个知识点的学习都是垫脚石,除了坚持不懈,还要不断的学习,不断的实践,买来开发板自己研究,去网上搜集各种资料,从多次失败中总结经验,每次踩过的坑都是经验的积累过程,学习的过程不就是把知识变成自己的嘛,能灵活运用了才是真的学到了。

    图片3.png 

    ④心得

    作为一个女汉子我想对那些想接触单片机以及嵌入式的萌新说,我一开始也是被嵌入式做的产品吸引才学的,也做了无数次的实验,经历过无数次的失败,也担心不是科班出身还想做电子产品,被质疑的眼神以及话语再退缩了。

    开始找工作确实很没有底气,总是觉得自己不行,不敢投简历,不敢去面试,一段时间的低迷让我整个人有点没了方向。谁让我还算强大呢,即使是兴趣是最好的老师,那也离不开对爱好的不离不弃啊~汗水下面永远都是会夹杂点泪水的呢,笑到最后的永远都是靠坚持的。

    我只是想告诉大家如果对嵌入式感兴趣就一定去试试,不管结果怎么样,爱好就去接触下,没准就能爱了呢,会有很大收获的。

    大家一定要有个记录的好习惯,好记性不如烂笔头,记录不仅可以鼓励自己,还能留下你的拼搏奋斗的脚印。回头发现原来自己还能如此优秀。

    行走江湖,技艺可多但是需精湛,每个项目的磨炼,每个日夜的奋斗都会给你留下美好的回忆。同为爱好者,我们有机会可以一起畅谈人生,畅谈理想~

    收藏 0 回复 0 浏览 148
  • 单片机编程关键字之volatile

    volatile修饰的变量是说这变量可能会被意想不到地改变通常对于程序员而言,单片机中用的就算常见了。


    volatile 是易变的,不稳定的意思。其实对于很多人来说,根本没见过这个关键字,不知道它的存在。也有很多人知道它的存在,根本没用过我对它有种“杨家有女初长成,养在深闺无人识”的感觉。

    那么volatile关键字到底是什么意思呢,怎么用呢。


    1volatile其实和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素而改变,比如操作系统、硬件或者其他线程等等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

    ①、我们举个例子,

    int i=10;

    int j=i; //①语句

    int k=i; //②语句

    此时编译器对代码进行优化,这是因为在①、②两条语句中,i没有被用作左值(没有被赋值),这时候编译器认为是i的值没有发生改变,所以在①语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在②语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值(不会编译生成装在内存的汇编指令,比如ARMLDM指令),这样提高了效率。但要注意①和②语句之间确认i没有被用作左值才行。

    ②、再看一个例子:

    volatile int i=10;

    int j=i;   //③语句

    int k = i;   //④语句

    volatile关键字告诉编译器,i是随时可能发生改变的。每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k中。

    这样看来,如果i是一个寄存器变量,表示一个端口数据或者是多个线程的共享数据,那么就容易出错,所以说,volatile可以保证对特殊地址的稳定访问。


    2我们知道做电子方面技术工作的一般面试的时候都有笔试,比如单片机软件方面,考题基本都会有对这个关键字的考察,可想在单片机中这个关键字的重要性,一般题目会有对这个关键字的定义是什么,就是你得知道它的概念,然后就是举例说明这个关键字使用的例子,这个时候就能考察出大家对这个关键字的具体理解了。

    一般我们知道的是

    1、 并行设备的硬件寄存器(比如状态寄存器)

    2、 一个中断服务子程序中会访问到的非自动变量

    3、 多线程应用中被几个任务共享的变量

    当我们回答出这些时基本可以知道你对这个关键字是懂的,如果做嵌入式的话,程序员经常和硬件、中断、RTOS等等打交道,所以这个关键字必须要懂


    3那么我们再延伸一下,一个参数既可以是const也可以是volatile,那么举个例子就是只读的状态寄存器,那么只读就是const,并且要确定程序不能试图去修改它,再有就是volatile代表状态寄存器,可能被意想不到的改变。


    4那么指针是不是可以用到这个volatile关键字吗,是可以的。

    这个我们只要了解即可,用的不多。但是得知道。举个例子就是当一个中断服务子程序修改一个指向一个buffer的指针的时候。修饰也和const类似,const有常量指针和指针常量的说法,volatile也可以这样认为,

    比如修饰由指针指向的对象或数据是constvolatile的。

    例如:

    volatile  char  *p1;

    比如指针自身的值---一个代表地址的整数变量是constvolatile的。

    例如:

    char*  volatile  p1;

    对于这个关键字不仅C语言有,其他语言比如C++,JAVA其实都有。其他语言大部分是因为多线程共享变量的使用不被编译器优化的错误产生,比如优化编译器把一个变量从内存装入CPU寄存器中,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这回造成程序的错误执行。那么用了volatile来修饰变量了呢就是要告诉编译器每次操作这个变量的时候一定要从内存中真正取出,而不是使用已经存在寄存器的值。

    对于volatile怎么修饰变量,什么变量需要这个关键字修饰,大家心里有数了吧?

    收藏 0 回复 0 浏览 147
  • 白话文讲解ModBus协议

    ModBus是什么?干什么用的?我们一起来了解下吧。


    作为一些大型工业商,其实需要不同厂商提供的控制设备来组成一个工业网路,有了网络是不是需要监控啊?就像你的汽车一样,其实有一个总的控制系统在监控着油箱,行驶安全等等很多信息,所以才呈现给我们一个安全的驾驶体验。那么开发总的控制系统如果那么多的设备都各自有一套通信方案,开发难度可想而知了吧?这个时候就需要有一个标准了,那么这个modbus就是自动控制业界的标准,其实可以理解为我们交互的一个标准协议。这样对开发进度提升了,对通信安全提升了,还方便多个链路之间的通信,集中监控也更加方便了。


    既然是通信的标准,也就是规范了通信的应用层。根据这个标准我们各自去进行工作就好了。这个标准的网络架构我们一起来看下:


    图片1.jpg 

    这个协议定义了一个控制器能认识的使用的消息结构,而不管是经过何种网络进行通信的。


    我们看到网络中每种设备(PLCHMI、控制面板、驱动程序、动作控制、输入/输出设备)都能使用modbus协议来启动远程操作。

    通常我们在串行通信中用到modbus都是主从结构,总线上有一个主节点,一个或多个从节点。从节点地址是唯一的,通信模式是主节点发起请求,子节点没有收到来自主节点的请求时,从不会发送数据,子节点之间从不会互相通信。主节点在同一时刻只会发起一个modbus事物处理。


    我们说到这种协议是主从协议模式,主节点可以广播给所有节点请求,这就是广播模式,这种模式就是从节点不需要应答,接收到处理就可以了,地址0是专门用于表示广播数据的。


    还有一种是单播模式,就是主节点以特定地址访问子节点,子节点接到并处理完请求后,子节点向主节点返回一个应答。

    那我们一起看下协议描述:

    图片2.jpg 

    首先我们看两个概念,ADU:应用数据单元;PDU:协议数据单元。可以理解为PDU就是我们的应用层协议解析需要的。


    其实简单来看就是这样的一个结构,地址域只针对于从节点而言,也有规定(0是广播地址,1~247是从节点地址,248-255预留)其实就是一个字节的分配了。


    那么功能码就是指明要执行的动作。

    功能码后面的数据域就很容易理解了,是表示含有请求和响应参数的数据域。数据域虽然给了长度范围,也可以是没有的,功能码就能代表操作了。


    后面还有一个校验,就是做过通信的都知道校验是必须要的。否则怎么确保数据的正确性。

    对于ADU的长度也是有限制的,最大ADU256个字节,具体在什么物理层上通信对于PDU就有区别了,比如RS232/RS485 ADU = 地址域(1字节)+ PDU253字节)+CRC2字节)=256字节;还支持以太网口,也就是在TCP/IP协议层上封装了一层modbus协议,这样应用范围更广了。那么TCP MODBUS ADU = 249字节 + MBAP7字节) =256字节。


    到这里我们就可以知道了协议结构、协议模型、协议规则。简单来说就是主机是老大,它说了算,它想设置或者读取哪个从机,从机才能做出响应,所以说从机是被动的。当广播发送的时候无需应答,这就是定义的规则,有了规则做事就方便多了啊。


    具体的还详细做了主机的处理模型,从机的处理模型,所有正常的和异常的处理都在规则里面了,是不是很贴心。基本上把逻辑关系都考虑到了,只要按照逻辑关系图去写程序就好了。那么对于解析而言,主要还是对于功能码和数据域的值了。也就是到了上层应用了。

    对于串行传输还有两种模式,RTU模式和ASCII模式。


    我们先来了解一下RTU模式:

    图片3.jpg 

    对于报文格式就是上面这样的,子节点收到信息先解析是否是自己节点,然后对校验做出比对处理。然后就是上层的功能码和数据的处理了。除了数据解析还有一个超时处理,总不能一直接收吧,有个超时的要求,两个字节之间间隔大于1.5个字符时间,报文帧就被认为不完整应该被接收节点丢弃。两帧数据之间也有时间间隔要求,最小间隔是3.5个字符时间。


    这个模式也是我们在工业控制中通用的模式,协议紧凑。

    还有一个ASCII模式:

    图片4.jpg 

    我们都知道ASCII码是一个字符一个字符发送的,也就是表示0-9A-F;那么就是说一个字符表示四位二进制,也就是我们前面说的一个字节需要两个ASCII字符表示,所以这个相对RTU模式时序要求不高,自然应用场合也是有区别的。


    RTU不同的是还增加了一个起始字符和结束字符,校验方式是LRC校验方式,校验不包含起始字符和结束字符的。对比而言,我们看到是一个字节由两个字符表示的。字符间隔最大可以达到1S,相对宽松。


    结构清晰了,规则有了就是可以去解析了,主要还是对功能码和数据域的规则解析了,不同的功能码要处理什么功能的数据区,这个都是要根据规则去解析处理。


    解析这种标准协议首先就是要分好层,逻辑关系要处理清楚,模块处理要结合实际应用映射关系,对于从节点有接收有应答,就是一个完整的闭环。你对modbus了解了吗?


    收藏 0 回复 0 浏览 147
  • 位段操作

    大家好!我是张飞实战电子蔡琰老师,今天给大家分享位段操作。

    位段操作允许单次加载/存储操作(读/写)访问单个数据位,对于Cortex-M3,两个预定义的位段区域支持这种特性,其中一个位于SRAM区域的头1MB,另外一个则位于外设区域的头1MB。这两个区域可以同普通存储器一样访问,不过它们还可以通过被称作位段别名的独立区域进行操作。当使用位段别名地址时,可以通过每个字对齐的地址中数据的最低位,来访问每个单独的位。

    例如,要将地址0x20000000中数据的第2位置1,除了可以通过读出数据、设置位然后写回数据的方式外,还可以通过单一指令执行这个操作,下面看一下两种情况的汇编执行流程。

    图片2.jpg

    图片3.jpg

    类似地,如果我们需要读取存储器位置中的一个位,位段特性可以简化应用程序代码。例如,如果我们需要确定地址0x20000000处数据的第2位,我们可以采取下面图所示的步骤。

    图片4.jpg

    位段操作并不是一个新的想法,事实上,类似的特性已经在像8051之类的8位微处理器上存在30多年了。尽管Cortex-M3并没有位操作的特殊指令,而定义了特殊区域却可以让对这些区域的访问自动转换为位段操作。

    下面是Cortex-M3在位段存储器寻址里使用的术语:

    位段区域:支持位段操作的存储器区域。

    位段别名:访问位段别名会引起对位段区域的访问(位段操作)。

    在位段区域里,每个字被位段别名寻址区域里的32个字的最低位表示。事实上,在访问位段别名区域时,地址被重映射为位段地址。对于读操作,字被读出并且选定的位会被移入读返回数据的最低位;对于写操作,写入的位数据会被移入所需位的位置,并且执行读-修改-写的操作。


    收藏 0 回复 0 浏览 144
  • USB之数据包和握手包

    前面的文章我们一起了解了USB的包结构以及令牌包,今天我们来说说USB的数据包和握手包.

    顾名思义,数据包就是用来传输数据的,USB1.1协议中,只有两种数据包:DATA0包和DATA1包。在USB2.中又增加了DATA2MDATA,主要用在高速分裂事务和高速高带宽同步传输中。

    数据包都具有同样的结构:一个同步域,后面跟整数字节的数据,然后是CRC16校验,最后是包结束符EOP,如图1所示。

    image.png 

    1

    之所以有不同类型的数据包,是用在当握手包出错时纠错.下面以DATA0包和DATA1包的切换为例进行具体的解释。

    主机和设备都会维护自己的一个数据包类型切换机制:当数据包成功发送或者接收时,数据包类型切换。当检测到对方所使用的数据包类型不对时,USB系统认为这发生了一个错误,并试图从错误中恢复。数据包类型不匹配主要发生在握手包被损坏的情形。当一端已经正确接收到数据并返回确认信号时,确认信号却在传输过程中被损坏。这时另一端就无法知道刚刚发送的数据是否已经成功,这时它只好保持自己的数据包的类型不变。如果对方下一次使用的数据包类型跟自己的不一致,则说明它刚刚已经成功接收到数据包了(因为它已经做了数据包切换,只有正确接收才会如此);如果对方下一次使用的数据包类型跟自己的一致,则说明对方没有切换数据包类型,也就是说,刚刚的数据包没有发送成功,这是上一次的重试操作。

     

    握手包有ACKNAKSTALLNYETACK表示正确接收数据,并且有足够的空间来容纳数据。主机和设备都可以用ACK来确认,NAKSTALLNYET只有设备能够返回,主机不能使用这些握手包。

    image.png 

    2

    >NAK表示没有数据需要返回,或者数据正确接收但是没有足够的空间来容纳它们。当主机收到NAK,知道设备还未准备好,主机会在以后合适的时机进行重试传输。

    > STALL表示设备无法执行这个请求,或者端点已经被挂起了,它表示一种错误的状态。设备返回 STLSTALL,需要主机进行干预才能解除这种状态。

    >NYET只在USB2.0的高速设备输出事务中使用,它表示设备本次数据成功接收,但是没有足够的空间来接收下一次数据。主机在下一次输出数据时,将先使用PING令牌包来试探设备是否有空间接收数据,以避免不必要的带宽浪费。

    需要注意的是,返回NAK并不表示数据出错,只是说明设备暂时没有数据传输或者暂时没有能力接收数据。当USB主机或者设备检测到数据出错时(CRC校验错、PID校验错、位填充错等),将什么都不返回。这时等待接收握手包的一方就会收不到握手包从而等待超时。

    以上就是数据包和握手包的内容,你明白了吗?


    收藏 0 回复 0 浏览 134
×
蔡琰