单片机

做单片机设计,有几个要点需要特别注意,如以下所示!

1、单片机的工作频率

单片机的设计应根据客户的需求来选择较低的工作频率,首先介绍一下这样做的优点:采用低的晶振和总线频率使得我们可以选择较小的单片机满足时序的要求,这样单片机的工作电流可以变得更低,最重要的是VDD到VSS的电流峰值会更小。

当然这里需要做一个妥协,因为客户的要求可能是兼容的和平台化的(目前汽车电子的发展趋势就是平台化),选择较高的工作频率可以兼容更多的平台,也方便以后升级和扩展,因此要选择一个较低的可以接受的工作频率。

2、恰当的输出驱动能力

在给定负载规范,上升和下降时间,选择适当的输出的上升时间,最大限度地降低输出和内部驱动器的峰值电流是减小EMI的最重要的设计考虑因素之一。驱动能力不匹配或不控制输出电压变化率,可能会导致阻抗不匹配,更快的开关边沿,输出信号的上冲和下冲或电源和地弹噪声。

设计单片机的输出驱动器,首先确定模块需求的负载,上升和下降的时间,输出电流待续哦啊,根据以上的信息驱动能力,控制电压摆率,只有这样才能得到符合模块需求又能满足EMC要求。驱动器能力比负载实际需要的充电速度高时,会产生的更高的边沿速率,这样会有两个缺点:

(1)信号的谐波成分增加了。

(2)与负载电容和寄生内部bonding线,IC封装,PCB电感一起,会造成信号的上冲和下冲。

选择合适的的di/dt开关特性,可通过仔细选择驱动能力的大小和控制电压摆率来实现。最好的选择是使用一个与负载无关的恒定的电压摆率输出缓冲器。同样的预驱动器输出的电压摆率可以减少(即上升和下降时间可以增加),但是相应的传播延迟将增加,我们需要控制总的开关时间)。

使用单片机的可编程的输出口的驱动能力,满足模块实际负载要求。可编程的输出口的驱动器的最简单是的并联的一对驱动器,他们的MOS的Rdson不能,能输出的电流能力也不相同。我们在测试和实际使用的时候可以选择不同的模式。实际上目前的单片机一般至少有两种模式可选择,有些甚至可以有三种(强,中等,弱)。

当时序约束有足够的余量的时候,通过降低输出能力来减缓内部时钟驱动的边沿。减少同步开关的峰值电流和di/dt,一个重要的考虑因素就是降低内部时钟驱动的能力(其实就是放大倍数,穿通电流与之相关型很大)。降低时钟边沿的电流,将显著改善EMI。当然这样做的缺点就是,由于时钟和负载的开通时间的变长使得单片机的平均电流可能增加。快速边沿和相对较高的峰值电流,时间更长边沿较慢的电流脉冲这两者需要做一个妥协。

晶振的内部驱动(反向器)最好不要超过实际的需求,因为当增益过大的时候会带来更大的干扰。

3、设计最小穿通电流的驱动器

时钟、总线和输出驱动器应尽可能使得传统电流最小,穿通电流【重叠电流,短路电流】,是从单片机在切换过程中,PMOS和NMOS同时导通时候,电源到地线的电流,穿通电流直接影响了EMI和功耗。

这个内容实际上是在单片机内部的,时钟、总线和输出驱动器,消除或减少穿通电流的方法是尽量先关闭一个FET,然后再开通一个FET。当电流较大时,需要额外的预驱动电路或电压摆率。

文章来源:网络(版权归原著作者所有)

围观 447

名称:IIC协议 EEPROM24c02 通过串口通信存数读取数据

内容:此程序用于检测EEPROM性能,测试方法如下:写入24c02一个数据,然后在内存中改变这些数据, 掉电后主内存将失去这些信息,然后从24c02中调入这些数据。看是否与写入的相同。

电脑通过串口发送一个十六进制的数据到单片机,存储进24c02,要求断电重启后在数码管上显示上一次发送的数据。

(本例是1us机器周期,即晶振频率要小于12MHZ)

[cpp] view plain copy
#include //头文件的包含
#include

#define _Nop() _nop_() //定义空指令
#define DataPort P0
sbit WEI=P2^7;
sbit DUAN=P2^6;
// 常,变量定义区
unsigned char code dofly_DuanMa[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00};// 显示段码值0~F,-,全空
unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码

unsigned char TempData[8];

sbit SDA=P2^1; //模拟I2C数据传送位
sbit SCL=P2^0; //模拟I2C时钟控制位

bit ack; //应答标志位

unsigned char res;
void DelayUs2x(unsigned char t);//函数声明
void DelayMs(unsigned char t);

void Delay(unsigned int t)
{
while(t--);
}

void InitUART(void)
{
SCON=0x50;
TMOD|=0x20;
TH1=0xFD;
TR1=1;
EA=1;
}

void DelayUs2x(unsigned char t)
{
while(--t);
}

void DelayMs(unsigned char t)
{

while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}

