单片机

单片机主要作用是控制外围的器件,并实现一定的通信和数据处理。但在某些特定场合,不可避免地要用到数学运算,尽管单片机并不擅长实现算法和进行复杂的运算。下面主要是介绍如何用单片机实现数字滤波。

在单片机进行数据采集时,会遇到数据的随机误差,随机误差是由随机干扰引起的,其特点是在相同条件下测量同一量时,其大小和符号会现无规则的变化而无法预测,但多次测量的结果符合统计规律。为克服随机干扰引起的误差,硬件上可采用滤波技术,软件上可采用软件算法实现数字滤波。滤波算法往往是系统测控算法的一个重要组成部分,实时性很强。

采用数字滤波算法克服随机干扰的误差具有以下优点:

1、数字滤波无需其他的硬件成本,只用一个计算过程,可靠性高,不存在阻抗匹配问题。尤其是数字滤波可以对频率很低的信号进行滤波,这是模拟滤波器做不到的。

2、数字滤波使用软件算法实现,多输入通道可共用一个滤波程序,降低系统开支。

3、只要适当改变滤波器的滤波程序或运算,就能方便地改变其滤波特性,这对于滤除低频干扰和随机信号会有较大的效果。

4、在单片机系统中常用的滤波算法有限幅滤波法、中值滤波法、算术平均滤波法、加权平均滤波法、滑动平均滤波等。

(1)限幅滤波算法

该运算的过程中将两次相邻的采样相减,求出其增量,然后将增量的绝对值,与两次采样允许的最大差值A进行比较。A的大小由被测对象的具体情况而定,如果小于或等于允许的最大差值,则本次采样有效;否则取上次采样值作为本次数据的样本。

算法的程序代码如下:

#defineA //允许的最大差值
chardata; //上一次的数据
char filter()
{
chardatanew; //新数据变量
datanew=get_data(); //获得新数据变量
if((datanew-data)>A||(data-datanew>A))
return data;
else
returndatanew;
}

说明:限幅滤波法主要用于处理变化较为缓慢的数据,如温度、物体的位置等。使用时,关键要选取合适的门限制A。通常这可由经验数据获得,必要时可通过实验得到。

(2)中值滤波算法

该运算的过程是对某一参数连续采样N次(N一般为奇数),然后把N次采样的值按从小到大排列,再取中间值作为本次采样值,整个过程实际上是一个序列排序的过程。

算法的程序代码如下:

