MSP430 LIN总线编程

                                             MSP430 LIN总线编程

                                                                                             Lis, 2021-2-3

     时隔接近20年,CSDN我回来了...以下为本人原创. 如转载,请注明出处!

      LIN总线在汽车领域应用十分的广泛。汽车上的油泵,自动折叠反光镜,大灯,锁等等慢速通信都会有LIN总线的应用身影。但网络上你几乎找不到MSP430在这方面的应用,就算去TI的官方网站上去找,去问客服,也找不到,MSP430似乎没有车规级型号,新能源汽车上几乎清一色的使用TI的DSP车规级芯片,所以也基本没有人在MSP430上使用LIN总线。但是掌握LIN总线的应用,会给我们在一些项目里带来很大的帮助。至于什么是LIN,什么CAN这些的术语,大家自己百度应该可以找到很详细介绍,这里不做过多的说明。

     以下是我做的一些笔记,为了避免重复劳动,浪费时间,就直接截图上来了。

[1] LIN总线特点

[二]物理层连接

[三]接口电路

   这里我选择了最小封装的TJA1027,8脚芯片,以下为LIN master模式的配置电路。 详细关于TJA1027请自行网上找它的datasheet

[四]LIN-BUS的帧格式

Break长度一般为为13位,我们称之为:间隔场.(参考网上的一张比较不错的图)

示波下的真实waveform:

逻辑分析仪下的 读某品牌油泵的时序:

[五]MSP430F24X下的LIN BUS配置

 这里我使用MSP430F249为例,UART模块,需支持SCI功能。才可以支持LIN,所以不是所有的MSP430系列都支持LIN总线,查看Datasheet是最有效的方式。

  1. 在Slave 模式下,UART需支持自动波特率检测(在一些特定标准下,波特率是特定的)
  2. UART=8 bit,LSB优先,无奇偶位,1停止位 。 这点和普通的串口单元设置基本一样
  3. 接口驱动芯片,这里我选用的是TJA1027,实现通信电平上面的转换

  1. 主模式: 自动生成间隔场(break)和同步码(synch)
  2. 选择自动波特率检测模式  UCTXBRK=1
  3. DELIMx指定 break Delimiter的长度,默认为1位周期
  4. 检测TXBUF是否准备就绪,并向TXBUF写入同步码 0x55h
  5. 传输13位间隔场后,然后就是break delimiter 和synch 同步场,UCTXBRK在同步载入TX移位寄存器后自动重设,写入TXBUF的数据正常传输

[六]代码部分

  1.PID部分:ID只是高6个位,后两个位为奇偶效验码.

//---------------------------------------------------------------------------//
//                       uchar LIN_GetPID(uchar id)                          //
//Description: calculate  odd and even parity for ID Frame                   // 
//   Parity:                                                                 //
//             P0= id0^id1^id2^id4      ==>Even  bit6                        //                   
//             p1=~(id1^id3^id4^id5)    ==>Odd   bit7                        //
//---------------------------------------------------------------------------//
uchar LIN_GetPID(uchar id)
{
  uchar parity=0, p0,p1;

   p0 =id;
   p0^=id>>1;
   p0^=id>>2;
   p0^=id>>4;
   p0&=0x01;
   
   p1 =id>>1;
   p1^=id>>3;
   p1^=id>>4;
   p1^=id>>5;
   p1=~p1;
   p1&=0x01;
   
  parity=id|(p0<<6)|(p1<<7);
  
  return parity;
}

2.checksum

LIN总线中的checksum算法为带进位的累加。 在LIN总线里,有两种校验方式,一种称为标准验校,和增强型校验。 代码中我做了相关的说明。

//---------------------------------------------------------------------------//
//                               calculate checksum                          //  
//paremeters: uchar id:           slaver id                                  //
//            uchar *data         array of data,maximum:8 bytes              //
//            uchar len            length of the data array                  // 
//---------------------------------------------------------------------------//
uchar LIN_Checksum(uchar id,uchar *data,uchar len)
{
  uint16 sum = 0;
  uchar  i;
  
  //if it's not a diagnostic package  | id==0x3c using normal checksum,otherwise using enhance checksum  
     if (id!=0x3c)                                                             
     {
        sum=LIN_GetPID(id);
     }
    
     for(i = 0; i < len; i++)
     {
        sum +=data[i];
        if(sum&0xff00)
        {
          sum&=0x00ff;
          sum+=1;
        }  
     }

    sum=~sum;
  
  return (uchar)sum;
}

3.添加发送间隔场和同步场

我在代码中加了宏代码,以方便我配置LIN端口使用UART0 或UART1


//----------------------------------------------------------------------------//
//                    void USART_UCA0_Send_Byte(uchar data)
//----------------------------------------------------------------------------//
void USART_UCA0_Send_Byte(uchar data)
{
   UCA0TXBUF = data;
   while(!Get_Bit(UC0IFG,UCA0TXIFG));
}

