2016-09-12 26 views
1

現在STM32F4をSTM32F429ZI Nucleo-144 Boardで使用しています。私は、このマイクロコントローラを使用して、直交エンコーダインタフェースを介してロータリエンコーダの位置を評価しようとしています。ドキュメントを見ると、これはタイマーで行われます。私はA/Bエンコーダの出力をマイクロのPA6とPC7に接続していますが、カウントがドリフトしているように見えます。STM32F4エンコーダーの数が変化しない場合

デバッグ中に、エンコーダ出力の1つをマイクロコントローラに接続してモータを動かすと、エンコーダラインの1つだけが接続されていてもカウントが増減することに気付きました。私はTI1とTI2の両方のエッジをカウントしているので、これは起こってはいけません。下の図を正しく読んでいると、私のラインの1つが内部プルアップを使ってハイに保持されているため、他の入力のクロックパルスは上下/上下に移動し、2つの異なるカウント間でサイクリングする必要があります。ただし、エンコーダを回転させている場合、カウントは方向に応じて増減し続けます。

1つのエンコーダ入力のみでエンコーダカウントが変化するのはなぜですか?私はまた、コードだけでなく、アクティブなカウントが1つだけであることを証明するためにスコープトレースを添付しています。

EDIT:私はまた、両エッジから上昇エッジに極性を変えようとしましたが、認識される利点はありません。さらなる調査の際

enter image description here

enter image description here

#include "stm32f4xx_hal.h" 
#include "encoder_test.h" 

GPIO_InitTypeDef GPIO_InitStruct; 
TIM_HandleTypeDef Timer_InitStruct; 
TIM_Encoder_InitTypeDef Encoder_InitStruct; 

void EncoderTest_Init() 
{ 
    __HAL_RCC_GPIOA_CLK_ENABLE(); 
    __HAL_RCC_GPIOC_CLK_ENABLE(); 
    __HAL_RCC_TIM3_CLK_ENABLE(); 

    /**TIM3 GPIO Configuration 
    PA6  ------> TIM3_CH1 
    PC7  ------> TIM3_CH2 
    */ 

    GPIO_InitStruct.Pin = GPIO_PIN_6; 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
    GPIO_InitStruct.Pull = GPIO_PULLUP; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; 
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; 
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 

    GPIO_InitStruct.Pin = GPIO_PIN_7; 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
    GPIO_InitStruct.Pull = GPIO_PULLUP; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; 
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; 
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 

    Timer_InitStruct.Instance = TIM3; 
    Timer_InitStruct.Init.Period = 0xFFFF; 
    Timer_InitStruct.Init.CounterMode = TIM_COUNTERMODE_UP; 
    Timer_InitStruct.Init.Prescaler = 1; 
    Timer_InitStruct.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 

    Encoder_InitStruct.EncoderMode = TIM_ENCODERMODE_TI12; 
    Encoder_InitStruct.IC1Filter = 0x00; 
    Encoder_InitStruct.IC1Polarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE; 
    Encoder_InitStruct.IC1Prescaler = TIM_ICPSC_DIV1; 
    Encoder_InitStruct.IC1Selection = TIM_ICSELECTION_DIRECTTI; 
    Encoder_InitStruct.IC2Filter = 0x00; 
    Encoder_InitStruct.IC2Polarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE; 
    Encoder_InitStruct.IC2Prescaler = TIM_ICPSC_DIV1; 
    Encoder_InitStruct.IC2Selection = TIM_ICSELECTION_DIRECTTI; 

    if (HAL_TIM_Encoder_Init(&Timer_InitStruct, &Encoder_InitStruct) != HAL_OK) 
    { 
     while (1); 
    } 

    if (HAL_TIM_Encoder_Start_IT(&Timer_InitStruct, TIM_CHANNEL_1) != HAL_OK) 
    { 
     while (1); 
    } 
} 


void TIM3_IRQHandler() 
{ 
    HAL_TIM_IRQHandler(&Timer_InitStruct); 
} 
+0

それはインクリメンタルエンコーダのように見えます。アングルを把握する必要がある場合、アブソリュートロータリーエンコーダが最適ですか?最初の位置からポジションを評価することはできますが(それがわかっている場合)、ある時点で割り込みを逃してカウントを失うことになります – Emilien

答えて

0

、問題はプリスケーラによるものであることが表示されます。プリスケーラは、偶数値を指定するとエンコーダモードでは機能しません。プリスケーラは入力値+1であるため、STM32F4 HALを使用すると、入力されたプリスケーラは偶数でなければなりません。

forum postでこの問題の唯一の人ではないことが確認されました。ポストでは、プリスケーラはエンコーダモードと互換性がないかもしれないとの議論がありますが、これはまだ確認されていません。私はSTの下に行くために電子メールをSTに送ってきました。サポートされていない場合は、プリスケーラ値0を入力することは安全です。ここ

は以下作業コードである:

#include "stm32f4xx_hal.h" 
#include "encoder_test.h" 

GPIO_InitTypeDef GPIO_InitStruct; 

TIM_HandleTypeDef Timer3_InitStruct; 
TIM_Encoder_InitTypeDef EncoderTim3_InitStruct; 

