标签目录:摩登3代理1980

摩登3娱乐怎么样?_C/C++中宏定义的经典运用

在C语言中宏定义是比较有用的技巧,在Linux源码中经常使用一些宏定义,比如宏container_of()等都是经典的宏定义表示方式。在C++不再主张使用宏定义,但是宏定义实际上却是是一个非常有用的手段。实质上宏定义能够搞定的实现采用其它的实现也是可以的,宏定义的作用是简单的替代作用,掌握这个是理解的关键,以前在没有代码阅读量的时候总是以为宏定义就是简单的定义一些常量什么的,实质上不然,宏定义完全可以写成函数的形式,但是宏定义和函数有一定的差别,函数的调用一般采用栈的方式实现,这时候存在局部变量,形参、实参等问题,如果不理解C语言的本质,很多时候非常容易搞错,但是宏定义则不然,宏定义没有调用的过程,宏的实现仅仅是一个替换过程,不用压栈出栈,宏实现的类似函数修改的就是当前区域中的变量,不是局部变量。这也是一些较深层次的问题,在刚学习C语言的时候很多人只要看见类似于函数的形式都认为是函数,实质上不一定,很有可能就是采用宏定义实现的类函数,这时候就可能导致所谓的形参实参问题发生较大的变化。关于宏的问题在面试笔试的过程中、写代码的过程中都是非常有用的部分,我就不再做介绍。 今天看了一遍博客《Reduce C-language coding errors with X macros》,感觉文章写得非常的好,也对自己写代码有了一定的帮助,所以就将该文章用我自己的语言,写出来和大家分享分享吧。 本文引用地址:http://www.eepw.com.cn/article/201612/324488.htm 在嵌入式实时操作系统中,经常将系统分成很多层次,很多个模块,每一个模块都有自己的初始化过程,这时候我们一般采用的形式如下所示: typedef void(*p_func_t)(void); enum { STATE_0, STATE_1, STATE_2, … STATE_M, NUM_STATES }; p_func_t inital_table[NUM_STATES] { func_0, func_1, func_2, … func_M, }; 这种实现方法是比较常见的实现方式,但是这种方法的缺点是所有的初始化过程是按照一定的顺序的,而且不能随机的初始化,因此如果在编码的过程中将状态号与初始化函数对应错误,将出现比较难以发现的错误,这种错误经常出现,当然有些编译器以及支持随机的初始化过程,但是并不具有通用性,而且这种实现方式代码比较多,能不能采用宏定义的方式简化代码量呢?当然是可以的,采用类似于函数的宏定义就可以实现,具体的实现如下: typedef void(*p_func_t)(void); #define STATE_TABLE ENTRY(STATE_0,func_0) ENTRY(STATE_1,func_1) ENTRY(STATE_2,func_2) ENTRY(STATE_3,func_3) ENTRY(STATE_4,func_4) enum{ #define ENTRY(a,b) a, STATE_TABLE #undef ENTRY NUM_STATES }; p_func_t inital_table[NUM_STATES] = { #define ENTRY(a,b) b, STATE_TABLE #undef ENTRY }; 上面这种实现方式的优点是运用了宏定义简少代码量。我做一个简要的分析,首先采用宏定义定义了一组ENYRT,其中包含两个参数,分别是状态号STATE_N,和状态对应的初始化函数,这种实现方式能够避免上面所谓的状态号与函数对应错误的问题,因为在宏定义的过程中一般都会认真的确定各种接口,对应好了只需要定义相关的函数就可以啦。在enum中采用了#define和#undef来限定这一组宏定义的作用范围,在个作用域中,ENTRY(a,b)是表示“a,”,需要注意不能忽略a后的,因为这就是在enum中定义变量后要添加的符号,我想大家应该知道enum{a,b,c,d}每一个成员后面都包含”,”的特性的。也就是说在这作用域中,ENTRY(a,b)被替换为”a,”,那么这时候STATE_TABLE就被替换为STATE_0,STATE_1等,然后和NUM_STATES就组成了第一个例程中的enum结构。而在p_func_t jumptable[NUM_STATES]仍然采用了了STATE_TABLE,由于采用了#define和#undef限定了宏的作用范围,这时的ENTRY(a,b)将被替代为“b,”,也就是func_0,func_1等,这样也就完成了函数指针数组的初始化过程,这样的初始化能够减少状态号与初始化函数对应出错的情况。 这样的实现也可以认为是宏定义的巧妙运用,但是这种方法还是存在一些问题,因为采用#define 和#undef这种方法很可能导致错误的产生,因为很有可能不能很好的把握这个限定作用域的使用方法,这时候可以采用一种新的类似函数的实现方法,可以让STATE_TABLE带一个参数,也就是采用类似命令的形式定义相关的内容: typedef void(*p_func_t)(void); /*以下产生几个常用的命令*/ /*enum产生*/ #define EXPAND_AS_ENUM(a,b) a, /*初始化表产生*/ #define EXPAND_AS_INITTABLE(a,b) b, /*声明各个函数*/ #define EXPAND_AS_FUNCDEC(a,b) void b(void); /*将STATE_TABLE的参数就是具体的命令*/ #define STATE_TABLE(ENTRY) ENTRY(STATE_0,func_0) ENTRY(STATE_1,func_1) ENTRY(STATE_2,func_2) ENTRY(STATE_3,func_3) ENTRY(STATE_4,func_4) /*定义enum*/ enum{ STATE_TABLE(EXPAND_AS_ENUM) NUM_STATES }; /*声明各个函数*/ STATE_TABLE(EXPAND_AS_FUNCDEC) /*初始化表*/ p_func_t inital_table[NUM_STATES] = { STATE_TABLE(EXPAND_AS_INITTABLE) }; 以上实现方法能够较好的避免#define和#undef的限定作用域问题,这实际上采用ENTRY作为参数传递给STATE_TABLE,然后ENTRY可用来实现不同的指令,这些指令的定义也是一系列的宏定义,这种实现架构能够比较好的避免缺少声明等问题。同时也较少了错误的产生可能。 上一页 1 2 下一页

摩登3注册网站_基于CC2430和DS18B20的无线测温系统设计

目前,很多场合的测温系统采用的还是有线测温设备,由温度传感器、分线器、测温机和监控机等组成,各部件之间采用电缆连接进行数据传输。这种系统布线复杂、维护困难、成本高,可采用无线方案解决这些问题。无线测温系统是一种集温度信号采集、大容量存储、无线射频发送、LED(或LCD)动态显示、控制与通信等功能于一体的新型系统。 本文从低功耗、小体积、使用简单等方面考虑,基于射频SoCCC2430和数字温度传感器DS18B20设计了一个无线测温系统,整个系统由多个无线节点和1个基站组成。无线节点工作在各个测温地点,进行温度数据采集和无线发送。基站与多个节点进行无线通信,并通过数码管将数据显示出来,同时可以通过RS-232串口将数据发送给PC。 CC2430简介 CC2430是TI/ChipconAs公司最新推出的符合2.4GIEEE802.15.4标准的射频收发器.利用此芯片开发的无线通信设备支持数据传输率高达250kbit/s可以实现多点对多点的快速组网。CC2430的主要性能参数如下:   (1)工作频带范围:2.400~2.4835GHz;  (2)采用IEEE802.15.4规范要求的直接序列扩频方式;   (3)数据速率达250kbit/s码片速率达2MChip/s;   (4)采用o-QPSK调制方式;   (5)超低电流消耗(RX:19.7mA,TX:17.4mA)高接收灵敏度(-99dBm);   (6)抗邻频道干扰能力强(39dB);   (7)内部集成有VCO、LNA、PA以及电源整流器 采用低电压供电(2.1~3.6V);   (8)输出功率编程可控;   (9)IEEE802.15.4MAC层硬件可支持自动帧格式生成、同步插入与检测、16bitCRC校验、电源检测、完全自动MAC层安全保护(CTR,CBC-MAC,CCM);   (10)与控制微处理器的接口配置容易(4总线SPI接口);   (11)采用QLP-48封装,外形尺寸只有77mm。CC2430只需要极少的外围元器件,其典型应用电路如图2所示。它的外围电路包括晶振时钟电路、射频输入/输出匹配电路和微控制器接口电路3个部分。                         芯片本振信号既可由外部有源晶体提供,有晶振1为基于CC2430芯片的ZigBee在智能交通系统中的应用32MHz,晶振2为32.768kHz。射频输入/输出匹配电路主要用来匹配芯片的输入输出阻抗,使其输入输出阻抗为60Ω,同时为芯片内部的PA及LNA提供直流偏置。 CC2430可以通过4线SPI总线(SI、SO、SCLK、CSn)设置芯片的工作模式 并实现读/写缓存数据 读/写状态寄存器等。通过控制FIFO和FIFOP管脚接口的状态可设置发射/接收缓存器。注意:在SPI总接口上进行的地址和数据传输大多是MSB优先的。   CC2420片内有33个16比特状态设置寄存器,在每个寄存器的读/写周期中,SI总线上共有24比特数据,分别为:1比特RAM/寄存器选择位(0:寄存器,1:RAM),1比特读/写控制位(0:写,1:读),6比特地址选择位、16比特数据位。在数据传输过程中CSn必须始终保持低电平。另外,通过CCA管脚状态的设置可以控制清除通道估计,通过SFD管脚状态的设置可以控制时钟/定时信息的输入。这些接口必须与微处理器的相应管脚相连来实现系统射频功能的控制与管理。CC2430先将要传输的数据流进行变换,每个字节被分组为两个符号,每个符号包括4个比特LSB优先传输。每个被分组的符号用32码片的伪随机序列表示,共有16个不同的32码片伪随机序列。经过DSSS扩频变换后,码片速率达到2Mchips/s,此码片序列再经过O-QPSK调制,每个码片被调制为半个周期的正弦波。码片流通过I/Q通道交替传输,两通道延时为半个码片周期。   CC2430为IEEE802.15.4的数据帧格式提供硬件支持。其MAC层的帧格式为 头帧+数据帧+校验帧;PHY层的帧格式为,同步帧+PHY头帧+MAC帧,帧头序列的长度可以通过寄存器的设置来改变。可以采用16位CRC校验来提高数据传输的可靠性。发送或接收的数据帧被送入RAM中的128字节的缓存区进行相应的帧打包和拆包操作。 DS18B20概述 DS18B20是美国DALLAS公司的“单总线”数字温度传感器,它具有结构简单、体积小、功耗低、无须外接元件、用户可自行设定预警上下限温度等特点。“单总线”结构独特而且经济,采用一根I/O数据线既可供电又可传输数据,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。 3引脚封装的DS18B20形如一只三极管,其内部结构如图2所示。主要由四部分组成:64位光刻ROM、温度传感器、非易失性的温度报警触发器和配置寄存器。此外,还有电源检测模块、存储和控制逻辑器、中间结果缓存器和8位循环冗余校验码(CRC)发生器。 ROM中的64位序列号是出厂前被光刻好的,可以看作该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。DS18B20内部的RAM由9个字节的高速缓存器和E2PROM组成,数据先写入高速缓存器,经校验后再传送给E2PROM。通过DS18B20功能命令对RAM进行操作。 DS18B20的测量温度范围为-55℃~125℃,在-10℃~85℃范围内,精度为0.5℃,可编程设定9~12位的分辨率,默认值为12位,转换12位温度信号所需时间为750ms(最大)。检测温度由2字节组成,字节1的高5位S代表符号位,字节0的低4位是小数部分,中间7位是整数部分。 无线测温系统组成及硬件设计 无线测温系统主要可分为基站和无线节点两大部分。每套系统一般只有1个基站,包括微控制器及射频收发单元、显示单元、报警单元、电源模块及接口单元,主要硬件连接。 接口单元是为了方便射频模块和PC的通信,通常可采用RS-232接口、USB接口、以太网接口等,其中,RS-232接口是目前PC与通信工业中应用最广泛的一种串行接口。本文使用RS-232接口,采用MAX3221芯片实现RS-232电平与TTL电平之间的转换。MAX3221是MAXIM公司生产的一种RS-232接口芯片,使用单一电源电压供电,电源电压在3.0~5.5V范围内都可以正常工作。 基站接收到数据后,将温度信息通过数码管(或液晶显示屏)显示出来,根据需要,还可以通过RS-232接口与PC进行通信。为简化系统,本设计直接用CC2430的I0口驱动数码管,但是I0口不具备数据保持能力,需要外接一定大小的上拉电阻,显示方法采用扫描法。采用一个蜂鸣器作为报警装置,当温度超过设定范围时,鸣叫报警。射频天线采用单鞭天线。 无线节点分布在温度采集点,由数字温度传感器DS18B20、射频CC2430、天线及电池组成。在实际应用中,可以有多个无线节点,它们与基站之间通过射频进行无线通信。DS18B20有寄生电源和外部电源两种供电方式,本文采用外部供电方式,VDD引脚直接连接外部电源。DS18B20在空闲时,其D1脚由上拉电阻置为高电平。无线节点的天线根据实际需要可选用单鞭天线,陶瓷天线或PCB印制天线 基于CC2430和DS18B20的无线测温系统工作原理及ZigBee网络   在系统中的工作架构无线温度信号控制系统的管理模式就是集中管理,分级控制,充分利用现有设施,按实际现状先进行单个用户的自适应协调,然后是主干线的协调控制,实现分布式协调的分级控制,最终达到区域控制的系统最优。        基于CC2430和DS18B20的无线测温的系统,系统具有以下几个特点:   (1)整个控制系统的各个模块具有高集成度、高可靠性和低功耗、低成本、体积小等优点,维护保养十分方便,只需更换相应节点即可,避免了传统控制线路本身带来许多麻烦,从而大大减少了设备购置成本,建设安装成本和系统维护成本。   (2)卓越的物理性能,整个网络所使用的无线频率是国际通用的免费频段(2.4~2.48GHzISM),传输的方式是抗干扰能力强的直序扩频方式(DSSS),特别适合在干扰较大的环境中使用。   (3)网络的自组织、自愈能力强,ZigBee的自组织功能:无需人工干预,网络节点能够感知其他节点的存在,并确定连接关系,组成结构化的网络;ZigBee自愈功能:增加或者删除一个节点,节点位置发生变动,节点发生故障等,网络都能够自我修复,并对网络拓扑结构进行相应地调整,无需人工干预,保证整个系统仍然能正常工作。 结束语   通过系统的设计和对于CC2430芯片的使用,感觉到ZigBee无线温度传感网络应用前景非常广阔,CC2430芯片是真正意义上的SOC芯片,使得我们开发ZigBee无线传感网络会更加方便,产品开发周期会大大缩短。 蜂鸣器相关文章:蜂鸣器原理

