打印

MSP430在运行过程中会出现复位

[复制链接]
2149|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
mouxiang|  楼主 | 2014-12-10 10:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 mouxiang 于 2014-12-10 11:06 编辑

想请教大家一个问题。

使用了MSP430的两个串口,UART0和UART1。上位机通过UART0与MSP430通信,根据其发送过来的指令,MSP430会启动UART1发送相应的指令去查询一个485设备,然后将查询到的值通过UART0回送给上位机。UART0和UART1的波特率都设定为115200,这样一个通信周期为7.5~8ms。

使用了定时器A,其中,A0的周期为2ms,A1的周期为100us。在A0中我打开了总中断,这样A1的中断能够打断A0的中断,从而使得100us定时器能够准确定时。在A0的中断服务程序中,我放了一些判断代码和IO操作的代码,例如获取光电管状态的代码,但是不多。现在的问题是,MSP430运行一段时间后会发生复位。如果我将获取光电管状态的代码放在main中执行,就不会复位了。

我比较迷惑的是,造成复位的原因是定时器呢还是UART通信?或者是两者共同造成的?因为我放在定时器中断服务中的代码的执行时间应该是很短的,不会超过1ms,照理说那段代码放在定时器里和放在main中是没什么区别的。

各位朋友如果有这方面的经验,还请指点一下,十分感谢!

整个代码比较复杂,各种命名的含义也不太好解释,我贴出来大家也不一定看得明白。所以我后面会陆续将一些函数做一些简化修改会贴出来。

相关帖子

沙发
mouxiang|  楼主 | 2014-12-10 10:59 | 只看该作者
本帖最后由 mouxiang 于 2014-12-10 11:05 编辑
void TIMERA_init(void)
{
  CCTL0 = CCIE;                     // 开启比较器0中断
  CCR0 = 2000;                    // 2ms
  CCTL1 = CCIE;                     // 开启比较器1中断
  CCR1 = 100;                      //
  TACTL = TASSEL_2 + ID_3 + MC_1;           // SMCLK, 8分频为1Mhz, Up to CCR0
}

#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  _EINT();//开总中断,以便100us定时器能够正常进行

  if(System_Time_Interval(Timer_2ms_Count, System_Timer) >= 20)//时间间隔20*100us=2ms
  {
    Get_System_Time_Current_Count(Old_Timer_2ms_Count, Timer_2ms_Count);
    Get_System_Time_Current_Count(Timer_2ms_Count, System_Timer);
      
    Timer_A1_count++;
    Flag_Timer_A1_Updated = 1;
   
    //下面这段被注释掉的代码,此时放在main中运行,MSP430不会出现复位;若放在此处运行,则MSP430运行一段时间后就会出现复位
//    if(Phototube_Info_is_Needed)
//    {
//      Get_Phototube_Info_In_TimerA();
//    }      
  }

  /***************************/
  //这里是一些输出口开关操作
  /***************************/
}

#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A1 (void)
{
  if( TAIV != 0x02)//比较器1中断
    return;
  
  CCR1 += 100;
  if(CCR1 >= 2000)
    CCR1 -= 2000;
  
  System_Time_Increase(System_Timer);
}
以上是定时器的初始化和中断服务程序。

使用特权

评论回复
板凳
mouxiang|  楼主 | 2014-12-10 11:15 | 只看该作者
UART0和UART1只会触发接收中断,其发送是在main中进行的,这里我贴出其初始化代码和发送代码。
//初始化串口通信UART0, UART0为控制板与PC机的通信
void InitUART0(void)
{
  P3SEL |= 0x30;                            // P3.4,5 = USART0 TXD/RXD
  
  ME1 |= UTXE0 + URXE0;                     // Enable USART0 TXD/RXD
  
  UCTL0 |= CHAR;                            // 8-bit character, USART0

  UTCTL0 |= SSEL1;                          // UCLK = SMCLK, USART0

  if( ((P4IN&0x04)>>2) == 1){//根据工作模式确定波特率,如果MODE_INPUT0为0,即P4.2为1,则采用57600波特率
  UBR00 = 0x8A;//0x45;                             // USART0,波特率:57600
  UBR10 = 0x00;//0x00;                             //
  UMCTL0 = 0xDE;//0xAA;                            // Modulation
  }
  else{//否则采用115200波特率
  UBR00 = 0x45;//0x45;                             // USART0,波特率:115200
  UBR10 = 0x00;//0x00;                             //
  UMCTL0 = 0x4A;//0xAA;                            // Modulation
  }

  UCTL0 &= ~SWRST;                          // USART0,SWRST复位

  IE1 |= URXIE0;                            // USART0,接收中断允许
}

