STM32F0-LIN总线通讯程序代码 主从调试OK

最近在调试LIN总线通讯,使用的是STM32F072。使用F0与F1区别还是有一点,不过大致都可以共用,这里总结一下遇到的一些问题和解决方法。

首先看到上图,一帧的结构数据其实简单理解就是发送同步间隔段之后+串口数据。

发送同步间隔段F0遇到的问题就是没有发送断行字符的功能,需要用IO模拟同步间隔段,而F1有,可以直接调用库函数,或者直接操作寄存器。

F1 :CR1寄存器

所以F0需要模拟发送同步间隔段

/**
  * @brief  发送IO切换io模式	
  * @param  无
  * @retval 无
  */
void GPIO_Tx_Normal_Config(uint8_t Set)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  //设置发送的引脚为普通IO
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	if(0 == Set)
	{
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通IO
	}
	else
	{
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  //复用IO
	}
  GPIO_Init(GPIOB, &GPIO_InitStructure); //引脚初始化
}

/**
  * @brief  LIN同步间隔段发送		
  * @param  无
  * @retval 无
  */
void LIN_SendBreak(void) //仿造Break时序写的
{
	/*F1 可以直接调用库函数
		USART_SendBreak(USART1);
	*/
	GPIO_Tx_Normal_Config(0);
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);
	delay_us(700);
    GPIO_SetBits(GPIOB,GPIO_Pin_6);
	GPIO_Tx_Normal_Config(1);
	delay_us(55);

}

解决这个问题后,发送基本就是很简单,加上0x55同步段,加上PID,加上要发的数据,最后发送校验和。

用以下部分代码举例主机发送完整的一帧数据过程。

//主机写:发送帧头 + 响应
u8 senddata[8] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
u8 Linbuffer[11];

//同步段+PID+数据段(1~8)+校验和=(最大11个字节)

PID = LIN_GetPID(FrameID);	//获取PID
	
Linbuffer[0] = 0x55;
Linbuffer[1] = PID;	
for ( i = 0; i < 8; i++)
{
	Linbuffer[i + 2] = *(senddata + i);		
}	

Checksum = LIN_GetChecksum(FrameID,Linbuffer,DataLen); //获取校验和	
Linbuffer[8 + 2] = Checksum;	
				
LIN_SendBreak(USARTx); 				

LIN_SendBytes(USARTx, Linbuffer, 11);	

下面是一些主从都用到的代码

/**
  * @brief LIN_PID校验函数		
  * @param ID(FrameID):帧ID(0 ~ 63) 
  * P0(bit6) =   ID0 ^ ID1 ^ ID2 ^ ID4   <==>  (偶校验:操作数中1的个数为偶数,校验位为0,1的个数为奇数校验位为1)
  * P1(bit7) = ~(ID1 ^ ID3 ^ ID4 ^ ID5)  <==>  (奇校验:操作数中1的个数为奇数,校验位为0,1的个数为偶数校验位为1)
  * @retval 返回PID
  */
uint8_t LIN_GetPID(uint8_t ID)  
{
	uint8_t PID = 0,P0 = 0,P1 = 0;	
	P0 = (((ID>>0)^(ID>>1)^(ID>>2)^(ID>>4))&0x01)<<6; //偶校验位           			
	P1 = ((~((ID>>1)^(ID>>3)^(ID>>4)^(ID>>5)))&0x01)<<7; //奇校验位	
	PID = (ID|P0|P1);	
	return PID;   
}

/**
  * @brief  LIN协议规定校验和长度为1个字节			
  * @param  ID:校验ID,pData:数据指针,DataLen:数据长度
  * @retval 累加校验和
  */
uint8_t LIN_GetChecksum(uint8_t ID, uint8_t* pData,uint8_t DataLen) 			 
{
	  uint8_t i = 0;
	  uint16_t CheckSum = 0;  	
	  if(ID!=0x3C)
		{    //诊断帧只能使用标准校验和,标准校验和不包含PID     
			CheckSum = LIN_GetPID(ID);	//获取PID    		
	  }
	  for ( i = 2; i < DataLen; i++)
		{
			CheckSum += pData[i];		  
			if (CheckSum > 0xFF){
				CheckSum -= 0xFF;  
			}
	  }
	  return (~CheckSum) & 0xFF; 
}

总的来说简单的发送过程就是这样,当然为了严谨性使用的时候主从都需要加入接收缓存区减少丢包,还有加入错误判断和断开检测等。

有不懂的朋友可以在评论区留言交流,大家一下学习。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值