摩登3咨询:_三菱PLC与CC-Link配置与应用

CC-Link通信原理简介 本文引用地址:http://www.eepw.com.cn/article/201609/303858.htm CC-Link的底层通讯协议遵循RS485。 一般情况下,CC-Link主要采用广播-轮询的方式进行通讯。具体的方式是:主站将刷新数据(RY/RWw)发送到所有从站,与此同时轮询从站1;从站 1对主站的轮询作出响应(RX/RWr),同时将该响应告知其它从站;然后主站轮询从站2(此时并不发送刷新数据),从站2给出响应,并将该响应告知其它从站;依此类推,循环往复。广播-轮询时的数据传输帧格式请参照图2,该方式的数据传输率非常高。 除了广播-轮询方式以外,CC-Link也支持主站与本地站、智能设备站之间的瞬时通讯。从主站向从站的瞬时通讯量为150字节/数据包,由从站向主站的瞬时通讯量为34字节/数据包。瞬时传输时的数据传输帧格式请参照图2,由此可见瞬时传输不会对广播轮询的循环扫描时间造成影响。 CC所有主站和从站之间的通讯进程以及协议都由通讯用LSI-MFP(Mitsubishi Field Network Processor)控制,其硬件的设计结构决定了CC-Link的高速稳定的通讯。 CC-Link网络设置与编程 在基于CC-Link现场总线的应用过程中,最为重要的一部分便是对系统进行通信初始化设置。目前CC-Link通信初始化设置的方法一般有三种,1)采用的是最基本的方法,即通过编程来设置通信初始化参数。2)使用CC-Link通信配置的组态软件GX-Configurator for CC-Link,采用通信初试化设置的方法。该组态软件可以对A系列和QnA系列的PLC进行组态,实现通信参数的设置,整个组态的过程十分简单,但遗憾的是,目前该方法还不支持Q系列的PLC。3)通过CC-Link网络参数来实现通信参数设定。这是Q系列的PLC新增的功能,而A系列和QnA系列PLC并不具备这项功能。整个设置的过程相当方便。只要在GPPW软件的网络配置菜单中,设置相应的网络参数,远程I/O信号就可自动刷新到CPU内存,还能自动设置CC-Link远程元件的初始参数。如果整个CC-Link现场总线系统是由Q系列和64个远程I/O模块构成的,甚至不须设置网络参数即可自动完成通信设置的初试化。 对Q型PLC来说,利用网络参数设置的方法是最为简单有效的,只要按规定填写一定量的参数之后就能够很好的取代繁冗复杂的顺控程序。在发生错误或是需要修改参数时,同组态软件一样,也能很快地完成,减少设置时间。然而它的不足之处,在于设置过程中跳过了很多重要的细节,从而无法真正掌握PLC的内部的运作过程,比较抽象。例如在填写了众多参数之后,虽然各站的数据链路能正常执行,但是却无法理解这些参数之间是如何联系的,如何作用的,如何使得各站的数据链接得以正常完成。在实际CC-Link的应用中,通过网络参数来进行通信初始化设置的方法不失为一种最为优越的方法,方便、可靠、功能全面这三点就已经很好的满足了系统的需求,缩短了CC-Link现场总线在应用于各种不同的工控场合时设计和调试的时间,降低了工作的难度,更方便了以后的故障检修和维护。遗憾的是它只适用于小Q系列PLC。