#define N11 //定义获得的数据个数
char filter()
{
charvalue_buff[N]; //定义存储数据的数组
char count,i,j,temp;
for(count=0;count
{
value_buf[count]=get_data();
delay(); //如果采集数据比较慢,那么就需要延时或中断
}
for(j=0;j
{
for(value_buff[i]>value_buff[i+1]
{
temp=value_buff[i];
value_buff[i]=value_buff[i+1];
value_buff[i+1]=temp;
}
}
returnvalue_buff[(N-1)/2];
}

说明:中值滤波比较适用于去掉由偶然因素引起的波动和采样器不稳定而引起的脉动干扰。若被测量值变化比较慢,采用中值滤波法效果会比较好,但如果数据变化比较快,则不宜采用此方法。

(3)算术平均滤波算法

该算法的基本原理很简单,就是连续取N次采样值后进行算术平均。

算法的程序代码如下:

char filter()
{
int sum=0;
for(count=0;count
{
sum+=get_data();
delay():
}
return (char)(sum/N);
}

说明:算术平均滤波算法适用于对具有随机干扰的信号进行滤波。这种信号的特点是有一个平均值,信号在某一数值附近上下波动。信号的平均平滑程度完全到决于N值。当N较大时,平滑度高,灵敏度低;当N较小时,平滑度低,但灵敏度高。为了方便求平均值,N一般取4、8、16、32之类的2的整数幂,以便在程序中用移位操作来代替除法。

(4)加权平均滤波算法

由于前面所说的“算术平均滤波算法”存在平滑度和灵敏度之间的矛盾。为了协调平滑度和灵敏度之间的关系,可采用加权平均滤波。它的原理是对连续N次采样值分别乘上不同的加权系数之后再求累加,加权系数一般先小后大,以突出后面若干采样的效果,加强系统对参数变化趋势的认识。各个加权系数均小于1的小数,且满足总和等于1的结束条件。这样加权运算之后的累加和即为有效采样值。设D为N个采样值的加权平均值:XN-i为第N-i次采样值;N为采样次数;Ci为加权系数。加权系数Ci体现了各种采样值在平均值中所占的比例。一般来说采样次数越靠后,取的比例越大,这样可增加新采样在平均值中所占的比重。加权平均值滤波法可突出一部分信号抵制另一部分信号,以提高采样值变化的灵敏度。

样例程序代码如下:

char codejq[N]={1,2,3,4,5,6,7,8,9,10,11,12}; //code数组为加权系数表,存在程序存储区
char codesum_jq=1+2+3+4+5+6+7+8+9+10+11+12;
char filter()
{
char count;
char value_buff[N];
int sum=0;
for(count=0;count
{
value_buff[count]=get_data();
delay();
}
for(count=0;count
sum+=value_buff[count]*jq[count];
return(char)(sum/sum_jq);
}

(5)滑动平均滤波算法

以上介绍和各种平均滤波算法有一个共同点,即每获取一个有效采样值必须连续进行若干次采样,当采速度慢时,系统的实时得不到保证。这里介绍的滑动平均滤波算法只采样一次,将一次采样值和过去的若干次采样值一起求平均,得到的有效采样值即可投入使用。如果取N个采样值求平均,存储区中必须开辟N个数据的暂存区。每新采集一个数据便存入暂存区中,同时去掉一个最老数据,保存这N个数据始终是最新更新的数据。采用环型队列结构可以方便地实现这种数据存放方式。

程序代码如下:

char value_buff[N];
char i=0;
char filter()
{
char count;
int sum=0;
value_buff[i++]=get_data();
if(i==N)
i=0;
for(count=0;count
sum=value_buff[count];
return (char)(sum/N);
}

(6)低通滤波

将普通硬件RC低通滤波器的微分方程用差分方程来表求,变可以采用软件算法来模拟硬件滤波的功能,经推导,低通滤波算法如下:

Yn=a* Xn+(1-a) *Yn-1

式中 Xn——本次采样值

Yn-1——上次的滤波输出值;

,a——滤波系数,其值通常远小于1;

Yn——本次滤波的输出值。

由上式可以看出,本次滤波的输出值主要取决于上次滤波的输出值(注意不是上次的采样值,这和加权平均滤波是有本质区别的),本次采样值对滤波输出的贡献是比较小的,但多少有些修正作用,这种算法便模拟了具体有教大惯性的低通滤波器功能。滤波算法的截止频率可用以下式计算:

fL=a/2Pit pi为圆周率3.14…

式中 a——滤波系数;

, t——采样间隔时间;

例如:当t=0.5s(即每秒2次),a=1/32时;

fL=(1/32)/(2*3.14*0.5)=0.01Hz

当目标参数为变化很慢的物理量时,这是很有效的。另外一方面,它不能滤除高于1/2采样频率的干搅信号,本例中采样频率为2Hz,故对1Hz以上的干搅信号应采用其他方式滤除,低通滤波算法程序于加权平均滤波相似,但加权系数只有两个:a和1-a。为计算方便,a取一整数,1-a用256-a,来代替,计算结果舍去最低字节即可,因为只有两项,a和1-a,均以立即数的形式编入程序中,不另外设表格。虽然采样值为单元字节(8位A/D)。为保证运算精度,滤波输出值用双字节表示,其中一个字节整数,一字节小数,否则有可能因为每次舍去尾数而使输出不会变化。

设Yn-1存放在30H(整数)和31H(小数)两单元中,Yn存放在32H(整数)和33H(小数)中。

小结一下吧:数字滤波器,说白了,就是多次采样求平均值的一个过程,精确一点的,就是再顺序排列,去掉首位再求平均值,就是求平均数!!

本文转自:玩转单片机,转载此文目的在于传递更多信息,版权归原作者所有。

围观 188

影响单片机系统可靠安全运行的主要因素主要来自系统内部和外部的各种电气干扰,并受系统结构设计、元器件选择、安装、制造工艺影响。这些都构成单片机系统的干扰因素,常会导致单片机系统运行失常,轻则影响产品质量和产量,重则会导致事故,造成重大经济损失。

形成干扰的基本要素有三个:

(1)干扰源。指产生干扰的元件、设备或信号。如:雷电、继电器、可控硅、电机、高频时钟等都可能成为干扰源。

(2)传播路径。指干扰从干扰源传播到敏感器件的通路或媒介。典型的干扰传播路径是通过导线的传导和空间的辐射。

(3)敏感器件。指容易被干扰的对象。如:A/D、 D/A变换器,单片机,数字IC,弱信号放大器等。

1、干扰的耦合方式

(1)直接耦合:

这是最直接的方式,也是系统中存在最普遍的一种方式。比如干扰信号通过电源线侵入系统。对于这种形式,最有效的方法就是加入去耦电路。

(2)公共阻抗耦合:

这也是常见的耦合方式,这种形式常常发生在两个电路电流有共同通路的情况。为了防止这种耦合,通常在电路设计上就要考虑。使干扰源和被干扰对象间没有公共阻抗。

(3)电容耦合:

又称电场耦合或静电耦合。是由于分布电容的存在而产生的耦合。

(4)电磁感应耦合:

又称磁场耦合。是由于分布电磁感应而产生的耦合。

(5)漏电耦合:

这种耦合是纯电阻性的,在绝缘不好时就会发生。

2、常用硬件抗干扰技术

针对形成干扰的三要素,采取的抗干扰主要有以下手段。

2.1、抑制干扰源

抑制干扰源就是尽可能的减小干扰源的du/dt, di/dt。这是抗干扰设计中最优先考虑和最重要的原则,常常会起到事半功倍的效果。 减小干扰源的du/dt主要是通过在干扰源两端并联电容来实现。减小干扰源的di/dt则是在干扰源回路串联电感或电阻以及增加续流二极管来实现。

抑制干扰源的常用措施如下:

(1)继电器线圈增加续流二极管,消除断开线圈时产生的反电动势干扰。仅加续流二极管会使继电器的断开时间滞后,增加稳压二极管后继电器在单位时间内可动作更多的次数。

(2)在继电器接点两端并接火花抑制电路(一般是RC串联电路,电阻一般选几K到几十K,电容选0.01uF),减小电火花影响。

(3)给电机加滤波电路,注意电容、电感引线要尽量短。

(4)电路板上每个IC要并接一个0.01μF~0.1 μF高频电容,以减小IC对电源的影响。注意高频电容的布线,连线应靠近电源端并尽量粗短,否则,等于增大了电容的等效串联电阻,会影响滤波效果。

(5)布线时避免90度折线,减少高频噪声发射。

(6)可控硅两端并接RC抑制电路,减小可控硅产生的噪声(这个噪声严重时可能会把可控硅击穿的)。

2.2、切断干扰传播路径

按干扰的传播路径可分为传导干扰和辐射干扰两类。

所谓传导干扰是指通过导线传播到敏感器件的干扰。高频干扰噪声和有用信号的频带不同,可以通过在导线上增加滤波器的方法切断高频干扰噪声的传播,有时也可加隔离光耦来解决。电源噪声的危害最大,要特别注意处理。

所谓辐射干扰是指通过空间辐射传播到敏感器件的干扰。一般的解决方法是增加干扰源与敏感器件的距离,用地线把它们隔离和在敏感器件上加屏蔽罩。

切断干扰传播路径的常用措施如下:

(1)充分考虑电源对单片机的影响。电源做得好,整个电路的抗干扰就解决了一大半。许多单片机对电源噪声很敏感,要给单片机电源加滤波电路或稳压器,以减小电源噪声对单片机的干扰。比如,可以利用磁珠和电容组成π形滤波电路,当然条件要求不高时也可用100Ω电阻代替磁珠。

(2)如果单片机的I/O口用来控制电机等噪声器件,在I/O口与噪声源之间应加隔离(增加π形滤波电路)。

(3)注意晶振布线。晶振与单片机引脚尽量靠近,用地线把时钟区隔离起来,晶振外壳接地并固定。

(4)电路板合理分区,如强、弱信号,数字、模拟信号。尽可能把干扰源(如电机、继电器)与敏感元件(如单片机)远离。

(5)用地线把数字区与模拟区隔离。数字地与模拟地要分离,最后在一点接于电源地。A/D、D/A芯片布线也以此为原则。

(6)单片机和大功率器件的地线要单独接地,以减小相互干扰。大功率器件尽可能放在电路板边缘。

(7)在单片机I/O口、电源线、电路板连接线等关键地方使用抗干扰元件如磁珠、磁环、电源滤波器、屏蔽罩,可显著提高电路的抗干扰性能。

2.3、提高敏感器件的抗干扰性能

提高敏感器件的抗干扰性能是指从敏感器件这边考虑尽量减少对干扰噪声的拾取,以及从不正常状态尽快恢复的方法。

提高敏感器件抗干扰性能的常用措施如下:

(1)布线时尽量减少回路环的面积,以降低感应噪声。

(2)布线时,电源线和地线要尽量粗。除减小压降外,更重要的是降低耦合噪声。

(3)对于单片机闲置的I/O口,不要悬空,要接地或接电源。其它IC的闲置端在不改变系统逻辑的情况下接地或接电源。

(4)对单片机使用电源监控及看门狗电路,如: IMP809,IMP706,IMP813, X5043,X5045等,可大幅度提高整个电路的抗干扰性能。

(5)在速度能满足要求的前提下,尽量降低单片机的晶振和选用低速数字电路。

(6)IC器件尽量直接焊在电路板上,少用IC座。

2.4、其它常用抗干扰措施

(1)交流端用电感电容滤波:去掉高频低频干扰脉冲。

(2)变压器双隔离措施:变压器初级输入端串接电容,初、次级线圈间屏蔽层与初级间电容中心接点接大地,次级外屏蔽层接印制板地,这是硬件抗干扰的关键手段。次级加低通滤波器:吸收变压器产生的浪涌电压。

(3)采用集成式直流稳压电源: 有过流、过压、过热等保护作用。

(4)I/O口采用光电、磁电、继电器隔离,同时去掉公共地。

(5)通讯线用双绞线:排除平行互感。

(6)防雷电用光纤隔离最为有效。

(7)A/D转换用隔离放大器或采用现场转换:减少误差。

(8)外壳接大地:解决人身安全及防外界电磁场干扰。

(9)加复位电压检测电路。防止复位不充分, CPU就工作,尤其有EEPROM的器件,复位不充份会改变EEPROM的内容。

(10)印制板工艺抗干扰:

① 电源线加粗,合理走线、接地,三总线分开以减少互感振荡。

② CPU、RAM、ROM等主芯片,VCC和GND之间接电解电容及瓷片电容,去掉高、低频干扰信号。

③ 独立系统结构,减少接插件与连线,提高可靠性,减少故障率。

④ 集成块与插座接触可靠,用双簧插座,最好集成块直接焊在印制板上,防止器件接触不良故障。

⑤ 有条件的采用四层以上印制板,中间两层为电源及地。

来源:电子产品世界

围观 130

I/O口是单片机与外界联系的通道。它可对各类外部信号(开关量、模拟量、频率信一号)进行检测、判断、处理,并可控制各类外部设备。单片机通过I/O口感知外界的存在,而外界也通过I/O口感知单片机的存在。


现在的单片机I/O口已经集成了更多的特性和功能。因此,在学习某一款单片机时,需要先了解其I/O口具有哪些特性和特殊的应用功能(不同的单片机是有所差别的),并因地制宜设计外围电路、编写控制软件,充分发挥该I/O口的优势。


1. 输入/输出概念

大多数I/O口都是双向三态的。根据具体应用情况,可以分为输入口和输出口。输人口用来读取外部输人的电平信号,输出口则用于对外输出一个电平信号。

有些单片机(如PIC)允许设置I/O口的输入/输出状态。这样做的好处是可以让I/O口适应更多的应用环境:当I/O口处于输入状态时,对外表现为“高阻态”;而当I/O口处于输出状态时,对外可以提供更大的灌电流或拉电流,这样可以直接驱动一些如LED之类的负载。无需再外扩驱动电路了。

2. 输入门槛电平

对于51系列单片机来说,输入电平低于0.7V就是低电平,高于1. 8 V就是高电平。如果输入的电平介于二者之间,那么CPU在读取该I/O口时可能会得到一个不确定的错误数据。一般来说,我们不希望输入口上出现这种模棱两可的电平状态(除非那个口是ADC检测口)。

3. 最大输出电流

这个特性是针对输出来讲的。最大输出电流包括两种:灌电流和拉电流。灌电流是指当I/O口输出“0”(低电平)时允许灌人(流入)该I/O口的电流;拉电流则是指当I/O口输出“1"(高电平)时允许流出的电流。

4. 输出电平

这个特性是也针对输出来讲的,包括两种:“0”(低电平电压)和“1"(高电平电压)。理想状态上来说,输出高电平应该等于单片机的工作电压Vcc。但是实际由于内阻的关系,输出高电平会略低于Vcc。尤其是当拉电流较大时,高电平会被进一步拉低。同样的道理,输出低电平也往往不是正好等于0V,而是有可能比0V高出一点。

5. I/O口附加功能

许多单片机都为I/O口集成了许多新的功能控制,包括内部上拉/下拉电阻功能、R-op-TION功能以及漏极(或集电极)开路功能。如果能够合理地使用这些功能,就可以简化外围工作电路。

6. I/O口功能的拓展与复用

包括中断、唤醒、ADC检测以及PWM输出等。

本文转自:电工学习网,转载此文目的在于传递更多信息,版权归原作者所有。

围观 75

LED数码显示器的连接与编程

在单片机系统中,通常用LED数码显示器来显示各种数字或符号。由于它具有显示清晰、亮度高、使用电压低、寿命长的特点,因此使用非常广泛。

八段LED显示器

引入:还记得我们小时候玩的“火柴棒游戏”吗,几根火柴棒组合起来,可以拼成各种各样的图形,LED显示器实际上也是这么一个东西。


八段LED显示器由8个发光二极管组成。基中7个长条形的发光管排列成“日”字形,另一个贺点形的发光管在显示器的右下角作为显示小数点用,它能显示各种数字及部份英文字母。

LED显示器有两种不同的形式:一种是8个发光二极管的阳极都连在一起的,称之为共阳极LED显示器;另一种是8个发光二极管的阴极都连在一起的,称之为共阴极LED显示器。

共阴和共阳结构的LED显示器各笔划段名和安排位置是相同的。当二极管导通时,相应的笔划段发亮,由发亮的笔划段组合而显示的各种字符。

8个笔划段hgfedcba对应于一个字节(8位)的D7 D6 D5 D4 D3 D2 D1 D0,于是用8位二进制码就可以表示欲显示字符的字形代码。例如,对于共阴LED显示器,当公共阴极接地(为零电平),而阳极hgfedcba各段为0111011时,显示器显示"P"字符,即对于共阴极LED显示器,“P”字符的字形码是73H。如果是共阳LED显示器,公共阳极接高电平,显示“P”字符的字形代码应为10001100(8CH)。

这里必须注意的是:很多产品为方便接线,常不按规则的方法去对应字段与位的关系,这时字形码就必须根据接线来自行设计了,后面我们会给出一个例子。

1、静态显示接口

在单片机应用系统中,显示器显示常用两种方法:静态显示和动态扫描显示。所谓静态显示,就是每一个显示器都要占用单独的具有锁存功能的I/O接口用于笔划段字形代码。这样单片机只要把要显示的字形代码发送到接口电路,就不用管它了,直到要显示新的数据时,再发送新的字形码,因此,使用这种方法单片机中CPU的开销小。

可以提供单独锁存的I/O接口电路很多,这里以常用的串并转换电路74LS164为例,介绍一种常用静态显示电路,以使大家对静态显示有一定的了解。MCS-51单片机串行口方式押为移们寄存器方式,外接6片74LS164作为6位LED显示器的静态显示接口,把8031的RXD作为数据输出线,TXD作为移位时钟脉冲。74LS164为TTL单向8位移位寄存器,可实现串行输入,并行输出。其中A、B(第1、2脚)为串行数据输入端,2个引脚按逻辑与运算规律输入信号,公一个输入信号时可并接。T(第8脚)为时钟输入端,可连接到串行口的TXD端。每一个时钟信号的上升沿加到T端时,移位寄存器移一位,8个时钟脉冲过后,8位二进制数全部移入74LS164中。R(第9脚)为复位端,当R=0时,移位寄存器各位复0,只有当R=1时,时钟脉冲才起作用。Q1…Q8(第3-6和10-13引脚)并行输出端分别接LED显示器的hg---a各段对应的引脚上。

关于74LS164还可以作如下的介绍:所谓时钟脉冲端,其实就是需要高、低、高、低的脉冲,不管这个脉冲是怎么来的,比如,我们用根电线,一端接T,一端用手拿着,分别接高电平、低电平,那也是给出时钟脉冲,在74LS164获得时钟脉冲的瞬间(再讲清楚点,是在脉冲的沿),如果数据输入端(第1,2引脚)是高电平,则就会有一个1进入到74LS164的内部,如果数据输入端是低电平,则就会有一个0进入其内部。在给出了8个脉冲后,最先进入74LS164的第一个数据到达了最高位,然后再来一个脉冲会有什么发生呢?再来一个脉冲,第一个脉冲就会从最高位移出,就象车站排队买票,栏杆就那么长,要从后面进去一个人,前面必须要从前面走出去一个人才行。

搞清了这一点,下面让我们来看电路,6片7LS164首尾相串,而时钟端则接在一起,这样,当输入8个脉冲时,从单片机RXD端输出的数据就进入到了第一片74LS164中了,而当第二个8个脉冲到来后,这个数据就进入了第二片74LS164,而新的数据则进入了第一片74LS164,这样,当第六个8个脉冲完成后,首次送出的数据被送到了最左面的164中,其他数据依次出现在第一、二、三、四、五片74LS164中。有个问题,在第一个脉冲到来时,除了第一片74LS164中接收数据外,其他各片在干吗呢?它们也在接收数据,因为它们的时钟端都是被接在一起的,可是数据还没有送到其他各片呢,它们在接收什么数据呢?。。。。。。其实所谓数据不过是一种说法而已,实际就是电平的高低,当第一个脉冲到来时,第一片164固然是从单片机接收数据了,而其它各片也接到前一片的Q8上,而Q8是一根电线,在数字电路中它只可能有两种状态:低电平或高电平,也就是“0”和“1”。所以它的下一片74LS164也相当于是在接收数据啊。只是接收的全部是0或1而已。这个问题放在这儿说明,可能有朋友不屑一顾,而有的朋友可能还是不清楚,这实际上涉及到数的本质的问题,如果不懂的,请仔细思考,并找一些数字电路的数,理解164的工作原理,再来看这个问题。务必搞懂,搞懂了这一点,你的级别就高过初学者了。


入口:把要显示的数分别放在显示缓冲区60H-65H共6个单元中,并且分别对应各个数码管LED0-LED5。

出口:将预置在显示缓冲区中的6个数成相应的显示字形码,然后输出到显示器中显示。

显示程序如下:
DISP: MOV SCON,#00H ;初始化串行口方式0
MOV R1,#06H ;显示6位数
MOV R0,#65H ;60H-65H为显示缓冲区
MOV DPTR,#SEGTAB ;字形表的入口地址
LOOP:
MOV A,@R0 ;取最高位的待显示数据
MOVC A,@A+DPTR ;查表获取字形码
MOV SBUF,A ;送串口显示
DELAY: JNB TI,DELAY ;等待发送完毕
CLR TI ;清发送标志
DEC R0 ;指针下移一位,准备取下一个待显示数
DJNZ R1,LOOP ;直到6个数据全显示完。
RET
SETTAB: ;字形表,前面有介绍,以后我们再介绍字形表的制作。
DB 03H 9FH 27H 0DH 99H 49H 41H 1FH 01H 09H 0FFH
; #9; 0 1 2 3 4 5 6 7 8 9 消隐码

测试用主程序
ORG 0000H
AJMP START
ORG 30H
START: MOV SP,#6FH
MOV 65H,#0
MOV 64H,#1
MOV 63H,#2
MOV 62H,#3
MOV 61H,#4
MOV 60H,#5
LCALL DISP
SJMP $

如果按图示数码管排列,则以上主程序将显示的是543210,想想看,如果要显示012345该怎样送数?

下面我们来分析一下字形表的制作问题。先就上述“标准”的图形来看吧。写出数据位和字形的对应关系并列一个表如下(设为共阳型,也就是相应的输出位为0时笔段亮)


如何,字形表会做了吧,就是这样列个表格,根据要求(0亮或1亮)写出相应位的0和1,就成了。做个练习,写出A-F的字形码吧。

如果为了接线方便而打乱了接线的顺序,那么字形表又该如何接呢?也很简单,一样地列表啊。以新实验板为例,共阳型。接线如下:
P0.7 P0.6 P0.5 P0.4 P0.3 P0.2 P0.1 P0.0
C E H D G F A B

则字形码如下所示:
;0 00101000 28H
;1 01111110 7EH
;2 10100100 0A4H
;3 01100100 64H
;4 01110010 72H
;5 01100001 61H
;6 00100001 21H
;7 01111100 7CH
;8 00100000 20H
;9 01100000 60H

作为练习,大家写出A-F的字形代码。

本来这里是讲解显示器的静态接口的,到此应当可算结束了,但是我还想接着上面讲到的数的本质的问题再谈一点。单片机中有一些术语、名词本来是帮助我们理解事物的,但有时我们会被这些术语的相关语义所迷惑,以致不能进一步认清他们的本质,由此往往陷入困惑的境界。只有深入地了解了74LS164的工作特性,才能真正理解何谓串行的数据。

本文来源网络,版权归原作者所有。

围观 65

PLC底层,实际就是单片机在运行,它只不过是基于单片机的基础,开发出来的一款二次应用的工业逻辑控制器,方便具有电工思维的用户来使用,所以PLC对比单片机的最大优势就是简单易用。PLC既然是基于单片机来开发的,PLC所有功能,单片机肯定可以都做到,比如一些计时,计数,中断,模拟量处理,通讯,逻辑控制,这些单片机都可以实现,而且响应速度上比PLC还要快很多,精度也会比PLC高。

但是PLC使用了扫描周期来避免立刻刷新I/O端口状态,这点从软件而言,牺牲了速度,可靠性却强了很多,用户无论如何编程刷写程序,一般都不会发生死机等问题。毕竟大多数工业场合,往往毫秒级别的响应就足够了,并不需要非常高速的实时控制。而单片机虽然编程更加灵活,但是对编程人员要求太高了,稍微有差错,就可能会造成一些死循环或者逻辑不正常。

PLC硬件电路,一般电源会考虑到工业电网污染问题,在稳压滤波上做了很多设计。输入输出回路,往往也会使用光耦来隔离,电路元件选型都严格要求工业级别的,电路板布线也会考虑到干扰问题,PCB板子也会加涂层之类保护。而单片机,往往从商用民用角度去选型和设计,可靠性没有PLC的高,电子元件也未必像工业那样严格选择,整体的可靠性不如PLC。对于工业场所,产品的稳定可靠性,还有耐用性,是非常重要的,毕竟工业设备价值比较贵重,需要长期24小时不断电运转,很多会连续工作十多年。

PLC简单易学易用

单片机太麻烦,首先要有一定的电子电路基础,往往软件和硬件人员还分开,但是你要编写软件,一般也要知道一些硬件的东西,这个对于一般的工控人员而言,是比较费劲的,毕竟电气和电子还是有一定差距的。如果针对某款工业设备来开发一款单片机控制板,也不是三天两头就可以制作好的,涉及到选型和调试等问题,稳定下来还真需要一段时间。

单片机早期使用汇编语言,现在虽然进步了,基本上可以使用C语言编程了,但是C语言是面向过程的语言,一般人学习起来段期间也是不太好掌握的。即使你掌握了某款单片机编程,换了一种,学习起来依然是要花时间的,毕竟细节的东西挺多。

而PLC是梯形图编程,和线下的继电器电路几乎一模一样,只要有电工基础的人,摸索一个月基本上都可以胜任了,有一种PLC的应用基础,换一个牌子,一般也可以很快上手。而且硬件产品市场上已经有现成的了,并不需要自己去操心底层的电子硬件电路。

PLC符合电工的使用习惯

电工的思维习惯就是找线,改线和接线,PLC就是迎合这个来设计的,在电脑上,也基本上是面对常开和常闭触点的组合问题,一些自保和互锁电路而已,编程起来和接线是大同小异。而且PLC和外围的接线,人家已经设计成一排排的端子,直接接上去就可以了,并不用考虑太多细节。

而单片机完全是字母花的编程,并不直观,虽然可以通过一些循环跳转结构来处理,但是和接线是两码事情了,想让一个电工去掌握这些复杂的逻辑思维,又要兼顾外围的线路和控制问题,是比较操心的。

来源:电工电气学习

围观 75

作为一个接触单片机编程工作多年的硬件研发人员,简单的谈下我心里的单片机分类。

一、第一类,标准51单片机

第一类就是MCS51系列,这是一种很早很早的单片机类型,是标准51内核的,大多数硬件研发人员都是从51单片机入门的,而且现在大学里如果开了单片机课程,一般也都是学习的51单片机。

51单片机的优势是内部结构很简单,只有定时器,串口和中断,比较容易理解,还有就是用的人太多了,各种例程和文章都很容易找到,所以很利于入门上手。另外现在宏晶科技出了各种小封装的51系列的单片机,使通过51单片机做一些基础小项目成为可能,所以现在51系列单片机还有人用来做板子。

我当时学习的时候,书上是这样说的,单片机分两种内部结构,一种是冯.诺依曼结构,另一种是RISC精简指令集结构,51内核的单片机属于冯.诺依曼结构,其他内核的单片机都是RISC结构。而RISC结构是比较先进的,因为这种结构的单片机执行命令的时候是同时读取指令和数据,冯.诺依曼结构需要先读指令再读数据才能执行,所以冯.诺依曼结构的处理速度慢。

标准的51单片机,比如ATMEL的AT89C51或者AT89S51系列,是12个指令周期执行一条指令,也就是如果是12M的晶振,则单片机的系统时钟是十二分之一微秒,那么执行一条指令就是十二分之一微秒的12倍,也就是1微秒,简单说就是1秒钟执行一百万条指令,其实还是挺快的啊,呵呵。

二、51类衍生单片机

所谓单片机,其实跟电脑CPU一样,也是在晶元上刻电路,按照一定的图纸刻电路。芯片设计现在也是热门行业,我国也在大力发展国产芯片,比如华为的麒麟系列。

说远了,51单片机内核的芯片设计图纸被公开了,所以有些设计能力一般的厂家基于这些公开图纸,做了一些衍生的51内核的单片机。我记得大概有这么几家,一个是飞利浦的P89C51系列,一种是新华龙的C8051FXXX系列,还有就是宏晶科技的STC89C5X系列,AD公司的ADUC8XX系列。

这几种单片机就是提升了51单片机的内部资源,比如标准51单片机的RAM很小,只有256字节,还不是都能用,这些单片机就增加了内部RAM的容量,一般是增加到4K了,通过MOVX指令访问。还有就是增加了一些内部功能模块,比如AD,DA等等。

这里特别要提的有两点,一个是宏晶科技也就是STC,出了大量51内核的各种封装的单片机,其中一部分不像标准51单片机那样,都是以12T的速度工作的(这里的T指的是系统时钟周期),STC单片机有些可以以6T速度工作,还有的可以以1T的速度工作。

另一个要提的点是,51系列单片机内部是不带仿真接口的,也就是说51内核的单片机都不能在线仿真,只能通过比较复杂的专用仿真器来进行程序仿真,这种仿真机一般都比较贵,我原来用的时候,得几千块钱。但是新华龙的C8051系列是个另类,这一系列的单片机,可以使用新华龙公司的简单的仿真器EC5来在线仿真,这种仿真器相对比较便宜。

所以一般我们调试51单片机程序的时候,会直接把程序烧写到板子上观察执行效果,利用板子上的一些led指示灯指示下工作状态,或者在程序的一些关键位置插入一些串口发数指令,把我们关注的一些变量的数值,发送到电脑上观察结果。至于在哪里插入发数指令,发送那些数据到电脑上,这就需要对编程结构比较熟悉了,这其实对初学者也是一种另类的锻炼方式。但是如果程序过于复杂,可能要观察的数据很多,都发到电脑上也不一定能理清发送的顺序,会带来对程序执行的误判,所以51单片机不太适合编写过于复杂的程序。

三、过去其他几家知名单片机厂家

不用51内核,自己设计单片机内核的厂家也有很多,我接触过的主要有Microchip的和ATMEL的Mega系列,这两种单片机我的理解是抗干扰能力比较强,适合做工业设计。

其中Microchip自成体系,有自己的汇编语言格式,C语言编程也有自己的IDE环境,烧写器,仿真器也是专用的,比较贵,但是很好用。

而ATMEL的Mega系列可以通过keil或者IAR的编译环境来编程,高级的芯片内部带内部仿真模块,低端常用的MEGA8系列是没有的,但是Mega单片机是串行编程的,可以使用简单的编程器进行编程,国内好用的Mega编程器是双龙的,200多元,算便宜了。

说到编程,也就是把写好编译通过的程序烧写到单片机里面,早期的单片机都是通过并行接口的,所以需要的编程器很大,而且不能在线编程,就是要把单片机放到编程器上烧写好程序,再装到目标板上。而Mega系列单片机是很早就支持在线编程的,就是你可以先把单片机焊接到目标板上,再通过编程器直接在目标板上编程,这是Mega的一个巨大优势。

四、台湾厂商

我国台湾的芯片行业还是挺发达的,也有一些厂商自己出单片机,我用到过的有松瀚SONIX,合泰HOTEL,新茂等等,其中松瀚和合泰是感觉针对某一种民用品专门出一种单片机,比如我原来用到的松瀚单片机,只有4K的程序区,芯片连串口都没有,只有一个8位定时器,但是带一个12位的AD,就是针对需要AD采集的小系统设计的。这类单片机的特点是功能单一,应用领域指向性很强,价格非常便宜,甚至都没有FLASH的,编程也没有C语言接口,需要使用汇编语言编程。

说到这里提两点,一个是使用汇编语言编程,我们知道汇编语言是可以直接翻译成机器指令的,也就是一条汇编语言对应一条机器语言,而一个单片机执行一条机器语言的时间我们是知道的,所以我们就能计算出我们写的一段汇编语言的程序的精确的执行时间,这是很有好处的,我们可以不用系统定时器,就可以做到精确定时。而C语言编程,是需要通过编译器把C语言编译成机器语言的,一段C语言程序,通过不用的编译程序,编译成的机器语言是不一样的,就是同样的编译程序,两次编译出的机器语言也可能不一样,所以C语言程序的精确定时,只能依赖定时器。另外用汇编语言可以精确的计算程序存储的容量,比如一个4K程序容量的单片机,表示能烧写进去4K条机器语言,那么我们就可以写4K条汇编语言的程序,是保证能够烧写进去的;而C语言就不一定,因为不能把握C语言被编译完后的机器指令条数,所以就不能明确的知道我们写的C语言程序,是不是能烧写到单片机里面去。这也就是这些台湾产的单片机只支持汇编语言的一个原因,因为你可以精确的计算你写的程序容量,这样就可以选合适容量的单片机来用,毕竟4K容量的单片机比8K容量的单片机要便宜。

另一个要提的是FLASH,FLASH是指烧写程序的区域,这部分区域如果是FLASH,那说明这个区域可以多次使用,就是我们烧写进去一个程序,发现有些问题,可以通过编程器把程序擦除,重新再写新的程序;很多单片机厂家都说单片机的FLASH支持几万次写入,据我的经验,一般几百次是可靠的,再多就不一定了。我们知道单片机没烧写程序的时候,内部全是1,烧写就是把一部分1改写成0,这样1和0搭配就是机器指令,FLASH烧写次数过多的话,虽然也能提示烧写成功,但是有个别的1可能就烧写不成0了,这样相对应的机器指令就变了,程序的执行结果就不对了。

相对FLASH,台湾产的单片机很多都是OTP的,所谓OTP就是one time program,就是只能烧写一次的意思,这种单片机,一旦程序烧写错了,这个芯片就只能作废了,需要换新的单片机重新烧写。这样看不是浪费很大,确实是,这种OTP芯片适合程序定型后的批量生产,OTP的好处还是便宜,比FLASH的便宜。

五、当前流行的几种单片机

当前流行的单片机,一般都是ARM7内核的芯片,一般不装复杂的系统,只当做高速单片机用。这种芯片跟前面说过的各种单片机相比,程序容量更大,一般都是64k起步的,RAM空间也起码有16K,所以我们用这种单片机编程,不必考虑程序是不是能放下的问题,一般就是用C语言编程就好了。而且这类芯片内部都自带倍频电路,用STM32F10X系列举例,这种单片机一般外接8M的晶振,内部9倍频,芯片的工作频率可以达到72M。

正是由于这种单片机程序空间很大,所以经常会装一些小系统,比如UCOS等。编程环境一般用通用的编程环境,流行的是KEIL和IAR。这种单片机基本都内置JTAG接口,或者SW接口,提供在线的编程和调试功能,编程调试器一般使用JLINK或者ULINK一类的。

现在常用的芯片一般是NXP的LPC系列和ST意法半导体的STM32系列,基本款的芯片价格现在也很便宜,10块钱内有大把的芯片可以选择,现在基本已经可以替代上面说的那些中单片机了。

本文转自: 老张的工作室,转载此文目的在于传递更多信息,版权归原作者所有。

围观 71

实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。

1 使用定时器/计数器实现精确延时

单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。本程序中假设使用频率为12 MHz的晶振。最长的延时时间可达216=65 536 μs。若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。

在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。

2 软件延时与时间计算

在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。下面介绍几种软件延时的方法。

2.1 短暂延时

可以在C文件中通过使用带_NOP_( )语句的函数实现,定义一系列不同的延时函数,如Delay10us( )、Delay25us( )、Delay40us( )等存放在一个自定义的C文件中,需要时在主程序中直接调用。如延时10 μs的延时函数可编写如下:

void Delay10us( ) {
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
}

Delay10us( )函数中共用了6个_NOP_( )语句,每个语句执行时间为1 μs。主函数调用Delay10us( )时,先执行一个LCALL指令(2 μs),然后执行6个_NOP_( )语句(6 μs),最后执行了一个RET指令(2 μs),所以执行上述函数时共需要10 μs。  可以把这一函数当作基本延时函数,在其他函数中调用,即嵌套调用[4],以实现较长时间的延时;但需要注意,如在Delay40us( )中直接调用4次Delay10us( )函数,得到的延时时间将是42 μs,而不是40 μs。这是因为执行Delay40us( )时,先执行了一次LCALL指令(2 μs),然后开始执行第一个Delay10us( ),执行完最后一个Delay10us( )时,直接返回到主程序。依此类推,如果是两层嵌套调用,如在Delay80us( )中两次调用Delay40us( ),则也要先执行一次LCALL指令(2 μs),然后执行两次Delay40us( )函数(84 μs),所以,实际延时时间为86 μs。简言之,只有最内层的函数执行RET指令。该指令直接返回到上级函数或主函数。如在Delay80μs( )中直接调用8次Delay10us( ),此时的延时时间为82 μs。通过修改基本延时函数和适当的组合调用,上述方法可以实现不同时间的延时。

2.2 在C51中嵌套汇编程序段实现延时

在C51中通过预处理指令#pragma asm和#pragma endasm可以嵌套汇编语言语句。用户编写的汇编语言紧跟在#pragma asm之后,在#pragma endasm之前结束。

如:#pragma asm

汇编语言程序段

#pragma endasm

延时函数可设置入口参数,可将参数定义为unsigned char、int或long型。根据参数与返回值的传递规则,这时参数和函数返回值位于R7、R7R6、R7R6R5中。在应用时应注意以下几点:

◆ #pragma asm、#pragma endasm不允许嵌套使用;

◆ 在程序的开头应加上预处理指令#pragma asm,在该指令之前只能有注释或其他预处理指令;

◆ 当使用asm语句时,编译系统并不输出目标模块,而只输出汇编源文件;

◆ asm只能用小写字母,如果把asm写成大写,编译系统就把它作为普通变量;

◆ #pragma asm、#pragma endasm和 asm只能在函数内使用。

将汇编语言与C51结合起来,充分发挥各自的优势,无疑是单片机开发人员的最佳选择。

2.3 使用示波器确定延时时间

利用示波器来测定延时程序执行时间。方法如下:编写一个实现延时的函数,在该函数的开始置某个I/O口线如P1.0为高电平,在函数的最后清P1.0为低电平。在主程序中循环调用该延时函数,通过示波器测量P1.0引脚上的高电平时间即可确定延时函数的执行时间。方法如下:

sbit T_point = P1^0;
void Dly1ms(void) {
unsigned int i,j;
while (1) {
T_point = 1;
for(i=0;i<2;i++){
for(j=0;j<124;j++){;}
}
T_point = 0;
for(i=0;i<1;i++){
for(j=0;j<124;j++){;}
}
}
}
void main (void) {
Dly1ms();
}

把P1.0接入示波器,运行上面的程序,可以看到P1.0输出的波形为周期是3 ms的方波。其中,高电平为2 ms,低电平为1 ms,即for循环结构“for(j=0;j<124;j++) {;}”的执行时间为1 ms。通过改变循环次数,可得到不同时间的延时。当然,也可以不用for循环而用别的语句实现延时。这里讨论的只是确定延时的方法。

2.4 使用反汇编工具计算延时时间

用Keil C51中的反汇编工具计算延时时间,在反汇编窗口中可用源程序和汇编程序的混合代码或汇编代码显示目标应用程序。为了说明这种方法,还使用“for (i=0;i

C:0x000FE4CLRA//1T
C:0x0010FEMOVR6,A//1T
C:0x0011EEMOVA,R6//1T
C:0x0012C3CLRC//1T
C:0x00139FSUBBA,DlyT //1T
C:0x00145003JNCC:0019//2T
C:0x00160E INCR6//1T
C:0x001780F8SJMPC:0011//2T

可以看出,0x000F~0x0017一共8条语句,分析语句可以发现并不是每条语句都执行DlyT次。核心循环只有0x0011~0x0017共6条语句,总共8个机器周期,第1次循环先执行“CLR A”和“MOV R6,A”两条语句,需要2个机器周期,每循环1次需要8个机器周期,但最后1次循环需要5个机器周期。DlyT次核心循环语句消耗(2+DlyT×8+5)个机器周期,当系统采用12 MHz时,精度为7 μs。

当采用while (DlyT--)循环体时,DlyT的值存放在R7中。相对应的汇编代码如下:

C:0x000FAE07MOVR6, R7//1T

C:0x00111F DECR7//1T

C:0x0012EE MOVA,R6//1T

C:0x001370FAJNZC:000F//2T

循环语句执行的时间为(DlyT+1)×5个机器周期,即这种循环结构的延时精度为5 μs。

通过实验发现,如将while (DlyT--)改为while (--DlyT),经过反汇编后得到如下代码:

C:0x0014DFFE DJNZR7,C:0014//2T

可以看出,这时代码只有1句,共占用2个机器周期,精度达到2 μs,循环体耗时DlyT×2个机器周期;但这时应该注意,DlyT初始值不能为0。

注意:计算时间时还应加上函数调用和函数返回各2个机器周期时间。

本文章来源网络,如果原作者不支持咱们转发,请联系删除,谢谢!

围观 81

说到单片机编程,不得不说到状态机,状态机做为软件编程的主要架构已经在各种语言中应用,当然包括C语言,在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。灵活的应用状态机不仅是程序更高效,而且可读性和扩展性也很好。状态无处不在,状态中有状态,只要掌握了这种思维,让它成为您编程中的一种习惯,相信您会受益匪浅。

状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果联系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:

①现态:是指当前所处的状态。

②条件:又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

如果我们进一步归纳,把“现态”和“次态”统一起来,而把“动作”忽略(降格处理),则只剩下两个最关键的要素,即:状态、迁移条件。

状态机的表示

状态机的表示要领有许多种,我们可以用文字、图形或表格的形式来表示一个状态机。

举个简单的例子:就按键处理来说,击键动作本身也可以看做一个状态机。一个细小的击键动作包含了:释放、抖动、闭合、抖动和重新释放等状态。

当我们打开思路,把状态机作为一种思想导入到程序中去时,就会找到处理疑问的一条有效的捷径。有时候用状态机的思维去思考程序该干什么,比用控制流程的思维去思考,可能会更有效。这样一来状态机便有了更实际的功用。废话不多说,实践才是检验真理的唯一标准。

几种状态机介绍

也许有人觉得状态机把问题复杂化了,其实做过软件设计的人无形之中已经在用状态机,下面就总结介绍几种状态机。

1、switch case结构状态机

switch( )
case1:
if(not反复执行状态1)
进入1状态前要做的准备
进入1状态的过程
if(not反复执行状态1)
离开状态1的过程
case2:

但这种方式不能很有效预定义所有的状态,也不能把这些状态之间的切换过程合理的定义出来,“状态”本身没有一个合理的定义,几乎是一种面向过程的方式,只过这种方式足够简单,也最容易让人接受,缺点就没有“状态”的定义和指派功能,导致状态的混乱,出现状态处理重复代码,甚至处理不一致的问题,按照OO的观念,状态描述本来就应该是一种实体。

2、ifelse语句结构状态机

这种状态机相对灵活一点,但对于一些大的项目,系统软件设计会相对复杂。

3、消息触发状态机

该类型的状态机实现方式也是很多的,形态多样,但万变不离其宗的就是状态机的4要素及现态、条件、动作、次态。

原理:一旦有消息触发,系统服务函数立即寻找所在状态的消息与消息处理函数对,找到后执行消息处理函数

步骤:

1.添加消息与消息映射

BEGIN_MESSAGE_ MAP(Name,Count) :状态机名,消息数
ADD_NEW_MSG_ITEM (Msg,OnMsg) :消息与消息处理函数
END_MESSAGE_MAP:结束

2.在这里注册
BEGIN_Register_Task:头
...
ADD_Register_Task(Name,Count):状态机名,消息数
...
END_Register_Task:尾

3.划分电子秤状态,完成以上步骤后,完成OnMsg消息处理函数。

Void OnMsg(void)
{

}

说明:以上用宏完成,具体宏是如下定义:
#defineBEGIN_MESSAGE_MAP(Name,Count)constMSG_NODE_TYP MSG_node_Array_##Name[(Count)]={
#defineADD_NEW_MSG_ITEM(Msg,OnMsg){Msg,OnMsg},
#define END_MESSAGE_MAP };
#define BEGIN_Register_Task const MSG_MAP TaskMap[TotalTask]={
#defineADD_Register_Task(Name,Count) {(MSG_NODE_TYP*)MSG_node_Array_##Name,Count},
#define END_Register_Task };

从以上代码可知:添加消息与消息映射实际上是定义消息与消息处理函数对的数组,以形成一个表;注册状态机实际上是把所有消息对数组的入口定义成一个数组,以形成一个表。

消息如何被执行

分发消息

void Default_DisposeMessage(unsigned char *pMsg)
{
unsigned chari;
unsigned charcount=TaskMap[g_Status].cItemCount;
//定位到状态表
for(i=0;i < count;i++)
{
if(*pMsg==TaskMap[g_Status].pMsgItems.msg)
//看能否匹配消息
{
TaskMap[g_Status].pMsgItems.pMsgFunc();
//找到就执行消息处理函数
return;
}
}
}

void DispatchMessage(unsigned char*pMsg)
{
if(*pMsg)
{
Default_DisposeMessage(pMsg);
}
}

核心函数:消息处理中心

void Message_Dispose_Central(void)
{
BYTE Msg;
while(GetMessage(&Msg)) //获取消息
{
TranslateMessage(&Msg); //解释消息
DispatchMessage(&Msg); //分发消息
}
}

本文转自:电子产品世界,转载此文目的在于传递更多信息,版权归原作者所有。

围观 65

页面

订阅 RSS - 单片机