个人成就
- 发布了50篇内容
- 获得了4次赞同
- 获得了3次收藏
个人简介
擅长领域
暂时没有设置哦~
-
红外遥控原来这么简单!
大家好!我是张飞实战电子蔡琰老师!今天给大家分享红外遥控接收。
平时我们经常会用到遥控器,那么现在遥控器也分很多种类,有使用红外通信的,也有使用蓝牙,无线的等,今天我们来一起解码一下红外的工作原理。
大家看现在图中的是2个红外对管,左边是发射端,右边是接收端,
遥控器上有一个红外发射二极管,发射红外数据信息,电视机上有一个红外接收管,接收红外信息,那么到底是怎么把数据从二极管中发送出去的呢?
如上图,遥控器发送之前要先进行编码调制,然后进行信号放大发射,接收设备需要先对这个信号进行解调,解调之后的信号送给单片机,单片机进行解码(分析是什么数据)。
调制过程就是需要加上载波信号,中间加载了一个载波信号,发送的数据就是通过载波信号送出去的,对应的接收信号就需要对收到的载波信号进行解调处理了,即信号还原。
一般情况下接收头,只能解调固定的一种载波频率信号,那遥控器的发送信号的载波频率要与接收头所用的频率一致,否则是没办法正确接收的。自然界中存在红外光,进行调制主要是为了避免一些干扰,以防止传输出错。下面我们一起来看看遥控器传输的协议编码规则。
遥控器信号开始的地方有一段特殊长度的信号,这个我们叫它是引导码,引导码是9ms高电平+4.5ms的低电平,单片机只有结束到了正确的引导码,才可以开始接收后续的数据。
我们知道有效数据要么是0,要么是1,0或者1都是由一个固定的高电平+低电平组成,数据1: 0.56ms高电平+1.69ms低电平组成,数据0: 0.56ms高电平+0.56ms低电平组成,也就是说收到这样的一个高电平+低电平的数据就是认为收到有效数据了,再根据判断时间来区分是0还是1。通过分析出来0 1,再把这些0 1组合成一个有用的数据,然后进行处理执行动作,比如切换频道,关机、开机等。这样就是一个完成的遥控器发送,接收原理了。
上图是我们实测的一个遥控器解调后的波形中,你能分析出图中传输的数据吗?
-
白话文讲解ModBus协议
ModBus是什么?干什么用的?我们一起来了解下吧。
作为一些大型工业商,其实需要不同厂商提供的控制设备来组成一个工业网路,有了网络是不是需要监控啊?就像你的汽车一样,其实有一个总的控制系统在监控着油箱,行驶安全等等很多信息,所以才呈现给我们一个安全的驾驶体验。那么开发总的控制系统如果那么多的设备都各自有一套通信方案,开发难度可想而知了吧?这个时候就需要有一个标准了,那么这个modbus就是自动控制业界的标准,其实可以理解为我们交互的一个标准协议。这样对开发进度提升了,对通信安全提升了,还方便多个链路之间的通信,集中监控也更加方便了。
既然是通信的标准,也就是规范了通信的应用层。根据这个标准我们各自去进行工作就好了。这个标准的网络架构我们一起来看下:
这个协议定义了一个控制器能认识的使用的消息结构,而不管是经过何种网络进行通信的。
我们看到网络中每种设备(PLC、HMI、控制面板、驱动程序、动作控制、输入/输出设备)都能使用modbus协议来启动远程操作。
通常我们在串行通信中用到modbus都是主从结构,总线上有一个主节点,一个或多个从节点。从节点地址是唯一的,通信模式是主节点发起请求,子节点没有收到来自主节点的请求时,从不会发送数据,子节点之间从不会互相通信。主节点在同一时刻只会发起一个modbus事物处理。
我们说到这种协议是主从协议模式,主节点可以广播给所有节点请求,这就是广播模式,这种模式就是从节点不需要应答,接收到处理就可以了,地址0是专门用于表示广播数据的。
还有一种是单播模式,就是主节点以特定地址访问子节点,子节点接到并处理完请求后,子节点向主节点返回一个应答。
那我们一起看下协议描述:
首先我们看两个概念,ADU:应用数据单元;PDU:协议数据单元。可以理解为PDU就是我们的应用层协议解析需要的。
其实简单来看就是这样的一个结构,地址域只针对于从节点而言,也有规定(0是广播地址,1~247是从节点地址,248-255预留)其实就是一个字节的分配了。
那么功能码就是指明要执行的动作。
功能码后面的数据域就很容易理解了,是表示含有请求和响应参数的数据域。数据域虽然给了长度范围,也可以是没有的,功能码就能代表操作了。
后面还有一个校验,就是做过通信的都知道校验是必须要的。否则怎么确保数据的正确性。
对于ADU的长度也是有限制的,最大ADU是256个字节,具体在什么物理层上通信对于PDU就有区别了,比如RS232/RS485 ADU = 地址域(1字节)+ PDU(253字节)+CRC(2字节)=256字节;还支持以太网口,也就是在TCP/IP协议层上封装了一层modbus协议,这样应用范围更广了。那么TCP MODBUS ADU = 249字节 + MBAP(7字节) =256字节。
到这里我们就可以知道了协议结构、协议模型、协议规则。简单来说就是主机是老大,它说了算,它想设置或者读取哪个从机,从机才能做出响应,所以说从机是被动的。当广播发送的时候无需应答,这就是定义的规则,有了规则做事就方便多了啊。
具体的还详细做了主机的处理模型,从机的处理模型,所有正常的和异常的处理都在规则里面了,是不是很贴心。基本上把逻辑关系都考虑到了,只要按照逻辑关系图去写程序就好了。那么对于解析而言,主要还是对于功能码和数据域的值了。也就是到了上层应用了。
对于串行传输还有两种模式,RTU模式和ASCII模式。
我们先来了解一下RTU模式:
对于报文格式就是上面这样的,子节点收到信息先解析是否是自己节点,然后对校验做出比对处理。然后就是上层的功能码和数据的处理了。除了数据解析还有一个超时处理,总不能一直接收吧,有个超时的要求,两个字节之间间隔大于1.5个字符时间,报文帧就被认为不完整应该被接收节点丢弃。两帧数据之间也有时间间隔要求,最小间隔是3.5个字符时间。
这个模式也是我们在工业控制中通用的模式,协议紧凑。
还有一个ASCII模式:
我们都知道ASCII码是一个字符一个字符发送的,也就是表示0-9,A-F;那么就是说一个字符表示四位二进制,也就是我们前面说的一个字节需要两个ASCII字符表示,所以这个相对RTU模式时序要求不高,自然应用场合也是有区别的。
跟RTU不同的是还增加了一个起始字符和结束字符,校验方式是LRC校验方式,校验不包含起始字符和结束字符的。对比而言,我们看到是一个字节由两个字符表示的。字符间隔最大可以达到1S,相对宽松。
结构清晰了,规则有了就是可以去解析了,主要还是对功能码和数据域的规则解析了,不同的功能码要处理什么功能的数据区,这个都是要根据规则去解析处理。
解析这种标准协议首先就是要分好层,逻辑关系要处理清楚,模块处理要结合实际应用映射关系,对于从节点有接收有应答,就是一个完整的闭环。你对modbus了解了吗?
-
单片机编程关键字之volatile
volatile修饰的变量是说这变量可能会被意想不到地改变。通常对于程序员而言,单片机中用的就算常见了。
volatile 是易变的,不稳定的意思。其实对于很多人来说,根本没见过这个关键字,不知道它的存在。也有很多人知道它的存在,根本没用过,我对它有种“杨家有女初长成,养在深闺无人识”的感觉。
那么volatile关键字到底是什么意思呢,怎么用呢。
1、volatile其实和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素而改变,比如操作系统、硬件或者其他线程等等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
①、我们举个例子,
int i=10;
int j=i; //①语句
int k=i; //②语句
此时编译器对代码进行优化,这是因为在①、②两条语句中,i没有被用作左值(没有被赋值),这时候编译器认为是i的值没有发生改变,所以在①语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在②语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值(不会编译生成装在内存的汇编指令,比如ARM的LDM指令),这样提高了效率。但要注意①和②语句之间确认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也可以这样认为,
比如修饰由指针指向的对象或数据是const或volatile的。
例如:
volatile char *p1;
比如指针自身的值---一个代表地址的整数变量是const或volatile的。
例如:
char* volatile p1;
对于这个关键字不仅C语言有,其他语言比如C++,JAVA其实都有。其他语言大部分是因为多线程共享变量的使用不被编译器优化的错误产生,比如优化编译器把一个变量从内存装入CPU寄存器中,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这回造成程序的错误执行。那么用了volatile来修饰变量了呢就是要告诉编译器每次操作这个变量的时候一定要从内存中真正取出,而不是使用已经存在寄存器的值。
对于volatile怎么修饰变量,什么变量需要这个关键字修饰,大家心里有数了吧?
-
位段操作
大家好!我是张飞实战电子蔡琰老师,今天给大家分享位段操作。
位段操作允许单次加载/存储操作(读/写)访问单个数据位,对于Cortex-M3,两个预定义的位段区域支持这种特性,其中一个位于SRAM区域的头1MB,另外一个则位于外设区域的头1MB。这两个区域可以同普通存储器一样访问,不过它们还可以通过被称作位段别名的独立区域进行操作。当使用位段别名地址时,可以通过每个字对齐的地址中数据的最低位,来访问每个单独的位。
例如,要将地址0x20000000中数据的第2位置1,除了可以通过读出数据、设置位然后写回数据的方式外,还可以通过单一指令执行这个操作,下面看一下两种情况的汇编执行流程。
类似地,如果我们需要读取存储器位置中的一个位,位段特性可以简化应用程序代码。例如,如果我们需要确定地址0x20000000处数据的第2位,我们可以采取下面图所示的步骤。
位段操作并不是一个新的想法,事实上,类似的特性已经在像8051之类的8位微处理器上存在30多年了。尽管Cortex-M3并没有位操作的特殊指令,而定义了特殊区域却可以让对这些区域的访问自动转换为位段操作。
下面是Cortex-M3在位段存储器寻址里使用的术语:
位段区域:支持位段操作的存储器区域。
位段别名:访问位段别名会引起对位段区域的访问(位段操作)。
在位段区域里,每个字被位段别名寻址区域里的32个字的最低位表示。事实上,在访问位段别名区域时,地址被重映射为位段地址。对于读操作,字被读出并且选定的位会被移入读返回数据的最低位;对于写操作,写入的位数据会被移入所需位的位置,并且执行读-修改-写的操作。
-
USB之数据包和握手包
前面的文章我们一起了解了USB的包结构以及令牌包,今天我们来说说USB的数据包和握手包.
顾名思义,数据包就是用来传输数据的,在USB1.1协议中,只有两种数据包:DATA0包和DATA1包。在USB2.中又增加了DATA2和 MDATA包,主要用在高速分裂事务和高速高带宽同步传输中。
数据包都具有同样的结构:一个同步域,后面跟整数字节的数据,然后是CRC16校验,最后是包结束符EOP,如图1所示。
图1
之所以有不同类型的数据包,是用在当握手包出错时纠错.下面以DATA0包和DATA1包的切换为例进行具体的解释。
主机和设备都会维护自己的一个数据包类型切换机制:当数据包成功发送或者接收时,数据包类型切换。当检测到对方所使用的数据包类型不对时,USB系统认为这发生了一个错误,并试图从错误中恢复。数据包类型不匹配主要发生在握手包被损坏的情形。当一端已经正确接收到数据并返回确认信号时,确认信号却在传输过程中被损坏。这时另一端就无法知道刚刚发送的数据是否已经成功,这时它只好保持自己的数据包的类型不变。如果对方下一次使用的数据包类型跟自己的不一致,则说明它刚刚已经成功接收到数据包了(因为它已经做了数据包切换,只有正确接收才会如此);如果对方下一次使用的数据包类型跟自己的一致,则说明对方没有切换数据包类型,也就是说,刚刚的数据包没有发送成功,这是上一次的重试操作。
握手包有ACK、NAK、 STALL和NYET。ACK表示正确接收数据,并且有足够的空间来容纳数据。主机和设备都可以用ACK来确认,而NAK、 STALL、NYET只有设备能够返回,主机不能使用这些握手包。
图2
>NAK表示没有数据需要返回,或者数据正确接收但是没有足够的空间来容纳它们。当主机收到NAK时,知道设备还未准备好,主机会在以后合适的时机进行重试传输。
> STALL表示设备无法执行这个请求,或者端点已经被挂起了,它表示一种错误的状态。设备返回 STLSTALL后,需要主机进行干预才能解除这种状态。
>NYET只在USB2.0的高速设备输出事务中使用,它表示设备本次数据成功接收,但是没有足够的空间来接收下一次数据。主机在下一次输出数据时,将先使用PING令牌包来试探设备是否有空间接收数据,以避免不必要的带宽浪费。
需要注意的是,返回NAK并不表示数据出错,只是说明设备暂时没有数据传输或者暂时没有能力接收数据。当USB主机或者设备检测到数据出错时(如CRC校验错、PID校验错、位填充错等),将什么都不返回。这时等待接收握手包的一方就会收不到握手包从而等待超时。
以上就是数据包和握手包的内容,你明白了吗?