Цикл while, в данном конкретном случае, не нужен, если только МК не будет делать еще что-то. Следовало-бы проиниацилизировать переменные pauseCnt и pulseCnt их соответствующими значениями из дефайном в начале кода в функции настройки таймера.
Не понял зачем его вообще включать для данного приложения? В коде прерывание происходит каждый раз по достижении счетчиком таймера его максимального значения. Вопрос первоначально был как обойтись одним таймером. Чего хотите добиться сейчас, задействовав второй таймер?
Вообще задача в том, чтобы отправлять с таймера А пачку импульсов и принимать пришедший сигнал на таймер В.
Решила постепенно разбираться. Сейчас мне не понятно, почему в прерывании не выполняются условия. Также есть вопрос, как добавить в данный код работу таймера В.
Есть еще вопрос почему код по захвату у меня не заходит в прерывание: void main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
почему код по захвату у меня не заходит в прерывание
Потому что таймер стоит и не считает. Запишите значение МС_1 в TBCTL. Кроме того, TBCL0=0 дефолтно и для запуска таймера там должно быть ненулевое значение. Ну и ещё этот таймер, согласно конфигурации тактируется от ACLK. Чему равна эта частота (из кода определить это невозможно)?
Остальные вопросы я не понял. Что значит "принимать пришедший сигнал на таймер В"? И какие условия должны выполняться в прерывании (сейчас там никаких условий не проверяется)?
Напишите нормально что надо сделать, я не телепат. Если это студенческая методичка, лучше выложите её сюда полностью. Кроме того, какие имеете средства отладки (FET debugger? Лог. анализатор? Среда разработки?). Если у Вас демо-плата с MSP430, что за плата.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Задача в том, чтобы отправлять пачку импульсов с таймера А на ультразвуковой датчик, излучать, а затем принимать усиленный отраженный сигнал на вход таймера В.
Прерывания таймера В должны происходить тогда, когда на вход его поступает отраженный сигнал. Нужно выводить время с начала запуска таймера В и захвата сигнала. Также останавливать таймер и запускать заново после расчета времени.
Вообще я тактирую от SMCLK (TBSELL_2) ибо когда пыталась от ACLK таймер В не считал.
Среда разработки - code composer studio. Демо платы нет, есть схема с микроконтроллером msp430f149. Средство отладки - FET debugger.
В прошлый раз я был не прав с советами. Теперь задачу понял. Вот рабочий код использования Таймера для захвата. Он измеряет длительность нажатия кнопки, подсоединённой между P1.1 и землёй. Для этого в P1.1 задействован внутренний подтягивающий резистор. Только что протестил его на макетке при тактировании таймера от ACLK. Код работает с Таймером А, т.к. в моём МК G2553 нет Таймера B, однако работа с последним полностью аналогична. В принципе, код работы с таймером у Вас был правильный. Следует только сбрасывать флаг прерывания в ISR. Спойлер
Код:
#include "io430.h"
void Clock_config(); // function prototypes void Ports_config(); void TimerA_config(); unsigned int lastCapture; unsigned int duration; // button press duration
int main() { WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer Clock_config(); // set 8 MHz MSCK, 2 MHz SMCLK Ports_config(); // set up ports for GPIO TimerA_config(); // configure TimerA module capture __enable_interrupt(); // enable interrupts globally
while(1) { __low_power_mode_0(); // wait for capture __no_operation(); __no_operation(); // set breakpoint here to examine duration } }
В данном примере #pragma vector=TIMER0_A0_VECTOR // TimerA handler __interrupt void TimerA_ISR(void) { if (P1IN & P1) // button is released { duration = TACCR0 - lastCapture; __low_power_mode_off_on_exit(); } lastCapture = TACCR0; TA0CCTL0_bit.CCIFG = 0; // clear TimerA capture } есть условие if (P1IN & P1) , а если не использовать кнопку, то условие должно быть: что если CAP ==1? или просто if(CCIFG)?
Не нужно там никакого условия. Вход в обработчик прерывания произойдёт как только совершится захват. Кстати, я вспомнил, что у меня есть MSP430FR5730 с Таймером B и адаптировал код для IAR под него. Спойлер
Код:
#include "io430.h"
void Clock_config(); // function prototypes void Ports_config(); void TimerB_config(); unsigned int lastCapture; unsigned int duration; // button press duration
int main() { WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer REFCTL0_L |= REFTCOFF; // disable temp sensor Ports_config(); // set up ports for GPIO Clock_config(); // set 8 MHz MSCK, 1 MHz SMCLK TimerB_config(); // configure TimerB module capture __enable_interrupt(); // enable interrupts globally
while(1) { __low_power_mode_0(); // wait for capture __no_operation(); __no_operation(); // set breakpoint here to examine duration } }
void Clock_config() // configure clock system { CSCTL0_H = CSKEY_H; // unlock the clock interface CSCTL4_L = XT1DRIVE1; // crystal drive level while (SFRIFG1_L & OFIFG) // wait for 32KHz oscillator to start { CSCTL5_L &= ~XT1OFFG; // clear XT1 fault flag SFRIFG1_L &= ~OFIFG; // clear oscillator fault flag } CSCTL3 = DIVS_3; // set 8 MHz MCLK, SMCLK }
TB0CTL = 0; // stop capture duration = TB0CCR0 - lastCapture; lastCapture = TB0CCR0; TB0CCTL0_bit.CCIFG = 0; // clear TimerB capture flag __low_power_mode_off_on_exit(); // wake up CPU on exit }
В схеме помимо МК есть кнопка между выводом P2.1 и землёй. Таймер Б изначально остановлен и программа ожидает прерывания по спаду уровня на P2.1, которое происходит по нажатии на кнопку. Как произойдёт нажатие, пин P2.1 переконфигурируется на работу с модулем захвата канала 0 Таймера Б и сам таймер запускается в режим захвата по нарастающему уровню сигнала на P2.1, который образуется по отпускании кнопки. Как только захват произойдёт, таймер останавливается, кнопка переконфигугируется на GPIO и весь процесс повторяется. В этом примере Таймер Б тактируется от кварцевого генератора XT1 на порте J, стабилизированным часовым кристаллом. Код проверен в железе и работоспособность его гарантируется.
__low_power_mode_off_on_exit(); // wake up CPU on exit } int main() { WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer Ports_config(); // set up ports for GPIO TimerA_config(); // configure TimerA module for 40 KHz TimerB_config(); __enable_interrupt(); // enable interrupts globally __low_power_mode_0(); // wait for char receive }
Нужно раскомментить строку где сбрасывается флаг прерывания ТаймераА в его обработчике, если синтакс позволяет. Как написано сделано неправильно. Попробуйте так: TACTL &= ~TAIFG;
Я не пишу под CCS и не знаю его синтаксиса. Нужно добиться сброса флага прерывания в отладчике. При пошаговой отладке в пока находитесь в прерывании после сброса флага может сгенерироваться новое и тогда отладка зациклится. Лучше отладчиком пошагово в прерывание не заходить. Вообще, зачем пошагово отлаживаете? Убирайте здесь длинные листинги под спойлер и пользуйтесь тагом "код". Там хоть какое-то форматирование текста есть.
Добавлено позже: Для гарантированного сброса флага таймера А, независимо от того как в CCS определена константа TAIFG, напишите: TACTL &= 0xFFFE; Причина невыхода из прерывания Таймера А ещё и в том, что при выходе из прерывания состояние процессора восстанавливается таким, которым оно было до входа. А поскольку в main() процессор помещается в сон, то и пробуждаться по выходу из обработчика он не будет.
Посмотрев Ваш код подробнее не обнаружил там сброса флага Таймера Б - тогда код и там циклится будет, принимая во внимание, что приоритет таймера Б выше, чем А. В моём коде выше для этого была строчка: TB0CCTL0_bit.CCIFG = 0; Кроме того, если в конце обработчика таймера Б стоит __low_power_mode_off_on_exit(); то куда будет выход по пробуждении, если в main() нет цикла?
Я модифицировал свой код, следуя Вашему. У меня он выходит в main() там где указано установить breakpoint. Для этого я подсоединил выход PWM (у меня Р1.0) к входу захвата Таймера Б (Р2.1). Только смысла я в нём не вижу. Захват будет& происходить по первому фронту импульса PWM и переменная duration будет всегда принимать разные значения, что и подтверждается на практике. Спойлер
Код:
#include "io430.h" #define PULSE_CNT 5 // # of pulses in a burst #define PAUSE_CNT 10 // pause duration
void Clock_config(); // function prototypes void Ports_config(); void TimerA_config(); void TimerB_config(); unsigned int lastCapture; unsigned int duration; // button press duration char timerMode; // 0: burst, 1:pause char pulseCnt, pauseCnt;
int main() { WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer REFCTL0_L |= REFTCOFF; // disable temp sensor Ports_config(); // set up ports for GPIO Clock_config(); // set 8 MHz MSCK, 1 MHz SMCLK TimerA_config(); // configure TimerA module for PWM TimerB_config(); // configure TimerB module capture
while(1) { __low_power_mode_0(); // wait for capture __no_operation(); __no_operation(); // set breakpoint here to examine duration } }
void Clock_config() // configure clock system { CSCTL0_H = CSKEY_H; // unlock the clock interface CSCTL4_L = XT1DRIVE1; // crystal drive level while (SFRIFG1_L & OFIFG) // wait for 32KHz oscillator to start { CSCTL5_L &= ~XT1OFFG; // clear XT1 fault flag SFRIFG1_L &= ~OFIFG; // clear oscillator fault flag } CSCTL3 = DIVS_3; // set 8 MHz MCLK/1MHz SMCLK }
Сегодня я смогла добраться до осциллографа и посмотреть что происходит. Пачки излучаются, но нужна все-таки больше пауза. Я пыталась поменять в #define PAUSE_CNT 10 // pause duration значение на 2000, но мах задержка 7.5 мсек. Как можно увеличить до секунды?
Насчет таймера В, в ccs нельзя написать TB0CCTL0_bit.CCIFG = 0; поэтому пишу TBCCTL0 &= ~CCIFG;. Пока разбираюсь что в схеме не так и почему не происходит захвата и зажигания светодиода в этом случае.
Насколько я понимаю, на вход Таймера А поступает частота 720 кгц, так что если он досчитает до 18, то это будет соответствовать периоду ультразвука 40 кгц. Этот таймер 16-битный, и максимальное значение туда можно отправить PAUSE_CNT=65535, что будет соответствовать задержке в 65535/720 = 91 миллисек. Если нужна большая задержка, то можно задействовать 32-битный счётчик прерываний в программе обработчика Таймера А или прескейлер 1:8 на входе таймера. Однако, он у Вас может быть уже задействован для получения частоты в 720 кгц на счетном входе. Поэтому я и спрашивал выше как Вы получили частоту 720 кгц на этом входе. Напишите в деталях систему и настройки тактирования МК и таймера.
А нужна-ли Вам такая большая задержка в 1 сек? Я полагаю целью проекта является построение ультразвукового локатора. Если принять скорость звука в воздухе 333 м/с (если правильно со школы помню), то максимальная дальность Вашего устройства с секундной паузой будет около 150м. Однако, мне не представляется реальным получить радиус действия более где-то 10м. Или причина в секундной задержке - экономия токопотребления? Проясните этот момент. Может заодно схемкой устройства поделитесь, можно через ЛС.
Скорее всего это частота осциллятора DCO, так как я в коде не подключаю внешний кварц. Да, вы правы, это схема локатора, который должен измерять расстояние до 3-х метров. 3 метра это около 0,018 сек. Сейчас я могу добиться только измерения расстояния до 0.5 метров. Так как используется диффузионный режим работы ультразвукового датчика, то лучше иметь большую паузу таймера а, для того, чтобы пластины в датчике могли успокоиться и без проблем переключиться на нужный режим.
Хорошо, пусть будет 1 сек. А с чем связано ограничение в 0.5м сейчас? Я не увидел новых вопросов в последнем сообщении. Полагаю, проблемы с программированием таймеров решены (?)
Кстати, что в проекте фиксировано кроме устройства дальномера? Я имею в виду МК и датчик. Этот уж слишком древний. А насчёт датчика - если устроит дальность до 2м с погрешностью около 3%, посмотрите на датчики другого типа VL6180X.
0,5 метров не связано ни с чем. Просто максимальное время паузы можно сделать - 7 мсек, а это как раз 0,5 м. Пыталась с помощью delay(); попробовать сделать задержку, но не выходит сделать больше паузу чем 7 мсек. Вопрос мой тот же, как реализовать паузу в 1 сек? Что такое прескейлер, а также что такое 32-битный счётчик прерывания и есть ли у вас пример его использования?
Я всё-таки не понял какие проблемы с получением задержки в 1 сек между пачками. Вы писали что использовали PAUSE_CNT = 2000. Почему не 40000? Период обнуления таймера для генерации частоты ШИМ 40 кгц - 1/40 мсек. Т.е. для получения 1 сек нужно сосчитать 40000 прерываний в обработчике. Попробуйте это сначала, только объявите переменную pauseCnt как unsigned int. У меня всё работает. Это брутальное решение, т.к. процессор будет часто пробуждаться лишь для увеличения счётчика, но зато быстро реализуемое.
Правильнее было-бы уменьшить частоту на входе счётчика таймера, задействовав его прескайлер, т.е. делитель входной частоты в максимальным делением 1:8 на время паузы. Тогда можно будет считать лишь до 5000. А если ещё увеличить период обнуления до 50000 в режиме подсчёта паузы, то можно будет считать до 11. А применив прескайлер 1:8 и установив период таймера 45000, можно будет считать лишь до 2. Короче, вариантов масса. Прочитать про прескайлер (input divider) можно в ДШ. Он управляется битами IDx в регистре TACTL.
Кстати о птичках: когда Вы писали про 2000, я полагаю, что не изменили тип переменной pauseCnt с char на unsigned int. При этом в переменную типа char нельзя будет записать что-то более 255, и если записываете туда 2000 (0х790 hex), то компилятор обрубит её до младшего байта (0х90). При этом максимальная зaдержка пачек действительно будет 256/40 = 6.4мсек.
Я поменяла тип и получилось сделать паузу в 250 мсек.
Но скорее всего не работает режим захвата. Пытаюсь проверить что происходит заход в прерывание таймера Б - пытаюсь зажечь диод. Но безуспешно: #include "msp430f149.h"
#define PULSE_CNT 4 // # of pulses in a burst #define PAUSE_CNT 10000 // pause duration
void Ports_config(); void TimerA_config(); char timerMode; // 0: burst, 1:pause unsigned int pulseCnt, pauseCnt; unsigned int lastCapture; unsigned int duration;
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 32
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения