# Таймеры - ШИМ

Хоть нам и удалось в прошлом разделе сделать "мигание по синусоиде", оно было прерывистым и не очень красивым. Хотелось бы добиться плавного изменения яркости, без заметного для глаза мерцания. В этом нам поможет ШИМ - широтно-импульсная модуляция (PWM - pulse-width modulation).

## Что такое ШИМ

В прошлом упражнении мы уже видели, что у таймера есть период - значения, достигая которого он сбрасывается. Таким образом, можно говорить о частоте таймера, с этой частотой у нас вызывались прерывания и эта же частота будет использоваться для ШИМ.

ШИМ нужна для генерации сигналов, переключающихся между двумя значениями (условно, 0 и 1) с постоянной частотой:

<figure><img src="/files/0WhLk6NJVktzSMs9fUBF" alt=""><figcaption><p>Примеры сигналов</p></figcaption></figure>

Видно, что частота ("время" от начала одного сигнала до следующего) постоянно - эта та же частота, что была и у прерывания и задается с помощью **Counter Period**. Duty cycly, или коэффициент заполнения, отмеченный на графике, управляется с помощью второго счетчика - **pulse**, по достижении которого сигнал переходит в состояние 0.

Представим, что counter period у нас 20. Тогда для получения таких сигналов, как на рисунке, нам нужно выставить pulse:

1. 10
2. 15
3. 5

Если частота ШИМ достаточно велика (тысячи КГц), то держа таким образом светодиод во включенном состоянии 50/75/25 процентов времени, мы получим стабильную яркость в 50/75/25 или любой другой процент от максимальной. Переключения с такой частотой будут не различимы для глаза.

{% hint style="info" %}
Аналогичным образом можно управлять, например, скоростью DC-мотора
{% endhint %}

## Управление яркостью светодиода с помощью ШИМ

### Настройка микроконтроллера

Выберем ножку диода `PA5`, и назначим ей режим `TIM2_CH1` - это означает, что для нее мы будем использовать первый канал генерации PWM из второго таймера (дальше станет понятнее, что имеется ввиду).

<figure><img src="/files/ABQHrzh8DvtFDTK9Q5Y4" alt=""><figcaption></figcaption></figure>

Теперь необходимо настроить `TIM2`:

<figure><img src="/files/ZGtkiIyEDiLERVpER05E" alt=""><figcaption></figcaption></figure>

С **Clock Source**, **Prescaler** и **Counter Period** мы уже разбирались. Тут важны следующие новые настройки:&#x20;

* `Channel1 - PWM Generation CH1` - указывает, что на первом канале таймера (который мы как раз привязали к светодиоду) нужно генерировать ШИМ
* `PWM Generation Channel 1 - Pulse - 10` - значение, контролирующее коэффициент заполнения сигнала. При `pulse == 10` и `period == 500`, заполнение равно 2%

Очевидно, что чтобы менять яркость светодиода, необходимо просто менять значение pulse по синусоиде - при **prescaler** 16, частота таймера получилась равной 10 МГц, и с периодом 500 - частота ШИМ 20 КГц. С такой частотой, при управлении яркостью через **pulse** никакого мерцания заметно не будет, и можно рассматривать коэффициент заполнения просто как процент от максимальной яркости.

В таком случае, все что нам осталось сделать, это запустить ШИМ и в цикле устанавливать pulse как синус от какого-то X. Тут удобно привести большой кусок кода из `main`, в котором содержится вся эта логика:

```c
/* USER CODE BEGIN 2 */
double x = 0;
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
    HAL_Delay(0.05);
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 125*(sin(x*3.14)+1));
    if (x < 2) x += 0.001;
    else x = 0;
/* USER CODE END WHILE */
```

Залив этот код на контроллер, мы увидим, как светодиод плавно меняет яркость, без заметного мерцания.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://voltbro.gitbook.io/vbcores/tutorials/stm32-cube-ide/taimery-shim.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
