Arduinoライブラリをstm32に移植しようとしています。 Arduinoでは、millis()
は起動からのミリ秒数を返します。 stm32に同等の機能はありますか? stm32f0MCUを使用しています。
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;
}
_
注意すべきいくつかの警告。
SysTickは24ビットカウンターです。オーバーフローでラップします。値を比較するとき、または遅延メソッドを実装するときは、このことに注意してください。
SysTickは、プロセッサコアクロックから派生しています。電力を節約するためにコアクロックを遅くするなど、コアクロックをいじる場合は、SysTick周波数も手動で調整する必要があります。
HAL_GetTick(): this function gets current SysTick counter value (incremented in SysTick interrupt) used by peripherals drivers to handle timeouts.
を使用できます
独自のタイマーを設定することをお勧めします。
タイマーを作成するには、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 */
}
タイマーでやることをお勧めします。このようにして、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の時間変数もオーバーフローする可能性があることを知っておく必要がありますが、これは詳細であり、簡単に管理できます。
状況によっては、この目的でSysTickを使用できない場合があります。たとえば、すでにSysTickを実装しているFreeRTOSを使用する場合です。この場合、タスクでコードを実行すると、vTaskDelayを使用できます。あなたがやりたいことに応じて、ソフトウェアタイマーもトリックを作ることができます: http://www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html
SysTickを使用できず、FreeRTOSなどがない場合は、割り込みを使用してタイマーを設定し、コードを適切なコールバックに配置できます。
まあ、正しい答えを得るにはもっと情報が必要だと思いますが、ベストショットをあげます。
アプリケーションで考慮する必要がある考慮事項。高解像度の測定を行う場合(正確な時間が必要)、MCUの内部クロックは完全に正確ではないため、精度のために外部水晶を提供する必要があります。
それを念頭に置いて、あなたがしなければならないことは次のとおりです。
void interrupt TIMX_interrupt(void){ counter++; // this will have the time count in MS. }
millis()
という名前の関数を作成します。uint32_t millis(void){ return counter; }
このようにして、このMCUで同じ機能を使用できます。