Микроконтроллеры

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Микроконтроллеры » STM32 & STM8 » Практика » Реализация точных задержек в программе


Реализация точных задержек в программе

Сообщений 1 страница 4 из 4

1

Очень часто в программе есть необходимость выполнять задержку выполнения программы на некоторый промежуток времени. Не буду приводить все варианты реализации функции Delay. Из всевозможных способов всегда лучше других это аппаратный. Кортексы с ядрами M3, M4, M7 содержат в своем составе модуль DWT (Data Watchpoint and Trace Unit). В нем есть 32 битный счетчик тиков (циклов тактовой частоты ядра) его мы и будем использовать для реализации функций задержки (не подходит для использования в многопоточных приложениях). Работа функций выполняеться в блокирующем режиме.

  Модули библиотеки обращаються к main.h где я указываю основные параметры программы и именно тут я подключаю все хедеры относящиеся к конкретному МК в проекте, так они могут использоваться в разных проетах без внесения изменений.

main.h

Код:
/*
 * main.h
 *
 *  Created on: 31 янв. 2018 г.
 *      Author:
 */

#ifndef MAIN_H_
#define MAIN_H_

#include "stm32f4xx.h"

// системная частота в герцах
#define  SYS_CLK           16000000

#endif /* MAIN_H_ */


Отдельный модуль для работы с WDT:
F4xx_DWT.h

Код:
/*
 * F4xx_DWT.h
 *
 *  Created on: 31 янв. 2018 г.
 *      Author: Home
 */

#ifndef F4XX_DWT_H_
#define F4XX_DWT_H_

#include <main.h>

void DWT_CYC_Counter_Enable(void);

#endif /* F4XX_DWT_H_ */

F4xx_DWT.c

Код:
/*
 * F4xx_DWT.c
 *
 *  Created on: 31 янв. 2018 г.
 *      Author: Home
 */

#include <F4xx_DWT.h>

void DWT_CYC_Counter_Enable(void)
{
  /* запускаем таймер DWT_CYC */
  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  DWT->CYCCNT = 0;
  DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}


Модуль содержит всего одну функцию void DWT_CYC_Counter_Enable(void), которая разрешает работу счетчика.

F4xx_Delay.h

Код:
/*
 * F4xx_Delay.h
 *
 *  Created on: 31 янв. 2018 г.
 *      Author: Home
 */

#ifndef F4XX_DELAY_H_
#define F4XX_DELAY_H_

#include <F4xx_DWT.h>

// задержка в микросекундах
void Delay_us(__IO uint32_t tDelay);

// задержка в милисекундах
void Delay_ms(__IO uint32_t tDelay);

#endif /* F4XX_DELAY_H_ */


F4xx_Delay.c

Код:
/*
 * F4xx_Delay.c
 *
 *  Created on: 31 янв. 2018 г.
 *      Author: Home
 */

#include <F4xx_Delay.h>


// задержка в микросекундах
void Delay_us(__IO uint32_t tDelay)
{
  DWT->CYCCNT = 0;
  tDelay = tDelay * (SYS_CLK /1000000);
  while (DWT->CYCCNT < tDelay);
}

// задержка в милисекундах
void Delay_ms(__IO uint32_t tDelay)
{
  DWT->CYCCNT = 0;
  tDelay = tDelay * (SYS_CLK /1000);
  while (DWT->CYCCNT < tDelay);
}


в данном модуле раелизованы функции задержки для микросекундных интервалов и миллисекундных.

Пример использования:

Код:
/* Includes */
#include "main.h"
#include <F4xx_DWT.h>
#include <F4xx_Delay.h>

/* Private macro */

// гасим все светодиоды
#define  LED_CLR_ALL           GPIOD->BSRR = GPIO_BSRR_BR_12 | GPIO_BSRR_BR_13 | GPIO_BSRR_BR_14 | GPIO_BSRR_BR_15
// включаем соотв.светодиод
#define  LED1_SET                GPIOD->BSRR = GPIO_BSRR_BS_12
#define  LED2_SET                GPIOD->BSRR = GPIO_BSRR_BS_13
#define  LED3_SET                GPIOD->BSRR = GPIO_BSRR_BS_14
#define  LED4_SET                GPIOD->BSRR = GPIO_BSRR_BS_15
#define  DELAY_INIT_CNT          500000

// тестовая нога для анализатора
#define  TST_CLR                 GPIOD->BSRR = GPIO_BSRR_BR_0
#define  TST_SET                 GPIOD->BSRR = GPIO_BSRR_BS_0

/* Private variables */
/* Private function prototypes */
/* Private functions */
void RCC_Init(void);
void GPIO_Init(void);

void RCC_Init(void)
{
  RCC->AHB1ENR = RCC_AHB1ENR_GPIODEN;  // включаем тактирование GPIOD
}

void GPIO_Init(void)
{
  GPIOD->MODER = GPIO_MODER_MODER0_0 | GPIO_MODER_MODER12_0 | GPIO_MODER_MODER13_0 | GPIO_MODER_MODER14_0 | GPIO_MODER_MODER15_0;  // настраиваем PD12, PD13, PD14, PD15 как "двухтактный выход общего назначения"
}

int main(void)
{
uint32_t a;

  RCC_Init();
  GPIO_Init();
  DWT_CYC_Counter_Enable();

  while(1)
  {
   LED_CLR_ALL;
   LED1_SET;
   Delay_ms(500);

   LED_CLR_ALL;
   LED2_SET;
   Delay_us(500000);

   LED_CLR_ALL;
   LED3_SET;
   Delay_ms(500);

   LED_CLR_ALL;
   LED4_SET;
   Delay_us(500000);
  }
}


Программа под F4Discovery.

Отредактировано MasterElectric (2018-02-28 23:00:07)

2

не подходит для использования в многопоточных приложениях

Да оно вообще мало где подходит... если разобраться... Разве что... как один из возможных вариантов...

В Ф0 нет DWT априори...
Мало чем отличается от использования обычного таймера...
Работа функций выполняется в блокирующем режиме...
В таком виде точность не максимально возможная...
Сама формулировка "Очень часто в программе есть необходимость выполнять задержку выполнения программы на некоторый промежуток времени" ущербна по сути... особенно при использовании СТМ...

3

HHIMERA Все это я понимаю (и описано), суть в том что многие не знают что он вообще есть этот WDT. Я даже не пользуюсь этим способом. Точность хорошая по сравнению с (код я сегодня увидел на другом форуме, он из "жизни"):

Код:
void delay(unsigned long p)
{
	while(p>0){p--;}
}

4

То что "многие не знают что он вообще есть этот WDT"... согласен...
Чтобы улучшить точность... нужно произвести холостой вход в функцию... или производить коррекцию вручную...
Ваще... эта тема сильно пережёвывалась в своё время на Элхе...


Вы здесь » Микроконтроллеры » STM32 & STM8 » Практика » Реализация точных задержек в программе