打印

基于MSP430的MODBUS通信程序

[复制链接]
5151|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dillion117|  楼主 | 2010-5-16 16:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
版主可以帮我看看我的程序还有什么欠缺么,有些地方实在不知道怎么写了,能帮忙改一下。谢谢



#include "msp430x14x.h"
#define  uchar unsigned char
#define  uint unsigned int
/****************************************************************************/
#define  P3_0_WDI  0x01  //WDT
#define  P3_1_BEEP  0x02  //蜂鸣
#define  P3_2_RTS1  0x04  //RS485A控制
#define  P3_3_RTS  0x08  //RS485B控制
#define  P5_5_DAT  0x20  //LED DAT  BC7281B接口
#define  P5_6_KEY  0x40  //LED KEY
#define  P5_7_CLK  0x80  //LED CLK
/****************************************************************************/
uchar CAddress;  //仪表地址
uchar Cbps=3,Cbpss=4;
uchar Cdata8=0,Cdata8s=0;
uchar Cmima[4];//密码
typedef enum
{
SYS_Idle,//空闲
        SYS_Txd,//发送数据
        SYS_Twait1,//发送等待
SYS_Twait2, //发送等待
SYS_Rwait,//接收等待
}SYS_STATE;
SYS_STATE systemState;
uchar Rxok=0;
uchar Cflag,Crep=0,Cdscon=0;
uint Csearch[16];
uint nHmax[16];      //20mA液位值
uint fXiuZheng[16];//修正系数
uchar CregArry[32];//液位值
uchar Cmnumber=12;
uchar Ckey_number;
uchar FlashWord[10];
uchar CDispBuff[12];
uint  *pq=(uint *)0xfd00;//指向Flash
unsigned char aRxBuff0[16]; //接收数据缓冲区
unsigned char NRxBuff0=0;
unsigned char aTxBuff0[128]; //发送数据缓冲区
unsigned char NTxBuff0=0;
unsigned  char commandPending0=0,Ntxd0=0;
uint timeoutCounter0=0;
uint RXcrc0;
uint UstarReg0,UregNum0;
uint txwait0;
uchar bUartRxErr0;
uchar Couttime,Couttime1,CdelayT,CdelayT1;
unsigned char aRxBuff1[16]; //接收数据缓冲区
unsigned char NRxBuff1=0;
unsigned char aTxBuff1[32]; //发送数据缓冲区
unsigned char NTxBuff1=0;
unsigned  char commandPending1=0,Ntxd1=0;
uint timeoutCounter1=0;
uint RXcrc1;
uint UstarReg1,UregNum1;
uint txwait1;
uchar bUartRxErr1;
unsigned char *puchMsg ; /* 要进行CRC校验的消息 */
unsigned int CRC16(uchar *puchMsg, uchar usDataLen)
{
  unsigned char uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
  unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
  unsigned uIndex ; /* CRC循环中的索引 */
  while (usDataLen--) /* 传输消息缓冲区 */
  {
    uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */
    uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
    uchCRCLo = auchCRCLo[uIndex] ;
  }
  return (uchCRCHi << 8 | uchCRCLo) ;
}