void Display(unsigned char FirstBit,unsigned char Num)
{
unsigned char i;
for(i=0;i {
DataPort=0; //清空数据,防止有交替重影
DUAN=1; //段锁存
DUAN=0;

DataPort=dofly_WeiMa[i+FirstBit]; //取位码
WEI=1; //位锁存
WEI=0;

DataPort=TempData[i]; //取显示数据,段码
DUAN=1; //段锁存
DUAN=0;

Delay(200); // 扫描间隙延时,时间太长会闪烁,
//太短会造成重影

}
}

/*------------------------------------------------
启动总线
------------------------------------------------*/
void Start_I2c()
{
SDA=1; //发送起始条件的数据信号
_Nop();
SCL=1;
_Nop(); //起始条件建立时间大于4.7us,延时
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; //发送起始信号
_Nop(); //起始条件锁定时间大于4μ
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; //钳住I2C总线,准备发送或接收数据
_Nop();
_Nop();
}
/*------------------------------------------------
结束总线
------------------------------------------------*/
void Stop_I2c()
{
SDA=0; //发送结束条件的数据信号
_Nop(); //发送结束条件的时钟信号
SCL=1; //结束条件建立时间大于4μ
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; //发送I2C总线结束信号
_Nop();
_Nop();
_Nop();
_Nop();
}

void SendByte(unsigned char c)
{
unsigned char BitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
if((c< else SDA=0;
_Nop();
SCL=1; //置时钟线为高,通知被控器开始接收数据位
_Nop();
_Nop(); //保证时钟高电平周期大于4μ
_Nop();
_Nop();
_Nop();
SCL=0;
}

_Nop();
_Nop();
SDA=1; //8位发送完后释放数据线,准备接收应答位
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
else ack=1; //判断是否接收到应答信号
SCL=0;
_Nop();
_Nop();
}

unsigned char RcvByte()
{
unsigned char retc;
unsigned char BitCnt;

retc=0;
SDA=1; //置数据线为输入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; //置时钟线为低,准备接收数据位
_Nop();
_Nop(); //时钟低电平周期大于4.7us
_Nop();
_Nop();
_Nop();
SCL=1; //置时钟线为高使数据线上数据有效
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}

/*----------------------------------------------------------------
应答子函数
原型: void Ack_I2c(void);

----------------------------------------------------------------*/
void Ack_I2c(void)
{

SDA=0;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); //时钟低电平周期大于4μ
_Nop();
_Nop();
_Nop();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
_Nop();
_Nop();
}
/*----------------------------------------------------------------
非应答子函数
原型: void NoAck_I2c(void);

----------------------------------------------------------------*/
void NoAck_I2c(void)
{

SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); //时钟低电平周期大于4μ
_Nop();
_Nop();
_Nop();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
_Nop();
_Nop();
}

/*----------------------------------------------------------------
向无子地址器件发送字节数据函数
函数原型: bit ISendByte(unsigned char sla,ucahr c);
功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
----------------------------------------------------------------*/
/*bit ISendByte(unsigned char sla,unsigned char c)
{
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(c); //发送数据
if(ack==0)return(0);
Stop_I2c(); //结束总线
return(1);
}
*/

