本帖最后由 袁胜富 于 2023-10-12 09:05 编辑
#申请原创#
一、概述
CH32X035拥有两个高级定时器,TIM1和TIM2,每个定时器拥有四个输入通道,可以输出PWM也可以捕获PWM,平时也可以作为通用定时器使用。
在无刷有霍尔感应的电机,每一个电机需要一个霍尔板,霍尔板上有三颗霍尔元件,通用感应磁场位置进行编码,从而进行六步换相。在生产霍尔板时,需要对其进行良品测试,一般治具下面放个旋转电机,电机轴上放一个磁铁,转动电机模拟磁场变化,在盘上开辟可以完全同心的位置固定霍尔PCB板,当电机转动磁场变化产生霍尔信号,捕获霍尔信号的两两之间的相位差可以判定霍尔PCB的好坏。
此篇评测的是利用CH32X035的TIM2高级定时器外设捕获霍尔的三个信号,计算相位差,从而知道霍尔板的好坏。有兴趣或者有需要完整方案的人士可以联系我。
于是乎为了和大家分享,我出了这个文章。
二、原理分析和硬件连接
原理分析
图1如上图1
所示U1、U2和U3都是霍尔元件,一般公司生产需要测量硬件的好坏,在制作测试治具时一般需要使用定时器的输入捕获功能。
图2
记H1的上升沿时刻为T1,记H2的上升沿时刻为T2,记H3的上升沿时刻为T3,周期为T。
H1和H2两个霍尔之间的相位差计算公式如下:
H2和H3两个霍尔之间的相位差计算公式如下:
硬件连接
霍尔板开发板
Hall1------>PA0
Hall2------>PA1
Hall3------>PA2
VCC------->VCC
GND------->GND
三、代码
HALL.H代码:
#ifndef __HALL_H
#define __HALL_H
#include "debug.h"
#include "String.h"
#include "Stdlib.h"
#include "Stdio.h"
#include "Stdarg.h"
#include "ctype.h"
typedef struct
{
float Current_H1_H2_Phase_Diff;//H1和H2的相位差的当前测量值
float LowerLimit_H1_H2_Phase_Diff;//H1和H2的相位差的下限值
float UpperLimit_H1_H2_Phase_Diff;//H1和H2的相位差的上限值
float Current_H2_H3_Phase_Diff;//H2和H3的相位差的当前测量值
float LowerLimit_H2_H3_Phase_Diff;//H2和H3的相位差的下限值
float UpperLimit_H2_H3_Phase_Diff;//H2和H3的相位差的上限值
float Current_NTC_ADC_Value;//敏电阻电压当前测量值
float LowerLimit_NTC_ADC_Value;//热敏电阻电压下限值
float UpperLimit_NTC_ADC_Value;//热敏电阻电压上限值
float Motor_DIR;//电机的转向设置---》1正转----》0反转
float Hall_Board_Relay_Time;
}Hall_DATA_TYPEDEF;
extern Hall_DATA_TYPEDEF HALL_Capture_Data;
extern volatile int HFlag;
extern volatile int H1_Value;
extern volatile int H2_Value;
extern volatile int H3_Value;
void Hall_Singal_Captrue(void);
#endif
Hall.c代码
#include "Hall.h"
Hall_DATA_TYPEDEF HALL_Capture_Data ={0,0,0,0,0,0,0,0,0,0,0};
volatile int Over_flower=0;
volatile int H1_Value=0;
volatile int H2_Value=0;
volatile int H3_Value=0;
volatile int HFlag=0;
volatile int temp=0;
volatile int f1=0,f2=0,f3=1;
void TIM2_CC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void TIM2_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void Hall_Singal_Captrue(void)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
TIM_ICInitTypeDef TIM_ICInitStructure={0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};
NVIC_InitTypeDef NVIC_InitStructure={0};
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init( GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 48-1;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM2, &TIM_ICInitStructure );
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM2, &TIM_ICInitStructure );
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM2, &TIM_ICInitStructure );
NVIC_InitStructure.NVIC_IRQChannel = TIM2_UP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig( TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_Update, ENABLE );
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_Update);
TIM_Cmd( TIM2, ENABLE );
}
void TIM2_UP_IRQHandler(void)
{
if(TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) != RESET)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
{
Over_flower++;
}
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
void TIM2_CC_IRQHandler(void)
{
if(TIM_GetFlagStatus(TIM2, TIM_FLAG_CC1)!= RESET)
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
if(f3 == 1)
{
H1_Value = (TIM2->CNT + 1) + (Over_flower * 65536);
HFlag = 1;
TIM_SetCounter(TIM2, 0);
Over_flower = 0;
f3 = 0;
f1 = 1;
}
}
}
if(TIM_GetFlagStatus(TIM2, TIM_FLAG_CC2)!= RESET)
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
{
if(f1 == 1)
{
H2_Value = (TIM2->CNT + 1) + (Over_flower * 65536);
f2 = 1;
f1= 0 ;
}
}
}
if(TIM_GetFlagStatus(TIM2, TIM_FLAG_CC3)!= RESET)
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)
{
if(f2 == 1)
{
H3_Value = (TIM2->CNT + 1) + (Over_flower * 65536);
f2 = 0;
f3 = 1;
}
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3);
}
Main.c代码
#include <stdio.h>
#include "debug.h"
#include "Hall.h"
u8 H1=0,H2=0,H3=0;
float UV_Temp=0.0;
float VW_Temp=0.0;
int NTC_Temp = 0;
float ntc_Temp=0.0;
float UV=0.0;
float VW=0.0;
/*********************************************************************
* @fn main
*
* [url=home.php?mod=space&uid=247401]@brief[/url] Main program.
*
* [url=home.php?mod=space&uid=266161]@return[/url] none
*/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init(115200);
Hall_Singal_Captrue();//波形捕获定时器初始化
while(1)
{
if(HFlag == 1)
{
HFlag= 0;
HALL_Capture_Data.Current_H1_H2_Phase_Diff = ((float)H2_Value/(float)H1_Value)*360.0;
HALL_Capture_Data.Current_H2_H3_Phase_Diff = ((float)(H3_Value -H2_Value)/(float)H1_Value)*360.0;
printf("UV_Value=%f\r\n",HALL_Capture_Data.Current_H1_H2_Phase_Diff);
printf("VW_Value=%f\r\n\r\n",HALL_Capture_Data.Current_H1_H2_Phase_Diff);
}
}
}
四、展示
工程源码在附件。
|