void EncoderTest_Init_Tim3() 
{ 
    __HAL_RCC_GPIOA_CLK_ENABLE(); 
    __HAL_RCC_GPIOC_CLK_ENABLE(); 
    __HAL_RCC_TIM3_CLK_ENABLE(); 

    /**TIM3 GPIO Configuration 
    PA6  ------> TIM3_CH1 
    PC7  ------> TIM3_CH2 
    */ 

    GPIO_InitStruct.Pin = GPIO_PIN_6; 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
    GPIO_InitStruct.Pull = GPIO_PULLDOWN; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; 
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; 
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 

    GPIO_InitStruct.Pin = GPIO_PIN_7; 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
    GPIO_InitStruct.Pull = GPIO_PULLDOWN; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; 
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; 
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 

    Timer3_InitStruct.Instance = TIM3; 
    Timer3_InitStruct.Init.Period = 0xFFFF; 
    Timer3_InitStruct.Init.CounterMode = TIM_COUNTERMODE_UP; 
    Timer3_InitStruct.Init.Prescaler = 10; 
    Timer3_InitStruct.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 

    EncoderTim3_InitStruct.EncoderMode = TIM_ENCODERMODE_TI12; 
    EncoderTim3_InitStruct.IC1Filter = 0x00; 
    EncoderTim3_InitStruct.IC1Polarity = TIM_INPUTCHANNELPOLARITY_RISING; 
    EncoderTim3_InitStruct.IC1Prescaler = TIM_ICPSC_DIV4; 
    EncoderTim3_InitStruct.IC1Selection = TIM_ICSELECTION_DIRECTTI; 
    EncoderTim3_InitStruct.IC2Filter = 0x00; 
    EncoderTim3_InitStruct.IC2Polarity = TIM_INPUTCHANNELPOLARITY_RISING; 
    EncoderTim3_InitStruct.IC2Prescaler = TIM_ICPSC_DIV4; 
    EncoderTim3_InitStruct.IC2Selection = TIM_ICSELECTION_DIRECTTI; 

    if (HAL_TIM_Encoder_Init(&Timer3_InitStruct, &EncoderTim3_InitStruct) != HAL_OK) 
    { 
     while (1); 
    } 

    if (HAL_TIM_Encoder_Start_IT(&Timer3_InitStruct, TIM_CHANNEL_1) != HAL_OK) 
    { 
     while (1); 
    } 
} 



void TIM3_IRQHandler() 
{ 
    HAL_TIM_IRQHandler(&Timer3_InitStruct); 
} 

EDIT: STの技術サポートと話した後、エンコーダインターフェースは、偶数又は奇数の、プリスケーラ値で使用することを意図するものではないしました。私は以下の回答を貼り付けましたが、動作するように見えるプリスケーラ値を使用しても、エンコーダは時間の経過とともにドリフトをカウントする可能性があります。

もう1つの解決策は、プリスケーラを使用せず、代わりにhereの方法を使用して16ビット値を32ビット空間に拡張することです。スケールに割り込みオーバーフローを使用して、私の経験では

:STのフォーラムに2013年11月19日に


ユーザーgoosen.kobus.001から:私はリンクが死んで行く場合には、ここでのアプローチを転載しています特に高解像度のエンコーダを使用している場合は、エンコーダの信頼性が高くなりません。エンコーダの値が割り込みに入る瞬間に符号が変わることがあります。これは、エンコーダ位置0に移動するように指令されたサーボモータのように、エンコーダが0でストールすると想定される場合に特に当てはまります。

私が見つけた最良の方法は、手動で行うことです。これは私の手順です:

  1. 少なくとも10〜20倍のエンコーダ値を読み込み、制御ループが(、頻繁に実行されていることを、あなたのエンコーダがフルスピードで回転している場合、すなわち、エンコーダ値がまだ読まれていることを確認オーバーフロー間。私のサーボモータアプリケーションで1msのループ間隔が十分であった。

  2. 最後の読み取りエンコーダ値を追跡する。

  3. 分割象限に現在と前回のエンコーダ値(最上位2ビット)すなわちpos_now & = 0xC000; pos_last & = 0xC000;エンコーダは、最後のステップで0象限3または3象限0から移動したかどうかを確認する

  4. チェック:

    4.1(pos_now == 0 & & pos_last == 0xC000)upper_word ++場合。

    4.2 if(pos_now == 0xC000 & & pos_last == 0)upper_word--;

これが私がエンコーダの読み取りループを頻繁に実行する必要がある理由です。値を頻繁に読み取って、読み取りの間に象限0 - > 1 - > 2 - > 3に行くことが不可能であることを確認する必要があります。 このロジックを、例えば10kHzで動作する別のタイマー割り込みに入れることも可能です。あなたは常に最新のエンコーダ値を持っています。


STの応答:

こんにちは、

私はデザインやタイマーの建築家からのフィードバックを持っています。 エンコーダのインターフェイスは、エンコーダの解像度をダウングレードしないためにプリスケーラなしで動作するように設計されています。

ご覧のとおり、プリスケーラの値でも機能しないが、奇数のものでも機能しないことが確認されています。 プリスケーラ用のサブカウンタがあり、これは単方向であり、カウンタ方向の影響を受けず、タイマ・クロックの各立ち上がりエッジでインクリメントされます(プリスケーラなし)。 カウンタクロックは、タイマクロック(プリスケーラなし)の各立ち上がりエッジで更新されますが、プリスケーラのサブカウンタがプログラムされた値に達し、方向ビットの値に応じてカウンタがインクリメントされます。

したがって、カウンタは異なる方向(奇数クロックサイクル数ごと)で更新されるため、プリスケーラなしの場合と同じ動作になりますが、それ以外の場合、方向は常に同じです。カウンタが更新され、エンコーダインターフェイスが正しく動作しません。

プリスケーラを使用できますが、奇数値を使用できます。

推奨される使用例はプリスケーラなしです。

敬具

ST MCU技術サポート

関連する問題