C/C++中宏定义的经典运用

在C语言中宏定义是比较有用的技巧,在Linux源码中经常使用一些宏定义,比如宏container_of()等都是经典的宏定义表示方式。在C++不再主张使用宏定义,但是宏定义实际上却是是一个非常有用的手段。实质上宏定义能够搞定的实现采用其它的实现也是可以的,宏定义的作用是简单的替代作用,掌握这个是理解的关键,以前在没有代码阅读量的时候总是以为宏定义就是简单的定义一些常量什么的,实质上不然,宏定义完全可以写成函数的形式,但是宏定义和函数有一定的差别,函数的调用一般采用栈的方式实现,这时候存在局部变量,形参、实参等问题,如果不理解C语言的本质,很多时候非常容易搞错,但是宏定义则不然,宏定义没有调用的过程,宏的实现仅仅是一个替换过程,不用压栈出栈,宏实现的类似函数修改的就是当前区域中的变量,不是局部变量。这也是一些较深层次的问题,在刚学习C语言的时候很多人只要看见类似于函数的形式都认为是函数,实质上不一定,很有可能就是采用宏定义实现的类函数,这时候就可能导致所谓的形参实参问题发生较大的变化。关于宏的问题在面试笔试的过程中、写代码的过程中都是非常有用的部分,我就不再做介绍。 今天看了一遍博客《Reduce C-language coding errors with X macros》,感觉文章写得非常的好,也对自己写代码有了一定的帮助,所以就将该文章用我自己的语言,写出来和大家分享分享吧。 本文引用地址:http://www.eepw.com.cn/article/201612/324488.htm 在嵌入式实时操作系统中,经常将系统分成很多层次,很多个模块,每一个模块都有自己的初始化过程,这时候我们一般采用的形式如下所示: typedef void(*p_func_t)(void); enum { STATE_0, STATE_1, STATE_2, … STATE_M, NUM_STATES }; p_func_t inital_table[NUM_STATES] { func_0, func_1, func_2, … func_M, }; 这种实现方法是比较常见的实现方式,但是这种方法的缺点是所有的初始化过程是按照一定的顺序的,而且不能随机的初始化,因此如果在编码的过程中将状态号与初始化函数对应错误,将出现比较难以发现的错误,这种错误经常出现,当然有些编译器以及支持随机的初始化过程,但是并不具有通用性,而且这种实现方式代码比较多,能不能采用宏定义的方式简化代码量呢?当然是可以的,采用类似于函数的宏定义就可以实现,具体的实现如下: typedef void(*p_func_t)(void); #define STATE_TABLE ENTRY(STATE_0,func_0) ENTRY(STATE_1,func_1) ENTRY(STATE_2,func_2) ENTRY(STATE_3,func_3) ENTRY(STATE_4,func_4) enum{ #define ENTRY(a,b) a, STATE_TABLE #undef ENTRY NUM_STATES }; p_func_t inital_table[NUM_STATES] = { #define ENTRY(a,b) b, STATE_TABLE #undef ENTRY }; 上面这种实现方式的优点是运用了宏定义简少代码量。我做一个简要的分析,首先采用宏定义定义了一组ENYRT,其中包含两个参数,分别是状态号STATE_N,和状态对应的初始化函数,这种实现方式能够避免上面所谓的状态号与函数对应错误的问题,因为在宏定义的过程中一般都会认真的确定各种接口,对应好了只需要定义相关的函数就可以啦。在enum中采用了#define和#undef来限定这一组宏定义的作用范围,在个作用域中,ENTRY(a,b)是表示“a,”,需要注意不能忽略a后的,因为这就是在enum中定义变量后要添加的符号,我想大家应该知道enum{a,b,c,d}每一个成员后面都包含”,”的特性的。也就是说在这作用域中,ENTRY(a,b)被替换为”a,”,那么这时候STATE_TABLE就被替换为STATE_0,STATE_1等,然后和NUM_STATES就组成了第一个例程中的enum结构。而在p_func_t jumptable[NUM_STATES]仍然采用了了STATE_TABLE,由于采用了#define和#undef限定了宏的作用范围,这时的ENTRY(a,b)将被替代为“b,”,也就是func_0,func_1等,这样也就完成了函数指针数组的初始化过程,这样的初始化能够减少状态号与初始化函数对应出错的情况。 这样的实现也可以认为是宏定义的巧妙运用,但是这种方法还是存在一些问题,因为采用#define 和#undef这种方法很可能导致错误的产生,因为很有可能不能很好的把握这个限定作用域的使用方法,这时候可以采用一种新的类似函数的实现方法,可以让STATE_TABLE带一个参数,也就是采用类似命令的形式定义相关的内容: typedef void(*p_func_t)(void); /*以下产生几个常用的命令*/ /*enum产生*/ #define EXPAND_AS_ENUM(a,b) a, /*初始化表产生*/ #define EXPAND_AS_INITTABLE(a,b) b, /*声明各个函数*/ #define EXPAND_AS_FUNCDEC(a,b) void b(void); /*将STATE_TABLE的参数就是具体的命令*/ #define STATE_TABLE(ENTRY) ENTRY(STATE_0,func_0) ENTRY(STATE_1,func_1) ENTRY(STATE_2,func_2) ENTRY(STATE_3,func_3) ENTRY(STATE_4,func_4) /*定义enum*/ enum{ STATE_TABLE(EXPAND_AS_ENUM) NUM_STATES }; /*声明各个函数*/ STATE_TABLE(EXPAND_AS_FUNCDEC) /*初始化表*/ p_func_t inital_table[NUM_STATES] = { STATE_TABLE(EXPAND_AS_INITTABLE) }; 以上实现方法能够较好的避免#define和#undef的限定作用域问题,这实际上采用ENTRY作为参数传递给STATE_TABLE,然后ENTRY可用来实现不同的指令,这些指令的定义也是一系列的宏定义,这种实现架构能够比较好的避免缺少声明等问题。同时也较少了错误的产生可能。 上一页1 2 下一页