Использование триггеров: различия между версиями
Андрей (обсуждение | вклад) Нет описания правки Метка: визуальный редактор отключён |
Дмитрий (обсуждение | вклад) (исправил библиотеки) |
||
(не показано 8 промежуточных версий 2 участников) | |||
Строка 10: | Строка 10: | ||
После этого нужно выбрать источник тактирования, который будет использоваться для подсчета. Выберем, например, тактирование от системной частоты. Для тактирования от внутреннего источника оставим источник синхронизации по умолчанию. | После этого нужно выбрать источник тактирования, который будет использоваться для подсчета. Выберем, например, тактирование от системной частоты. Для тактирования от внутреннего источника оставим источник синхронизации по умолчанию. | ||
Далее следует выбрать нужный вам делитель частоты. | Далее следует выбрать нужный вам делитель частоты. В примере выбран делитель 128. | ||
Активный фронт задает фронт, по которому будет происходить увеличение счетчика. Эта настройка используется при внешнем источнике синхронизации. В нашем примере тактирование от внутреннего источника, поэтому эта настройка нам не нужна. | Активный фронт задает фронт, по которому будет происходить увеличение счетчика. Эта настройка используется при внешнем источнике синхронизации. В нашем примере тактирование от внутреннего источника, поэтому эта настройка нам не нужна. | ||
Строка 28: | Строка 28: | ||
Нажимаем кнопку генерации. В итоге у нас появится проект для PlatformIo. Далее работа идет в visual studio code. | Нажимаем кнопку генерации. В итоге у нас появится проект для PlatformIo. Далее работа идет в visual studio code. | ||
==Использование библиотеки HAL_Timer16== | ==Использование библиотеки HAL_Timer16== | ||
В сгенерированном проекте в файле main.c должна быть функция Timer16_1_Init, в которой будут заданы настройки для Timer16_1. Выглядит она так:<syntaxhighlight lang="c" line="1"> | В сгенерированном проекте в файле main.c должна быть функция Timer16_1_Init, в которой будут заданы настройки для Timer16_1. Выглядит она так: | ||
{{#spoiler:show=Развернуть код|hide=Свернуть код| | |||
<syntaxhighlight lang="c" line="1"> | |||
static void Timer16_1_Init(void) | static void Timer16_1_Init(void) | ||
{ | { | ||
Строка 36: | Строка 38: | ||
htimer16_1.Clock.Source = TIMER16_SOURCE_INTERNAL_SYSTEM; | htimer16_1.Clock.Source = TIMER16_SOURCE_INTERNAL_SYSTEM; | ||
htimer16_1.CountMode = TIMER16_COUNTMODE_INTERNAL; /* При тактировании от Input1 не имеет значения */ | htimer16_1.CountMode = TIMER16_COUNTMODE_INTERNAL; /* При тактировании от Input1 не имеет значения */ | ||
htimer16_1.Clock.Prescaler = | htimer16_1.Clock.Prescaler = TIMER16_PRESCALER_128; | ||
htimer16_1.ActiveEdge = TIMER16_ACTIVEEDGE_RISING; /* Выбирается при тактировании от Input1 */ | htimer16_1.ActiveEdge = TIMER16_ACTIVEEDGE_RISING; /* Выбирается при тактировании от Input1 */ | ||
Строка 59: | Строка 61: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
}} | |||
Кроме этого в функции SystemClock_Config приведены настройки для тактирования. Убедитесь что в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_TIMER16_1_M. Сама функция должна выглядеть примерно так: | |||
{{#spoiler:show=Развернуть код|hide=Свернуть код| | |||
<syntaxhighlight lang="c" line="1"> | |||
void SystemClock_Config(void) | |||
{ | |||
RCC_OscInitTypeDef RCC_OscInit = {0}; | |||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; | |||
RCC_OscInit.OscillatorEnable = RCC_OSCILLATORTYPE_OSC32K | RCC_OSCILLATORTYPE_OSC32M; | |||
RCC_OscInit.OscillatorSystem = RCC_OSCILLATORTYPE_OSC32M; | |||
RCC_OscInit.AHBDivider = 0; | |||
RCC_OscInit.APBMDivider = 0; | |||
RCC_OscInit.APBPDivider = 0; | |||
RCC_OscInit.HSI32MCalibrationValue = 0; | |||
RCC_OscInit.LSI32KCalibrationValue = 0; | |||
HAL_RCC_OscConfig(&RCC_OscInit); | |||
PeriphClkInit.PMClockAHB = PMCLOCKAHB_DEFAULT; | |||
PeriphClkInit.PMClockAPB_M = PMCLOCKAPB_M_DEFAULT | PM_CLOCK_WU_M | PM_CLOCK_PAD_CONFIG_M; | |||
PeriphClkInit.PMClockAPB_P = PMCLOCKAPB_P_DEFAULT | PM_CLOCK_UART_0_M | PM_CLOCK_TIMER16_1_M; | |||
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_NO_CLK; | |||
PeriphClkInit.RTCClockCPUSelection = RCC_RTCCLKCPUSOURCE_NO_CLK; | |||
HAL_RCC_ClockConfig(&PeriphClkInit); | |||
} | |||
</syntaxhighlight> | |||
}} | |||
Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно. Для этого нужно подключить библиотеки uart_lib и xprintf: | |||
{{#spoiler:show=Развернуть код|hide=Свернуть код| | |||
<syntaxhighlight lang="c" line="1"> | |||
#include "mik32_hal_rcc.h" | |||
#include "mik32_hal_timer16.h" | |||
#include <gpio.h> | |||
#include "uart_lib.h" | |||
#include "xprintf.h" | |||
</syntaxhighlight> | |||
}} | |||
Для инициализации UART в функции main после функции тактирования SystemClock_Config следует написать: | |||
<syntaxhighlight lang="c" line="1" start="1"> | |||
UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0); | |||
</syntaxhighlight> | |||
Скорость UART задается делителем во втором аргументе функции. При такой записи скорость будет 9600 бод. | |||
В начале main.c можно видеть объявление структуры с набором настроек для выбранного таймера, которую использует функция инициализации Timer16_1_Init. | |||
{{#spoiler:show=Развернуть код|hide=Свернуть код| | |||
<syntaxhighlight lang="c" line="1"> | |||
Timer16_HandleTypeDef htimer16_1; | |||
void SystemClock_Config(void); | |||
static void Timer16_1_Init(void); | |||
</syntaxhighlight> | |||
}} | |||
Перед инициализацией таймера (функция Timer16_1_Init) следует настроить вывод Port1.9 в режим второй функции вывода (GPIO1.9). Для начала нужно включить тактирование GPIO1. Для этого можно воспользоваться функцией HAL_RCC_ClockEnable(HAL_CLOCK_GPIO_1) или в функции SystemClock_Config добавить PM_CLOCK_GPIO_1_M в PeriphClkInit.PMClockAPB_P. Перевод вывода во вторую функцию осуществляется с помощью регистра PORT_1_CFG (PAD_1_CFG). Убедитесь что в функции SystemClock_Config присутствует PMCLOCKAPB_M_DEFAULT или PM_CLOCK_PAD_CONFIG_M, которые отвечают за тактирование контроллера выводов. В дальнейшем вместо записи в регистры будет использоваться библиотека. | |||
Для запуска таймера в одиночном режиме нужно вызвать функцию HAL_Timer16_StartContinuousMode и передать в нее адрес на структуру htimer16_1. Затем для ожидания события можно воспользоваться функцией HAL_Timer16_WaitTrigger. Флаг триггера EXTTRIG очищается внутри функции. Также для очистки флага триггера можно использовать функцию HAL_Timer16_ClearTriggerFlag. | |||
Функция main должно выглядеть примерно так: | |||
{{#spoiler:show=Развернуть код|hide=Свернуть код| | |||
<syntaxhighlight lang="c" line="1"> | |||
int main() | |||
{ | |||
SystemClock_Config(); | |||
UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0); | |||
HAL_RCC_ClockEnable(HAL_CLOCK_GPIO_1); | |||
/************************Включить GPIO1.9 для триггера Timer16_1************************/ | |||
HAL_RCC_ClockEnable(HAL_CLOCK_GPIO_1); | |||
PAD_CONFIG->PORT_1_CFG |= (1 << (2 * 9)); // Установка порта 1 в режим GPIO | |||
GPIO_1->DIRECTION_IN = 1 << 9; // Установка направления порта в вход | |||
/***************************************************************************************/ | |||
Timer16_1_Init(); | |||
/*****************Запуск таймера в одиночном или продолжительном режиме*****************/ | |||
HAL_Timer16_StartSingleMode(&htimer16_1); | |||
//HAL_Timer16_StartContinuousMode(&htimer16_1); | |||
/***************************************************************************************/ | |||
/* Ожидание флага триггера */ | |||
HAL_Timer16_WaitTrigger(&htimer16_1); | |||
while (1) | |||
{ | |||
/* Очистка флага триггера */ | |||
HAL_Timer16_ClearTriggerFlag(&htimer16_1); | |||
/* Вывод значения счетчика */ | |||
xprintf("Counter = %d\n", HAL_Timer16_GetCounterValue(&htimer16_1)); | |||
} | |||
} | |||
</syntaxhighlight> | |||
}} | |||
[[Файл:After.png|мини|Рисунок 3 - вывод UART]] | |||
Как только на выводе Port1.9 появится активный фронт начнется отсчет таймера. Пример вывода изображен на рисунке 3. |
Текущая версия от 10:04, 24 марта 2023
В примере будет задействован один из триггеров Timer16_1. Таймер будет запускаться по нарастающему фронту на GPIO1.9.
Работа с конфигуратором (В разработке)
Для начала настроем в конфигураторе тактирование mik32, например, от внешнего кварца 32МГц. Затем настроем делители шины. Так как Timer16 тактируется от шины APB_P_CLK, то зададим делители AHB_DIV и APB_P_DIV. В данном примере оставим делители по умолчанию. В итоге вкладка с тактированием должна выглядеть так:
(Картинка тактирования из конфигуратора. В работе)
Затем перейдем к настройке самого таймера. Для этого откроем вкладку Timer16_1 и включим таймер, выбрав один из режимов. Выберем режим счетчика.
После этого нужно выбрать источник тактирования, который будет использоваться для подсчета. Выберем, например, тактирование от системной частоты. Для тактирования от внутреннего источника оставим источник синхронизации по умолчанию.
Далее следует выбрать нужный вам делитель частоты. В примере выбран делитель 128.
Активный фронт задает фронт, по которому будет происходить увеличение счетчика. Эта настройка используется при внешнем источнике синхронизации. В нашем примере тактирование от внутреннего источника, поэтому эта настройка нам не нужна.
Следующая настройка - период. Это верхний предел, до которого считает таймер. В нашем примере таймер будет считать до максимального значения 65535.
Режим обновления регистров задает когда будут обновляться регистры ARR - значение автоматической перезагрузки (верхний предел счета таймера) и CMP - значение сравнения. Выберем, например, обновление после каждого доступа к записи.
Далее идут настройки триггера. В источнике триггера выберем GPIO1.9. Активный фронт триггера нарастающий. Включение функции timeout разрешает повторное срабатывание триггера во время счета. При выключенной функции timeout повторное срабатывание во время счета будет проигнорировано и станет доступно только после окончания счета.
После этого останется настроить цифровой фильтр от помех, если он нужен. При включении фильтра должен использоваться внутренний источник синхронизации.
В итоге настройки таймера в конфигураторе должны выглядеть примерно так:
(Объяснение работы с конфигуратором. В разработке)
Нажимаем кнопку генерации. В итоге у нас появится проект для PlatformIo. Далее работа идет в visual studio code.
Использование библиотеки HAL_Timer16
В сгенерированном проекте в файле main.c должна быть функция Timer16_1_Init, в которой будут заданы настройки для Timer16_1. Выглядит она так:
Кроме этого в функции SystemClock_Config приведены настройки для тактирования. Убедитесь что в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_TIMER16_1_M. Сама функция должна выглядеть примерно так:
Для демонстрации вывода текста в PeriphClkInit.PMClockAPB_P присутствует PM_CLOCK_UART_0_M. У вас его может не быть так как UART нужно включить отдельно. Для этого нужно подключить библиотеки uart_lib и xprintf:
Для инициализации UART в функции main после функции тактирования SystemClock_Config следует написать:
UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);
Скорость UART задается делителем во втором аргументе функции. При такой записи скорость будет 9600 бод.
В начале main.c можно видеть объявление структуры с набором настроек для выбранного таймера, которую использует функция инициализации Timer16_1_Init.
Перед инициализацией таймера (функция Timer16_1_Init) следует настроить вывод Port1.9 в режим второй функции вывода (GPIO1.9). Для начала нужно включить тактирование GPIO1. Для этого можно воспользоваться функцией HAL_RCC_ClockEnable(HAL_CLOCK_GPIO_1) или в функции SystemClock_Config добавить PM_CLOCK_GPIO_1_M в PeriphClkInit.PMClockAPB_P. Перевод вывода во вторую функцию осуществляется с помощью регистра PORT_1_CFG (PAD_1_CFG). Убедитесь что в функции SystemClock_Config присутствует PMCLOCKAPB_M_DEFAULT или PM_CLOCK_PAD_CONFIG_M, которые отвечают за тактирование контроллера выводов. В дальнейшем вместо записи в регистры будет использоваться библиотека.
Для запуска таймера в одиночном режиме нужно вызвать функцию HAL_Timer16_StartContinuousMode и передать в нее адрес на структуру htimer16_1. Затем для ожидания события можно воспользоваться функцией HAL_Timer16_WaitTrigger. Флаг триггера EXTTRIG очищается внутри функции. Также для очистки флага триггера можно использовать функцию HAL_Timer16_ClearTriggerFlag.
Функция main должно выглядеть примерно так:
Как только на выводе Port1.9 появится активный фронт начнется отсчет таймера. Пример вывода изображен на рисунке 3.