接触器启停时,主循环无法执行,定时器中断可以运行,.....
用51做了一个控制器,控制一个接触器运行,接触器的触头还没有带负载,接触器线圈有阻容吸收回路,现在在接触器启停时,有时会出现主循环无法执行(主循环里有一个计数器,死机时计数器的值已经没有变化了),但是定时器中断还可以正常运行的情况,定时器1ms中断一次,里面有一个呼吸灯等程序,死机时,呼吸灯还在运行,这个是怎么回事主循环如下
void main(void)
{
SytemInit();
while(1)
{
CheckLostPower(); //检测是否掉电,如有掉电,写EEPROM
AnalogInput();
OutputCurrent(); //阀位输出
key_display(); //键盘及显示
CycleCounter++; //主程序循环计数器,可删除
if(CycleCounter>=65535) CycleCounter=0;
if(UartSendFlag==1)
{
printf("ADC0_result=%u\r\n",ADC0_result);
printf("voltage=%f\r\n",ADC0_voltage);
printf("Valve_position=%f\r\n",Valve_position);
printf("\n");
UartSendFlag=0;
}
}
}
定时器中断如下:
//中断服务程序区
//定时器T0中断服务程序,1ms中断一次
void tm0() interrupt 1 using 1
{
ET0=0;
BreathLampCounter++; //呼吸灯计数器加一
UartSendCounter++; //串口定时发送计数器加一
QD10MS++; //10ms读一次IO口
if( QD10MS>=10 )
{
QD10MS=0;;
m_OpenLimit=OpenLimit;
m_CloseLimit=CloseLimit;
m_OpenRemote=OpenRemote;
m_CloseRemote=CloseRemote;
}
if(BreathLampCounter>=1500) //呼吸灯计数器清零
{
BreathLampCounter=0;
}
if(BreathLampCounter<=30) //点亮、熄灭呼吸灯,LED1用作呼吸灯
{
LED1_ON
}
else
{
LED1_OFF
}
if(UartSendCounter>=1000) //串口每秒自动发送一次
{
UartSendCounter=0;
UartSendFlag=1;
}
if(BuzerFlag==1)
{
LED3_ON
BUZZER_ON
BuzerCounter++;
if(BuzerCounter>=5)
{
BuzerCounter=0;
BUZZER_OFF
LED3_OFF
BuzerFlag=0;
}
}
ET0=1;
return;
} 进了假死状态,连个看门狗都没有。直接给零分。
举个例子,IIC编程。
1.clk=1;启动clk拉高;
2.while(sda==0);等待sda为零。
3.XXX继续。
在2这里,sda一直无法拉低,一直为1,程序就好像是死了。
怎么解决呢?
设置一个等待超时就行。
ucha i=0;
1.clk=1;启动clk拉高;
2.while(sda==0)
{
i++;
if(i>250)break;
}等待sda为零。
3.XXX继续。
看门狗是故意没有加的,因为想找出程序死机的原因
我检查一下有没有类似你说的IIC的原因 把程序多余的地方全部删掉,只留下开关接触器的部分,还是一样的现象,主循环中的串口无法发送,定时器中断可以执行,呼吸灯在闪烁
void SytemInit(void)
{
ValveStop
BUZZER_OFF
GPIO_config(); //------------外设初始化--------------
UartInit(); //所有GPIO初始化
TimerInit(); //所有定时器初始化
ES=0; //串口发送信息,最好先关闭串口中断ES=0,这里没有关
TI=1;
EA=1; //打开全局中断开关
}
//------------主函数--------------
void main(void)
{
SytemInit();
while(1)
{
if(P70==0)
ValveClose
if(P70==1)
ValveStop
CycleCounter++; //主程序循环计数器,可删除
if(CycleCounter>=65535) CycleCounter=0;
if(UartSendFlag==1)
{
printf("CycleCounter=%u\r\n",CycleCounter);
UartSendFlag=0;
}
}
}
//中断服务程序区
//定时器T0中断服务程序,1ms中断一次
void tm0() interrupt 1 using 1
{
ET0=0;
BreathLampCounter++; //呼吸灯计数器加一
UartSendCounter++; //串口定时发送计数器加一
if(BreathLampCounter>=1500) //呼吸灯计数器清零
BreathLampCounter=0;
if(BreathLampCounter<=30) //点亮、熄灭呼吸灯,LED1用作呼吸灯
LED1_ON
else
LED1_OFF
if(UartSendCounter>=1000) //串口每秒自动发送一次
{
UartSendCounter=0;
UartSendFlag=1;
}
ET0=1;
return;
} 有没有可能一直在中断里面跑。 lingdianhao 发表于 2021-9-6 17:35
有没有可能一直在中断里面跑。
但是中断程序里面的代码执行完后,应该会返回到主程序中呀 lingdianhao 发表于 2021-9-6 17:35
有没有可能一直在中断里面跑。
因为中断程序里面没有任何的循环 看程序运行的结果,不像是死机,只是不能返回到主循环而已 传说中的程序跑飞了? 任何地方不要出现无超时的死等,一旦等待的事件没发生,就会一直等下去,而MCU并没有死。 可能就是串口死了,判断不到发送完成标志 中断服务子程序里面的代码太多了,新手常见大错误之一。 小李非刀 发表于 2021-9-7 15:05
任何地方不要出现无超时的死等,一旦等待的事件没发生,就会一直等下去,而MCU并没有死。 ...
已经把程序简化了,没有等待的语句 boycn 发表于 2021-9-7 17:26
可能就是串口死了,判断不到发送完成标志
串口发送用的是printf函数,正常不会死机吧,我试试把这句取消看 饭桶 发表于 2021-9-7 20:53
中断服务子程序里面的代码太多了,新手常见大错误之一。
中断里面13行的c语句,其实不算多,也没有循环和函数调用 GLSHME 发表于 2021-9-8 08:24
中断里面13行的c语句,其实不算多,也没有循环和函数调用
也有可能是一直进了其它的中断,把串口接收中断和发送中断都关闭试试 GLSHME 发表于 2021-9-8 08:23
串口发送用的是printf函数,正常不会死机吧,我试试把这句取消看
去掉printf函数,大概率好了{:lol:} 检查硬件。大概率板子没布好。 rube 发表于 2021-9-9 13:14
去掉printf函数,大概率好了
删掉了printf语句,还是会出现IO口不受控制,有时蜂鸣器会乱响。 wangzex 发表于 2021-9-9 16:30
检查硬件。大概率板子没布好。
大概率是线路板布局的原因,用另外一块开发板,把IO口引到这块板子的继电器控制线路上,没有在出现死机等现象。 这块板子是为了验证电路功能,所以没有考虑太多的抗干扰措施,但是没有想到干扰这么大,接触器频繁启停时,一旁的戴尔显示器也被搞得频繁重启复位。 单片机加隔离吧,很爽的。那种隔离电源模块也不贵 GLSHME 发表于 2021-9-10 08:24
大概率是线路板布局的原因,用另外一块开发板,把IO口引到这块板子的继电器控制线路上,没有在出现死机等 ...
那就是布板的问题,只考虑连通,不考虑干扰。 具体用的哪个型号? modbus 发表于 2021-9-10 16:31
具体用的哪个型号?
STC8A8K64S4 线路板排版很关键,板子没布好再好的抗干扰单片机也没有用。要不然,应届毕业生跟多年经验的老工程师就没工资区别了。
页:
[1]