stm 32 TIM 1 PWMマルチチャネルキャプチャモード速度測定
一つのプロジェクトの要求で、速度を測る必要があるので、前からstm 32の捕獲モードを学びたいと思っていましたが、この機会に、ちょうど利用して、今共有します.
ハードウェア:
MCU:stm32f103zet6
プラットフォーム:航太電子流行7号スマートカー
表示:mini 12864
ソフトウェア:
言語:C言語
IDE:keil5
速度測定部分の環境は典型的な速度測定方法であり、速度測定コード盤に光電対管を加え、単片機は光電対管モジュールから伝わるPWM波を採集し、2つの車輪に対して速度を測定し、実際の速度は2つの車輪の大きな値を取る.
ソフトウェアにはTIM 1のキャプチャモードが採用されており、チャネルCH 1とCH 4が使用されており、それぞれPA 8とPA 11に対応しており、まず公式の入力キャプチャモードの説明を参照してください.
入力キャプチャモードでは、ICx信号上の対応するエッジが検出されると、カウンタの現在値は、キャプチャ/比較レジスタ(TIMx_CCRx)にラッチされる.キャプチャイベントが発生すると、対応するCCxIFフラグ(TIMx_SRレジスタ)が1セットされ、割り込みまたはDMA動作が開放されると、割り込みまたはDMA要求が発生する.キャプチャイベントが発生したときにCCxIFフラグがすでに高い場合、重複キャプチャフラグCCxOF(TIMx_SRレジスタ)は1にセットされる.書き込みCCxIF=0は、CCxIFを消去したり、TIMx_に読み出して格納したりすることができるCCRxレジスタのキャプチャデータは、CCxIFをクリアすることもできる.書き込みCCxOF=0は、CCxOFをクリアします.
次の例では、TI 1入力の立ち上がりエッジでカウンタの値をTIMx_にキャプチャする方法を示します.CCR 1レジスタでは、ステップは以下の通りです.
●有効入力端子の選択:TIMx_CCR 1はTI 1入力に接続する必要があるのでTIMx_に書き込むCCR 1レジスタのCC 1 S=01は、CC 1 Sが’00’でない限り、チャネルが入力され、TIMx_CCR 1レジスタは読み取り専用になります.
・入力信号の特徴に応じて、入力フィルタを所望の帯域幅(すなわち、入力がTIxの場合、入力フィルタ制御ビットはTIMx_CCMRxレジスタにおけるICxFビット)に設定する.入力信号が最大5個の内部クロックサイクルの時間内にジッタすると仮定し、フィルタの帯域幅が5個のクロックサイクルよりも長いように構成しなければならない.したがって、(fDTS周波数で)連続して8回サンプリングして、TI 1の最後の真のエッジ変換、すなわちTIMx_CCMR 1レジスタにはIC 1 F=001が書き込まれる.
●TIMx_でTI 1チャネルの有効な変換エッジを選択CCERレジスタにCC 1 P=0(立ち上がりエッジ)を書き込む.
・入力プリスプリッタを構成する.この例では、各有効レベル変換時に発生することをキャプチャしたいので、プリスプリッタは禁止される(TIMx_CCMR 1レジスタを書き込むIC 1 PS=00).
●TIMx_の設定CCERレジスタのCC 1 E=1であり、キャプチャカウンタの値をキャプチャレジスタに許可する.●必要に応じてTIMx_を設定DIERレジスタのCC 1 IEビットは関連割り込み要求を許可し、TIMx_を設定するDIERレジスタのCC 1 DEビットはDMA要求を許可する.
入力キャプチャが発生した場合:
●有効なレベル変換が発生した場合、カウンタの値がTIMx_に転送されるCCR 1レジスタ.
●CC 1 IFフラグが設定されている(割り込みフラグ).少なくとも2つの連続したキャプチャが発生した場合、CC 1 IFはクリアされず、CC 1 OFもセット1される.
●CC 1 IEビットが設定されていると、割り込みが発生します.
・CC 1 DEビットが設定されている場合、DMA要求も発生する.キャプチャオーバーフローを処理するためには、キャプチャオーバーフローフラグの読み出し前にデータの読み出しを行うことが推奨される.これは、キャプチャオーバーフローフラグの読み出し後およびデータの読み出し前に生じる可能性のあるキャプチャオーバーフロー情報の損失を回避するためである.
注意:TIMx_の設定EGRレジスタ内の対応するCCxGビットは、ソフトウェアによって入力キャプチャ割り込みおよび/またはDMA要求を生成することができる.
なお、初期化時にはホッピングのサンプリング回数を設定する必要があり、車輪によるPWM波の周波数が捕獲速度に対して低いため、サンプリング回数を大きく設定すべきであり、最大32回の対応値で0 x 0 fを設定する.これまで気づかなかったが、デフォルトの0にしていたため、結果が大きく、変動も大きく、サンプリングが間違った結果となった.
以下はTM 1捕獲モードの初期化であり、72 Mの結晶振動速度を採用し、配置されたタイマー周波数は10 KHzであり、周期は65535である.
speed.c
次のマクロ定義に注意してください.異なるチャネルで取得された取得値は、異なるレジスタにあります.
また、プレミアムタイマー1を使用しているため、割り込み入口はTIM 1_CC_IRQn
stm32f10x_it.c
次に、割り込み処理関数を見て、最も隣接する2つの下降エッジの時間を記録し、bufに記録する.bufのデータは最も近いパルス周期の時間であり、後のフィルタ計算を便利にし、左右輪の速度測定は同じ割り込み関数にある.
speed.c
次に、速度の計算を開始し、最大値と最小値をフィルタリングし、重み付け平均値を求めると、比較的安定した速度値が得られます.次の2つの関数は、速度が必要なときに呼び出すことができます.リアルタイム計算は必要ありません.LeftPeriodBufとRightPeriodBufの値が最新になるからです.
ハードウェア:
MCU:stm32f103zet6
プラットフォーム:航太電子流行7号スマートカー
表示:mini 12864
ソフトウェア:
言語:C言語
IDE:keil5
速度測定部分の環境は典型的な速度測定方法であり、速度測定コード盤に光電対管を加え、単片機は光電対管モジュールから伝わるPWM波を採集し、2つの車輪に対して速度を測定し、実際の速度は2つの車輪の大きな値を取る.
ソフトウェアにはTIM 1のキャプチャモードが採用されており、チャネルCH 1とCH 4が使用されており、それぞれPA 8とPA 11に対応しており、まず公式の入力キャプチャモードの説明を参照してください.
入力キャプチャモードでは、ICx信号上の対応するエッジが検出されると、カウンタの現在値は、キャプチャ/比較レジスタ(TIMx_CCRx)にラッチされる.キャプチャイベントが発生すると、対応するCCxIFフラグ(TIMx_SRレジスタ)が1セットされ、割り込みまたはDMA動作が開放されると、割り込みまたはDMA要求が発生する.キャプチャイベントが発生したときにCCxIFフラグがすでに高い場合、重複キャプチャフラグCCxOF(TIMx_SRレジスタ)は1にセットされる.書き込みCCxIF=0は、CCxIFを消去したり、TIMx_に読み出して格納したりすることができるCCRxレジスタのキャプチャデータは、CCxIFをクリアすることもできる.書き込みCCxOF=0は、CCxOFをクリアします.
次の例では、TI 1入力の立ち上がりエッジでカウンタの値をTIMx_にキャプチャする方法を示します.CCR 1レジスタでは、ステップは以下の通りです.
●有効入力端子の選択:TIMx_CCR 1はTI 1入力に接続する必要があるのでTIMx_に書き込むCCR 1レジスタのCC 1 S=01は、CC 1 Sが’00’でない限り、チャネルが入力され、TIMx_CCR 1レジスタは読み取り専用になります.
・入力信号の特徴に応じて、入力フィルタを所望の帯域幅(すなわち、入力がTIxの場合、入力フィルタ制御ビットはTIMx_CCMRxレジスタにおけるICxFビット)に設定する.入力信号が最大5個の内部クロックサイクルの時間内にジッタすると仮定し、フィルタの帯域幅が5個のクロックサイクルよりも長いように構成しなければならない.したがって、(fDTS周波数で)連続して8回サンプリングして、TI 1の最後の真のエッジ変換、すなわちTIMx_CCMR 1レジスタにはIC 1 F=001が書き込まれる.
●TIMx_でTI 1チャネルの有効な変換エッジを選択CCERレジスタにCC 1 P=0(立ち上がりエッジ)を書き込む.
・入力プリスプリッタを構成する.この例では、各有効レベル変換時に発生することをキャプチャしたいので、プリスプリッタは禁止される(TIMx_CCMR 1レジスタを書き込むIC 1 PS=00).
●TIMx_の設定CCERレジスタのCC 1 E=1であり、キャプチャカウンタの値をキャプチャレジスタに許可する.●必要に応じてTIMx_を設定DIERレジスタのCC 1 IEビットは関連割り込み要求を許可し、TIMx_を設定するDIERレジスタのCC 1 DEビットはDMA要求を許可する.
入力キャプチャが発生した場合:
●有効なレベル変換が発生した場合、カウンタの値がTIMx_に転送されるCCR 1レジスタ.
●CC 1 IFフラグが設定されている(割り込みフラグ).少なくとも2つの連続したキャプチャが発生した場合、CC 1 IFはクリアされず、CC 1 OFもセット1される.
●CC 1 IEビットが設定されていると、割り込みが発生します.
・CC 1 DEビットが設定されている場合、DMA要求も発生する.キャプチャオーバーフローを処理するためには、キャプチャオーバーフローフラグの読み出し前にデータの読み出しを行うことが推奨される.これは、キャプチャオーバーフローフラグの読み出し後およびデータの読み出し前に生じる可能性のあるキャプチャオーバーフロー情報の損失を回避するためである.
注意:TIMx_の設定EGRレジスタ内の対応するCCxGビットは、ソフトウェアによって入力キャプチャ割り込みおよび/またはDMA要求を生成することができる.
なお、初期化時にはホッピングのサンプリング回数を設定する必要があり、車輪によるPWM波の周波数が捕獲速度に対して低いため、サンプリング回数を大きく設定すべきであり、最大32回の対応値で0 x 0 fを設定する.これまで気づかなかったが、デフォルトの0にしていたため、結果が大きく、変動も大きく、サンプリングが間違った結果となった.
以下はTM 1捕獲モードの初期化であり、72 Mの結晶振動速度を採用し、配置されたタイマー周波数は10 KHzであり、周期は65535である.
speed.c
void MeaSpeedInit(void)
{
//
GPIO_InitTypeDef WheelGPIO_InitStructure;
NVIC_InitTypeDef WheelNVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// 10000
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 7200-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
/************** ******************/
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0f;
// PA8
WheelGPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
WheelGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
WheelGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &WheelGPIO_InitStructure);
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
/************** ******************/
/************** ******************/
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0f;
// PA11
WheelGPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
WheelGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
WheelGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &WheelGPIO_InitStructure);
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE);
/************** ******************/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
WheelNVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
WheelNVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
WheelNVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
WheelNVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&WheelNVIC_InitStructure);
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_Cmd(TIM1, ENABLE);
}
次のマクロ定義に注意してください.異なるチャネルで取得された取得値は、異なるレジスタにあります.
// TIM1 1
#define LEFTCAPTURECHANNEL TIM1, TIM_IT_CC1
#define LEFTCAPTUREVALUE TIM_GetCapture1(TIM1)
//TIM1 4
#define RIGHTCAPTURECHANNEL TIM1, TIM_IT_CC4
#define RIGHTCAPTUREVALUE TIM_GetCapture4(TIM1)
また、プレミアムタイマー1を使用しているため、割り込み入口はTIM 1_CC_IRQn
stm32f10x_it.c
/**-------------------------------------------------------
* @ TIM1_IRQHandler
* @ TIM1 ,
* @
* @
***------------------------------------------------------*/
void TIM1_CC_IRQHandler(void)
{
WheelCaptureIRQ();
}
次に、割り込み処理関数を見て、最も隣接する2つの下降エッジの時間を記録し、bufに記録する.bufのデータは最も近いパルス周期の時間であり、後のフィルタ計算を便利にし、左右輪の速度測定は同じ割り込み関数にある.
speed.c
/*
stm32f10x-it.c TIMx_IRQHandler()
*/
void WheelCaptureIRQ(void)
{
if(TIM_GetITStatus(LEFTCAPTURECHANNEL) == SET)
{
speed_contiue=100;
TIM_ClearITPendingBit(LEFTCAPTURECHANNEL);
if(LeftWheelCaptureTime == 0)
{
LeftWheel1stCapture = LEFTCAPTUREVALUE;
LeftWheelCaptureTime = 1;
}
else if(LeftWheelCaptureTime == 1)
{
LeftWheel2ndCapture = LEFTCAPTUREVALUE;
if (LeftWheel2ndCapture > LeftWheel1stCapture)
{
LeftWheelPulsePeriod = (LeftWheel2ndCapture - LeftWheel1stCapture);
}
else
{
LeftWheelPulsePeriod = ((0xFFFF - LeftWheel1stCapture) + LeftWheel2ndCapture);
}
LeftPeriodBuf[LeftPeriodIndex++] = LeftWheelPulsePeriod;// 10
if(LeftPeriodIndex == PERIOD_BUFSIZE)
LeftPeriodIndex = 0;
LeftWheelCaptureTime= 0;
}
}
if(TIM_GetITStatus(RIGHTCAPTURECHANNEL) == SET)
{
speed_contiue=100;
TIM_ClearITPendingBit(RIGHTCAPTURECHANNEL);
if(RightWheelCaptureTime == 0)
{
RightWheel1stCapture = RIGHTCAPTUREVALUE;
RightWheelCaptureTime = 1;
}
else if(RightWheelCaptureTime == 1)
{
RightWheel2ndCapture = RIGHTCAPTUREVALUE;
if (RightWheel2ndCapture > RightWheel1stCapture)
{
RightWheelPulsePeriod = (RightWheel2ndCapture - RightWheel1stCapture);
}
else
{
RightWheelPulsePeriod = ((0xFFFF - RightWheel1stCapture) + RightWheel2ndCapture);
}
RightPeriodBuf[RightPeriodIndex++] = RightWheelPulsePeriod;// 10
if(RightPeriodIndex == PERIOD_BUFSIZE) RightPeriodIndex = 0;
RightWheelCaptureTime= 0;
}
}
}
次に、速度の計算を開始し、最大値と最小値をフィルタリングし、重み付け平均値を求めると、比較的安定した速度値が得られます.次の2つの関数は、速度が必要なときに呼び出すことができます.リアルタイム計算は必要ありません.LeftPeriodBufとRightPeriodBufの値が最新になるからです.
unsigned int GetLeftSpeed(void)
{
int index,intex_temp=0;
uint16_t LeftPeriodBufTemp[PERIOD_BUFSIZE];
u8 max_index=0,min_index=0;
uint16_t LeftValueTemp=0;
unsigned int LeftValueAvg=0;//
u8 index_total=0;
//
for(index = LeftPeriodIndex;index < PERIOD_BUFSIZE ;index++)
{
LeftPeriodBufTemp[intex_temp++] = LeftPeriodBuf[index];
}
for(index = 0;index < LeftPeriodIndex ;index++)
{
LeftPeriodBufTemp[intex_temp++] = LeftPeriodBuf[index];
}
//
LeftValueTemp = LeftPeriodBufTemp[0];
for(index = 0;index < PERIOD_BUFSIZE-1; index++)
{
if(LeftValueTemp < LeftPeriodBufTemp[index+1])
{
max_index = index+1;
LeftValueTemp = LeftPeriodBufTemp[index+1];
}
}
//
LeftValueTemp = LeftPeriodBufTemp[0];
for(index = 0;index < PERIOD_BUFSIZE-1; index++)
{
if(LeftValueTemp > LeftPeriodBufTemp[index+1])
{
min_index = index+1;
LeftValueTemp = LeftPeriodBufTemp[index+1];
}
}
//
for(index = 0;index < PERIOD_BUFSIZE;index++)
{
if((index != min_index) && (index != max_index))
{
LeftValueAvg += LeftPeriodBufTemp[index]*(index+1);
index_total += index+1;
}
}
LeftValueAvg = LeftValueAvg/index_total;//
for(index = 0;index < PERIOD_BUFSIZE;index++)
{
printf("%d\t",LeftPeriodBufTemp[index]);
}
if(LeftValueAvg == 0) return 0;
LeftValueAvg = 10445/LeftValueAvg;
printf("\t%d\r
",LeftValueAvg);
return LeftValueAvg;
}
unsigned int GetRightSpeed(void)
{
int index,intex_temp=0;
uint16_t RightPeriodBufTemp[PERIOD_BUFSIZE];
u8 max_index=0,min_index=0;
uint16_t RightValueTemp=0;
unsigned int RightValueAvg=0;//
u8 index_total=0;
//
for(index = RightPeriodIndex;index < PERIOD_BUFSIZE ;index++)
{
RightPeriodBufTemp[intex_temp++] = RightPeriodBuf[index];
}
for(index = 0;index < RightPeriodIndex ;index++)
{
RightPeriodBufTemp[intex_temp++] = RightPeriodBuf[index];
}
//
RightValueTemp = RightPeriodBufTemp[0];
for(index = 0;index < PERIOD_BUFSIZE-1; index++)
{
if(RightValueTemp < RightPeriodBufTemp[index+1])
{
max_index = index+1;
RightValueTemp = RightPeriodBufTemp[index+1];
}
}
//
RightValueTemp = RightPeriodBufTemp[0];
for(index = 0;index < PERIOD_BUFSIZE-1; index++)
{
if(RightValueTemp > RightPeriodBufTemp[index+1])
{
min_index = index+1;
RightValueTemp = RightPeriodBufTemp[index+1];
}
}
//
for(index = 0;index < PERIOD_BUFSIZE;index++)
{
if((index != min_index) && (index != max_index))
{
RightValueAvg += RightPeriodBufTemp[index]*(index+1);
index_total += index+1;
}
}
RightValueAvg = RightValueAvg/index_total;//
if(RightValueAvg == 0) return 0;
RightValueAvg = 10445/RightValueAvg;
return RightValueAvg;
}