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. Тестова плата. Прошивка через UART та через 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
Дякую за матеріал, дуже допоміг. Тільки я збирав проект через Cube MX, хоча також використав режим таймера - Encoder Mode. Все просто чудово працює
Недавні записи
- Розпізнавання мови (Speech recognition)
- Selenium
- Комп'ютерний зір (Computer Vision)
- Деякі думки про точність вимірювань в електроприводі
- Датчики Холла 120/60 градусів
- Модуль драйверів напівмосту IGBT транзисторів
- Драйвер IGBT транзисторів на A316J
- AS5600. Варіант встановлення на BLDC мотор
- DC-DC для IGBT драйверів ізольований 2 W +15 -8 вольт
- U-FOC - Векторне керування безколекторними моторами
Tags
esp8266 examples adc usart rfid eb-500 soldering lcd stm32 raspberry-pi python mongodb gps mpu-9250 sensors led hih-4000 foc ngnix wifi servo sms ethernet bldc 3d-printer bluetooth mpx4115a web pmsm options remap solar timer bme280 mpu-6050 avr docker flash bkp capture gpio uart meteo i2c usb rtc encoder programmator ssd1306 battery displays java-script barometer watchdog eeprom flask websocket pwm dht11 motor ssd1331 piezo smd brushless atmega books css git st-link dc-dc html nodemcu dma nvic rs-232 exti tim bmp280 max1674
Архіви