Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2742
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

Таймеры

348

Рисунок 31: Как включить Одноимпульсный режим в таймере

Важно отметить, что на момент написания данной главы код, созданный CubeMX, был не так хорош. Код не использует HAL_TIM_OnePulse_ConfigChannel(), и каждый канал сконфигурирован так, что он будет использоваться независимо. Это приводит к более избыточному и запутанному коду. Однако, возможно, что когда вы прочитаете данную главу, ST уже исправит эту часть.

11.3.9. Режим энкодера

Поворотные энкодеры – это устройства, которые обладают очень широким спектром применения. Они используются для измерения скорости, а также углового положения вращающихся объектов. Их можно использовать для измерения оборотов и направления вращения двигателя, для управления серводвигателями, а также шаговыми двигателями и т. д. Существует несколько типов поворотных энкодеров: оптические, механические, магнитные.

Инкрементные энкодеры представляют собой тип поворотных энкодеров, которые обеспечивают периодический выходной сигнал при обнаружении движения. Механический тип требует устранения помех и обычно используется как «цифровой потенциометр». Большинство современных домашних и автомобильных стереосистем используют механические поворотные энкодеры для регулировки громкости. Инкрементный поворотный энкодер является наиболее широко используемым из всех поворотных энкодеров из-за его низкой стоимости и способности выдавать сигналы, которые можно легко интерпретировать для предоставления связанной с движением информации, такой как скорость.

Рисунок 32: Прямоугольные сигналы, генерируемые квадратурным энкодером на каналах A и B

Они используют два выхода, называемых A и B, которые называются квадратурными выходами, так как они на 90 градусов сдвинуты по фазе, как показано на рисунке 32. Направление вращения двигателя зависит о того, опережает фаза A фазу B или фаза B опережает фазу A. Необязательный третий канал – индексный импульс (или нуль-метка)

Таймеры

349

– возникает один раз за оборот и используется как эталон для измерения абсолютной позиции. Существует несколько способов определения направления вращения и положения поворотного энкодера. Подключив выводы A и B к двум I/O микроконтроллера, можно определить, когда сигнал становится высоким и низким. Это можно выполнить как вручную (используя прерывания для захвата при смене состояния канала), так и с помощью таймера: его каналы можно сконфигурировать в режиме захвата входного сигнала, при этом значения захвата сравниваются для вычисления направления вращения и скорости энкодера.

Таймеры общего назначения STM32 предоставляют удобный способ считывания вращающихся энкодеров: этот режим и впрямь называется режимом энкодера, и он значительно упрощает процесс захвата. Когда таймер конфигурируется в режиме энкодера, регистр счетчика таймера (TIMx_CNT) увеличивается/уменьшается на фронтах входных каналов.

Рисунок 33: Как скорость и направление вращения энкодера вычисляются таймером в Режиме энкодера

Доступны два режима захвата: X2 и X4. В режиме X2 регистр CNT увеличивается/уменьшается на каждом фронте только одного канала (T1 или T2). В режиме X4 регистр CNT обновляется на каждом фронте обоих каналов: это удваивает частоту захвата. Направление вращения автоматически определяется и предоставляется программисту в регистре TIMx_DIR, как показано на рисунке 33. Путем регулярного сравнения значений регистра счетчика CNT можно получить число оборотов в минуту (RPM), учитывая количество импульсов, которые энкодер генерирует за оборот.

К инкрементным механическим энкодерам, как правило, должна быть применена борьба с дребезгом контактов из-за шумного выхода. Обычно используется компаратор в качестве каскада фильтрации этих устройств, особенно если они используются для сопряжения двигателей и других шумных устройств. При определенных условиях каскад

Таймеры

350

входного фильтра таймера STM32 может использоваться для фильтрации каналов A и B, уменьшая количество электронных компонентов спецификации компонентов платы.

Режим энкодера доступен только на каналах TI1 и TI2 и активируется с помощью функ-

ции HAL_TIM_Encoder_Init() и экземпляра структуры Си TIM_Encoder_InitTypeDef, которая

определена следующим образом.

typedef struct {

 

 

/* Канал

T1 */

 

 

uint32_t

EncoderMode;

/* Задает режим энкодера.

*/

uint32_t

IC1Polarity;

/* Задает активный фронт входного сигнала.

*/

uint32_t

IC1Selection;

/* Задает вход.

*/

uint32_t

IC1Prescaler;

/* Задает предделитель захвата входного сигнала.

*/

uint32_t

IC1Filter;

/* Задает фильтр захвата входного сигнала.

*/

/* Канал

T2 */

 

 

uint32_t

IC2Polarity;

/* Задает активный фронт входного сигнала.

*/

uint32_t

IC2Selection;

/* Задает вход.

*/

uint32_t

IC2Prescaler;

/* Задает предделитель захвата входного сигнала.

*/

uint32_t

IC2Filter;

/* Задает фильтр захвата входного сигнала.

*/

} TIM_Encoder_InitTypeDef;

Мы встречали большинство полей TIM_Encoder_InitTypeDef в предыдущих параграфах. Единственной ремаркой является EncoderMode, которое может принимать значения

TIM_ENCODERMODE_TI1 или TIM_ENCODERMODE_TI2 для установки режима энкодера X2 на од-

