【转】msp430单片机 can总线开发编程实例

2019-07-16 15:20发布

程序示例:#include "CAN.h"
#include "msp430_config.h"
#include "mcp2515.h"
#define uchar unsigned char
#define uint unsigned int
uchar flag;
INT16U NUM_COUNT = 0;
INT8U  Time_Flag = 0;
#define CAN_RST_0      P1OUT &=~BIT1   //
#define CAN_RST_1      P1OUT |= BIT1    //
uchar Address;                      //地址
uchar RecvBuff[8]={0};              //接收缓存区      
uchar SendBuff[8]={0}, SendIndex=0; //发送缓存区,接发送数据缓存区对应数
uchar can_isr_flag = 0;         //P1.2有CAN中断标志:接收、发送、错误、溢出
uchar can_rcv_data_flag = 0;    //CAN接收数据标志
uchar datapro_write_flag=0;//处理接收的数据正确,置位发送
uchar times;                   //计数次数
uchar SYSTime;
/////////////////////////////////////////////////////////////////////////////////////////////
void delay(uint x)
{
  uchar i;
  while(x--) for(i=120;i>0;i--);
}
///////////////////////////////////////////////////////////
void Init_Clk()
{
  uchar i;
  BCSCTL1&=~XT2OFF;             //打开XT2振荡器 //基础时钟控制寄存器BCSCTL1的第7位置0,使XT2启动
  do
  {
    IFG1 &= ~OFIFG;               // 清除振荡器失效标志
    for (i = 0xFF; i > 0; i--);   // 延时,等待XT2起振
  }
  while ((IFG1 & OFIFG) != 0);     // 判断XT2是否起振
  BCSCTL2 =SELM_2+SELS+DIVS_0;    //选择MCLK为XT2  SMCLK为XT2 不分频
}
/////////////////////////////////////////////////////////
void Init_TimeA()
{
   TACCTL0 = CCIE;               //TBCCR0允许中断
   TACCR0 = 8000;                //TIME:8000/(8mhz) =1ms                     
   TACTL = TASSEL_2 + MC_1;     //SMCLK,增计数模式
   _BIS_SR( GIE);     
}  
///////////////////////////////////////////////////////////
void set_p12_to_int( void )
{

P1DIR&=~BIT2; // 中断引脚应该设置为输入
P1IES|=BIT2;  //设置为下降沿触发,=0上升触发
P1IFG&=~BIT2; //因为P2IES设置会使中断标志位置位,故清零
P1IE|=BIT2;   //设置中断使能
}
//////////////////////////////////////////////
void init_SD24()
{
  uint i;
  SD24CTL = SD24SSEL_1+SD24REFON+SD24DIV_3;                       // 1.2V ref, SMCLK,SMLCK 8分频
  SD24INCTL0 = SD24INCH_0+SD24GAIN_16;                            // Set channel A0+/- 16倍增益  
  SD24CCTL0 |= SD24SNGL  + SD24IE+SD24OSR_512+SD24DF;             // Single conv,enable interrupt  采样率为512  数据格式(当增益为1时0-32768表示0~-600mv  65535~32768表示0~600mv)  
  for (i = 0; i < 0x3600; i++);                                   // Delay for 1.2V ref startup
}
/////////////////////////////////////////////////////////////////////
void RecvDataProc()  //处理从can来的数据或者命令
{
  if(RecvBuff[1]<0x40)
  {
    switch(RecvBuff[1])
    {
      case 0x01:   //读地址 ,单机命令  
          SendBuff[0]=0x00;
          SendBuff[1]=0x01;
          SendBuff[2]=Address;
          SendBuff[3]=0X21;
          SendIndex=4;  
          datapro_write_flag=1;
          break;
      case 0x02:   //读压力
          SendBuff[0]=Address;
          SendBuff[1]=0x02;
          SendBuff[2]= Ch0Adc /256;
          SendBuff[3]= Ch0Adc %256;
          SendBuff[4]= 0X21;
          SendIndex=5;
          datapro_write_flag=1;
          break;         
      default  :
        datapro_write_flag=0;
        break;
    }//end switch
  }//end
}
/************************************************************************************
** 函数名称: Pro_CAN_ERROR()
** 功能描述: CAN总线错误处理
** 输  入  : 数据类型       形参名      功能
** 输  出  : 数据类型       形参名      功能
** 全局变量: 无
** 调用模块: 无
*************************************************************************************/
void Pro_CAN_ERROR( void )
{
       unsigned char num;
       num=mcp2515_read_register( E** );         // 读错误标志寄存器,判断错误类型
       if( num & EWARN )                           // 错误警告寄存器,当TEC或REC大于或等于96时置1
       {
              mcp2515_write_register( TEC, 0 );
              mcp2515_write_register( REC, 0 );
       }
       if( num & RXWAR )                           // 当REC大于或等于96时置1
       { ;    }
       if( num & TXWAR )                           // 当TEC大于或等于96时置1
       { ;    }
       if( num & RXEP )                       // 当REC大于或等于128时置1
       { ;    }
       if( num & TXEP )                       // 当TEC大于或等于128时置1
       { ;    }
       if( num & TXBO )              // 当TEC大于或等于255时置1
       { delay_s(10);      }               //延时10s,等待单片机看门狗复位
       if( num & RX0OVR )                  // 接收缓冲区0溢出
       {
         mcp2515_write_register( E**, num & ~RX0OVR );             // 清中断标志;    // 根据实际情况处理,一种处理办法是发送远程桢,请求数据重新发送
       }
       if( num & RX1OVR )                  // 接收缓冲区1溢出
       {
          mcp2515_write_register( E**, num & ~RX1OVR );             // 清中断标志;
       }
}
/************************************************************************************
** 函数名称: CAN_ISR()
** 功能描述: CAN中断处理函数
*************************************************************************************/
void CAN_ISR(void)
{
  uchar num1,num2,num3,num,i;
  num1 = mcp2515_read_register(CANINTF);
                        // 读中断标志寄存器,根据中断类型,分别处理
   //---------------------------  报文错误中断
   if( num1 & MERRF )                                 
   {
      mcp2515_write_register( CANINTF, num1 & ~MERRF );             // 清中断标志
   }
   //---------------------------  唤醒中断
   if( num1 & WAKIF )
   {
      mcp2515_write_register( CANINTF, num1 & ~WAKIF );             // 清中断标志
      mcp2515_write_register( CANCTRL, CAN_NORMAL_MODE );           // 唤醒后,在仅监听模式,须设置进入正常工作模式
        //---------------------------  判断是否进入正常工作模式
      do
      {
          num = mcp2515_read_register( CANSTAT )& CAN_NORMAL_MODE;
      }
      while( num != CAN_NORMAL_MODE );
   }
   //---------------------------  Error interrupt!
   if(num1 & ERRIF)                                    // 错误中断
   {
      mcp2515_write_register(CANINTF, num1 & ~ERRIF);               // 清中断标志
      Pro_CAN_ERROR( );                                // 分别处理各个错误
   }
   //---------------------------  TX2 success!
   if( num1 & TX2IF )                                  // 发送2成功中断
   {
      mcp2515_write_register( CANINTF, num1 & ~TX2IF );             // 清中断标志
   }
   //---------------------------  TX1 success!
   if( num1 & TX1IF )                                  // 发送1成功中断
   {
      mcp2515_write_register( CANINTF, num1 & ~TX1IF );             // 清中断标志
   }
   //---------------------------  TX0 success!
   if(num1 & TX0IF)                                    // 发送0成功中断
   {
      mcp2515_write_register(CANINTF, num1 & ~TX0IF);               // 清中断标志
   }
   //---------------------------  RX1 interrupt!
   if( num1 & RX1IF )                                  // 接收1成功中断
   {
      mcp2515_write_register( CANINTF, num1 & ~RX1IF );             // 清中断标志
   }
  if(num1 & RX0IF)
  {
    mcp2515_write_register(CANINTF, num1 & ~RX0IF);  // 清中断标志
    num2 = mcp2515_read_register( RXB0SIDL );
    num3 = mcp2515_read_register( RXB0DLC );
    num = num3 & 0x0f;                               // 求数据长度
    if( num2 & IDE )                                 // 收到扩展帧
      {
         //---------------------------  Buffer 0 received extended remote frame!
         if( num3 & RTR )                              // 远程桢,则读取标识符,按照此标识符发送要求的数据
           { ; }
         else                                          // 数据桢,接收处理数据
            {  //---------------------------  Buffer 0 received extended data frame,data length is num
               for( i = 0; i < num; i++ )
               {
                  RecvBuff[ i ] = mcp2515_read_register( RXB0D0 + i );
               }
            }
        }
    RecvDataProc();        //处理接收到的数据命令,诸如:读地址、读压力、设置地址。。。。
  }  
}
/////////////////////////////////////////////////////////
void can_service()
{
if(can_isr_flag==1)            //如果有CAN中断
   {   
    can_isr_flag=0;
    CAN_ISR();                  //can中断处理 :接收数据,以及错误、溢出等中断处理
    if(datapro_write_flag==1)
          {
            datapro_write_flag=0;
            CAN_TX_D_Frame( 0, SendIndex, &SendBuff[0] );     // 通过CAN发送缓冲区0,发送数据长度为SendIndex的扩展帧数据,数据在 SendBuff[]中  
          }
   }  
}
////////////////////////////////////////////////////////////////////////
void main(void)
{  
/******************************************************************/  
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  Init_Clk();

  CAN_RST_1;        //mcp2515退出复位
  set_p12_to_int();
   init_SD24();
/****************************************************************/
  UCB0_SPI_Init(0X40);          //USCI SPI模式初始化
  UCB0_SPI_WriteByte(0X00);
/*******************************************************************/
  CanBusConfig();               //MCP2515初始化模块
  delay_s(1);
  Init_TimeA();
__enable_interrupt();         //Enable the Global Interrupt

  while(1)
  {        
      if(SYSTime>=10)   //TIME:100ms*10=1 S
        {
          SYSTime=0;
          ConvToPreVal();   
        }
      can_service();   //CAN服务程序,接收数据并按照协议处理数据,然后将处理的结果通过CAN总线上传
   }
}
/******************************************************************
函数名称:
函数功能:CAN接收中断处理函数
入口参数:
返回参数:
函数说明:
******************************************************************/
#pragma vector = PORT1_VECTOR
__interrupt void CanRxISR_Handler(void)
{
if((P1IFG&BIT2) == BIT2) //处理P1IN.2中断
    {  
     P1IFG &= ~BIT2; //清除中断标志
     can_isr_flag=1;
    }
}
/////////////////////////////////////////////////////////////
#pragma vector=TIMERA0_VECTOR      
__interrupt void Timer_A (void)
{
  __disable_interrupt();
  times++;   
  if(times>=100)  //IME:1ms*100=100MS            
  {
   SYSTime++;
   SD24CCTL0 |= SD24SC;//AD开始转换
   times=0;
   }
__enable_interrupt();
}
/////////////////////////////////////////////////////////////////
uchar FilterIndex=0;
uint FilterBuf[4]={0};
#pragma vector=SD24_VECTOR            //SD24 interrupt
__interrupt void SDA24(void)
{               
  //滑动平均滤波算法(递推平均滤波法)
  uchar i;
  long  uint sum=0;
  FilterBuf[FilterIndex++]=SD24MEM0;// Save CH0 results (clears IFG)
  if(FilterIndex==4) FilterIndex=0; //先进先出,再求平均值
  for(i=0;i<4;i++)sum+=FilterBuf;
  Ch0Adc=(sum/4);
  SD24INCTL0 = SD24INCH_0;
  SD24CCTL0 |= SD24SNGL  + SD24IE+SD24OSR_256;    // Single conv,enable interrupt  采样率为512  数据格式(当增益为1时0-32768表示0~-600mv  65535~32768表示0~600mv
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。