• 学习笔记—芯片的启动

    一个芯片启动的时候会执行哪些动作

    06-13 81浏览
  • STM32ADC自身的误差来源剖析

    本文章主要研究影响STM32 ADC模数转换器精度的主要误差来源,为嵌入式开发遇到采样问题时提供一些参考思路。

    06-06 87浏览
  • 如何快速评估一款MCU是否能跑系统RTOS?

    最近有朋友在后台中私信我,说现在做项目的时候有时候总是会考虑要不要用RTOS,或者怎么考量什么时候该用RTOS?

    05-28 4070浏览
  • STM32ADC自身的误差来源剖析

    本文章主要研究影响STM32 ADC模数转换器精度的主要误差来源,为嵌入式开发遇到采样问题时提供一些参考思路。

    05-19 226浏览
  • 清晰明了,一文带你搞懂I2C通信时序!

    I²C是一种串行、半双工通信总线,使用多主从架构,是由Philips公司在1980年代初设计的,主要用于近距离、低速的芯片之间的通信。由于其简单性,它被广泛用于微控制器与传感器阵列,显示器,IoT设备,EEPROM等之间的通信。

    05-15 387浏览
  • 嵌入式开发,要学会高效阅读芯片数据手册

    还记得刚开始做嵌入式的时候,面对芯片数据手册(datasheet)那叫一个头大! 动辄几十页的文档,密密麻麻的术语和图表,简直像天书。 后来我发现很多工程师都有类似的困扰。即便现在我已经用过成百上千种芯片,面对一些“奇葩”数据手册,依然会抓狂。 选芯片和读数据手册,其实可以有章法可循。这篇文章我想分享一下我这些年总结的经验,教你如何快速上手一份数据手册,少走弯路。 我会以 SiC45x 降压 DC/DC 转换芯片为例,带你一步步拆解数据手册的阅读技巧。 从哪里开始读数据手册? 别笑,我的第一步真的是直接翻到典型应用电路(Typical Application Circuit)。 这部分通常是数据手册的“门面担当”,能让你迅速抓住芯片的核心用法。 如果一份数据手册连典型应用电路都没有,我十有八九会直接 Pass 掉这颗芯片! 为什么?因为典型应用电路就像一份“速成指南”,能告诉你: 芯片的基本接法是什么样; 需要多少外部元件; 大概能用在什么场景。 以 SiC45x 的典型应用电路(见图1)为例,它在数据手册的第一页就给了我们不少信息: 图1:SiC45x 典型应用电路 通过这个图,哪怕你对这颗芯片一无所知,也能快速get到: 输入电压范围是 4.5V 到 20V; 没有外部 MOSFET,说明这颗芯片内部集成了功率管(对高功率稳压器来说挺硬核!); 支持 I2C 通信,还能改地址; 有 RT/SYNC 引脚,说明可以调开关频率; 有 ENABLE、PGood、SALRT 等状态引脚,说明可能不依赖 I2C 也能用。 虽然这些信息不足以直接画原理图,但已经足够让你对芯片有个初步印象,是个不错的起点! 例外情况:如果是微控制器(MCU),因为功能太复杂,数据手册通常不会有完整的典型应用电路,而是会拆分成几个关键模块的接法,比如去耦电容、晶振、编程接口等。 如果 MCU 数据手册还贴心地附上“最小硬件连接”示意图,那真是良心厂家,值得加分! 别错过两个“描述”部分 数据手册里通常有两个地方会介绍芯片的功能,一个是开头的描述(Description),另一个是稍后几页的操作描述(Operational Description)。这两个部分乍看有点重复,但其实各有侧重。 开头的描述:通常在第一页,像是芯片的“自我介绍”,简明扼要地告诉你这颗芯片是干啥的,适合什么场景。读完这个,你大概就能判断芯片符不符合你的需求。 操作描述:这个部分一般在引脚定义、绝对最大值和框图之后,内容更详细,会把开头的描述再细化一遍,还会分模块讲解芯片的各个功能块。 图2:SiC45x 数据手册的两种描述 以 SiC45x 为例(见图2),开头的描述让你快速了解芯片是个降压转换器,支持 I2C 控制,而操作描述则会进一步拆解每个功能模块,比如开关频率设置、I2C 通信协议等。 建议:选芯片时可以先快速扫一眼这两个部分,设计原理图时再反复回来查操作描述里的公式和设置方法。 绝对最大值:设计的安全底线 看完典型应用电路和描述,我会直接跳到绝对最大值(Absolute Maximum Ratings)和推荐工作条件(Recommended Operating Conditions)。这两部分是芯片的“红线”,告诉你芯片能承受的极限和建议的工作范围。 图3:SiC45x 绝对最大值表格 以 SiC45x 的绝对最大值(见图3)为例: 最大输入电压是 28V,但推荐工作电压只有 20V。这意味着你不能直接用 24V 电源供电,但如果有上游的过压保护(比如钳位到 24V),20V 是可以安全使用的。 还会列出每个引脚的最大电压和电流,方便你检查设计是否超限。 Tips:绝对最大值是“不能碰的雷区”,但不代表芯片能长期稳定工作在这些极限条件下。推荐工作条件才是你设计时的参考标准! 引脚定义表:设计时的“速查宝典” 了解了芯片的基本功能和电气限制后,我会去看引脚定义表(Pin Description),也叫引脚功能表。这个表格通常在典型应用电路和绝对最大值之间,列出了每个引脚的名称、功能和简单描述。设计电路时,这个表格是我翻得最多的部分,堪称“速查宝典”。 图4:SiC45x 引脚定义表 比如 SiC45x 的引脚定义表(见图4),我们能快速知道 RT/SYNC 引脚是用来设置开关频率的。但具体用多大的电阻对应什么频率?这时需要翻到操作描述里的“RT/SYNC 引脚和开关模式配置”部分,里面会有详细的电阻值表格(见图5)。 图5:SiC45x 开关频率设置表格 功能框图:深入理解芯片内部 几乎所有数据手册都会有个功能框图(Functional Block Diagram),展示芯片的内部结构。SiC45x 的框图如图6所示: 图6:SiC45x 功能框图 框图不一定每次都用得上,但关键时刻能帮大忙,比如: 搞清楚不同地(GND)之间的连接方式; 了解芯片的驱动电路类型; 弄明白如何绕过某些功能模块; 看内部电压是怎么生成的。 我通常会在设计后期或者调试时参考框图,尤其是遇到奇怪问题时,它能帮你从芯片内部逻辑去分析。 那些密密麻麻的图表怎么办? SiC45x 数据手册光图表就占了9页!(见图7)说实话,我平时不太会逐一细看这些图表,它们不是我的标准阅读流程。但某些场景下,比如想了解芯片的启动特性或效率曲线,图表还是很有用的。 图7:SiC45x 数据手册中的图表页 建议:除非有特殊需求(比如分析启动时间或热性能),可以先跳过图表,专注前面的核心内容。 PCB 布局建议:参考但别盲从 SiC45x 数据手册有个亮点:整整三页的 PCB 布局建议!(见图8)这在数据手册里算少见,尤其对开关电源这种对布局敏感的芯片,布局建议特别重要。 图8:SiC45x PCB 布局建议 不过,我得提醒一句:别把布局建议当“圣经”。厂家提供的建议通常是通用的,实际设计中你可能需要根据具体情况调整。比如,SiC45x 的布局建议里提到电源和地平面怎么布,但图示里有些细节可能不太合理。我的做法是参考这些建议作为起点,然后结合自己的经验优化。 别忘了检查勘误表! 数据手册不是完美的,尤其是刚发布时,难免有印刷错误或遗漏。这些问题通常会在 勘误表 部分修正,列在数据手册末尾或单独文档里。Errata 还可能指出芯片本身的硬件问题,比如某个引脚功能有 Bug,未来版本会修复。 Tips: 一定要用最新版数据手册,直接从厂家官网下载。 尤其是 MCU,勘误表可能单独发布,设计前务必查阅。 总结:从“天书”到“工具书” 读数据手册就像啃一本技术“天书”,但只要掌握方法,就能把它变成你的“工具书”。通过 SiC45x 的例子,我分享了我的阅读流程: 先看典型应用电路,快速了解芯片用法; 读两个描述部分,抓住芯片的核心功能; 检查绝对最大值和推荐工作条件,确保设计安全; 熟读引脚定义表,设计时反复参考; 必要时看功能框图和图表,解决疑难问题; 参考 PCB 布局建议,但灵活调整; 别忘了检查勘误表,避免踩坑。 希望这些经验能让你下次面对数据手册时信心满满!如果你有其他读数据手册的技巧,欢迎在评论区分享,咱们一起进步!

    05-13 288浏览
  • 嵌入式程序的链接和装入

    将目标文件中的各个逻辑段链接起来形成装配模块的工作,由链接脚本文件完成,将装配块装入相应内存区的工作由装入程序

    05-07 269浏览
  • 一文搞懂ARM处理器架构

    1、嵌入式处理器基础 典型的微处理器由控制单元、程序计数器(PC)、指令寄存器(IR)、数据通道、存储器等组成 。 指令执行过程一般分为: 取指: 从存储器中获得下一条执行的指令读入指令寄存器; PC: 程序计数器, 总是指向下一条将要执行的指令; IR: 指令寄存器,用于保持已取得指令;如图: 译码: 解释指令,决定指令的执行意义;如图: 执行: 从存储器向数据通道寄存器移动数据; 通过算术逻辑单元ALU进行数据操作;如图: 存储: 从寄存器向存储器写数据。如图: 在一些微处理器上,如ARM系列处理器、DSP等,指令实现流水线作业,指令过程按流水线的数目来进行划分。如5级流水线的处理器将指令分5个阶段执行。 (1)按存储结构分:冯·诺依曼体系结构和哈佛体系结构 冯·诺伊曼结构也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。 处理器,经由同一个总线传输来访问程序和数据存储器,程序指令和数据的宽度相同。如X86系列、ARM7等,如图: 哈佛结构是一种将程序指令存储和数据存储分开的存储器结构,目的是为了减轻程序运行时的访存瓶颈。哈佛结构的微处理器通常具有较高的执行效率。 Microchip公司的PIC系列芯片,摩托罗拉公司的MC68系列、Zilog公司的Z8系列、ATMEL公司的AVR系列和ARM公司的ARM9、ARM10和ARM11 等。如图: 按指令类型可分为:复杂指令集(CISC)处理器和精简指令集(RISC)处理器 。 CISC:复杂指令集(Complex Instru ction Set Computer); 具有大量的指令和寻址方式,那么就需要更多的解释器。 8/2原则:80%的程序只使用20%的指令; 大多数程序只使用少量的指令就能够运行。 CISC具有如下显著特点: (1) 指令格式不固定,指令长度不一致,操作数可多可少; (2) 寻址方式复杂多样,以利于程序的编写; (3) 采用微程序结构,执行每条指令均需完成一个微指令序列; (4) 每条指令需要若干个机器周期才能完成,指令越复杂,花费的机器周期越多。 RISC:精简指令集(Reduced Instruction Set Computer):指令数目少,在通道中只包含最有用的指令;执行时间短,确保数据通道快速执行每一条指令;使CPU硬件结构设计变得更为简单;每条指令都采用标准字长。 2、ARM处理器体系架构 ARM即Advanced RISC Machines的缩写。 1985年4月26日,第一个ARM原型在英国剑桥的Acorn计算机有限公司诞生。 20世纪80年代后期,ARM很快开发成Acorn的台式机产品,形成英国的计算机教育基础。 1990年成立了Advanced  RISC Machines Limited。 20世纪90年代,ARM32位嵌人式RISC(Reduced Instruction Set Computer)处理器扩展到世界范围,占据了低功耗、低成本和高性能的嵌入式系统应用领域的领先地位。 目前己经占有75%以上的32位嵌入式产品市场。 32位RISC处理器受到青睐,领先的是ARM嵌入式微处理器系列。 ARM公司虽然只成立20多年,但在1999年因移动电话火爆市场,其32位RISC处理器占市场份额超过了50%,2001年初,ARM公司的32位RISC处理器市场占有率超过了75%。ARM公司是知识产权供应商,是设计公司。由合作伙伴公司来生产各具特色的芯片。 ARM处理器特点: (1)ARM指令是32位定长的(除AArch64架构部分增加指令为64位外) (2)寄存器数量丰富(37个寄存器) (3)普通的Load/Store指令 (4)多寄存器的Load/Store指令 (5)指令的条件执行 (6)单时钟周期中的单条指令完成数据移位操作和ALU操作 (7)通过变种和协处理器来扩展ARM处理器的功能 (8)扩展了16位的Thumb指令来提高代码密度 ARM的命名规则, 大致分成两类类: 基于ARM Architecture版本的“处理器系列”命名规则; 基于ARM Architecture版本的“处理器型号”命名规则。 ARMv6 架构,引进了包括单指令多数据(SIMD)运算在内的一系列新功能。 ARMv6-M 架构,为低成本、高性能设备而设计,向以前由8位设备占主导地位的市场提供32位功能强大的解决方案。如Cortex™-M0和Cortex-M1。 ARMv7架构,所有ARMv7架构处理器都实现了Thumb-2 技术(一个经过优化的16/32位混合指令集),此架构分为3类处理器:Cortex-A -应用处理器、Cortex-R - 实时处理器、Cortex-M - 微控制器。 ARMv8架构,ARMv8-A将64位体系结构支持引入ARM体系结构中,其中包括:64位通用寄存器、SP(堆栈指针)和 PC(程序计数器),64位数据处理和扩展的虚拟寻址,兼容32位处理。 ARMv9架构,最重大的升级在于AI和安全,在兼容ARMv8的基础上,提升了安全性,增加了矢量计算、机器学习和数据信号处理等多方面能力,性能表现也将得到极大幅度的提升。 1)ARM数据类型 (1)双字节(Double-Word):64位 (2)字(Word):在ARM体系结构中,字的长度为32位。 (3)半字(Half-Word):在ARM体系结构中,半字的长度为16位。 (4)字节(Byte):在ARM体系结构中,字节的长度为8位。 2)ARM处理器存储格式 作为32位的微处理器,ARM体系结构所支持的最大寻址空间为4GB。 ARM体系结构可以用两种方法存储字数据,分别为大端模式和小端模式。 大端模式(高地高低):字的高字节存储在低地址字节单元中,字的低字节存储在高地址字节单元中。 3)ARM处理器工作状态 从编程的角度来看,ARM微处理器的工作状态一般ARM和Thumb有两种,并可在两种状态之间切换。 (1)ARM状态:此时处理器执行32位的字对齐ARM指令,绝大部分工作在此状态。 (2)Thumb状态:此时处理器执行16位的半字对齐的Thumb指令。 THUMB指令的特点: THUMB代码所需空间为ARM代码的70%; THUMB代码所使用的指令数比ARM代码多40%; 用32位存储器,ARM代码比THUMB代码快40%; 用16位存储器,THUMB代码比ARM代码快45%; 使用THUMB代码,外部存储器功耗比ARM代码少30% 4)ARM处理器工作模式 5)ARM Cortex-A处理器工作模式 6) Cortex-A寄存器组 34个通用寄存器,包括各种模式下的R0-R14和共用的R15程序计数器(PC),这些寄存器都是32位的。8个状态寄存器,Hyp模式独有一个ELR_Hyp寄存器。 7)程序状态寄存器CPSR和SPSR 和其他处理器一样,ARM有程序状态存储器来配置处理器工作模式和显示工作状态。ARM处理器有两个程序状态寄存器CPSR (Current Program Status Register,当前程序状态寄存器)和SPSR (Saved Program Status Register,备份的程序状态寄存器)。 CPSR可在任何运行模式下被访问,它包括条件标志位、中断禁止位、当前处理器模式标志位以及其他一些相关的控制和状态位。 每一种运行模式下都有一个专用的物理状态寄存器,称为SPSR为状态寄存器。 (1)N(Negative):当用两个补码表示的带符号数进行运算时,N=1表示结果为负,N=0表示结果为正数或零 (2)Z(Zero):Z=1表示运算结果为0,Z=0表示运算结果非零 (3)C(Carry):有4种方法可以设置C的值: 1)加法指令(包括比较指令CMP) 2)当运算产生进位时(无符号数溢出),C=1,否则C=0 3)减法运算(包括比较指令CMP) 4)当运算产生了借位(无符号数溢出),C=0,否则C=1 对于包含移位操作的非加/减运算指令,C为移出值的最后一位。对于其他的非加/减运算指令,C的值通常不变。 (4)V(Overflow):有2种方法设置V的值: 1)对于加/减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出。 2)对于其他的非加减法运算指令,V的值通常不变。 (5)I(Interrupt Request):I=1表示禁止响应irq,I=0表示允许响应 (6)F(Fast Interrupt Request):F=1表示禁止响应fiq,F=0表示允许响应 (7)T(Thumb):T=0表示当前状态位ARM状态,T=1表示为Thumb状态 (8)M4-M0:表示当前处理器的工作模式 8)工作模式的切换条件 (1)执行软中断(SWI)或复位命令(Reset)指令。如果在用户模式下执行SWI指令,CPU就进入管理(Supervisor)模式。 (2)有外部中断发生。如果发生了外部中断,CPU就会进入IRQ或FIQ模式。 (3)CPU执行过程中产生异常。最典型的异常是由于MMU保护所引起的内存访问异常,此时CPU会切换到Abort模式。如果是无效指令,则会进入Undefined模式。 (4)有一种模式是CPU无法自动进入的,这种模式就是System模式,要进入System模式必须由程序员编写指令来实现。要进入System模式只需改变CPSR的模式位为System模式对应的模式位即可。 (5)在任何特权模式下,都可以通过修改CPSR的MODE域来进入其他模式。不过需要注意的是由于修改的CPSR是该模式下的影子CPSR,即SPSR,因此并不是实际的CPSR,所以一般的做法是修改影子CPSR,然后执行一个MOVS指令来恢复执行某个断点并切换到新模式。 3、ARM处理器内存管理 1)什么是内存映射 内存映射指的是在ARM存储系统中,使用内存管理单元(MMU)实现虚拟地址到实际物理地址的映射,如图所示。 2)为什么要内存映射 A32架构的ARM的地址总线为32位,故CPU可寻址范围为0x00000000~0xffffffff寻址空间为4GB,所有的内部和外部存储或者外设单元都需要通过对应的地址来操作,不同芯片外设的种类数量寻址空间都不一样,为了能让内核更方便的管理不同的芯片设计,ARM内核会先给出预定义的存储映射。 芯片设计公司需要根据内核提供的预定义的存储器映射来定义芯片内部外设和外部的保留接口,这样做的好处是极大地减少了同一内核不同芯片间地址转化的麻烦(CPU操作统一的虚拟地址,实际物理地址交由MMU管理)。 3)位带操作 (1)什么是位带操作 举个简单的例子,在使用51单片机操作P1.0为低电平时我们知道这背后实际上就是往某个寄存器某个比特位中写1或0的过程,但在CPU操作的过程中每一个地址所对应的都是一个8位字节,怎么实现对其中某一位的直接操作,这就需要位带操作的帮助。 (2)哪些地址可以进行位带操作 上图中有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围(Bit band region),第二个则是片内外设区的最低 1MB 范围。 4)寄存器的地址计算 在ARM中所有的外设地址基本都是挂载在AHB或者APBx总线上,因此我们往往采用基地址+偏移地址+结构体的方式,来快速明了计算某一外设具体寄存器的地址,如图所示。 5)集成外设寄存器访问方法

    04-24 380浏览
  • 终于有人把OPC说清楚了

    一、初识OPC 1996年,微软‌与‌Fisher-Rosement‌、‌Intellution‌、‌Opto 22‌等工业自动化厂商成立‌OPC基金会‌,旨在通过统一接口解决设备互操作性问题‌,同年推出OPC Classic规范。OPC Classic规范基于Microsoft Windows技术,使用COM / DCOM(分布式组件对象模型)在软件组件之间交换数据。规范为访问过程数据、报警和历史数据提供了单独的定义。 OPC Classic主要有三个子规范: 1.OPC Data Access,即我们常说的OPC DA 。OPC DA规范定义了数据交换,包括值、时间和质量信息。 2.OPC Alarms & Events,即OPC AE。OPC AE规范定义了报警和事件类型消息信息的交换,以及变量状态和状态管理。 3.OPC Historical Data Access,即:OPC HDA。OPC HDA规范定义了可应用于历史数据、时间数据的查询和分析的方法。 二、OPCUA诞生 随着以服务为导向的架构的引入,跨平台的数据传输需求,以及大数据量传输的数据安全问题。2008年,OPC基金会发布了OPC统一架构(Unified Architecture),即OPC UA,这是一个独立于平台的面向服务的架构,它集成了现有OPC Classic规范的所有功能。 OPC UA是新一代的OPC标准,通过提供一个完整的,安全和可靠的跨平台的架构,以获取实时和历史数据和时间。OPCUA是目前已经使用的OPC工业标准的补充,提供重要的一些特性,包括如平台独立性,扩展性,高可靠性和连接互联网的能力。现在OPC UA已经成为独立于微软、UNIX或其他的操作系统企业层和嵌入式自动组建之间的桥梁。 作为工业4.0的重要协议之一,OPC UA具体以下特点: 1.统一架构:采用一套优化的基于TCP的统一架构二进制协议进行数据交换;同时支持网络服务(WEB SERVICES)和HTTP。在防火墙中只需打开一个端口即可。集成化的安全机制可确保在互联网上的安全通信。 2.平台开放:OPC UA软件的开发不再依靠和局限于任何特定的操作平台。过去只局限于Windows平台的OPC技术拓展到了Linux、Unix、Mac等各种其它平台。 3.安全通讯:OPC UA支持会话加密、信息签名等安全技术,每个UA的客户端和服务器都要通过OpenSSL证书标识,具有用户身份验证,审计跟踪等安全功能。 4.可扩展性:OPC UA的多层架构提供了一个“面向未来”的框架。诸如新的传输协议、安全算法、编码标准或应用服务等创新技术和方法可以并入OPC UA,同时保持现有产品的兼容性。 三、读写方式 无论是OPC DA还是OPC UA,在读写方式方面都是类似的。OPC读写方式主要有三种,分别是同步方式、异步方式及订阅方式,订阅方式仅针对读取有效。 1、同步方式: 同步方式是指当客户端发送请求后,必须等到服务器响应全部完成后才能返回,期间将一直处于等待状态,因此当多客户端向服务器操作时,客户端程序产生阻塞,同步通讯适用于客户端较少,数据量较小的场合,同步方式的工作流程如下图所示: 2、异步方式:异步方式是指当客户端发送请求后立即返回,不需要等待服务器的响应,可以进行其他操作,当服务器完成响应后会自动通知客户端,因此相对于同步通讯,异步通讯的效率更高,异步方式的工作流程如下图所示: 3、订阅方式:订阅方式在初始化时,就需要订阅相应的通信组Group,这样当服务器的Group组内有数据发生变化时,就会自动刷新客户端数据,客户端只需要向服务器发送一次请求,因此订阅方式的效率是非常高的,订阅方式的工作流程如下图所示: 四、OPC服务器 OPC通信基于服务器-客户端模型,如果要实现OPC通信,首先需要搭建一个OPC服务器环境,这里我们采用比较主流的KepServer软件,硬件采用西门子S7-1200PLC,通过KepServer对接S7-1200,然后作为服务器,可以通过OPCDA或OPCUA进行访问。 1、打开KepServer软件后,通过菜单新建一个项目,然后添加通道,选择驱动,这里我们可以看到支持的各种设备协议,然后按照下图进行操作: 2、添加设备:添加设备按照向导进行添加,这里的型号选择S7-1200,并设置正确的IP地址,其他默认下一步: 3、添加标记组:如果变量较多,可以按照类型创建不同的标记组进行分类: 4、添加标记:标记指的就是OPC变量,直接右击新建标记,然后按照说明填写即可,这里以浮点型为例,就填写DB1.DBD4这种格式,其他的数据类型根据提示编写。 5、保存项目:添加完成之后,直接保存项目,然后通过菜单 >> 运行时 >> 连接实现与PLC之间的连接。 6、监控变量:连接正常之后,通过点击Quick Client进行监控,点击相应的标记点,即可看到通信数值及通信状态,我们很轻松就读取到了PLC的数据。 五、OPC客户端 KepServer可以同时支持OPCDA和OPCUA,接下来我们用OPC客户端软件进行测试。 我们先测试OPCDA,打开FactorySoft OPC Client,点击OPC=>Connect,我们可以很轻松找到KepServer对应的的ServerName,如果不是同一台电脑,需要做DCOM配置。然后我们点击AddItem就可以找到KepServer中所有的变量,点击AddItem,即可进行监控。然后我们再测试一下OPCUA,OPCUA使用UAExpert软件,打开KepServer的OPCUA配置,我们可以看到相关的URL及安全性设置,如果连接不上,可以把安全策略设置为None。我们通过UAExpert来添加一下OPCUA服务器信息,。连接上服务器之后,可以搜到服务器中的OPCUA变量进行实时监控。通过整个过程,相信大家对OPC已经有了一定的了解: OPC最初制定时并不是作为一种通信协议,而是一种通信标准接口。 KepServer并不代表OPC,而是围绕‌OPC标准接口‌构建的一款OPC服务器软件。 OPCUA不再局限于接口标准或通信协议,而是接口标准与通信协议的综合体。 文章中涉及软件可以通过公众号后台回复102进行获取。后续可以通过C#编写对应的OPCDA及OPCUA客户端代码来实现OPC通信。

    04-02 452浏览
  • 单片机程序结构优化

    1、程序的书写结构 虽然书写格式并不会影响生成的代码质量,但是在实际编写程序时还是应该遵循一定的书写规则,一个书写清晰、明了的程序,有利于以后的维护。 在书写程序时,特别是对于While、for、do…while、if…else、switch…case 等语句或这些语句嵌套组合时,应采用“缩格”的书写形式。 2、标识符 程序中使用的用户标识符除要遵循标识符的命名规则以外,一般不要用代数符号(如a、b、x1、y1)作为变量名,应选取具有相关含义的英文单词(或缩写)或汉语拼音作为标识符,以增加程序的可读性,如:count、number1、red、work 等。 3、程序结构 C 语言是一种高级程序设计语言,提供了十分完备的规范化流程控制结构。因此在采用C 语言设计单片机应用系统程序时,首先要注意尽可能采用结构化的程序设计方法,这样可使整个应用系统程序结构清晰,便于调试和维护。 对于一个较大的应用程序,通常将整个程序按功能分成若干个模块,不同模块完成不同的功能。 各个模块可以分别编写,甚至还可以由不同的程序员编写,一般单个模块完成的功能较为简单,设计和调试也相对容易一些。在C 语言中,一个函数就可以认为是一个模块。 所谓程序模块化,不仅是要将整个程序划分成若干个功能模块,更重要的是,还应该注意保持各个模块之间变量的相对独立性,即保持模块的独立性,尽量少使用全局变量等。对于一些常用的功能模块,还可以封装为一个应用程序库,以便需要时可以直接调用。 但是在使用模块化时,如果将模块分成太细太小,又会导致程序的执行效率变低(进入和退出一个函数时保护和恢复寄存器占用了一些时间)。 4、定义常数 在程序化设计过程中,对于经常使用的一些常数,如果将它直接写到程序中去,一旦常数的数值发生变化,就必须逐个找出程序中所有的常数,并逐一进行修改,这样必然会降低程序的可维护性。因此,应尽量当采用预处理命令方式来定义常数,而且还可以避免输入错误。 5、减少判断语句 能够使用条件编译(ifdef)的地方就使用条件编译而不使用if 语句,有利于减少编译生成的代码的长度。 6、表达式 对于一个表达式中各种运算执行的优先顺序不太明确或容易混淆的地方,应当采用圆括号明确指定它们的优先顺序。一个表达式通常不能写得太复杂,如果表达式太复杂,时间久了以后,自己也不容易看得懂,不利于以后的维护。 7、函数 对于程序中的函数,在使用之前,应对函数的类型进行说明,对函数类型的说明必须保证它与原来定义的函数类型一致,对于没有参数和没有返回值类型的函数应加上“void”说明。如果需要缩短代码的长度,可以将程序中一些公共的程序段定义为函数。 如果需要缩短程序的执行时间,在程序调试结束后,将部分函数用宏定义来代替。注意,应该在程序调试结束后再定义宏,因为大多数编译系统在宏展开之后才会报错,这样会增加排错的难度。 8、尽量少用全局变量,多用局部变量 因为全局变量是放在数据存储器中,定义一个全局变量,MCU 就少一个可以利用的数据存储器空间,如果定义了太多的全局变量,会导致编译器无足够的内存可以分配;而局部变量大多定位于MCU 内部的寄存器中,在绝大多数MCU 中,使用寄存器操作速度比数据存储器快,指令也更多更灵活,有利于生成质量更高的代码,而且局部变量所能占用的寄存器和数据存储器在不同的模块中可以重复利用。 9、设定合适的编译程序选项 许多编译程序有几种不同的优化选项,在使用前应理解各优化选项的含义,然后选用最合适的一种优化方式。通常情况下一旦选用最高级优化,编译程序会近乎病态地追求代码优化,可能会影响程序的正确性,导致程序运行出错。 因此应熟悉所使用的编译器,应知道哪些参数在优化时会受到影响,哪些参数不会受到影响。 代码的优化 1、选择合适的算法和数据结构 应熟悉算法语言。将比较慢的顺序查找法用较快的二分查找法或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,这样可以大大提高程序执行的效率。 选择一种合适的数据结构也很重要,比如在一堆随机存放的数据中使用了大量的插入和删除指令,比使用链表要快得多。数组与指针具有十分密切的关系,一般来说指针比较灵活简洁,而数组则比较直观,容易理解。对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。 但是在Keil 中则相反,使用数组比使用的指针生成的代码更短。 2、使用尽量小的数据类型 能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。 当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C 编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。 3、使用自加、自减指令 通常使用自加、自减指令和复合赋值表达式(如a-=1 及a+=1 等)都能够生成高质量的程序代码,编译器通常都能够生成inc 和dec 之类的指令,而使用a=a+1 或a=a-1之类的指令,有很多C 编译器都会生成2~3个字节的指令。 4、减少运算的强度 可以使用运算量小但功能相同的表达式替换原来复杂的的表达式。如下: (1)求余运算 a=a%8; 可以改为: a=a&7; 说明:位操作只需一个指令周期即可完成,而大部分的C 编译器的“%”运算均是调用子程序来完成,代码长、执行速度慢。通常,只要求是求2n 方的余数,均可使用位操作的方法来代替。 (2)平方运算 a=pow(a,2.0); 可以改为: a=a*a; 说明:在有内置硬件乘法器的单片机中(如51 系列),乘法运算比求平方运算快得多,因为浮点数的求平方是通过调用子程序来实现的,在自带硬件乘法器的AVR 单片机中,如ATMega163 中,乘法运算只需2 个时钟周期就可以完成。 即使是在没有内置硬件乘法器的AVR单片机中,乘法运算的子程序比平方运算的子程序代码短,执行速度快。如果是求3 次方,如: a=pow(a,3.0); 更改为: a=a*a*a; 则效率的改善更明显。 (3)用移位实现乘除法运算 a=a*4; b=b/4; 可以改为: a=a<<2; b=b>>2; 说明:通常如果需要乘以或除以2n,都可以用移位的方法代替。在ICCAVR 中,如果乘以2n,都可以生成左移的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。 用移位的方法得到代码比调用乘除法子程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,如: a=a*9 可以改为: a=(a<<3)+a 5、循环 (1)循环语对于一些不需要循环变量参加运算的任务可以把它们放到循环外面,这里的任务包括表达式、函数的调用、指针运算、数组访问等,应该将没有必要执行多次的操作全部集合在一起,放到一个init 的初始化程序中进行。 (2)延时函数 通常使用的延时函数均采用自加的形式: void delay (void){unsigned int i;for (i=0;i<1000;i++); }将其改为自减延时函数:void delay (void){unsigned int i;for (i=1000;i>0;i--); } 两个函数的延时效果相似,但几乎所有的C 编译对后一种函数生成的代码均比前一种代码少1~3 个字节,因为几乎所有的MCU 均有为0转移的指令,采用后一种方式能够生成这类指令。在使用while 循环时也一样,使用自减指令控制循环会比使用自加指令控制循环生成的代码更少1~3 个字母。 但是在循环中有通过循环变量“i”读写数组的指令时,使用预减循环时有可能使数组超界,要引起注意。 (3)while 循环和do…while 循环 用while 循环时有以下两种循环形式: unsigned int i;i=0;while (i<1000){i++; //用户程序}或:unsigned int i;i=1000;do{i--; //用户程序}while (i>0); 在这两种循环中,使用do…while循环编译后生成的代码的长度短于while循环。 6、查表 在程序中一般不进行非常复杂的运算,如浮点数的乘除及开方等,以及一些复杂的数学模型的插补运算,对这些即消耗时间又消费资源的运算,应尽量使用查表的方式,并且将数据表置于程序存储区。 如果直接生成所需的表比较困难,也尽量在启动时先计算,然后在数据存储器中生成所需的表,后面在程序运行直接查表就可以了,减少了程序执行过程中重复计算的工作量。 7、其它 比如使用在线汇编及将字符串和一些常量保存在程序存储器中,均有利于优化。 乘除法优化 目前单片机的市场竞争很激烈,许多应用出于性价比的考虑,选择使用程序存储空间较小(如1K,2K)的小资源8位MCU芯片进行开发。一般情况下,这类MCU没有硬件乘法、除法指令,在程序必须使用乘除法运算时,如果单纯依靠编译器调用内部函数库来实现,常常会有代码量偏大、执行效率偏低的缺点。 上海晟矽微电子推出的MC30、MC32系列MCU,采用了RISC架构,在小资源8位MCU领域有广大的用户群和广泛的应用,本文就以晟矽微电的这两个系列产品的指令集为例,结合汇编与C编译平台,给大家介绍一种既省时又节约资源的乘除法算法。 1、乘法篇 单片机中的乘法是二进制的乘法,也就是把乘数的各个位与被乘数相乘,然后再相加得出,因为乘数和被乘数都是二进制,所以实际编程时每一步的乘法可以用移位实现。 例如:乘数R3=01101101,被乘数R4=11000101,乘积R1R0。步骤如下: 1、清空乘积R1R0; 2、乘数的第0位是1,那被乘数R4需要乘上二进制数1,也就是左移0位,加到R1R0里; 3、乘数的第1位是0,忽略; 4、乘数的第2位是1,那被乘数R4需要乘上二进制数100,也就是左移2位,加到R1R0里; 5、乘数的第3位是1,那被乘数R4需要乘上二进制数1000,也就是左移3位,加到R1R0里; 6、乘数的第4位是0,忽略; 7、乘数的第5位是1,那被乘数R4需要乘上二进制数100000,也就是左移5位,加到R1R0里; 8、乘数的第6位是1,那被乘数R4需要乘上二进制数1000000,也就是左移6位,加到R1R0里; 9、乘数的第7位是0,忽略; 10、这时候R1R0里的值就是最后的乘积,至此算法完成。 以上例子运算结果: R1R0 = R3 * R4= (R4<<6)+(R4<<5)+(R4<<3)+(R4<<2)+R4 = 101001111100001 实际运算流程图见下图: 在实际的程序设计过程中,程序优化有两个目标,提高程序运行效率,和减少代码量。我们来看下本文提供的汇编算法和普通C语言编程的效率和代码量对比。 表1.1是程序运行效率的对比数据(可能会有小的偏差),很明显汇编编译出来的运行时间要比C语言减少很多。 汇编(时钟周期) C语言(时钟周期) 8*8位乘法 79-87 184-190 16*8位乘法 201-210 362-388 16*16位乘法 234-379 396-468 表1.1  乘法运算时钟周期对比表 表1.2是程序代码量的对比数据(可能会有小的偏差),汇编占用的程序空间也要比C语言小很多。 汇编(Byte) C语言(Byte) 8*8位乘法 15 34 16*8位乘法 19 96 16*16位乘法 31 96 表1.2  乘法运算ROM空间使用情况对比表 综上两点,本文介绍的乘法算法各方面使用情况都要比C编译好很多。如果大家在使用过程中,原有的程序不能满足应用需求,例如遇到程序空间不够或者运行时间太久等问题,都可以按照以上方式进行优化。 汇编语言最接近机器语言的。在汇编语言中可以直接操作寄存器,调整指令执行顺序。由于汇编语言直接面对硬件平台,而不同的硬件平台的指令集及指令周期均有较大差异,这样会对程序的移植和维护造成一定的不便,所以我们针对精简指令集做了乘法运算的例程,便于大家的移植和理解。 2、除法篇 单片机中的除法也是二进制的除法,和现实中数学的除法类似,是从被除数的高位开始,按位对除数进行相除取余的运算,得出的余数再和之后的被除数一起再进行新的相除取余的运算,直到除不尽为止,因为单片机中的除法是二进制的,每个步骤除出来的商最大只有1,所以我们实际编程时可以把每一步的除法看作减法运算。 例如:被除数R3R4=1100110001101101,除数R5=11000101,商R1R0,余数R2。步骤如下: 1、清空商R1R0,余数R2;2、被除数放开最高位,第15位,为1,1比除数小,商为0,余数R2为1;3、上一步余数并上被除数次高位,第14位,得11,11仍然比除数小,商为0,余数R2为114、直到放开第8位后,得11001100,比除数大,商得1,余数R2为111;5、上一步余数并上被除数第7位,得1110,没有除数大,商为0,余数R2为1110;6、上一步余数并上被除数第6位,得11101,没有除数大,商为0,余数R2为11101;7、按照以上步骤,直到放开了被除数得第3位,得11101101,比除数大,商为1,余数R2为101000;8、上一步余数并上被除数第2位,得1010001,没有除数大,商为0,余数R2为1010001;9、上一步余数并上被除数第1位,得10100010,没有除数大,商为0,余数R2为10100010;10、上一步余数并上被除数第0位,得101000101,比除数大,商为1,余数R2为10000000;11、然后把以上所有步骤中得商从左至右依次排列就是最后的商100001001,余数为最后算得的余数10000000。 以上例子运算结果:R1R0 = R3R4 / R5 = 100001001 ;R2 = R3R4 % R5 = 10000000 实际运算流程图见下图: 除法运算的效率,代码量见以下表格 表2.1是程序运行效率和代码量的对比数据(可能会有小的偏差),很明显本文提供的汇编算法要优化的很多。 16/8位除法 汇编 C语言 时钟周期 287-321 740-804 使用空间(Byte) 35 142 表2.1  除法运算时钟周期对比表 所以对于除法运算,本文提供的方法也是相对较优的。 以下是针对精简指令集做的除法运算,16/8位的例程,便于大家的移植和理解。

    03-14 508浏览
正在努力加载更多...
广告