|
问题是这样的,几年前用的STC8F2K32S2的单片机,发现晶振受到外在干扰会死机(或者假死),有时即便开了看门狗也没用,只能断电后重启才能再次正常跑。用的是外部4M无源晶振,电容是22P。
然后小批量的做了些,发现偶尔有客户反应,运行模式会不受控制自动改变,查看现场发现有大功率电机干扰。我的理解是一般会干扰外部电路或者电源部分,而我的产品是220输入到隔离变压器整流滤波后进入单片机,对外输出部分也仅仅一个继电器触点的输出,电源上的干扰基本排除了,百思不得其解!
然后回来测试,发现人体或金属接触晶振输入脚,就有一定的概率会自动切换模式或者程序跑飞,再也跑不回来。我的理解是当接触到晶振,要么停止(程序也停止在原地),要么毛刺频率高(MCU会把晶振毛刺当成时钟而不受控制的执行指令),但是事实上不是这样,而是会出现不可预料的数据而导致程序跑飞。网上查了很多跑飞程序的原因,什么堆栈溢出,意外中断没清标志等等,但是都排除了!
为了测试把项目中其他任务统统取消了,主循环就一个显示代码,正常显示8个0,也没有任何中断,测试干扰晶振输入脚,依然有几率会出现黑屏不再亮屏或者出现8个其他数据,这问题一直困扰几年了,请版主们解释一下跑飞的原因!不要告诉我避免这个干扰的方法。
STC让我认识了单片机,也让我学到了不少知识,但是别家的一样的产品,连外围电路都一样,我也测试过,干扰结束后每次都能正常执行,不会出现显示数据不对或者跑飞。
下面这个是测试代码,正常显示00000000
干扰后有时会不显示,或者显示其他数据
unsigned char code seg[] =
{
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, //0-7
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E, //8-F
0xBF, 0xFF, 0x8C, 0x88, 0xC1, 0xA7, 0xA3, 0xC7, 0x91 //-
};
unsigned char code segdot[] =
{
0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78,
0x00, 0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0E,
0xBF, 0xFF
};
unsigned char pdata ledbuff[] =
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char pdata show[8]; //0-左上 7-右下
unsigned long count3num;
void Display(void)
{
static unsigned char i = 0;
SegDuan = 0xFF; //消隐
SegWei = 0x00;
SegWei = 0x01 << i; //驱动一位共阳
SegDuan = ledbuff[i];
i++;
if (i > 7)
i = 0;
}
void main(void)
{
unsigned char i;
P_SW2 |= 0x80;
XOSCCR = 0xC0; //外部晶振4M
while (!(XOSCCR & 0x01));
CLKDIV = 0x01;
CLKSEL = 0x01; //选择外部晶振
//CLKSEL = 0x11; //选择外部晶振输出到P5.4口
P_SW2 = 0x00;
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 |= 0x07;
P1M1 |= 0x00;
P2M0 |= 0xFF;
P2M1 |= 0x00;
P3M0 |= 0x20;
P3M1 |= 0x00;
P3M0 |= 0x00;
P3M1 |= 0x84;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P4 = 0xFF; //无用引脚拉高
P13 = 1;
P36 = 1;
P54 = 1;
P55 = 1;
EA = 1;
count3num = 0;
LedGreen = 0;
LedRed = 0;
OUT = 1; //继电器输出
//WDT_CONTR = 0x24;
while (1)
{
OUT = 0;
LedRed = 1;
show[0] = count3num / 10000000 % 10;
show[1] = count3num / 1000000 % 10;
show[2] = count3num / 100000 % 10;
show[3] = count3num / 10000 % 10;
show[4] = count3num / 1000 % 10;
show[5] = count3num / 100 % 10;
show[6] = count3num / 10 % 10;
show[7] = count3num % 10;
for(i=0;i<8;i++)
ledbuff[i] = seg[show[7-i]];
Display();
//WDT_CONTR |= 0x34;
}
}
|
|