/*----------------------------------------------------------------
向有子地址器件发送多字节数据函数
函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
----------------------------------------------------------------*/
bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
{
unsigned char i;

Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(suba); //发送器件子地址
if(ack==0)return(0);

for(i=0;i {
SendByte(*s); //发送数据
if(ack==0)return(0);
s++;
}
Stop_I2c(); //结束总线
return(1);
}

/*----------------------------------------------------------------
向无子地址器件读字节数据函数
函数原型: bit IRcvByte(unsigned char sla,ucahr *c);
功能: 从启动总线到发送地址,读数据,结束总线的全过程,从器件地
址sla,返回值在c.
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
----------------------------------------------------------------*/
/*bit IRcvByte(unsigned char sla,unsigned char *c)
{
Start_I2c(); //启动总线
SendByte(sla+1); //发送器件地址
if(ack==0)return(0);
*c=RcvByte(); //读取数据
NoAck_I2c(); //发送非就答位
Stop_I2c(); //结束总线
return(1);
}

*/
/*----------------------------------------------------------------
向有子地址器件读取多字节数据函数
函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
----------------------------------------------------------------*/
bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
{
unsigned char i;

Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(suba); //发送器件子地址
if(ack==0)return(0);

Start_I2c();
SendByte(sla+1);
if(ack==0)return(0);

for(i=0;i {
*s=RcvByte(); //发送数据
Ack_I2c(); //发送就答位
s++;
}
*s=RcvByte();
NoAck_I2c(); //发送非应位
Stop_I2c(); //结束总线
return(1);
}
/*------------------------------------------------
主函数
------------------------------------------------*/
void main()
{
unsigned char doflye; // 定义临时变量
unsigned char i;

IRcvStr(0xae,4,&doflye,1); //调用存储数据
TempData[0]=dofly_DuanMa[doflye/16];
TempData[1]=dofly_DuanMa[doflye%16];

InitUART();
ES=1;

while(1)
{
Display(0,2);
doflye=res;
ISendStr(0xae,4,&doflye,1); //写入24c02

}
}

void UART_SER(void) interrupt 4
{
unsigned char Temp;
// unsigned char i;
if(RI)
{
RI=0;
Temp=SBUF;
res=Temp;
TempData[0]=dofly_DuanMa[Temp/16];
TempData[1]=dofly_DuanMa[Temp%16];
}
if(TI)
TI=0;
}

文章来源:NK_test的博客 

围观 333

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

(1)干扰源,指产生干扰的元件、设备或信号,用数学语言描述如下:du/dt,di/dt大的地方就是干扰源。如:雷电、继电器、可控硅、电机、高频时钟等都可能成为干扰源。

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

(3)敏感器件,指容易被干扰的对象。如:A/D、D/A变换器,单片机,数字IC,弱信号放大器等。
抗干扰设计的基本原则是:抑制干扰源,切断干扰传播路径,提高敏感器件的抗干扰性能。(类似于传染病的预防)

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、切断干扰传播路径的常用措施如下:

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

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

(3)注意晶振布线。晶振与单片机引脚尽量靠近,用地线把时钟区隔离起来,晶振外壳接地并固定。此措施可解决许多疑难问题。

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

(5)用地线把数字区与模拟区隔离,数字地与模拟地要分离,最后在一点接于电源地。A/D、D/A芯片布线也以此为原则,厂家分配A/D、D/A芯片引脚排列时已考虑此要求。

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

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

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

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

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

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

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

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

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

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

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

先说说在这方面的经验:

软件方面:

1、常将不用的代码空间全清成“0”,因为这等效于NOP,可在程序跑飞时归位;

2、在跳转指令前加几个NOP,目的同1;

3、在无硬件WatchDog时可采用软件模拟WatchDog,以监测程序的运行;

4、涉及处理外部器件参数调整或设置时,为防止外部器件因受干扰而出错可定时将参数重新发送一遍,这样可使外部器件尽快恢复正确;

5、通讯中的抗干扰,可加数据校验位,可采取3取2或5取3策略;

6、在有通讯线时,如I^2C、三线制等,实际中我们发现将Data线、CLK线、INH线常态置为高,其抗干扰效果要好过置为低。

硬件方面:

1、地线、电源线的部线肯定重要了!

2、线路的去偶;

3、数、模地的分开;

4、每个数字元件在地与电源之间都要104电容;

5、在有继电器的应用场合,尤其是大电流时,防继电器触点火花对电路的干扰,可在继电器线圈间并一104和二极管,在触点和常开端间接472电容,效果不错!

6、为防I/O口的串扰,可将I/O口隔离,方法有二极管隔离、门电路隔离、光偶隔离、电磁隔离等;

7、当然多层板的抗干扰肯定好过单面板,但成本却高了几倍;

8、选择一个抗干扰能力强的器件比之任何方法都有效,这点应该最重要。

围观 407

随着电子信息科学技术信息化,智能化,网络化的发展,单片机与嵌入式也获得了广阔的应用空间。本文简单分析了单片机与嵌入式系统的联系、组成结构对比等基础知识,并列举了几种适用于PIC18F系列单片机的几种嵌入式实时操作系统。

单片机与嵌入式系统组成结构对比

(1)单片机基本结构
单片机由运算器、控制器、存储器、输入输出设备构成。

(2)嵌入式系统成部分:
嵌入式系统一般由以下几组嵌入式微处理器、外围硬件设备、嵌入式操作系统、特定的应用程序。
嵌入式系统设计的第一步是结合具体的应用,综合考虑系统对成本、性能、可扩展性、开发周期等各个方面的要求,确定系统的主控器件,并以之为核心搭建系统硬件平台。

单片机与嵌入式系统的联系

单片机是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域的广泛应用。从上世纪80年代,由当时的4位、8为单片机,发展到现在的32位300M的高速单片机。

最早的单片机是Intel公司的8048,它出现在1976年。Motorola同时推出了68HC05,Zilog公司推出了Z80系列,这些早期的单片机均含有256字节的RAM、4K的ROM、4个8位并口、1个全双工串行口、两个16位定时器。之后在80年代初,Intel又进一步完善了8048,在它的基础上研制成功了8051,这在单片机的历史上是值得纪念的一页,迄今为止,51系列的单片机仍然是最为成功的单片机芯片,在各种产品中有着非常广泛的应用。

嵌入式系统的出现最初是基于单片机的,从20世纪七十年代单片机的出现到今天各式各样的嵌入式微处理器,微控制器的大规模应用,使得汽车、家电、工业机器、通信装置以及成千上万种产品可以通过内嵌电子装置来获得更佳的使用性能:更容易使用、更快、更便宜。这些装置已经初步具备了嵌入式的应用特点,但是这时的应用只是使用8位的芯片,执行一些单线程的程序,还谈不上“系统”的概念。

从80年代早期开始,嵌入式系统的程序员开始用商业级的“操作系统”编写嵌入式应用软件,这使得可以获取更短的开发周期,更低的开发资金和更高的开发效率,“嵌入式系统”真正出现了。确切点说,这个时候的操作系统是一个实时核,这个实时核包含了许多传统操作系统的特征,包括任务管理、任务间通讯、同步与相互排斥、中断支持、内存管理等功能。

其中比较著名的有Ready System公司的VRTX、Integrated System
Incorporation(ISI)的PSOS和IMG的VxWorks、QNX公司的QNX等。这些嵌入式操作系统都具有嵌入式的典型特点:它们均采用占先式的调度,响应的时间很短,任务执行的时间可以确定;系统内核很小,具有可裁剪,可扩充和可移植性,可以移植到各种处理器上;较强的实时和可靠性,适合嵌入式应用。这些嵌入式实时多任务操作系统的出现,使得应用开发人员得以从小范围的开发解放出来,同时也促使嵌入式有了更为广阔的应用空间。

90年代以后,随着对实时性要求的提高,软件规模不断上升,实时核逐渐发展为实时多任务操作系统(RTOS),并作为一种软件平台逐步成为目前国际嵌入式系统的主流。这时候更多的公司看到了嵌入式系统的广阔发展前景,开始大力发展自己的嵌入式操作系统。除了上面的几家老牌公司以外,还出现了Palm OS,Win CE,嵌入式Linux,Lynx,Nucleux,以及国内的Hopen,Delta Os等嵌入式操作系统。随着嵌入式技术的发展前景日益广阔,相信会有更多的嵌入式操作系统软件出现。

适用于PIC18F系列单片机的几种嵌入式实时操作系统

如下图所示:

◆嵌入式系统是面向用户、面向产品、面向应用的,它必须与具体应用相结合才会具有生命力、才更具有优势。因此可以这样理解上述三个面向的含义,即嵌入式系统是与应用紧密结合的,它具有很强的专用性,必须结合实际系统需求进行合理的裁减利用。

◆嵌入式系统是将先进的计算机技术、半导体技术和电子技术和各个行业的具体应用相结合后的产物,这一点就决定了它必然是一个技术密集、资金密集、高度分散、不断创新的知识集成系统。所以,介入嵌入式系统行业,必须有一个正确的定位。例如Palm之所以在PDA领域占有70%以上的市场,就是因为其立足于个人电子消费品,着重发展图形界面和多任务管理;而风河的Vxworks之所以在火星车上得以应用,则是因为其高实时性和高可靠性。

◆嵌入式系统必须根据应用需求对软硬件进行裁剪,满足应用系统的功能、可靠性、成本、体积等要求。所以,如果能建立相对通用的软硬件基础,然后在其上开发出适应各种需要的系统,是一个比较好的发展模式。目前的嵌入式系统的核心往往是一个只有几K到几十K微内核,需要根据实际的使用进行功能扩展或者裁减,但是由于微内核的存在,使得这种扩展能够非常顺利的进行。

来源: 玩转单片机

围观 404

学习与应用单片机的高潮正在工厂、学校及企事业单位大规模地兴起。过去习惯于传统电子领域的工程师、技术员正面临着全新的挑战,如不能在较短时间内学会单片机,势必会被时代所遗弃,只有勇敢地面对现实,挑战自我,加强学习,争取在较短的时间内将单片机技术融会贯通,才能跟上时代的步伐。

但是,许多的学习者(包括在校学生),他们总不得要领,从一开始学习时的热情高涨,到最后的沮丧放弃,使得大家对单片机产生了既爱又怕的感觉。

学习单片机并不象学习传统数字电路或模拟电路那样比较直观,原因是除了“硬件”之外还存在一个“软件”的因素。正是这个“软件”因素的存在,使得许多初学者怎么也弄不懂单片机的工作过程,他们怎么也不明白为什么将几个数送来送去,就能控制一盏灯亮/灭?能控制一个电机变速?由此对单片机产生一种“神奇”、“敬畏”甚至“恐惧”感,阻碍了学习单片机的热情与兴趣,这就有社会上“单片机难学”一说。

笔者多年来与众多的电子爱好者、在校学生打过交道,深知他们学习单片机中碰到的难处,况且作者本人也是从一位电子爱好者成长为工程师的,此过程自然少不了学习、探索、实践、进步这样一条规律,因此深切地知道,学单片机难,主要是不得要领,难以入门。一旦找到学习的捷径,入了门,能初步掌握编程技术并产生实际效果,那么必然信心大增。接下来,再向新的深度、广度进军时,心里也不那么焦虑,比较坦然了,能够一步一个脚印下去扩展自己的知识面。这里根据笔者的经验谈谈学习方法、技巧及如何在较短时间内学会单片机。

学习单片机的最有效方法是理论与实践并重

对一个初学单片机的人来说,如果按教科书式的学法,上来就是一大堆指令、名词,学了半天还搞不清这些指令起什么作用,能够产生什么实际效果,那么也许用不了几天就会觉得枯燥乏味而半途而废。所以学习与实践结合是一个好方法,边学习、边演练,循序渐进,这样用不了几次就能将用到的指令理解、吃透、扎根于脑海,甚至“根深蒂固”。也就是说,当你此次学习完某几条指令后(一次数量不求多,只求懂),接下去就该做实验了,通过实验,使你感受刚才的指令产生了控制效果,眼睛看得见(灯光)、耳朵听得到(声音),更能深刻理解指令是怎样转化成信号去控制电子产品的。说句过分的话,单片机与其说是学出来的,还不如说是做实验练出来的,何况做实验本身也是一种学习过程。因此边学边练的学习方法,效果特别好,许多读者经3~6个月的学习已能开发简单的产品了(如霓红灯广告牌控制、累加计数器等)。

学习单片机要合理安排学习时间持之以恒

学习单片机可不能“三天打鱼、二天晒网”,要有持之以恒的毅力与决心,学习完几条指令后,就应及时做实验,融会贯通,而不要等几天或几个星期有时间后再做实验,这样效果不好甚至前学后忘。另外要有打“持久战”的心理准备,不要兴趣来时学上几天,无兴趣时凉上几星期。学习单片机很重要的一点就是持之以恒。
学习单片机要使用循环学习法使之根深蒂固

笔者曾在其它刊物举办过《手把手教你学单片机》讲座,该讲座入门起点低,很多朋友觉得好学、易学,很快就能将讲座从头至尾学完、学懂,但过了几个月,在开发产品时对指令的具体作用就有些淡忘了。根据现代科学的研究,对只短暂学过一遍的知识,充其量只比浮光掠影稍好。因此,较好的方法是,过一段时间后(1~2个月)再重新做一遍,这样反复循环几次就能彻底弄懂消化,永不忘却。有道是:若人生能细看《水浒传》10遍,那么里面的故事内容、人物场情将永生不忘。

学习单片机要进行适当投资购买实验器材及书籍资料

单片机技术是一门含金量高的技术,一旦学会后,它给你带来的效益回报当然也高,无论是应聘求职还是自起炉灶开厂办公司,其前景是光明无限。因此在学习时要舍得适当投资购买必要的学习、实验器材,另外还要经常去科技图书店看看,购买一些适合自己学习、提高的书籍。总之,春天不播种哪来秋天的收获?考虑到学习成本,对初学者可采用“程序完成后软件仿真→单片机烧录程序→试验板通电实验”的方法(现在的快闪型单片机其程序可烧写1000次以上),这样整套实验器材(不包括PC机)只有几百元,对大部分已工作的爱好者来说都有这个能力承受。而经济条件较好的读者可考虑使用在线仿真器(ICE)进行实验,这样学习时直观性更好。

总之这里所谈的就是作者的亲身体验。我们希望以最实用的方法,最易入门的手法,将初学者领进单片机世界的大门里,使这些仅稍懂硬件原理的人通过实践能理解软件的作用,让他们知道在单片机组成的系统中硬件与软件的区分并不绝对,硬件能做的工作一般情况下软件也能完成,软件的功能也可用硬件替代。等初步学会了单片机软件设计后,可将通常由硬件完成的工作交由软件实现,这样,系统的体积、功耗、成本将大大降低,而功能得到提升与增强,使习惯于传统电路设计的人对单片机产生一种妙不可言的相见恨晚之感,感觉到真正找到了一种理想化的器件,真正感受、体会到现代单片微型计算机的强大作用,从而投身于单片机的领域中。只要你肯努力、下功夫、多实践,一定会成功的。

本文转自:电工电子技术

围观 387

实验一 基本I/O口试验:点亮二极管

1、 试验现象:
8个二极管间隔发光。
 
2、 试验目的:
了解最简单的单片机程序的编写方法,了解单片机I/O口驱动二极管的方法
  
3、 试验任务分析:
要想让二极管按照我们的要求发光,首先要搞清楚电路的连接形式,我们先只看和这部分内容有关的电路。当JMP0跳线接在12位置时(选通二极管显示),电路如下图所示:
  

下面,分别把单片机各管脚功能作一简单解释

XTAL1和XTAL2端:
由于单片机是一种时序电路,工作的时候必须外加时钟周期,没有时钟周期,就不能执行程序代码,单片机就不能工作。
  
XTAL1和XTAL2即为外接时钟引脚。时钟的产生有两种方式,内部方式产生和外部方式产生。该电路是内部方式产生时钟的典型电路,内部时钟的晶振频率一般是4M~12M之间,学习板上用的是12M的晶振,外接两个谐振电容。该电容的典型值是30pf。
  
RST端:
RST是复位端,简单的说,单片机的复位和计算机的重启动是一样的概念。如何进行复位呢?只要在RST端加上高电平就可以了。
  
图示电路也是一个典型的复位电路,加电瞬间,电容两端相当于短路,RST端产生一个高电平,使得单片机复位。然后随着电容充电,RST电压慢慢下降,当降低到低电平时,单片机开始正常工作。同样,在按下按键时,RST也产生一个高电平,单片机也被复位。下载程序的时候,应该拔下RST跳线,即可断开复位电路,避免串入干扰信号。
  
EA/VPP:
EA端是内部程序存储器和外部程序存储器的选择端,当EA=1时,访问片内程序存储器,当EA=0时,访问片外程序存储器。对于我们的学习板来说,由于AT89S52自带8k的程序存储器,没有扩展外部程序存储器,所以应该接高电平。

VPP是引脚的第二功能,暂且不介绍了。
  
ALE:
地址锁存允许信号。在扩展了外部程序存储器的情况下,当单片机访问外部程序存储器时,ALE输出低8位地址的锁存信号。在本学习板上没有用到这个端子.
  
PROG为引脚的第二功能,暂且不介绍了,有兴趣的同学可以查询相关教材。
  
PSEN:
外部程序存储器读选通信号,由于在学习板上没有扩展外部程序存储器,所以这个脚也不用。
  
P1口:
P1口可作为通用的I/O口使用。在本电路中,P1.5口外接蜂鸣器(其余几个和本试验无关,暂不介绍)。上图可知,当P1.5输出高电平时,对应的三极管导通,蜂鸣器发声。(同学可能会问,这个功能好像和我们的试验任务没有什么关系啊,我一会在给大家解释)。
  
P3口:
P3口是双功能口,第一种功能和我们P1口类似,也可以作通用的I/O口使用。第二种功能和单片机的串行通信,中断等功能有关,我们暂且不介绍。以后用到相应功能在给大家介绍。
  
P2口:
P2也可以作为输入口或者输出口来用,在试验板上,P2口的作用在于选通数码管显示。在本例中我们不用。
  
P0口:
P0口在我们这个试验中扮演着重要的角色,从图上可知,发光二极管是由P0口驱动的。且慢,大家可能会发现,P0口是通过74AS244驱动发光二极管的,这是为什么呢?在这里,74AS244是个缓冲器,它的作用在于隔离单片机和外围电路,这样可以保护单片机,并且能够增强单片机的输出驱动能力。在该电路中,如果我们去掉74AS244,而直接把二极管接在P0输出口上,也是可以的,这是因为电源通过上拉电阻能够提供较大的驱动电流。
  
同时大家要注意,当P0口作为输出口使用的时候,它的输出级是漏级开路的形式,所以它应该外接上拉电阻,这时才能有高电平输出。(我们的板子上面用了一个排阻。漏级开路的输出级类似于ttl电路中集电极开路的输出级,大家可以参考随便一本数电教材,关于oc门的原理介绍,上面说得非常清楚。)
  
下面我们来看看怎样才能使得P0口驱动的8个二极管按照要求发光。我们发现,只要P0口相应的一个引脚输出低电平的时候,则对应的二极管发光。例如:欲LED1发光,只需要P0.0引脚输出相应的低电平就可以啦!
  
因此,如果我们需要8个二极管间隔发光,在板子上,从左至右依次为亮灭,则P0口的输出值应该是:01010101,即为55H。
  
好啦,分析清楚之后,我们可以开始写程序啦!
  
4、试验程序如下: 
org 0000h ;(1)

clr p1.5 ;(2)
  
loop: mov p0,#55h ;(3)
  
ajmp loop ;(4)
  
end ;(5)
  
注释
(1)org是个伪指令,也就是说它在汇编时不产生目标代码。(大家可以在medwin环境里打开反汇编窗口看看就明白啦。)它一般出现在每段源程序或者数据块的开始,指明此语句后面的程序或者数据块的起始地址。我们编写好的程序是存放在单片机的程序存储器中的,它的可寻址空间是64k,即0000h~0ffffh。这个语句表示我们的程序从程序存储器地址为0000h单元开始存放。
  
(2)从电路图上面可以看到P1.5连接蜂鸣器,所以这个语句的意思是,把P1.5置零,不让蜂鸣器响。由于单片机复位以后,P1口的内容为FFH,这样蜂鸣器就会一直响。所以要把该端子置零。当然,如果你不怕吵,这句话也可以不写。
  
(3)给P0口赋值55H,使得8个二极管间隔发光。
  
(4)跳转回标记为loop的指令。(注ljmp指令也具有同样的功能,两者区别是:ajmp只能在2k字节内转移,而ljmp可以在64k字节内转移。本程序用ajmp就足够了。)
  
(5)这同样也是一条伪指令,告诉我们程序到这里就结束啦。

好啦,然后把这个程序进行编译,下载,你就会看到学习板上的发光二极管乖乖的按照你的指令工作了。

5、 课后练习
(1)、学习该程序中出现的知识点涉及到的理论知识,包括I/O口,程序存储器,数据存储器,和使用到的指令。
  
(2)、编写程序,使得发光二极管从左到右四个亮,四个不亮

来源:玩转单片机

围观 438

随着大规模集成电路的不断发展,很多单片机都有内置A/D模块,因此,单片机的A/D转换可以用内置A/D模块也可以用外置A/D电路完成,现谈谈单片机A/D转换的工作原理及优缺点,并分析提高A/D转换精度的方法。

1、 A/D转换的工作原理及优缺点
  
(1)单片机片内A/D转换单片机片内A/D转换是利用单片机的内置A/D模块,通过选择不同的模拟量通道进行A/D转换。可以将模拟量直接输入到单片机对应的输入脚,外围电路简单。转换后的数据直接保存在片内寄存器中,数据提取方便。但大多数单片机的内置A/D模块只有8位和10位,无法进行高精度的A/D转换,原理如图1所示。
  


  
(2)单片机片外A/D转换单片机外置A/D转换是单片机通过一定的逻辑电路控制外置A/D转换电路进行A/D转换,外围电路相对复杂。单片机将转换结果通过一定的时序读取到单片机中,按要求通过选择A/D转换电路,可以实现高精度的A/D转换(可以达到14位、16位、22位甚至更高),原理如图2所示。


2、 A/D转换模块提高转换精度的方法

提高A/D转换精度的方法要提高A/D转换的精度,选用高精度的外部A/D转换器当然可以达到要求,除此之外,有没有其他方法呢?答案是肯定的。以下介绍几种利用片内A/D转换模块提高转换精度的方法。
  
(1)以采集电压为例,假设需要采集0.0~400.0 V直流电压,单片机A/D模块的基准电压VREF+取5.0 V,VREF-取0 V,需要采集的电压经过衰减,变成0.0~5.0 V,连接电路如图3所示。显然,如果要达0.1 V的精度,则A/D转换的分辨率必须小于1/4000,而片内A/D模块一般为10位,分辨率仅为1/1 024,达不到要求。由于模拟量(O~400V电压)输入大多不是稳定值,会有波动,为了得到更高精度的数据,可以将多次采集的数据累加后再取平均值(其实即使分辨率达到要求的A/D转换也要经过累加再取平均值,以得到更稳定的数据)。如果每间隔一定时间采集的10位数据为Di,取64个这样的数据累加后再除以16,就可以得到12位的数据D,即
 

 

这时D的分辨率是1/212=1/4 096。这样,就得到了更高精度的数据。

  
  
但是,如果模拟量(0~400V电压)输入值非常稳定,每间隔一定时间采集的10位数据Di都相同,以上方法就达不到要求了。
  
(2)如果在A/D转换过程中要得到局部更高精度的数据,例如检测蓄电池充放电过程中的电压,电压范围是0~18 V,一般精度达到0.02 V即可,但用户更关心8~13 V的电压,8~13 V内精度要达到0.01 V。为了解决这个问题,设计了原理如图4所示的电路。

单片机有内置10位A/D模块,Ui(0~20 V)电压经过R1、R2、P1衰减得到0~5 V的电压,该电压直接送到单片机的AN1输入口,即VAN1=Ui/4。U2A接成减法运算电路,即U2A 1端电压VU2A1=VAN1-2 V=Ui/4-2 V=(Ui-8 V)/4。U2B接成4倍放大电路,U2B 7端的电压VU2B7=VU2A×4=Ui-8 V。AN2输入并联一只5 V稳压二极管,以保证当输入电压大于8 V时,单片机AN2可以得到O~5 V电压。
  
单片机先采集AN1的数据,通过采集的数据判断输入电压是否在8~13 V之间,如果不在8~13 V,则采集到的数据就是模拟量(U)对应的数字量(D:000H~3FFH),精度为20 V/2010=20 V/1 024≈0.02 V,电压数据U=D×0.02 V;如果采集的数据在8~13 V之间,单片机再采集AN2的数据,采集到的数据加上8 V就是模拟量(U)对应的数字量(D:000H~3FFH),精度为(13-8)V/210=5 V/1 024≈0.005 V,电压数据U=8 V+D×0.005 V。这样,在8~13 V之间的A/D转换精度就大大提高了。

结语

随着工业自动控制的不断发展,单片机在工业自动控制的应用也越来越广。本文介绍的提高A/D转换精度的工作原理在实际应用中具有一定的使用价值,特别是通过简单的模拟运算电路,可以局部提高A/D转换精度。利用这个原理,如果将模拟量分段放大,也可以全范围提高A/D转换精度。这种方法在A/D转换领域有较好的应用前景。

围观 450

对于一个电子工程师来说,在单片机的电路设计中电磁干扰不仅关系了单片机在控制在中的能力和准确度,还关系到企业在行业中的竞争。对电磁干扰的设计本文主要从硬件和软件方面进行设计处理,下面就是从单片机的PCB设计到软件处理方面来介绍对电磁兼容性的处理。

一、影响EMC的因数

1.电压

电源电压越高,意味着电压振幅越大,发射就更多,而低电源电压影响敏感度。

2.频率

高频产生更多的发射,周期性信号产生更多的发射。在高频单片机系统中,当器件开关时产生电流尖峰信号;在模拟系统中,当负载电流变化时产生电流尖峰信号。

3.接地

在所有EMC题目中,主要题目是不适当的接地引起的。有三种信号接地方法:单点、多点和混合。在频率低于1MHz时,可采用单点接地方法,但不适宜高频;在高频应用中,最好采用多点接地。混合接地是低频用单点接地,而高频用多点接地的方法。地线布局是关键,高频数字电路和低电平模拟电路的接地电路尽不能混合。

4.PCB设计

适当的印刷电路板(PCB)布线对防止EMI是至关重要的。

5.电源往耦

当器件开关时,在电源线上会产生瞬态电流,必须衰减和滤掉这些瞬态电流。来自高di/dt源的瞬态电流导致地和线迹“发射”电压,高di/dt产生大范围的高频电流,激励部件和线缆辐射。流经导线的电流变化和电感会导致压降,减小电感或电流随时间的变化可使该压降最小。

二、对干扰措施的硬件处理方法

1.印刷线路板(PCB)的电磁兼容性设计

PCB 是单片机系统中电路元件和器件的支撑件,它提供电路元件和器件之间的电气连接。随着电子技术的飞速发展,PCB的密度越来越高。PCB设计的好坏对单片机系统的电磁兼容性影响很大,实践证实,即使电路原理图设计正确,印刷电路板设计不当,也会对单片机系统的可靠性产生不利影响。例如,假如印刷电路板的两条细平行线靠的很近,会形成信号波形的延迟,在传输线的终端形成反射噪声。因此,在设计印刷电路板的时候,应留意采用正确的方法,遵守PCB设计的一般原则,并应符合抗干扰的设计要求。要使电子电路获得最佳性能,元器件的布局及导线的布设是很重要的。

2.输入/输出的电磁兼容性设计

在单片机系统中输进/输出也是干扰源的传导线,和接收射频干扰信号的拾检源,我们设计时一般要采取有效的措施:

①采用必要的共模/差模抑制电路,同时也要采取一定的滤波和防电磁屏蔽措施以减小干扰的进进。

②在条件许可的情况下尽可能采取各种隔离措施(如光电隔离或者磁电隔离),从而阻断干扰的传播。

3.单片机复位电路的设计

在的单片机系统中,看门狗系统对整个单片机的运行起着特别重要的作用,由于所有的干扰源不可能全部被隔离或往除,一旦进进CPU干扰程序的正常运行,那么复位系统结合软件处理措施就成了一道有效的纠错防御的屏障了。常用的复位系统有以下两种:

① 外部复位系统。外部“看门狗”电路可以自己设计也可以用专门的“看门狗”芯片来搭建。然而,他们各有优缺点,大部分专用“看门狗”芯片对低频“喂狗”信号不能响应,而高频“喂狗”信号都能响应,使其在低频“喂狗”信号下产生复位动作而在高频的“喂狗”信号下不产生复位动作,这样,假如程序系统陷进一个死循环,而该循环中恰巧有着“喂狗”信号的话,那么该复位电路就无法实现它的应有的功能了。然而,我们自己可以设计一个具有带通的“喂狗”电路和其他复位电路构成的系统就是一个很有效外部监控系统了。

②现在越来越多的单片机都带有自己的片上复位系统,这样用户就可以很方便的使用其内部的复位定时器了,但是,有一些型号的单片机它的复位指令太过于简单,这样也会存在象上述死循环那样的“喂狗”指令,使其失往监控作用。有一些单片机的片上复位指令就做的比较好,一般他们把“喂狗”信号做成固定格式的多条指令依顺序来执行,假如有一定错误则该“喂狗”操纵无效,这样就大大进步了复位电路的可靠性。

4.振荡器

大部分的单片机都有一个耦合于外部晶体或陶瓷谐振器的振荡器电路。在PCB上,要求外接是电容、晶体或陶瓷谐振器的引线越短越好。RC振荡器对干扰信号有潜伏的敏感性,它能产生很短的时钟周期,因而最好选晶体或陶瓷谐振器。另外,石英晶体的外壳要接地。

5.防雷击措施

室外使用的单片机系统或从室外排挤引进室内的电源线、信号线,要考虑系统的防雷击题目。常用的防雷击器件有:气体放电管、TVS(Transient Voltage Suppression)等。气体放电管是当电源的电压大于某一数值时,通常为数十V或数百V,气体击穿放电,将电源线上强冲击脉冲导进大地。TVS可以看成两个并联且方向相反的齐纳二极管,当两端电压高于某一值时导通。其特点是可以瞬态通过数百乃上千A的电流。

三、对干扰措施的软件处理方法

电磁干扰源所产生的干扰信号在一些特定的情况下(比如在一些电磁环境比较恶劣的情况下)是无法完全消除的,终极将会进进CPU处理的的核心单元,这样在一些大规模集成电路经常会受到干扰,导致不能正常工作或在错误状态下工作。特别是像RAM这种利用双稳态进行存储的器件,往往会在强干扰下发生翻转,使原来存储的“0”变为“1”,或者“1”变为“0”;一些串行传输的时序及数据会因干扰而发生改变;更严重的会破坏一些重要的数据参数等;造成的后果往往是很严重的。在这种情况下软件设计的好坏直接影响到整个系统的抗干扰能力的高低。

1.程序会由于电磁干扰大致会一下几种情况:

①程序跑飞。

这种情况是最常见的干扰结果,一般来说有一个好的复位系统或软件帧测系统即可,对整个运行系统的不会产生太大的影响。

②死循环或不正常程序代码运行。

当然这种死循环和不正常程序代码并非设计职员有意写进的,我们知道程序的指令是由字节组成的,有的是单字节指令而有的是多字节指令,当干扰产生后使得PC指针发生变化,从而使原来的程序代码发生了重组产生了不可猜测的可执行的程序代码,那么,这种错误是致命的,它会有可能会往修改重要的数据参数,有可能产生不可猜测的控制输出等一系列错误状态。

2.对重要参数储存的措施

一般情况下,我们可以采用错误检测与纠正来有效地减少或避免这种情况的出现。根据检错、纠错的原理,主要思想是在数据写进时,根据写进的数据天生一定位数的校验码,与相应的数据一起保存起来;当读出时,同时也将校验码读出,进行判决。假如出现一位错误则自动纠正,将正确的数据送出,并同时将改正以后的数据回写覆盖原来错误的数据;假如出现两位错误则产生中断报告,通知CPU进行异常处理。所有这一切动作都是靠软件设计自动完成的,具有实时性和自动完成的特点。通过这样的设计,能大大进步系统的抗干扰能力,从而进步系统的可靠性。

检错与纠错原理:首先来看看检错和纠错的基本原理。进行差错控制的基本思想是在信息码组中以一定规则加进不同方式的冗余码,以便在信息读出的时候依靠多余的监视码或校码码来发现或自动纠正错误。

针对误码发生的特点,即错误发生的随机性和小概任性,它几乎总是随机地影响某个字节中的某一位(bit),因此,假如能够设计自动纠正一位错误,而检查两位错误的编码方式。就可以大大进步系统的可靠性。

3.对RAM和FLASH(ROM)的检测

在编制程序时我们最好是写进一些检测程序来测试RAM和FLASH(ROM)的数据代码,看有无发生错误,一旦发生要立即纠正,纠正不了的要及时给出错误指示,以便用户往处理。

另外,在编制程序时加进程序冗余是不可缺少的。在一定的地方加进三条或三条以上NOP指令对程序的重组有着很有效防止作用。同时,在程序的运行状态中要引进标志数据和检测状态,从而及时发现和纠正错误产生。

围观 356

经常接触单片机的朋友,肯定遇到过单片机程序跑飞的问题。由于程序较为复杂,所以一旦出现跑飞的现象就比较难以查找错误出现的地方,网络上对错误的解释和解决方法也比较五花八门,并不方便查找。小编特意帮大家整理了关于单片机程序跑飞死机的原因,大家快来看看能不能在其中找到自己想要答案吧。

单片机程序死机,跑飞了可以从以下几个方面查找原因:

1、意外中断。

是否打开了某个中断,但是没有响应和清除中端标志,导致程序一直进入中断,造成死机假象。

2、中断变量处理不妥。

若定义某些会在中断中修改的全局变量,这时要注意两个问题:首先为了防止编译器优化中断变量,要在这些变量定义时前加volatile,其次在主循环中读取中断变量前应该首先关闭全局中断,防止读到一半被中断给修改了,读完之后再打开全局中断;否则出现造成数据乱套。

3、地址溢出,常见错误为指针操作错误。

我要着重说的是数组下标使用循环函数中循环变量,如果循环变量没控制好则会出现数组下标越界,意外修改系统的寄存器造成死机,这种情况下如果死机说明运气好,否则后面不知道发生什么头疼的事。

4、无条件的死循环。

比如使用while(x);等待电平变化,正常情况下x都会变成0,就怕万一,因此最好加上时间限制。

5、看门狗没有关闭。

有的单片机即使没使用看门狗开机时也有可能意外自动开启了最小周期的看门狗,导致软件不断复位,造成死机,这个要看芯片手册,最好在程序复位后首先应该显式清除看门狗再关闭看门狗。

6、堆栈溢出。

最难查找的问题,对于容量小的单片机,尽量减少函数调用层级,减少局部变量,从而减少压栈的时候所需的空间。当你把以上几条都试过不能解决问题,试一试把你的被调用少函数直接内置到调用的地方并且把占用RAM大的局部变量改成全局变量,试一试说不定就可以了。

通过本篇文章,大家是否找到了自己想要的问题解决方法了呢?就算没有找到,本篇文章也能帮助大家在一定程度上预防跑飞现象的发生。

围观 229

页面

订阅 RSS - 单片机