peroid 0 14 июня, 2015 Опубликовано 14 июня, 2015 · Жалоба Всем доброго времени суток. Пытаюсь прикрутить к STM32f4-Discovery ультразвуковой дальномер US-015. Как я понял, нужно подать на ножку датчика импульс длиной 10 микросекунд, а потом посчитать ширину эха. Думаю, что решение через задержку в главном цикле не совсем правильно, поэтому пытаюсь прикрутить все это аппаратно. Как вариант решения, решил использовать режим одновибратора ТIM_SelectOnePulseMode(TIM9, TIM_OPMode_Single), но не могу понять как перезапустить импульс заново. Перезапускать его хочу его из TIM1_BRK_TIM9_IRQHandler, после того, как произойдет считывание ширины эха. Помогите пожалуйста подкостылить код, дабы запускать импульс по мере необходимости :smile3046: P.S. Длительность импульса задаю из главного цикла командой TIM_SetCompare1(TIM9, length); Вот настройки GPIO и TIM9: #include "UltraSonic_timer_ini.h" int capture=0; void UltraSonic_init(void) { GPIO_InitTypeDef UltraSonic_GPIO_init; TIM_TimeBaseInitTypeDef UltraSonic_TIM_BASE_Settings; TIM_OCInitTypeDef UltraSonic_TIM_OC_Settings; TIM_ICInitTypeDef UltraSonic_TIM_IC_Settings; //TAKTIRUEM RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE); UltraSonic_GPIO_init.GPIO_Mode=GPIO_Mode_AF; UltraSonic_GPIO_init.GPIO_OType=GPIO_OType_PP; UltraSonic_GPIO_init.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6; UltraSonic_GPIO_init.GPIO_PuPd=GPIO_PuPd_DOWN; UltraSonic_GPIO_init.GPIO_Speed=GPIO_Low_Speed; GPIO_Init(GPIOE, &UltraSonic_GPIO_init); GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_TIM9); GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_TIM9); UltraSonic_TIM_BASE_Settings.TIM_ClockDivision = TIM_CKD_DIV1; UltraSonic_TIM_BASE_Settings.TIM_CounterMode = TIM_CounterMode_Up; UltraSonic_TIM_BASE_Settings.TIM_Period = 1000; UltraSonic_TIM_BASE_Settings.TIM_Prescaler = 167; UltraSonic_TIM_BASE_Settings.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM9, &UltraSonic_TIM_BASE_Settings); UltraSonic_TIM_OC_Settings.TIM_OCIdleState = TIM_OCIdleState_Reset; UltraSonic_TIM_OC_Settings.TIM_OCMode = TIM_OCMode_PWM1; UltraSonic_TIM_OC_Settings.TIM_OCPolarity = TIM_OCPolarity_High; UltraSonic_TIM_OC_Settings.TIM_OutputState = TIM_OutputState_Enable; UltraSonic_TIM_OC_Settings.TIM_Pulse = 10; TIM_OC1Init(TIM9, &UltraSonic_TIM_OC_Settings); UltraSonic_TIM_IC_Settings.TIM_Channel = TIM_Channel_2; //Ispolzuem 2y kanal TIMER 9 UltraSonic_TIM_IC_Settings.TIM_ICFilter = 2; //Ne filtruem nichego UltraSonic_TIM_IC_Settings.TIM_ICPolarity = TIM_ICPolarity_Rising; //Schitaem po narastauschemu frontu UltraSonic_TIM_IC_Settings.TIM_ICPrescaler = TIM_ICPSC_DIV1; //Schitaem kajdiy impuls UltraSonic_TIM_IC_Settings.TIM_ICSelection = TIM_ICSelection_DirectTI; //Napryamuiu so vhoda!!! TIM_ICInit(TIM9, &UltraSonic_TIM_IC_Settings); TIM_ITConfig(TIM9, TIM_IT_CC2, ENABLE); TIM_Cmd(TIM9, ENABLE); TIM_SelectOnePulseMode(TIM9, TIM_OPMode_Single); NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); } void TIM1_BRK_TIM9_IRQHandler(void) { if (TIM_GetITStatus(TIM9, TIM_IT_CC2) != RESET) { TIM_ClearITPendingBit(TIM9, TIM_IT_CC2); capture = TIM_GetCapture2(TIM9); TIM_ClearFlag(TIM9,TIM_FLAG_Update); } } Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 5 15 июня, 2015 Опубликовано 15 июня, 2015 · Жалоба Режим one pulse mode просто сбрасывает битик TIM_CR1_CEN в момент, TIM_CNT станет равным TIM_ARR. Чтобы снова запустить таймер, надо установить этот бит обратно. Однако в момент прерывания он явно ещё тикает, и эта идея не работает, нужна какая-то другая :-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 16 июня, 2015 Опубликовано 16 июня, 2015 · Жалоба Игрался с HC-SR04 - та же штука - вид сбоку. Опрос в майне конечно не кошерно. Делал опрос эхо-пина в прерывании таймера, настроенный на 58мкс или его множителях. 58мкс==1см до объекта, точности хватает, получается обычный счетчик в сантиметрах. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
peroid 0 16 июня, 2015 Опубликовано 16 июня, 2015 · Жалоба Делал опрос эхо-пина в прерывании таймера... Сделал следующим образом - у таймера 9 настроил канал на сравнение: // Настроил Пин 6 как альтернативную функцию таймера 9. GPIO_InitTypeDef USonic_GPIOE_init; TIM_TimeBaseInitTypeDef USonic__TIMER_9_init; TIM_ICInitTypeDef USonic__IC_TIMER_9_def; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE); USonic_GPIOE_init.GPIO_Mode = GPIO_Mode_AF; USonic_GPIOE_init.GPIO_OType = GPIO_OType_PP; USonic_GPIOE_init.GPIO_Pin = GPIO_Pin_6; USonic_GPIOE_init.GPIO_PuPd = GPIO_PuPd_DOWN; USonic_GPIOE_init.GPIO_Speed = GPIO_High_Speed; GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_TIM9); GPIO_Init(GPIOE, &USonic_GPIOE_init); // Думается, что при частоте 168 МГц и предделителе 16800, частота таймера будет 10'000 тиков в секунду // Устанавливаю период, равный 10'000, чтобы таймер обнулялся каждые 10 милисекунд // Мне все время кажется, что где то тут у меня ошибка :) USonic__TIMER_9_init.TIM_ClockDivision = TIM_CKD_DIV1; USonic__TIMER_9_init.TIM_CounterMode = TIM_CounterMode_Up; USonic__TIMER_9_init.TIM_Period = 10000; USonic__TIMER_9_init.TIM_Prescaler = 16799; TIM_TimeBaseInit(TIM9, &USonic__TIMER_9_init); // Говорю таймеру считать по нарастающему фронту. USonic__IC_TIMER_9_def.TIM_Channel = TIM_Channel_2; USonic__IC_TIMER_9_def.TIM_ICFilter = 0; USonic__IC_TIMER_9_def.TIM_ICPrescaler = TIM_ICPSC_DIV1; USonic__IC_TIMER_9_def.TIM_ICSelection = TIM_ICSelection_DirectTI; USonic__IC_TIMER_9_def.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInit(TIM9, &USonic__IC_TIMER_9_def); // Включаю прерывания NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); TIM_ITConfig(TIM9, T// Vkluchaem TIMER // И сам таймер TIM_Cmd(TIM9, ENABLE); } void TIM1_BRK_TIM9_IRQHandler(void) { if (TIM_GetITStatus(TIM9,TIM_IT_CC2)!=RESET) { TIM_ClearITPendingBit(TIM9, TIM_IT_CC2); // Пишу значение, что насчитал таймер, в память. delay_us = TIM_GetCapture2(TIM9); } } Теперь беру таймер 7 и прикручиваю к нему ногу Е5: GPIO_InitTypeDef USonic_GPIOEout_init; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); USonic_GPIOEout_init.GPIO_Mode = GPIO_Mode_OUT; USonic_GPIOEout_init.GPIO_OType = GPIO_OType_PP; USonic_GPIOEout_init.GPIO_Pin = GPIO_Pin_5; USonic_GPIOEout_init.GPIO_PuPd = GPIO_PuPd_DOWN; USonic_GPIOEout_init.GPIO_Speed = GPIO_High_Speed; GPIO_Init(GPIOE, &USonic_GPIOEout_init); И таймер 7 наконец: TIM_TimeBaseInitTypeDef Delay_TIM_BASE_Settings; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); //Планируется, что таймер обнуляется каждую микросекунду Delay_TIM_BASE_Settings.TIM_ClockDivision = TIM_CKD_DIV1; Delay_TIM_BASE_Settings.TIM_CounterMode = TIM_CounterMode_Up; Delay_TIM_BASE_Settings.TIM_Period = 1; Delay_TIM_BASE_Settings.TIM_Prescaler = 83; Delay_TIM_BASE_Settings.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM7, &Delay_TIM_BASE_Settings); // Включаю прерывание NVIC_EnableIRQ(TIM7_IRQn); TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE); // Запускаю таймер TIM_Cmd(TIM7, ENABLE); // Вот тут планируется, что пока счетчик меньше 10 мкС, идет импульс. В противном случае - выход подтянут к земле. void TIM7_IRQHandler(void) { if (TIM_GetITStatus(TIM7,TIM_IT_Update)!=RESET) { if (us_delay < 10) { GPIO_SetBits(GPIOE, GPIO_Pin_5); }else { GPIO_ResetBits(GPIOE, GPIO_Pin_5); } us_delay++; if (us_delay >= 10000) { us_delay=0; } } Получилось .... какая то хрень получилась... Бытует мнение, что счетчик показывает часы до апокалипсиса, но вот только не эхо =( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
peroid 0 18 июня, 2015 Опубликовано 18 июня, 2015 · Жалоба Игрался с HC-SR04 - та же штука - вид сбоку. Опрос в майне конечно не кошерно. Делал опрос эхо-пина в прерывании таймера, настроенный на 58мкс или его множителях. 58мкс==1см до объекта, точности хватает, получается обычный счетчик в сантиметрах. Блин! Вот я Алень =) Сейчас перечитал пост тов. alexeyv и на меня снизошла благодать и полная алилуя! Можно ж не только формировать импульс, но и посчитать его тупо по прерываниям :maniac: Пока вход == 1 инкрементировать значение счетчика таймера каждый раз в прерывании по переполнению, а как только он упадет (сигнал) в ноль, то передать это значение в обработку!!! Но неужели нельзя прикрутить сюда таймер? по-любому можно =) Думал по переднему фронту принудительно обнулять таймер и начинать захват, но не могу понять как отловить задний фронт... подумывал уже запаралелить ногу на другой вход, по заднему фронту генерить прерывание и тянуть значение таймера в обработку, но жаба душит безумно! Отдать ногу на такую хрень - это очень плохо. Таймер 2 у меня занят, так что оба фронта не получится тут отслеживать.. только передний или задний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 19 июня, 2015 Опубликовано 19 июня, 2015 · Жалоба Пока вход == 1 инкрементировать значение счетчика таймера каждый раз в прерывании по переполнению, а как только он упадет (сигнал) в ноль, то передать это значение в обработку!!! :08: Добавьте конечный автомат: переход 0->1 - начало отсчета; удержание 1 - инкремент расстояния; переход 1->0 - конец счета. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ArtDenis 0 19 июня, 2015 Опубликовано 19 июня, 2015 · Жалоба Думал по переднему фронту принудительно обнулять таймер и начинать захват, но не могу понять как отловить задний фронт... подумывал уже запаралелить ногу на другой вход, по заднему фронту генерить прерывание и тянуть значение таймера в обработку, но жаба душит безумно! Отдать ногу на такую хрень - это очень плохо Ничего надо параллелить. Всё предусмотрено внутри таймера. Смотри в даташите главу "PWM input mode". Там прямо по шагам расписано как сделать, чтобы таймер автоматом обнулялся на фронте и автоматом считывал длительность на спаде импульса. Что-то мне подсказывает, что на эту тему есть и примеры HAL или STL Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться