四缸汽油机曲轴及凸轮轴信号生成(基于STM32)

曲轴凸轮轴位置信号对于发动机电控十分重要,通过它们可以确定曲轴当前转速,以及判定x缸活塞到达上止点(判缸),是喷油和点火的重要依据。本次实验我们尝试基于STM32F103的最小系统板,来模拟脉冲型曲轴和凸轮轴信号。

曲轴每旋转2圈,凸轮轴旋转1圈,完成4次点火(1-3-4-2)。4缸汽油机常见的曲轴信号为60-2,即一周58个周期脉冲加两个周期低电平;4缸汽油机常见凸轮轴信号为每转4个脉冲(对应x缸活塞上止点,曲轴换向),且在一缸脉冲后30°额外添加一个脉冲,作为1缸信号(类似于磁场定向中的Z脉冲信号)。实际的曲轴与凸轮轴通过正时链条(或皮带)连接,具有同步性。

 

本次实验采用两个定时器(定时器1,定时器2),一个定时器中断服务(定时器1更新中断)。定时器1通过PWM(硬件动作,节省计算资源)来模拟曲轴脉冲信号,脉冲计数则在定时器1中断服务中完成。定时器2通过PWM来模拟凸轮轴脉冲信号,而脉冲计数则在定时器1中断服务中完成。

首先给出两个定时器的配置,

void TIMER1_INIT(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//输出PWM需要配置为复用推挽
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM1);//定时器1启用内部时钟
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//时基单元配置
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Down;//向下计数
	TIM_TimeBaseInitStructure.TIM_Period = 100-1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);//初始化其他未设置的变量
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式(高有效)
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);//(第1通道)
	TIM_ClearFlag(TIM1, TIM_FLAG_Update);//清中断标志位
	TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);//开定时器中断
	
	TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清定时器1中断标志位
	TIM_Cmd(TIM1, DISABLE);//关定时器
	TIM_CtrlPWMOutputs(TIM1, DISABLE);//关pwm主使能(高级定时器独有)
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级配置
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStructure);//配置中断通道
}
void TIMER2_INIT(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);//定时器1启用内部时钟
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//时基单元配置
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 200-1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1080-1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);//初始化其他未设置的变量
//	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式(高有效)
//	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
//	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//关下路互补,做单(上)桥臂斩波
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);//(第1通道)
	
	TIM_SetCounter(TIM2, 197);//同步预装
	TIM_Cmd(TIM2, DISABLE);//等待软件开定时器2
}

为了保证两个定时的PWM脉冲尽量对齐,在主程序中依次开启两个定时器,

int main()
{	
	TIMER1_INIT();
	TIMER2_INIT();
	TIM_Cmd(TIM1, ENABLE);//曲轴信号
	TIM_Cmd(TIM2, ENABLE);//凸轮轴信号
	TIM_SetCompare1(TIM1, 0);
	TIM_SetCompare1(TIM2, 0);
	while(1)
	{
		
	}
}

考虑到曲轴和凸轮轴信号并非单纯的脉冲,其存在大周期,所以两定时器比较器的装载值在定时器1中断服务中根据脉冲计数值来给定。

这里有一些需要注意的地方:

PWM是硬件动作,软件对比较器装载值的实时修改有时是“不及时”的。具体来讲,以向上计数,上溢中断为例,当计数器周期为100,比较器装载50,我们将得到0.5占空比的PWM,当完成58个脉冲输出后,我们需要在下个中断服务中将比较器装载值改为1,或直接关PWM,这里就体现的软件“不及时”的问题,如下图

 可以看出,原本是完全低电平的最后两个周期出现了两个窄脉冲,这是因为由上溢中断到来至配置比较器装置(或关PWM),程序执行需要时间,而在这段时间中比较器值大于计数器,所以PWM会出高电平。考虑到上述问题,本次实验采用向下计数,这样当更新(下溢)中断到来时,比较器值小于计数器,PWM不会出高电平。如下图所示

 对于曲轴信号,脉冲计数器值58,59和118,119为全周期低电平,大于119则归零复位(曲轴转2圈,凸轮轴转1圈,进入下一周期)。

凸轮轴信号通过通过定时器2的PWM来模拟,曲轴完成两个60-2,凸轮轴完成一个4脉冲,+一个1后30°单脉冲,所以定时器1的PWM频率时定时器2的30倍,通过设置分频及计数器周期可以对定时器2的PWM周期灵活调整;通过定时器2计数器的预装值来微调其相位。最后对于1缸上止点后30°的单脉冲,可通过在中断服务中修改定时器2比较器装载值来实现,如下图,

这里30°可以通过曲轴脉冲数来确定,凸轮轴30°对应曲轴60°,即第10脉冲,至于凸轮轴脉冲宽度,可以自定。中断服务如下

void TIM1_UP_IRQHandler(void)//定时器1中断服务函数
{
	static uint16_t num;//曲轴脉冲计数器
	if(TIM_GetITStatus(TIM1, TIM_IT_Update)==SET)//查定时器1中断标志位
	{	
		TIM_CtrlPWMOutputs(TIM1, ENABLE);//开pwm主使能(高级定时器独有)
		num++;
		if(num>=10&&num<=12)
		{
			TIM_SetCompare1(TIM2, 100);
		}
		else if(num==58|num==59|num==118|num==119)
		{
			TIM_SetCompare1(TIM2, 20);
			TIM_CtrlPWMOutputs(TIM1, DISABLE);//关pwm主使能(高级定时器独有)
		}
		else if(num>119)
		{
			num = 0;
			TIM_SetCompare1(TIM2, 20);
			TIM_SetCompare1(TIM1, 50);
		}
		else 
		{
			TIM_SetCompare1(TIM2, 20);
			TIM_SetCompare1(TIM1, 50);
		}
		
		TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清定时器1中断标志位
	}
}

 最终效果如下,

介于本人水平有限,本次实验目的仅仅是抛砖引玉,希望大家能够贴上更简单的代码。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值