//---------------------------------------------------------------------------//
//                          LIN_Send_Break_Sync(void)                        //                 
//---------------------------------------------------------------------------//
void LIN_Send_Break_Sync(void)
{
   UCA0CTL0_bit.UCMODE0=1;
   UCA0CTL0_bit.UCMODE1=1;
    //4bit stop
   UCA0ABCTL_bit.UCDELIM0=1;
   UCA0ABCTL_bit.UCDELIM1=1;
   
   UCA0CTL1_bit.UCTXBRK=1;
   USART_UCA0_Send_Byte(0x55);
   UCA0CTL1_bit.UCTXBRK=0; 
}
4.一个完整帧的发送:
//---------------------------------------------------------------------------//
//                               LIN_Sendbuf                                 //
//                                                                           //
//paremeters: uchar id:           slaver id                                  //
//            uchar *data         array of data,maximum:8 bytes              //
//            uchar len            length of the data array                  //   
//---------------------------------------------------------------------------//
void LIN_Sendbuf(uchar id,uchar *data,uchar len)
{
  uchar check_sum, parity_id;
  uint16 i;
  
   LIN_Send_Break_Sync();
   
   parity_id=LIN_GetPID(id);
   USART_UCA0_Send_Byte(parity_id);
   
   for(i=0;i<len;i++){  
      USART_UCA0_Send_Byte(data[i]);
   }  
   check_sum=LIN_Checksum(id,data,len);
   USART_UCA0_Send_Byte(check_sum); 
}

5.发送读操作帧

//---------------------------------------------------------------------------//
//                 void LIN_RX_Ask(uchar id)                                 //
//                                                                           //
//definition: Send Syn frame to slaver, Slaver will send back the data       //
//parameter: uchar id                                                        //
//---------------------------------------------------------------------------//
void LIN_RX_Ask(uchar id)
{
   uchar parity_id;

   LIN_RX_Idx=0;
   LIN_Send_Break_Sync();
   parity_id=LIN_GetPID(id);
   USART_UCA0_Send_Byte(parity_id);
}

如这里的时序,master端发送Ask(break+sync+PID),然后slave同步并返回数据帧。 这个比较容易理解,类似于I2C,SPI,1 wire 总线。

6.接收处理:
  将接收处理部分写成单独的函数,然后放到串口接收中断中
   
//----------------------------------------------------------------------------//
//                    void USART_UCA0_Send_Byte(uchar data)
//----------------------------------------------------------------------------//
void USART_UCA0_Send_Byte(uchar data)
{
   UCA0TXBUF = data;
   while(!Get_Bit(UC0IFG,UCA0TXIFG));
}

//---------------------------------------------------------------------------//
//                 void LIN_Readbuf_Pro(uchar data)                          //  
//  put this function into RX intterruption                                  //
//---------------------------------------------------------------------------//
void LIN_Readbuf_Pro(uchar data)
{
  switch(LIN_RX_Idx)
  {
   case 0:
        if(data==0x55)
        {
           LIN_RX_Idx=1;
        }  
        break;
        
   case 1:
        LIN_RX_Frame.id=data&0x3F;
        LIN_RX_Idx=2;
        break;
   case 2:
   case 3:
   case 4:
   case 5:
   case 6:
   case 7:
   case 8:
   case 9:
        LIN_RX_Frame.d[LIN_RX_Idx-2]= data;
        LIN_RX_Idx++;
        break;
   case 10: 
        LIN_RX_Frame.chksum=data;
        LIN_RX_Idx=0;
        break;
  }      
}

串口接收中断:

//----------------------------------------------------------------------------//
//                  USCI0RX_ISR     UCA0 Interruption
//----------------------------------------------------------------------------//
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
       uchar data=0;
       data = UCA0RXBUF;
    // if (UC0IFG&UCA0RXIFG) 
   //  {
    
       LIN_Readbuf_Pro(data);    
    // }
}

7.串口设置

#define BAUD_UCA0     10417

//----------------------------------------------------------------------------//
uchar Get_UCBRS(float baud)
{
   return ((uchar)((baud-(uint16)baud)*8+0.5))<<1;
}


//----------------------------------------------------------------------------//
//                      void Init_Serial_Ports(void)
//----------------------------------------------------------------------------//
void Init_Serial_Ports(void)
{
    float tmp_baud;
             
        SetPinMode(UCA0_TXD_PIN);
        SetPinMode(UCA0_RXD_PIN);    
  
        tmp_baud=CPU_F/2/BAUD_UCA0;
        UCA0CTL1 |= UCSSEL_2 + UCSWRST;                                         //Set the clock of UCA0 =SMCL,UCSWRST Enable,initial all USCI registors 
        UCA0BR0 =(uchar)(tmp_baud);                                            //Low 8 bits
        
        UCA0BR1 =(uchar)((uint16)tmp_baud>>8);                                 // //High 8bits, NO parity check 
        
        UCA0MCTL = Get_UCBRS(tmp_baud);
       
        UCA0CTL1 &= ~UCSWRST;                                                   //clear UCSWRST bit
        UC0IE |= UCA0RXIE;                                                      //Enable RX Interruptor 
      
}

[7]测试板电路设计

    [1]电源部分

           先设计打算使用于24V电路,所以输入端,和LIN总线电压为24V,但是实际应用调试的油泵为12V,所以主供电也为12V。 这里做个说明. 

 

 [2]MSP430部分相对简单,最小系统,然后把端口都引出去

[3]LIN接口电路

[4]调试用TTL串行口电路

   增加缓冲电路,能有效加强TTL串口的可靠,稳定性。

[5]电路指示

[6]预留的一个大功率IO驱动口,用于驱动外部电磁阀等器件

[7]Layout

    根据schematic,布好PWB后,生成工艺文件以及BOM发给PCB工厂进行打样生产。

[8]实际调试,正常驱动某品牌汽车油泵

  • 12
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lijinjie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值