//初始化串口通信UART1
void InitUART1(void)
{
  P3SEL |= 0xC0;                            // P3.6,7 = USART1 TXD/RXD
  
  ME2 |= UTXE1 + URXE1;                     // Enable USART1 TXD/RXD
  
  UCTL1 |= CHAR;                            // 8-bit character, USART1
  
  UTCTL1 |= SSEL1;                          // UCLK = SMCLK, USART0

  if( ((P4IN&0x04)>>2) == 1){//根据工作模式确定波特率,如果MODE_INPUT0为0,即P4.2为1,则采用57600波特率
  UBR01 = 0x8A;//0x45;                             // USART0,波特率:57600
  UBR11 = 0x00;//0x00;                             //
  UMCTL1 = 0xDE;//0xAA;                            // Modulation
  }
  else{//否则采用115200波特率
  UBR01 = 0x45;//0x45;                             // USART0,波特率:115200
  UBR11 = 0x00;//0x00;                             //
  UMCTL1 = 0x4A;//0xAA;                            // Modulation
  }
  
  UCTL1 &= ~SWRST;                          // USART1,SWRST复位
  
  IE2 |= URXIE1;                            // USART1,接收中断允许
}

void UART0_LONG_CMD_Send(void)//附加协议长指令发送函数,一条指令24个字节
{
  unsigned i;
  COM2_DE_HIGH();//P4.0输出高电平,使能COM2的MAX485的DI口用于输出数据
  for(i=0; i<MAX_BYTES_LONG_CMD; i++)
  {
    TXBUF0=UART0_Long_CMD_buffer[i];
    while((UTCTL0&0x01)==0);   
    if(UART0_Long_CMD_buffer[i]==CMDEND_EXTRA)
    {
      COM2_DE_LOW();//P4.0输出低电平,禁止COM2的MAX485的DI口,等待数据传入
      return;
    }
  }
}

void UART1_Send(unsigned * UARTRX_buf)
{
  unsigned i;
  COM1_DE_HIGH();//P4.1输出高电平,使能COM1的MAX485的DI口用于输出数据
  for(i=0; i<Max_bytes_UART1; i++)
  {
    TXBUF1=UARTRX_buf[i];
    while((UTCTL1&0x01)==0);   
  }
  COM1_DE_LOW();//P4.1输出低电平,禁止COM1的MAX485的DI口,等待数据传入
}

使用特权

评论回复
地板
dirtwillfly| | 2014-12-10 11:30 | 只看该作者
我觉得有可能是堆栈溢出,造成的复位。
没看到你对下面代码使用的变量和函数的定义:
//    if(Phototube_Info_is_Needed)
//    {
//      Get_Phototube_Info_In_TimerA();
//    }  
这段代码有可能会因为多次执行到,从而多次分配和占用资源

使用特权

评论回复
5
mouxiang|  楼主 | 2014-12-10 11:41 | 只看该作者
Get_Phototube_Info_In_TimerA()定义如下:
void Get_Phototube_Info_In_TimerA(void)//精简的函数,仅用于在定时器中断中获取光电管状态变化的时刻
{  
  if(!Flag_for_Non_Trigger)
  {
    Phototube_1_State = Obtain_Phototube_State_1();//获取光电管1状态,这是一个读取IO口状态的操作
  }
  else
  {
    Phototube_1_State = 7;//处于不触发时间内,光电管状态设定为一直遮挡
    if(Count_for_Non_Trigger >= Effective_Irregular_Object_Not_Trigger_Time*5)//不触发时间到
    {
      Flag_for_Non_Trigger = 0;
      Count_for_Non_Trigger = 0;
    }
  }
  
  if(Phototube_1_State == 1 || Phototube_1_State == 5)         //这表明光电管开始被遮挡
  {
    Rejection_Admin[Rejection_Num].Rise_Time = Timer_A1_count;//存储光电管上升沿时刻
  }  
}
一般情况下,如果光电管不被遮挡,则Flag_for_Non_Trigger=0,Phototube_1_State=0,也就是说Get_Phototube_Info_In_TimerA()这个函数中仅仅只是获取光电管状态。

使用特权

评论回复
6
mouxiang|  楼主 | 2014-12-10 11:50 | 只看该作者
我要将光电管状态的代码放在定时器里的原因是,我需要精确获取光电管被遮挡的上升沿时刻,从而确定传送带上的物体位置。由于传送带速度较高,如果我获取光电上升沿时刻有误差,则物体位置就可能会有1cm以上的偏差。将获取光电管状态的代码放在main中的话,由于UART通信的执行时间能够达到8ms左右,那么这个上升沿时刻的误差肯定会比较大。

使用特权

评论回复
7
as564335sa| | 2014-12-10 11:59 | 只看该作者
查查数组越界堆栈溢出之类的,函数里不要开大数组

使用特权

