打印

程序跑飞问题

[复制链接]
12317|31
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Eve_dark|  楼主 | 2012-6-2 09:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Eve_dark 于 2012-6-2 09:22 编辑

我是做今年飞思卡尔智能车的,用的Kinetis10的主控芯片。但是现在程序有一个很奇怪的问题:会不定时跑飞。
就是程序开始运行后,在过一段时间之后,就会没有任何反应,在主循环中有加让LED灯闪烁的代码都没有反应。而且,每次跑飞的时间不确定,随机性很强,大概平均在1分钟以上。
请问各位大神这主是有哪些问题能引发随机性的程序跑飞呀??

整个程序结构采用简单的消息模式:
有两个主要中断,会在中断时发送消息,就是改变一个全局变量的值,主函数中死循环不断检测这个全局变量,如果有消息存在,就调用相应的处理函数,并清除这个消息。

大体如下:
int mainMsg=0;

void main()
{
    初始化;
    while(1)
    {
           switch(CheckMsg())
           {
                 case 平衡控制:
              调用响应控制函数;
                     break;
                 case 方向控制:
                     调用方向控制函数;
                     break;
                 case 串口消息:
                     调用串口消息函数;
                     break;
                 default:
                     break;
            }
     }
}

void timer()    //定时器中断
{
     if(达到5ms)
           mainMsg|=平衡控制消息;
   if(达到20ms)
           mainMsg|=方向控制消息;
}

我试过,如果进行非法计算(试过比如1/0或sqrt(-1))不会造成芯片跑飞,而且把所有用到的sprintf函数都换成了snpritnf函数防止缓存区溢出。但还是不能解决问题。

相关帖子

沙发
NE5532| | 2012-6-2 09:19 | 只看该作者
极为糟糕的硬件设计Or软件BUG,一般来说后者居多,处理方法:认真清理程序。

使用特权

评论回复
板凳
Eve_dark|  楼主 | 2012-6-2 09:25 | 只看该作者
我感觉是硬件问题的可能性不大,因为第一,跑飞之后直接复位程序,程序任然可以正常运行。第二,控制电机状态,就是基本让电机不转,还是会遇到这种情况。

使用特权

评论回复
地板
forgot| | 2012-6-2 09:27 | 只看该作者
对呀,调试调试程序吧

使用特权

评论回复
5
ayb_ice| | 2012-6-2 09:31 | 只看该作者
频繁跑飞,99.99%程序问题

使用特权

评论回复
6
Eve_dark|  楼主 | 2012-6-2 09:41 | 只看该作者
关键是没有什么头绪去调这个问题。我感觉,能够引起跑飞问题的情况本来就很少(之前遇到过缓存区溢出造成的),在这个程序中,把所有用到数组和指针的地方都查好几遍了。而且加上是小概率随机时间事件,导致很难再现程序错误。现在,我能尝试的唯一方法就是从分块一步步添加代码,看什么时候能够试出来问题。

使用特权

评论回复
7
ayb_ice| | 2012-6-2 10:47 | 只看该作者
频繁测试总能发现跑飞规律的,

我曾经花了15天解决一个一天最多只出一次的小BUG

根据你的描述,估计是共享资源的问题

我一向认为,
程序不乱跑,不死机,是最基本的要求
偶尔功能出错还可以接受

使用特权

评论回复
8
hjyt008| | 2012-6-2 10:59 | 只看该作者
肯定是有问题的啦,但是我不是专业的不知道是什么问题~~~~~~~~嘿嘿

使用特权

评论回复
9
NE5532| | 2012-6-2 12:32 | 只看该作者
推荐本版精华帖《程序调试黑宝书》

使用特权

评论回复
10
Eve_dark|  楼主 | 2012-6-2 20:32 | 只看该作者
想问问7楼,我也很怀疑是这个问题。但是,中断和主函数就共享一个全局变量mainMsg,用每一个位标志不同的消息。CheckMsg会从这个变量中检测某一位置一,并清除该位,返回该消息。
我认为,就算访问全局变量有冲突,顶多也就是少检测几个消息而已,不至于造成程序跑飞呀。想问一下,有除了内存溢出之外别的造成程序跑飞的原因吗?能举个例子吗?
还有呀,你当时那个bug是怎么调试的呀?总不会是看代码看出来的吧。。。

使用特权

评论回复
11
bingbo1970| | 2012-6-2 20:38 | 只看该作者
学习

使用特权

评论回复
12
NE5532| | 2012-6-2 20:55 | 只看该作者
想问问7楼,我也很怀疑是这个问题。但是,中断和主函数就共享一个全局变量mainMsg,用每一个位标志不同的消息。CheckMsg会从这个变量中检测某一位置一,并清除该位,返回该消息。
我认为,就算访问全局变量有冲突, ...
Eve_dark 发表于 2012-6-2 20:32


黑宝书里讲的有方法,这种一般要靠多测,积累经验来推理,就像破案一样。

使用特权

评论回复
13
Eve_dark|  楼主 | 2012-6-2 21:03 | 只看该作者
恩,先谢谢各位,明天再看看程序再说吧

使用特权

评论回复
14
Eve_dark|  楼主 | 2012-6-7 11:22 | 只看该作者
这两天查了一下,使用减少代码实验的方法,发现问题主要集中在测速部分。
测速部分是对两个AB两相的旋转编码器进行测速(在下面的程序中已经简化为一个,但同样有问题)。
A相接入单片机的计数器,B相接一般IO口。
程序通过一个定时器中断和一个外部中断来进行测速,大概过程如下:
每10ms发生一次定时器中断,以采集速度。