void UpdateStateMachine(void)
{
  static unsigned char CAdesm=1;
  static unsigned int ia;
  
  switch (systemState)
  {
  case SYS_Idle:
   
    P3OUT|=P3_2_RTS1;
    aTxBuff1[0]=CAdesm;//地址
    aTxBuff1[1]=0x03;//功能代码
    aTxBuff1[2]=0x00;//起始地址
    aTxBuff1[3]=0x00;//起始地址
    aTxBuff1[4]=0x00;//寄存器个数
    aTxBuff1[5]=0x01;//寄存器个数
    puchMsg=aTxBuff1;
    RXcrc1=CRC16(puchMsg, 6);//字符串校验
    aTxBuff1[6]=RXcrc1>>8;//功能代码
    aTxBuff1[7]=RXcrc1&0x00ff;
    NTxBuff1=0;
    systemState=SYS_Txd;
   
    break;
  case SYS_Txd:
    if (NTxBuff1<8)
    {
      TXBUF1=aTxBuff1[NTxBuff1];
      NTxBuff1++;
      systemState=SYS_Twait1;
    }
    else
    {
      ia=0;
      systemState=SYS_Twait2;
    }
    break;
  case SYS_Twait1:
    if (IFG2&UTXIFG1)//查询是否发送完毕
     {
        systemState=SYS_Txd;
     }
    break;
  case SYS_Twait2:
    ia++;
    if (ia>=CdelayT1)
    {
      CAdesm++;
      if (CAdesm>Cmnumber)
        CAdesm=1;
      systemState=SYS_Rwait;
      P3OUT&=~P3_2_RTS1;
      Rxok=0;
      ia=0;
    }
    break;
    case SYS_Rwait:
      ia++;
      if ((ia>=2500)||((Rxok==1)&&(ia>=80)))
      {
        systemState=SYS_Idle;
      }
      break;
  default :
    systemState=SYS_Idle;
    break;
  }
}

