11. STM32. Программирование STM32F103. TIMER. Encoder
Еще одна полезная функция таймера - возможность работы с инкрементными (квадратурными) энкодерами. Мы настроим таймер таким образом, чтобы он обрабатывал сигналы с двух своих входных каналов и менял свой счетчик в указанных пределах. То есть, когда мы будем вращать энкодер в одном направлении, счетчик таймера будет увеличиваться, в обратном - уменьшаться. В примере мы установим TIM_Period = 100. Это значит, что счетчик таймера будет уменьшаться или увеличиваться в зависимости от направления вращения энкодера в этих пределах. При прямом вращении энкодера, когда счетчик досчитает до 100, он перепрыгнет на 0. При обратном направлении, когда счетчик уменьшится до нуля, он автоматически перепрыгнет на 100. Нам больше ничего не придется контролировать, только считывать счетчик таймера. В следующем примере программа периодически опрашивает счетчик таймера и отправляет его значение в последовательный порт USART.
Схема:
В этом примере я использовал контактный энкодер. На каждый щелчок энкодера таймер изменяется на 2.
Пример 1:
#include <stm32f10x.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_tim.h>
#include <stm32f10x_usart.h>
#include <stdio.h>
#include <misc.h>
#define FORWARD 0
#define BACKWARD 1
#define NOREADY 0
#define READY 1
#define INIT 3
volatile uint8_t encoder_status = INIT;
volatile uint8_t encoder_direction = FORWARD;
void usart_init(void)
{
/* Enable USART1 and GPIOA clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* Configure the GPIOs */
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure the USART1 */
USART_InitTypeDef USART_InitStructure;
/* USART1 configuration ------------------------------------------------------*/
/* USART1 configured as follow:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
- USART Clock disabled
- USART CPOL: Clock is active low
- USART CPHA: Data is captured on the middle
- USART LastBit: The clock pulse of the last data bit is not output to
the SCLK pin
*/
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
/* Enable USART1 */
USART_Cmd(USART1, ENABLE);
}
void USARTSend(const unsigned char *pucBuffer)
{
while (*pucBuffer)
{
USART_SendData(USART1, *pucBuffer++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{
}
}
}
void encoder_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//Канали TIM3_CH1, TIM3_CH2 як вхід з підтяжкою
GPIO_InitTypeDef gpio_cfg;
gpio_cfg.GPIO_Mode = GPIO_Mode_IPU;
gpio_cfg.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
gpio_cfg.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio_cfg);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* Налаштовуємо TIM3 */
TIM_TimeBaseInitTypeDef TIMER_InitStructure;
TIM_TimeBaseStructInit(&TIMER_InitStructure);
// Вказуємо TIM_Period - до скількох рахувати таймеру при обертах енкодера
TIMER_InitStructure.TIM_Period = 100;
// Дозволяємо рахувати у обидва боки
TIMER_InitStructure.TIM_CounterMode = TIM_CounterMode_Up | TIM_CounterMode_Down;
TIM_TimeBaseInit(TIM3, &TIMER_InitStructure);
/* Налаштовуємо Encoder Interface */
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_Cmd(TIM3, ENABLE);
}
int main(void)
{
int i;
char buffer[80] = {`\0`};
usart_init();
encoder_init();
while (1)
{
// Виводимо положення енкодера
sprintf(buffer, "COUNTER: %d\r\n", TIM_GetCounter(TIM3));
USARTSend(buffer);
/* delay */
for(i=0;i<0x100000;i++);
}
}
Если Вам нужно, чтобы при переполнении счетчика таймера вызывалось прерывания, это можно сделать, как показано в следующем примере. В этом примере TIM_Period = 1, и теперь прерывания вызывается при каждой смене состояния энкодера.
Пример 2:
#include <stm32f10x.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_tim.h>
#include <stm32f10x_usart.h>
#include <stdio.h>
#include <misc.h>
#define FORWARD 0
#define BACKWARD 1
#define NOREADY 0
#define READY 1
#define INIT 3
volatile uint8_t encoder_status = INIT;
volatile uint8_t encoder_direction = FORWARD;
void usart_init(void)
{
/* Enable USART1 and GPIOA clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* Configure the GPIOs */
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure the USART1 */
USART_InitTypeDef USART_InitStructure;
/* USART1 configuration ------------------------------------------------------*/
/* USART1 configured as follow:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
- USART Clock disabled
- USART CPOL: Clock is active low
- USART CPHA: Data is captured on the middle
- USART LastBit: The clock pulse of the last data bit is not output to
the SCLK pin
*/
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
/* Enable USART1 */
USART_Cmd(USART1, ENABLE);
}
void USARTSend(const unsigned char *pucBuffer)
{
while (*pucBuffer)
{
USART_SendData(USART1, *pucBuffer++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{
}
}
}
void encoder_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//Канали TIM3_CH1, TIM3_CH2 як вхід з підтяжкою
GPIO_InitTypeDef gpio_cfg;
gpio_cfg.GPIO_Mode = GPIO_Mode_IPU;
gpio_cfg.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
gpio_cfg.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio_cfg);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// Налаштовуємо TIM3
TIM_TimeBaseInitTypeDef TIMER_InitStructure;
TIM_TimeBaseStructInit(&TIMER_InitStructure);
// Встановлюємо TIM_Period = 1. Таймер рахуватиме до 1. Переривання буде викликатися при кожній зміні положення енкодера
TIMER_InitStructure.TIM_Period = 1;
TIMER_InitStructure.TIM_CounterMode = TIM_CounterMode_Up | TIM_CounterMode_Down;
TIM_TimeBaseInit(TIM3, &TIMER_InitStructure);
// Налаштовуємо Encoder Interface та дозволяємо переривання
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
NVIC_EnableIRQ(TIM3_IRQn);
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
// Перше спрацювання відкидаємо. encoder_status == INIT може бути тільки один раз
if (encoder_status == INIT)
encoder_status = NOREADY;
else
encoder_status = READY;
/* У регістрі TIM3_CR1 біт TIM_CR1_DIR буде напрямок обертання енкодера*/
encoder_direction = (TIM3->CR1 & TIM_CR1_DIR ? BACKWARD : FORWARD);
}
}
int main(void)
{
char buffer[80] = {`\0`};
usart_init();
encoder_init();
while (1)
{
if (encoder_status)
{
encoder_status = NOREADY;
if (encoder_direction == FORWARD){
sprintf(buffer, "FORWARD\r\n");
//....
}
else{
sprintf(buffer, "BACKWARD\r\n");
//....
}
USARTSend(buffer);
}
}
}
Желаю успехов!
Смотри также:
- 1. STM32. Программирование STM32F103. Тестовая плата. Прошивка через последовательный порт и через ST-Link программатор
- 2. STM32. Программирование. IDE для STM32
- 3. STM32. Программирование STM32F103. GPIO
- 4. STM32. Программирование STM32F103. Тактирование
- 5. STM32. Программирование STM32F103. USART
- 6. STM32. Программирование STM32F103. NVIC
- 7. STM32. Программирование STM32F103. ADC
- 8. STM32. Программирование STM32F103. DMA
- 9. STM32. Программирование STM32F103. TIMER
- 10. STM32. Программирование STM32F103. TIMER. Захват сигнала
- 11. STM32. Программирование STM32F103. TIMER. Encoder
- 12. STM32. Программирование STM32F103. TIMER. PWM
- 13. STM32. Программирование STM32F103. EXTI
- 14. STM32. Программирование STM32F103. RTC
- 15. STM32. Программирование STM32F103. BKP
- 16. STM32. Программирование STM32F103. Flash
- 17. STM32. Программирование STM32F103. Watchdog
- 18. STM32. Программирование STM32F103. Remap
- 19. STM32. Программирование STM32F103. I2C Master
- 20. STM32. Программирование STM32F103. I2C Slave
- 21. STM32. Программирование STM32F103. USB
- 22. STM32. Программирование STM32F103. PWR
- 23. STM32. Программирование STM32F103. Option bytes
- 24. STM32. Программирование STM32F103. Bootloader
- STM32. Скачать примеры
- System Workbench for STM32 Установка на Ubuntu
- Keil uVision5 – IDE для STM32
- IAR Workbench – IDE для STM32
- Управление бесколлекторным двигателем постоянного тока (BLDC) с помощью STM32
- Управление PMSM с помощью STM32
Додати коментар
Недавні записи
- 🇺🇦 FOC Board STM32F103RB 🧩
- STM32 Motor control SDK - керування оборотами мотора за допомогою потенціометра 📑
- Flask✙Gunicorn✙Nginx➭😎
- STM32 Motor control SDK - програмне керування обертам мотора
- STM32 Motor control SDK - як створити перший проект
- Vue SVG. Приклад побудови живого параметричного креслення
- Вимірювання моменту мотора
- Vue SVG - компонент. Приклад 📑
- Flask + Vue 🏁 Финальный пример 🏁
- Flask, CORS, JSON-файл. Пример#6
Tags
bldc brushless stm32 motor web html css flask atmega foc git java-script pmsm raspberry-pi python websocket mongodb esp8266 nodemcu st-link tim timer docker ngnix programmator ssd1331 ssd1306 wifi uart meteo bme280 bmp280 i2c gps mpu-6050 mpu-9250 sensors 3d-printer options usb barometer remap watchdog flash eeprom rtc bkp encoder pwm servo capture examples dma adc nvic usart gpio books battery dc-dc sms max1674 avr lcd dht11 piezo rs-232 rfid solar exti bluetooth eb-500 displays ethernet led smd soldering mpx4115a hih-4000
Архіви