ном из двух каналов, а значение TIM_ENCODERMODE_TI12 для установки режима X4, так что регистр TIMx_CNT обновляется на каждом фронте каналов TI1 и TI2.

В следующем примере, предназначенном для работы на Nucleo-F030R8, имитируется инкрементальный энкодер при помощи TIM1 в режиме сравнения выходного сигнала. Ка-

налы OC1 и OC2 (PA8, PA9) TIM1 направляются к каналам TI1 и TI2 (PA6, PA7) TIM3 при помощи morpho-разъема и конфигурируются таким образом, что они генерируют два прямоугольных сигнала, имеющих одинаковый период, но смещенных по фазе. TIM3 затем конфигурируется в режиме энкодера. Таймер SysTick используется для генерации временного отсчета: каждые 1 с вычисляется количество импульсов вместе с направлением вращения энкодера. Затем определяется число оборотов в минуту (RPM), если предположить, что энкодер генерирует 4 импульса на каждый оборот (pulses per revolution). Наконец, нажав кнопку USER, можно изменить фазовый сдвиг между фазами A и B: это инвертирует вращение энкодера.

Имя файла: src/main-ex11.c

22 #define PULSES_PER_REVOLUTION 4

23

24int main(void) {

25HAL_Init();

26

27Nucleo_BSP_Init();

28MX_TIM1_Init();

29MX_TIM3_Init();

31HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);

32HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_1);

Таймеры

351

33 HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_2); 34

35cnt1 = __HAL_TIM_GET_COUNTER(&htim3);

36tick = HAL_GetTick();

37

38while (1) {

39if (HAL_GetTick() - tick > 1000L) {

40cnt2 = __HAL_TIM_GET_COUNTER(&htim3);

41if (__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3)) {

42if (cnt2 < cnt1) /* Проверка на опустошение счетчика */

43diff = cnt1 - cnt2;

44else

45diff = (65535 - cnt2) + cnt1;

46} else {

47if (cnt2 > cnt1) /* Проверка на переполнение счетчика */

48diff = cnt2 - cnt1;

49else

50diff = (65535 - cnt1) + cnt2;

51}

52

53sprintf(msg, "Difference: %d\r\n", diff);

54HAL_UART_Transmit(&huart2, (uint8_t*) msg, strlen(msg), HAL_MAX_DELAY);

56speed = ((diff / PULSES_PER_REVOLUTION) / 60);

58/* Если первые три бита регистра SMCR установлены в 0x3,

59* то таймер устанавливается в режим X4 (TIM_ENCODERMODE_TI12)

60* и нам нужно разделить счетчик импульсов на два, поскольку

61* он включает импульсы обоих каналов */

62if ((TIM3->SMCR & 0x3) == 0x3)

63

speed /= 2;

64

 

65sprintf(msg, "Speed: %d RPM\r\n", speed);

66HAL_UART_Transmit(&huart2, (uint8_t*) msg, strlen(msg), HAL_MAX_DELAY);

68dir = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);

69sprintf(msg, "Direction: %d\r\n", dir);

70HAL_UART_Transmit(&huart2, (uint8_t*) msg, strlen(msg), HAL_MAX_DELAY);

72tick = HAL_GetTick();

73cnt1 = __HAL_TIM_GET_COUNTER(&htim3);

74 }

75

76if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) {

77/* Инвертирование вращения, меняя значение CCR канала 1 и канала 2 */

78tim1_ch1_pulse = __HAL_TIM_GET_COMPARE(&htim1, TIM_CHANNEL_1);

79tim1_ch2_pulse = __HAL_TIM_GET_COMPARE(&htim1, TIM_CHANNEL_2);

80

81__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, tim1_ch2_pulse);

82__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, tim1_ch1_pulse);

Таймеры

352

83}

84}

85}

86

87/* Функция инициализации TIM1 */

88void MX_TIM1_Init(void) {

89TIM_OC_InitTypeDef sConfigOC;

91htim1.Instance = TIM1;

92htim1.Init.Prescaler = 9;

93htim1.Init.CounterMode = TIM_COUNTERMODE_UP;

94htim1.Init.Period = 999;

95

HAL_TIM_Base_Init(&htim1);

96

 

97sConfigOC.OCMode = TIM_OCMODE_TOGGLE;

98sConfigOC.Pulse = 499;

99sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

100sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

101sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;

102sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;

103sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;

104HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

106sConfigOC.Pulse = 999; /* Фаза B сдвигается на 90° */

107HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);

108}

110/* Функция инициализации TIM3 */

111void MX_TIM3_Init(void) {

112TIM_Encoder_InitTypeDef sEncoderConfig;

114htim3.Instance = TIM3;

115htim3.Init.Prescaler = 0;

116htim3.Init.CounterMode = TIM_COUNTERMODE_UP;

117htim3.Init.Period = 65535;

119sEncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;

121sEncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;

122sEncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;

123sEncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;

124sEncoderConfig.IC1Filter = 0;

126sEncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;

127sEncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;

128sEncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;

129sEncoderConfig.IC2Filter = 0;

131HAL_TIM_Encoder_Init(&htim3, &sEncoderConfig);

132}