OBD技术速成——J1850协议解析软件实现

在整理过程中进步,与君共勉!

J1850-PWM和J1850-VPW的通信协议底层时序可以参考:J1850-PWM和J1850-VPW协议底层时序

PWM和VPW的接收可以使用定时器的输入捕获功能,将总线收到的信号的脉冲宽度测出,可在中断中利用状态机实时解析数据(或者使用外部中断,上下沿触发,同时开启定时器,在外部中断函数中以定时器的计数值记录脉冲宽度)
PWM和VPW的发送可以使用定时器的比较输出功能,以STM32为例,根据发送数据的数据位脉宽改变CCR,到时间了触发中断可以在中断里利用状态机赋值下一个CCR,达到按协议输出信号的效果

部分配置如下:

void j1850_rxtimer_config(char *psel_Type)
{
    
    
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	switch (*psel_Type){
    
    
	case PSEL_TYPE_PWM:
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 
		TIM_DeInit(TIM3);
		TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
		TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
		TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
		TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
		TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

		TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
		TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
		TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
		TIM_ICInitStruct.TIM_ICFilter = 0;
		TIM_ICInitStruct.TIM_Channel = TIM_Channel_4;
		TIM_ICInit(TIM3, &TIM_ICInitStruct);
		nvic_Init(TIM3_IRQn,1,0,ENABLE);
		break;
	case PSEL_TYPE_VPW:
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 
		nvic_Init(TIM3_IRQn,1,0,DISABLE);
		TIM_DeInit(TIM3);
		TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
		TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
		TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
		TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
		TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
		
		nvic_Init(TIM3_IRQn,1,0,ENABLE);
	    break;
	}
}

void j1850_txtimer_config(char *psel_Type)
{
    
    //TIM4_CH1
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStruct;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); 
	nvic_Init(TIM4_IRQn,0,0,DISABLE);
	TIM_DeInit(TIM4);
	if (*psel_Type == PSEL_TYPE_PWM)
		j1850_txTimerIRQHandle = j1850_pwm_tx;
	else 
		j1850_txTimerIRQHandle = j1850_vpw_tx;
    TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
	TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_Timing;
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Disable;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
	TIM_OC4Init(TIM4, &TIM_OCInitStruct);
	TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
	nvic_Init(TIM4_IRQn,0,0,ENABLE);
}

这里还提供另一种实现思路:
发送部分:
1、开一个定时器TIM1,配置成PWM比较输出模式,
2、开启两个DMA通道,触发源为TIM1_DMA_update和TIM1_DMA_CC1
3、开2个同样大数组,一个是周期,一个是脉宽,大小为你要发送的最长数据的8倍,(一个数据为1个bit)
4、将你要发送的数据按顺序拆分为2bit一组,对照上面的关系图将周期和脉宽转换为定时器的pwm周期和脉宽值,填进表内,别忘了起始和结束脉冲
5、配置2个dma,发送数据量和数据源地址,地址为两个数组地址,打开dma的发送完成中断,打开TIM1 CC1,
6、剩下的事情就是让TIM和DMA自己嗨,等到程序自己进入了dma发送完成中断就是发送完成了

接收部分:
1、开一个定时器TIM4,配置成输入捕获模式,通道CC1和CC2
2、开启两个DMA通道,触发源为TIM_DMA_CC1和TIM_DMA_CC2
3、开启两个数组,同发送部分一样
4、启动tim的输入捕获和dma,等着vpw引脚信号到来,dma会自己将信号的周期和脉宽放入开好的数组内
5、将捕获到的脉宽和周期还原成原始数据,搞定收工!

猜你喜欢

转载自blog.csdn.net/weixin_44788542/article/details/111478301