以下是我做的一些条记,为了避免重复劳动,摧残浪费蹂躏韶光,就直接截图上来了。
[1] LIN总线特点这里我选择了最小封装的TJA1027,8脚芯片,以下为LIN master模式的配置电路。 详细关于TJA1027请自行网上找它的datasheet
[四]LIN-BUS的帧格式
Break长度一样平常为为13位,我们称之为:间隔场.(参考网上的一张比较不错的图)
一个完全的LIN通信帧
示波下的真实waveform
逻辑剖析仪下的 读某品牌油泵的时序
[五]MSP430F24X下的LIN BUS配置这里我利用MSP430F249为例,UART模块,需支持SCI功能。才可以支持LIN,以是不是所有的MSP430系列都支持LIN总线,查看Datasheet是最有效的办法。
在Slave 模式下,UART需支持自动波特率检测(在一些特定标准下,波特率是特定的)UART=8 bit,LSB优先,无奇偶位,1停滞位 。 这点和普通的串口单元设置基本一样接口驱动芯片,这里我选用的是TJA1027,实现通信电平上面的转换主模式: 自动天生间隔场(break)和同步码(synch)选择自动波特率检测模式 UCTXBRK=1DELIMx指定 break Delimiter的长度,默认为1位周期检测TXBUF是否准备就绪,并向TXBUF写入同步码 0x55h传输13位间隔场后,然后便是break delimiter 和synch 同步场,UCTXBRK在同步载入TX移位寄存器后自动重设,写入TXBUF的数据正常传输[六]代码部分1.PID部分:Protected 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 is 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 LIN_Readbuf_Pro(uchar data) // // put this function into RX interruption ////---------------------------------------------------------//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; }
串口吸收和发送处理:
//--------------------------------------------------------//// void USART_UCA0_Send_Byte(uchar data)//-------------------------------------------------------//void USART_UCA0_Send_Byte(uchar data){ UCA0TXBUF = data; while(!Get_Bit(UC0IFG,UCA0TXIFG));}//------------------------------------------------------//// 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; //Set the clock of UCA0 =SMCL,UCSWRST Enable,initial all USCI registors UCA0CTL1 |= UCSSEL_2 + UCSWRST; 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]实际调试,正常驱动某品牌汽车油泵
参考文档:
汽车通讯协议标准(LIN)范围规范TI MSP430F24X Family Datasheet