定时器中断进行一下操作:
读取计数器的计数值,并附加上方向pos保存到全局变量leftCount中。
清除保存的方向pos。
打开B相对应管脚的外部中断,上升沿触发。

B相的外部中断用来判断旋转方向:
在B相上升沿时,即中断触发时,判断A相的高低电平以确定方向,然后关闭该外部中断。

在测试中,主函数循环中不断让灯闪烁,但是运行这个程序,并让旋转编码器旋转,仍然会造成程序跑飞。

使用特权

评论回复
15
Eve_dark|  楼主 | 2012-6-7 11:23 | 只看该作者
下面是相关代码

static int oldCount;    //上一次计数器的值
static int pos;         //旋转方向
static int leftCount,rightCount;
extern void CountTimerIRQ(void);
extern void CountExtIRQ(void);

void InitCount()
{
        PORTC_PCR5=PORT_PCR_MUX(4);
        PORTE_PCR17=PORT_PCR_MUX(6);
        GPIOC_PDDR&=~((1<<5)|(1<<6)|(1<<7));
        GPIOE_PDDR&=~(1<<17);
        SIM_SCGC5|=SIM_SCGC5_LPTIMER_MASK;
        LPTMR0_PSR=LPTMR_PSR_PCS(1)|LPTMR_PSR_PBYP_MASK;
        LPTMR0_CSR=LPTMR_CSR_TPS(2)|LPTMR_CSR_TFC_MASK
                | LPTMR_CSR_TMS_MASK | LPTMR_CSR_TEN_MASK;
       
        oldCount=LPTMR0_CNR;
        pos=0;
        leftCount=0;
        rightCount=0;
        EnableIRQ(89);                            //开外部中断
        pit_init(1,SYSCLK/1000,10);        //用定时器来实现交替测速
}

int GetLeftSpeed()
{
        int ret;
        ret=leftCount;
        ASSERT(ret<200 && ret>-200);
        return ret;
}

int GetRightSpeed()
{
        return rightCount;
}

void CountTimerIRQ(void)    //定时器中断
{
        int count;

        PIT_TCTRL1 = ~(PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK);
        PIT_T标志寄存器1 = PIT_T标志寄存器_TIF_MASK;
        PORTC_PCR7&=~PORT_PCR_IRQC_MASK;

        count=LPTMR0_CNR;
        count=(count+0xffff-oldCount)%0xffff;
        leftCount=count*pos;
        pos=0;

        PORTC_ISFR=0xFFFFFFFF;
        PORTC_PCR7=PORT_PCR_MUX(1)|PORT_PCR_IRQC(0x9)
                |PORT_PCR_PE_MASK|PORT_PCR_PS_MASK;
        oldCount=LPTMR0_CNR;
        PIT_TCTRL1=(PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK);
}

void CountExtIRQ(void)      //外部中断,PORTC的5脚
{
        PORTC_PCR5=PORT_PCR_MUX(1)|PORT_PCR_PE_MASK|PORT_PCR_PS_MASK;

        if(GPIOC_PDIR&(1<<5))
                pos=-1;
        else
                pos=1;

        PORTC_PCR5=PORT_PCR_MUX(4);
        PORTC_PCR7&=~PORT_PCR_IRQC_MASK;
        PORTC_ISFR=0xFFFFFFFF;
}

int main(void)
{
        volatile int ret;
        int i=0;
       
        InitHard();     //包含InitCount
        while(1)
        {
                ret=GetLeftSpeed();
                Delay(20);
                i=(i+1)%50;
                if(i==0)
                        LightLed(3,0);
                else if(i==25)
                        LightLed(3,1);
        }
        return 0;
}

使用特权

评论回复
16
Eve_dark|  楼主 | 2012-6-7 11:25 | 只看该作者
本帖最后由 Eve_dark 于 2012-6-7 11:38 编辑

我现在准备先用D触发器焊一个小板,专门用来判断方向,就不用用软件检测方向了,应该可以避免这个问题。但是仍然对这个程序会跑飞感到奇怪,这个里面没有使用任何数组和指针,对全局变量的访问都相当于是原子操作,而且中断内部没有等待的函数,应该也不会造成死锁之类的问题吧。
还有就是,我还没有查到中断优先级的关系和中断是否可以重入,但是,就算中断可重入,也不会这样把。

使用特权

评论回复
17
ayb_ice| | 2012-6-7 11:47 | 只看该作者
我估计需要设置标志位
中断设置好标志后,主循环判断标志有效再处理

使用特权

评论回复
18
ayb_ice| | 2012-6-7 11:57 | 只看该作者
感觉LZ对pos变量的处理有问题

两个中断中都可以修改pos变量

使用特权

评论回复
19
Eve_dark|  楼主 | 2012-6-7 12:00 | 只看该作者
这是没办法的呀,定时器需要清除上一次检测的方向,而外部中断用来设置检测的方向。
但是,即使有错误值,程序也不会跑飞吧。。

使用特权

评论回复
20
Eve_dark|  楼主 | 2012-6-7 12:02 | 只看该作者
而且跑飞之后,别的中断中的程序也无法执行。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

30

帖子

1

粉丝