评论回复
8
mouxiang|  楼主 | 2014-12-10 17:20 | 只看该作者
我将定时器中断Timer_A()中的涉及到输出口开关操作的代码移到main中,Timer_A()中只保留光电管监测的代码,然后我让机器跑一晚上试试看会不会出现复位。如果这时仍然出现复位现象,那么我想可以判断是光电监测代码有问题。如果不出现复位,那么我可以判断是定时器中的代码执行时间稍长时与其他部分的代码有冲突,冲突可能最大的我估计是UART通信的代码。
我在UART1_Send()发送函数中有一句while循环:while((UTCTL1&0x01)==0); 是否有这种可能,就是我在用UART发送的时候被定时器中断打断,造成发送失败,一直死在这个while循环里,然后看门狗引起复位?

使用特权

评论回复
9
as564335sa| | 2014-12-10 19:41 | 只看该作者
mouxiang 发表于 2014-12-10 17:20
我将定时器中断Timer_A()中的涉及到输出口开关操作的代码移到main中,Timer_A()中只保留光电管监测的代码, ...

关掉狗试试便知

使用特权

评论回复
10
mouxiang|  楼主 | 2014-12-11 09:24 | 只看该作者
我昨天将定时器中断中输出口开关操作的代码移到了main中,而保留了光电监测代码。经过一晚上测试,机器没有出现复位。

此外,我今天会做一个测试,在定时器中断中放一个1ms的延时,如果这样也不会出现复位,那么可能是堆栈溢出造成的复位。

关闭看门狗的操作我今天也会去试一下。

使用特权

评论回复
11
HORSE7812| | 2014-12-11 10:20 | 只看该作者
学习

使用特权

评论回复
12
mouxiang|  楼主 | 2014-12-11 13:21 | 只看该作者
上午做了一下测试,是这么一个情况:如果在定时器中断中加入0.2ms的延时,则不会引发立即复位;如果加入0.3ms以上的延时,则会引起立即复位(我这里指的立即复位,意思是当上位机开始发起通信后,MSP430就不断复位。而之前我所说的复位是指能够正常开机运行一段时间,但是经过一晚上的运行后,可以观测到MSP430发生了复位)。关闭看门狗后,如果是加入0.2ms延时则不会复位,加入0.3ms延时则仍会复位,这说明复位不是由看门狗造成的,而应该是定时器中断中的代码执行时间过长与其他部分冲突而引起的。

我在定时器2ms中断中开了总中断,这是否会有影响?而且当我加入0.3ms延时的时候,MSP430是在上位机发起UART通信的时候才开始复位,这是否是由于UART通信的相关操作引起的?我的UART只用了接收中断,而接收中断应该是可以打断定时器2ms中断的(因为我开了总中断)。有没有可能是在这里出现了问题呢?

使用特权

评论回复
评分
参与人数 1威望 +8 收起 理由
dirtwillfly + 8 测试很认真,赞一个!
13
dirtwillfly| | 2014-12-11 16:32 | 只看该作者
mouxiang 发表于 2014-12-11 13:21
上午做了一下测试,是这么一个情况:如果在定时器中断中加入0.2ms的延时,则不会引发立即复位;如果加入0.3 ...

你看过你的定时器A0和A1的中断服务程序执行过程分别占用多长时间吗?
根据执行时间算一下,是不是造成多重中断嵌套了?

使用特权

评论回复
14
mouxiang|  楼主 | 2014-12-12 10:19 | 只看该作者
周末我会测试一下定时器A0中的中断服务程序代码执行时间。但定时器A1中的代码执行时间我不太好确定,因为我的系统时钟就是用定时器A1的100us周期来做的,不过应该不会超过5us。
假设我的A0的执行时间是0.3ms(周期为2ms),定时器A1的执行时间是5us(周期为100us),而我在A0中把总中断打开,这样是否会造成多重中断嵌套呢?这方面怎么去计算我还不是太了解,还请指点一下!
另外,我现在的做法是定时器A0中保留了光电监测代码,然后将输出口开关操作部分的代码进行了优化,使其基本上不占什么时间,这样的情况下,我跑了一晚上机器,没有出现复位。

使用特权

评论回复
15
dirtwillfly| | 2015-1-3 21:27 | 只看该作者
mouxiang 发表于 2014-12-12 10:19
周末我会测试一下定时器A0中的中断服务程序代码执行时间。但定时器A1中的代码执行时间我不太好确定,因为我 ...

楼主的问题解决了吗?

使用特权

评论回复
16
mouxiang|  楼主 | 2016-2-3 11:23 | 只看该作者
目前还是没有解决这个问题,只能是先把一些代码放在main中执行,尽量再做些优化。不过这种方法没有把定时器好好利用起来,以后肯定还是会碰到瓶颈。

使用特权

评论回复
17
bingg| | 2016-3-2 23:57 | 只看该作者
求答

使用特权

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

本版积分规则

3

主题

58

帖子

1

粉丝