void HandleUART0(void)
{
  
  uint i;
  if (NRxBuff0>0)
  {
    if(timeoutCounter0++ > Couttime)//接收超时
    {
      NRxBuff0=0;
          for (i=0;i<10;i++)
            {
              aRxBuff0[i]=0;
            }
    }
   
  }
  else
  {
      timeoutCounter0 = 0;// Don't let timeoutCounter slowly grow over many commands.
  }
  if (commandPending0 == 0)//收态
  {
        if (NRxBuff0>=8)
          {
            if ((aRxBuff0[3]==0x04)&&(aRxBuff0[1]==0x06))
            {
              if (NRxBuff0>=10)
              {
              puchMsg=aRxBuff0;
              RXcrc0=CRC16(puchMsg, NRxBuff0-2);//字符串校验
              i=aRxBuff0[NRxBuff0-2]*0x100+aRxBuff0[NRxBuff0-1];
              NRxBuff0=0;
              if  (RXcrc0==i)//通过CRC校验
              {
               if (aRxBuff0[0]==CAddress)
                {
                commandPending0 = 1;
                }
               
              }
              }
            }
            else
            {
              puchMsg=aRxBuff0;
              RXcrc0=CRC16(puchMsg, NRxBuff0-2);//字符串校验
              i=aRxBuff0[NRxBuff0-2]*0x100+aRxBuff0[NRxBuff0-1];
              NRxBuff0=0;
                if  (RXcrc0==i)//通过CRC校验
                {
                 if (aRxBuff0[0]==CAddress)
                  {
                  commandPending0 = 1;
                  }
                }
                else
                {
                   commandPending0 = 0;
                   NRxBuff0=0;
                   for (i=0;i<10;i++)
                    {
                      aRxBuff0[i]=0;
                    }
                }
            }
          }
  }
  else if (commandPending0 == 1)//命令处理
  {
   
      switch(aRxBuff0[1])
      {
      case 3:
      UstarReg0=aRxBuff0[2]*0x100+aRxBuff0[3];
      UregNum0=(aRxBuff0[4]*0x100+aRxBuff0[5])<<1;
      aTxBuff0[0]=CAddress;//地址
      aTxBuff0[1]=0x03;//功能代码
      
        aTxBuff0[2]=UregNum0;
        for (i=0;i<UregNum0;i++)
        {
          aTxBuff0[i+3]=CregArry[(UstarReg0<<1)+i];
        }
        puchMsg=aTxBuff0;
        RXcrc0=CRC16(puchMsg, UregNum0+3);//CRC计算
        aTxBuff0[UregNum0+3]=(RXcrc0&0xff00)>>8;  //CRC高字节
        aTxBuff0[UregNum0+4]=RXcrc0&0x00ff;//CRC低字节
        P3OUT|=P3_3_RTS;
        Ntxd0=UregNum0+5;
        NTxBuff0=0;
        commandPending0 = 2;
        //SendUart0(UregNum+5);//发送
      
      
      break;
      case 6:
      UstarReg0=aRxBuff0[2]*0x100+aRxBuff0[3];
      switch(UstarReg0)
        {
        case 0://初值
        
        break;
        case 1://地址
        
        break;
        case 2://20mA
      
        break;
        case 3://调相
        
        break;
        case 4://修正系数
        
        break;
        default :
        break;
        }
     
      commandPending0 = 0;
      
      break;  
      default :
        commandPending0 = 0;
        
      break;
      }//功能
   
  }
  else if (commandPending0 == 2)//发态
  {
   
      TXBUF0=aTxBuff0[NTxBuff0];
      NTxBuff0++;
      if (NTxBuff0>=Ntxd0)
      {
        commandPending0 = 4;
        txwait0=CdelayT;
      }
      else
      {
        commandPending0 = 3;
      }
   
  }
  else if(commandPending0 == 3)//发送等待状态
  {
     if (IFG1&UTXIFG0)//查询是否发送完毕
     {
       commandPending0 =2;
     }
  }
  else if(commandPending0 == 4)
  {
    if(--txwait0 == 0)
    {
    commandPending0 = 0;
    P3OUT&=~P3_3_RTS;
    }
  }
}
void HandleUART1(void)
{
  uint i;
  if (NRxBuff1>0)
  {
    if(timeoutCounter1++ > Couttime1)//接收超时
    {
      NRxBuff1=0;
          for (i=0;i<10;i++)
            {
              aRxBuff1[i]=0;
            }
    }
   
  }
  else
  {
      timeoutCounter1 = 0;// Don't let timeoutCounter slowly grow over many commands.
  }
  if (commandPending1 == 0)//收态
  {
        if (NRxBuff1>=7)
          {
              puchMsg=aRxBuff1;
              RXcrc1=CRC16(puchMsg, NRxBuff1-2);//字符串校验
              i=aRxBuff1[NRxBuff1-2]*0x100+aRxBuff1[NRxBuff1-1];
              NRxBuff1=0;
                if  (RXcrc1==i)//通过CRC校验
                {
                 
                  commandPending1 = 1;
                  
                }
                else
                {
                   commandPending1 = 0;
                   NRxBuff1=0;
                   for (i=0;i<10;i++)
                  {
                    aRxBuff1[i]=0;
                  }
                }
            
          }
  }
  else if (commandPending1 == 1)//命令处理
  {
   
      switch(aRxBuff1[1])
      {
      case 3:
      CregArry[(aRxBuff1[0]-1)<<1]=aRxBuff1[3];
      CregArry[((aRxBuff1[0]-1)<<1)+1]=aRxBuff1[4];
      Rxok=1;
      commandPending1 = 0;
      break;
      default :
        commandPending1 = 0;
      break;
      }//功能
   
  }
}
/************************************************************
*Function:系统初始化
*parameter:
*Return:
*Modify:
*************************************************************/
void system_ini( void )
{
    int i;
   
   
    WDTCTL = WDTPW + WDTHOLD;      //stop the Watch_dog counter
    _BIC_SR(0x20);     
    BCSCTL1=0x00;  //XT2 开启
    do
    {
IFG1 &=~OFIFG;
for (i=0;i<0xff;i++);
    }
    while ((IFG1&OFIFG)!=0);
    BCSCTL2 = SELM1+SELS; //MCLK=XT2,SMCLK=MCLK
    WDTCTL=WDTPW+WDTCNTCL+WDTSSEL; //clear the Watch_dog counter,select the 1 second period
    P1DIR=0x1C;
    P2DIR=0x00;
    P3DIR=0x0f;
    P3SEL=0xf0;   //Enable USART0,1
    P4DIR=0x02;
    P5DIR=0xa0;
    P6DIR=0x60;
    P5OUT|=P5_5_DAT;
    P5DIR&=~P5_5_DAT;
    pq=(unsigned int *)0xfd00;
    for (i=0;i<8;i++)       //读出FLASH保存的参数
    {
      FlashWord[i]=*pq;
      pq++;
    }
    CAddress=FlashWord[0]; //仪表地址
    if (CAddress>247)
      CAddress=1;
    Cbps=FlashWord[1];
    if (Cbps==0xff)
      Cbps=3;
    Cdata8=FlashWord[2];
    if (Cdata8==0xff)
      Cdata8=0;
    Cmima[0]=FlashWord[3]&0x0f;
    Cmima[1]=FlashWord[3]>>4;
    Cmima[2]=FlashWord[4]&0x0f;
    Cmima[3]=FlashWord[4]>>4;
    Cmnumber=FlashWord[5];
    if (Cmnumber==0xff)
      Cmnumber=11;
    Cbpss=FlashWord[6];
    if (Cbpss==0xff)
      Cbpss=4;
    Cdata8s=FlashWord[7];
    if (Cdata8s==0xff)
      Cdata8s=0;
    //TACTL = TASSEL0 + TACLR;    //select the MCLK as the clock in
    //CCTL0=CCIE;                 //enable the comparation interrupt of CC0
    //CCTL2=CCIE;
    //TACTL|=MC1;                 //continous increase counter   
    //TBCTL=TBSSEL0+TBCLR;   //TB初始化
    //TBCCTL0=CCIE;
    //TBCTL|=MC1;
    switch(Cdata8)
    {
    case 0:
      UCTL0 = CHAR+SWRST;         //8位数据,1位停止位,n校验
      break;
    case 1:
      UCTL0 = CHAR+SWRST+PENA;    //8位数据,1位停止位,奇校验
      break;
    case 2:
      UCTL0 = CHAR+SWRST+PENA+PEV;//8位数据,1位停止位,偶校验
      break;
    case 3:
      UCTL0 = CHAR+SWRST+SPB;         //8位数据,2位停止位,n校验
      break;
    case 4:
      UCTL0 = CHAR+SWRST+PENA+SPB;    //8位数据,2位停止位,奇校验
      break;
    case 5:
      UCTL0 = CHAR+SWRST+PENA+PEV+SPB;//8位数据,2位停止位,偶校验
      break;
    default :
      UCTL0 = CHAR+SWRST;         //8位数据,1位停止位,n校验
      break;
    }
    switch(Cbps)
    {
    case 0://1200
      UTCTL0 = SSEL1;             //选择UCLK = SMCLK
      UBR00 = 0x00;              //设置波特率1200bit/s
      UBR10 = 0x10;
      UMCTL0 = 0x00;
      Couttime=30;
      CdelayT=45;
      break;
    case 1://2400
      UTCTL0 = SSEL1;             //选择UCLK = SMCLK
      UBR00 = 0x00;              //设置波特率2400bit/s
      UBR10 = 0x08;
      UMCTL0 = 0x00;
      Couttime=16;
      CdelayT=30;
      break;
    case 2://4800
      UTCTL0 = SSEL1;             //选择UCLK = SMCLK
      UBR00 = 0x00;              //设置波特率4800bit/s
      UBR10 = 0x04;
      UMCTL0 = 0x00;
      Couttime=8;
      CdelayT=16;
      break;
    case 3://9600
      UTCTL0 = SSEL1;             //选择UCLK = SMCLK
      UBR00 = 0x00;              //设置波特率9600bit/s
      UBR10 = 0x02;
      UMCTL0 = 0x00;
      Couttime=4;
      CdelayT=8;
      break;
    case 4://19200
      UTCTL0 = SSEL1;             //选择UCLK = SMCLK
      UBR00 = 0x00;              //设置波特率19200bit/s
      UBR10 = 0x01;
      UMCTL0 = 0x00;
      Couttime=4;
      CdelayT=4;
      break;
    default :
      UTCTL0 = SSEL1;             //选择UCLK = SMCLK
      UBR00 = 0x00;              //设置波特率19200bit/s
      UBR10 = 0x01;
      UMCTL0 = 0x00;
      Couttime=4;
      CdelayT=4;
      break;
    }
    UCTL0 &= ~SWRST;
    ME1 |= UTXE0 + URXE0;       //打开模块USART0
    IE1 |= URXIE0 ;  //打开USART0接收中断
    P3OUT&=~P3_3_RTS;
    switch(Cdata8s)
    {
    case 0:
      UCTL1 = CHAR+SWRST;         //8位数据,1位停止位,n校验
      break;
    case 1:
      UCTL1 = CHAR+SWRST+PENA;    //8位数据,1位停止位,奇校验
      break;
    case 2:
      UCTL1 = CHAR+SWRST+PENA+PEV;//8位数据,1位停止位,偶校验
      break;
    case 3:
      UCTL1 = CHAR+SWRST+SPB;         //8位数据,2位停止位,n校验
      break;
    case 4:
      UCTL1 = CHAR+SWRST+PENA+SPB;    //8位数据,2位停止位,奇校验
      break;
    case 5:
      UCTL1 = CHAR+SWRST+PENA+PEV+SPB;//8位数据,2位停止位,偶校验
      break;
    default :
      UCTL1 = CHAR+SWRST;         //8位数据,1位停止位,n校验
      break;
    }
    switch(Cbpss)
    {
    case 0://1200
      UTCTL1 = SSEL1;             //选择UCLK = SMCLK
      UBR01 = 0x00;              //设置波特率1200bit/s
      UBR11 = 0x10;
      UMCTL1 = 0x00;
      Couttime1=30;
      CdelayT1=45;
      break;
    case 1://2400
      UTCTL1 = SSEL1;             //选择UCLK = SMCLK
      UBR01 = 0x00;              //设置波特率2400bit/s
      UBR11 = 0x08;
      UMCTL1 = 0x00;
      Couttime1=16;
      CdelayT1=30;
      break;
    case 2://4800
      UTCTL0 = SSEL1;             //选择UCLK = SMCLK
      UBR01 = 0x00;              //设置波特率4800bit/s
      UBR11 = 0x04;
      UMCTL1 = 0x00;
      Couttime1=8;
      CdelayT1=16;
      break;
    case 3://9600
      UTCTL1 = SSEL1;             //选择UCLK = SMCLK
      UBR01 = 0x00;              //设置波特率9600bit/s
      UBR11 = 0x02;
      UMCTL1 = 0x00;
      Couttime1=4;
      CdelayT1=8;
      break;
    case 4://19200
      UTCTL1 = SSEL1;             //选择UCLK = SMCLK
      UBR01 = 0x00;              //设置波特率19200bit/s
      UBR11 = 0x01;
      UMCTL1 = 0x00;
      Couttime1=4;
      CdelayT1=4;
      break;
    default :
      UTCTL1 = SSEL1;             //选择UCLK = SMCLK
      UBR01 = 0x00;              //设置波特率19200bit/s
      UBR11 = 0x01;
      UMCTL1 = 0x00;
      Couttime1=4;
      CdelayT1=4;
      break;
    }
    UCTL1 &= ~SWRST;
    ME2 |= UTXE1 + URXE1;       //打开模块USART1
    IE2 |= URXIE1 ;  //打开USART1接收中断
    P3OUT&=~P3_2_RTS1;
    TempDelay(2000);
    write728x(0x12,0xc8); // 初始化BC728x为164模式,保护(RP=1),不反相,BMS=1, KMS=0
    write728x(0x1b,0x00); // 初始化BC728x为不闪烁
    write728x(0x10,0xff); // 初始化BC728x为不闪烁
    write728x(0x1c,0xbf); // 初始化BC728x闪烁速度2Hz
    write728x(0x11,0x40); // 初始化BC728x闪烁速度2Hz
    write728x(0x16,0x00); // 初始化BC728x清屏
    write728x(0x17,0x00); // 初始化BC728x清屏
    CDispBuff[11]=0x0f;
    CDispBuff[10]=0x0f;
    CDispBuff[9]=0x0f;
    CDispBuff[8]=0x0f;
}
/************************************************************
*Function:主程序
*parameter:
*Return:
*Modify:
*************************************************************/
void main(void)
{
      system_ini();
      Beep();
      _EINT();
      while(1)
    {
        dog();
        key_int();      //键盘扫描
        HandleUART0();
HandleUART1();
        UpdateStateMachine();
        mDisplay();
    }
}

