web-dev-qa-db-ja.com

stm32のArduinomillis()

Arduinoライブラリをstm32に移植しようとしています。 Arduinoでは、millis()は起動からのミリ秒数を返します。 stm32に同等の機能はありますか? stm32f0MCUを使用しています。

9
user6064424

SysTickはARMこの目的のために提供されるコアペリフェラルです。これをニーズに合わせて調整してください:

まず、初期化します

_// Initialise SysTick to tick at 1ms by initialising it with SystemCoreClock (Hz)/1000

volatile uint32_t counter = 0;
SysTick_Config(SystemCoreClock / 1000);
_

割り込みハンドラーを提供します。コンパイラーは、追加の属性で装飾するために割り込みハンドラーを必要とする場合があります。

_SysTick_Handler(void) {
  counter++;
}
_

これがあなたのmillis()関数です。これ以上簡単なことはありません。

_uint32_t millis() {
  return counter;
}
_

注意すべきいくつかの警告。

  1. SysTickは24ビットカウンターです。オーバーフローでラップします。値を比較するとき、または遅延メソッドを実装するときは、このことに注意してください。

  2. SysTickは、プロセッサコアクロックから派生しています。電力を節約するためにコアクロックを遅くするなど、コアクロックをいじる場合は、SysTick周波数も手動で調整する必要があります。

11
Andy Brown

HAL_GetTick(): this function gets current SysTick counter value (incremented in SysTick interrupt) used by peripherals drivers to handle timeouts.を使用できます

6
nbout

独自のタイマーを設定することをお勧めします。

タイマーを作成するには、CubeMXまたは手動でプリスケーラと期間を設定する必要があります。
クロック構成

私のクロックは72MHzなので、これは72MHz/1MHz-1 = 71のプリスケーラが必要であることを意味します。したがって、割り込みを1ミリ秒に1回トリガーするため、周期は1MHz/1kHz-1 = 999になります。
プリスカラー計算

これがCubeMXでどのように見えるかです。
タイマー設定

次に、タイマーコールバック関数にカウンターインクリメントを追加します。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */
  if (htim->Instance == TIM10) {
    counter++;
  }
  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}
1
studentbrad

タイマーでやることをお勧めします。このようにして、1usステップを取得することもできます。タイムステップサイズを制御するだけです。とにかく、ほとんどのSTM32 MCUには8つ以上のタイマーがあるので、ほとんどの場合、自由に1つ取ることができます。非常に簡単な基本的な考え方を紹介します。

タイマーを作成するだけです。

uint32_t time = 0;

void enable_timer(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, ENABLE);
    TIM_TimeBaseInitTypeDef timerInitStructure;

    /* if MCU frequency 48 MHz, prescaler of value 48 will make 1us counter steps
    timerInitStructure.TIM_Prescaler = 48;

    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    /*how often you'll get irq*/
    timerInitStructure.TIM_Period = 0xFFFF; // will get irq each 65535us on TIMx->CNT overflow
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM16, &timerInitStructure);
    TIM_Cmd(TIM16, ENABLE);
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIM16_IRQn;
    /*for more accuracy irq priority should be higher, but now its default*/
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    TIM_ClearITPendingBit(TIM16,TIM_IT_Update);
    NVIC_Init(&NVIC_InitStruct);
    TIM_ITConfig(TIM16,TIM_IT_Update,ENABLE);
}

iRQでは、タイマーカウンターのオーバーフローを制御し、グローバル時間を更新する必要があります

void TIM16_IRQHandler(void){
if (TIM_GetITStatus(TIM16, TIM_IT_Update) != RESET){
    TIM_ClearITPendingBit(TIM16, TIM_IT_Update);
    time +=65535;
}

}

そしてリアルタイムは:

uint32_t real_time_us = time + (uint32_t)TIM16->CNT;

ただし、32ビットタイマーを自由に使用できる場合は、IRQなしでも実行できます。単にtime = TIMx-> CNTです。タイマーの設定とニーズによって異なります。また、uint32_tの時間変数もオーバーフローする可能性があることを知っておく必要がありますが、これは詳細であり、簡単に管理できます。

1
David.O

状況によっては、この目的でSysTickを使用できない場合があります。たとえば、すでにSysTickを実装しているFreeRTOSを使用する場合です。この場合、タスクでコードを実行すると、vTaskDelayを使用できます。あなたがやりたいことに応じて、ソフトウェアタイマーもトリックを作ることができます: http://www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html

SysTickを使用できず、FreeRTOSなどがない場合は、割り込みを使用してタイマーを設定し、コードを適切なコールバックに配置できます。

0
Tom

まあ、正しい答えを得るにはもっと情報が必要だと思いますが、ベストショットをあげます。

アプリケーションで考慮する必要がある考慮事項。高解像度の測定を行う場合(正確な時間が必要)、MCUの内部クロックは完全に正確ではないため、精度のために外部水晶を提供する必要があります。

それを念頭に置いて、あなたがしなければならないことは次のとおりです。

  1. 1msごとに割り込みを実行できるようにTIMを構成します
  2. TIM割り込みを有効にし、
  3. TIM割り込みで、このモジュールのグローバル変数として定義されているカウンター(これがあなたの時間になります)を増やします。

void interrupt TIMX_interrupt(void){ counter++; // this will have the time count in MS. }

  1. 次のようなカウンターを返すmillis()という名前の関数を作成します。

uint32_t millis(void){ return counter; }

このようにして、このMCUで同じ機能を使用できます。

0
adrianzx