/************************************************************
*Function:USART0RX中断处理  modbus_RTU 通讯协议
*parameter: 01 04 00 00 00 01 31 ca(上位机指令)
*Return:    01 04 02 DD DD CRCH CRCL(下位机应答)
*Modify:RS485接口 115200 E 8 1
*************************************************************/
#pragma vector=USART0RX_VECTOR
__interrupt void UsartRx0 (void)
{
    if((URCTL0&RXERR)==0)
    {
    aRxBuff0[NRxBuff0]=RXBUF0;
           NRxBuff0++;
           timeoutCounter0 = 0;
    }     //接收无错误发生
    else
    {
      aRxBuff0[NRxBuff0]=RXBUF0;    //接收出错
      bUartRxErr0=1;
      NRxBuff0=0;
      timeoutCounter0 = 0;
    }
}
/************************************************************
*Function:  USART1接收中断
*parameter:
*Return:
*Modify:
*************************************************************/
#pragma vector=USART1RX_VECTOR
__interrupt void UsartRx1(void)
{
  if((URCTL1&RXERR)==0)
    {
    aRxBuff1[NRxBuff1]=RXBUF1;
           NRxBuff1++;
           timeoutCounter1 = 0;
    }     //接收无错误发生
    else
    {
      aRxBuff1[NRxBuff1]=RXBUF1;    //接收出错
      bUartRxErr1=1;
      NRxBuff1=0;
      timeoutCounter1 = 0;
    }
  
}
/************************************************************
*Function:定时器TA0中断处理  定时1秒发波一次
*parameter:
*Return:
*Modify:
*************************************************************/
#pragma vector=TIMERA0_VECTOR
__interrupt void  timerA0 (void)
{
  
  
}
/************************************************************
*Function:定时器TA1中断处理
*parameter:
*Return:
*Modify:
*************************************************************/
#pragma vector=TIMERA1_VECTOR
__interrupt void timerA1 (void)
{
switch(TAIV)
        {
case 2:

break; //CCR1      
case 4:
CCR2+=32768;

break; //ccr2
case 10:

break;//A1溢出
        }
}
/************************************************************
*Function:定时器TB0中断处理,
*parameter:
*Return:
*Modify:
*************************************************************/
#pragma vector=TIMERB0_VECTOR
__interrupt void timerB0 (void)
{
  
  
}
/************************************************************
*Function:定时器TB1中断处理
*parameter:
*Return:
*Modify:
*************************************************************/
#pragma vector=TIMERB1_VECTOR
__interrupt void timerB1 (void)
{
switch(TBIV)
        {
case 2:

break; //CCR1      
case 4:

break; //ccr2
case 6:

break; //ccr3
case 8:

break; //ccr4
case 10:

break;  //ccr5
case 12:

break; //ccr6
case 14:

break; //B1溢出2
        }
}
/************************************************************
*Function:
*parameter:
*Return:
*Modify:
*************************************************************/
#pragma vector=COMPARATORA_VECTOR
__interrupt void comparatorA (void)
{
  
}
沙发
张涛0504| | 2010-11-4 14:53 | 只看该作者
你那个程序太牛了 小弟是初次接触  想研究下  能不能给小弟讲解指点一二呢 感激不尽哦

使用特权

评论回复
板凳
gaobq| | 2010-11-6 22:00 | 只看该作者
学习了

使用特权

评论回复
地板
maxsuntech| | 2011-1-14 20:01 | 只看该作者
感激

使用特权

评论回复
5
bbgan| | 2012-7-19 09:57 | 只看该作者
想求个430写的modbus上位机例程,初次接触,不懂

使用特权

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

本版积分规则

0

主题

1

帖子

1

粉丝