С кодом "while ((P1IN & BIT3) == 0) ;" в обработке прерывания нажатия кнопки, работает прекрасно.
Но дальше я захотел пойти дальше и проверить свою теорию, а именно организовать временную задержку, используя второй таймер (это чисто из интереса). Проблема - при отладке работает, а в реальности зависает при первом же нажатии на кнопке.
Сделал простейший проект, где по второму таймеру меняется состояние светодиодов - работает прекрасно. Прочитал мануал про таймеры А и В - не нашёл никакого предложения, говорящего о нюансах их совместной работе. Яндекс помучал - не нашёл. Плохо ищу.
"!" - логическое отрицание (его следует отличать от побитового - "~"). Если его аргумент не ноль, он превратит его в ноль. Если ноль - превратит в не ноль. А все условия в С проверяются на не_ноль/ноль.
Цитата:
В чём проблема, не подскажете?
Видимо, в архитектуре взаимодействия двух прерываний.
_________________ Разница между теорией и практикой на практике гораздо больше, чем в теории.
Видимо, в архитектуре взаимодействия двух прерываний.
вот полный код, проверено многократно - при отладке работает, при реальном полёте зависает при первом же нажатии на кнопку. Может, подскажете на какую-то некорректность. Спойлер#include "io430g2553.h"
unsigned int maxPause=0x1F;//FFF; unsigned int maxDelitel = 16; unsigned int i_time = 0, i_delitel = 1;
void timer_run();
int main( void ) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD;
//готовим порт с диодам P1DIR = (BIT0 + BIT6); //инициализируем выходы 0 и 6 P1OUT = BIT6; //ставим выход 6 в 1
//готовим таймер CCTL0 = CCIE; //разрешаем прерывание по переполнению счётчика-таймера A /* Timer0_A3 Capture/Compare Control 0 */ //используются три системных тактовых сигнала: ACLK, MCLK и SMCLK и INCLK (INCLK is device-specific) TACTL = (TASSEL_2 + MC_2 + ID_0); //ставим источник тактов на SMCLK, и режим таймера - continuous, и делитль =1 (1 2 4 __enable_interrupt(); //глобально разрешаем прерывания в status register
//готовим кнопку P1REN |= BIT3; //разрешаем подтяжку P1OUT |= BIT3; //подтяжка вывода P1.3 вверх, иначе будет всегда срабатывать if ((P1IN & BIT3) == 0)
P1IFG &= ~BIT3; // Очистка флага прерываний для P1.3 // P1IES |= BIT3; // Прерывание происходит по 1/0 (отпусканию/нажатию) P1IE |= BIT3; //разрешаем прерывание для P1.3
//прерывание по кнопке используем для игр с паузой #pragma vector = PORT1_VECTOR //приоритет 0xFFE4 __interrupt void PORT1_VECTOR_PRE (void) { //это вариант от YS //while (!(P1IN & BIT3));
P1IE &= ~BIT3; // Запрет прерываний на P1.3 if (i_delitel<=maxDelitel) i_delitel *= 2; else i_delitel = 1; P1IFG &= ~BIT3; // Очистка флага прерываний для P1.3, т.к. это прерывание имеет несколько флагов
//испоьзуем таймер B для борьбы с дребезгом TA1CCTL0 = CCIE; //разрешаем прерывание по переполнению счётчика-таймера B/* Timer1_A3 Capture/Compare Control 0 */ TA1CTL = (TASSEL_2 + MC_2 + ID_2); //ставим источник тактов на SMCLK, и режим таймера - continuous, и делитль =1 (1 2 4
//комментируем для работы с таймером В //P1IE |= BIT3; // Разрешение прерываний на P1.3 }
YS [добрался до MSP430] да, я неправильно вставил комментарии.
Теперь работают два таймера, только одно НО: до одной точки прерывания [часто] выполнение программы доходит 2 раза, скриншот прилагаю. У меня только одно соображение - таймер останавливается не сразу? Если я неправ, то каким образом выполнение программы доходит до точки прерывания (на скриншоте отмечен) 2 раза?
Возня вознёй с отладкой проблемы (суть: 2 раза запускается процедура прерывания таймера В и 2 раза - [почти полностью ] процедура прерывания нажатия кнопки), привела к: - источник проблемы исходит из процедуры обработки прерывания нажатия кнопки; - в этой процедуре прерывания нажатия кнопки интересно: точка остановки срабатывает 2 раза, только если поставил эту самую точку останова на:
Код:
TA1CCTL0 = CCIE;
или следующих строчках. Спойлер//используем таймер B для борьбы с дребезгом TA1CCTL0 = CCIE; //Разрешение прерывания захвата/сравнения счётчика-таймера B/* Timer1_A3 Capture/Compare Control 0 */ TA1CTL = (TASSEL_2 + MC_2 + ID_2); //ставим источник тактов на SMCLK, и режим таймера - continuous, и делитель =4 (1 2 4 Отсюда напрашивается вывод: прерывание таймера В вызывается, когда разрешаешь прерывание этого самого таймера. Я не прав?
Карма: 6
Рейтинг сообщений: 33
Зарегистрирован: Ср мар 02, 2011 07:47:39 Сообщений: 841 Откуда: Уфа
Рейтинг сообщения:0
YS писал(а):
Отсюда напрашивается вывод: прерывание таймера В вызывается, когда разрешаешь прерывание этого самого таймера. Я не прав?
Не должно. У вас нет таймера В...у вас два таймера А. В эррате на ваш кристалл ТА16 говорится, что после TACLR вызывается дополнительное прерывание. Попробуйте остановить таймер MC=0, не трогая TACLR.
Всю тему не читал, наверняка уже был такой вопрос: Можно ли этот лаунчпад использовать тупо как переходник USB - UART? И если да то куда подключаться для приема данных с него?
Да, можно. Нужно только правильно выставить 2 джампера на плате. Именно, этими джамперами можно подключть преобразователь к МК нз плате, или наоборот отключить от него. В последнем случае преобразователь можно будет использовать и с внешними устройствами вне платы. Какие именно джамперы написано в инструкции пользователя для платы.
//используем таймер B для борьбы с дребезгом TA1CCTL0 = CCIE; //Разрешение прерывания захвата/сравнения счётчика-таймера B/* Timer1_A3 Capture/Compare Control 0 */ TA1CTL = (TASSEL_2 + MC_2 + ID_2); //ставим источник тактов на SMCLK, и режим таймера - continuous, и делитль =4 (1 2 4 8)
я записал нехитрый код (с объявлением временной "экспериментальной" глобальной bool переменной b):
Код:
//используем таймер B для борьбы с дребезгом b = true; TA1CCTL0 = CCIE; //Разрешение прерывания захвата/сравнения счётчика-таймера B/* Timer1_A3 Capture/Compare Control 0 */ TA1CTL = (TASSEL_2 + MC_2 + ID_2); //ставим источник тактов на SMCLK, и режим таймера - continuous, и делитль =4 (1 2 4 8) b = false;
, обработчик таймера B (или "второй таймер А", как подсказывает Psych) выглядит таким образом:
Код:
#pragma vector = TIMER1_A0_VECTOR __interrupt void TIMER1_A0_PRE (void) { if (!(P1IN & BIT3)) return; if (b==true) return; // вот с этим стало нормально работать :)
P1IE |= BIT3; // Разрешение прерываний на P1.3 TA1CTL = 0; //останов таймера B }
Это всё работает нормально, что как-бэ подтвержало тогда мою догадку. И я тогда, с мыслью о сделанной работе, успокоился .
Теперь вот, [вернувшись в эту ветку,] попробую предворить в жизнь слова пользователя Psych: "В эррате на ваш кристалл ТА16 говорится, что после TACLR вызывается дополнительное прерывание. Попробуйте остановить таймер MC=0, не трогая TACLR".
P.S. Отладчик использую IAR EW for MSP430 IDE 5.51.6, скачанный с официального сайта. Тип лицензии - бесплатный, с ограничением ИК 4кб.
Вот рабочий пример обработки кнопок и борьбы с дребезгом. Различаются короткое и длинное нажатие кнопок. В качестве таймера задержки на нажатие/отпускание используется сторожевой таймер WDT. Легко делается на любое количество кнопок. Идея взята отсюда: http://bennthomsen.wordpress.com/ti-msp430-launchpad/using-the-switches/ Спойлер
Код:
//****************************************************************************** // Обработка кнопок с определением короткого и длинного нажатия. // Антидребезг реализован с помощью задержки на нажатие/отпускание кнопки. // Определение состояния кнопок происходит по прерываниям на портах i/o. // Длительность нажатия определяется по счетчику в интервальном таймере // (в данном примере каждые 4ms). Задержка выполнена на строжевом таймере (WDT) // переводимом на это время в режим интервального таймера. // Выполнение действий назначенных на кнопки осущесвляется в основном цикле // программы. //******************************************************************************
#include "msp430g2553.h" #include <stdint.h> // Standard integer types
while(1) { if (ButtonPress) { // Если была нажата кнопка switch (ButtonPress & (S1 + S2)) { case S1: // Нажата S1 if (LongPress) { // Если длинное нажатие LongPress = 0; // Сбрасываем флаг длительного нажатия P1OUT ^= LED_2; // Переключаем состояние выхода на противоположное } else { // Если короткое нажатие P1OUT ^= LED_1; // Переключаем состояние выхода на противоположное } break; case S2: // Нажата S2 if (LongPress) { LongPress = 0; // Сбрасываем флаг длительного нажатия // тут что-то делаем если длинное нажатие } else { // тут что-то делаем если короткое нажатие } break; } ButtonPress = 0; // Сбрасываем флаг нажатия кнопки } } }
То же, но без использования дополнительного таймера задержки: Спойлер
Код:
//****************************************************************************** // Обработка кнопок с определением короткого и длинного нажатия. // Антидребезг реализован с помощью задержки на нажатие/отпускание кнопки. // Определение состояния кнопок происходит по прерываниям на портах i/o. // Длительность времени задержки и нажатия определяются по счетчикам // в интервальном таймере (в данном примере каждые 4ms). // Выполнение действий назначенных на кнопки осущесвляется в основном цикле // программы. //******************************************************************************
#include "msp430g2553.h" #include <stdint.h> // Standard integer types
while(1) { if (ButtonPress) { // Если была нажата кнопка switch (ButtonPress & (S1 + S2)) { case S1: // Нажата S1 if (LongPress) { // Если длинное нажатие LongPress = 0; // Сбрасываем флаг длительного нажатия P1OUT ^= LED_2; // Переключаем состояние выхода на противоположное } else { // Если короткое нажатие P1OUT ^= LED_1; // Переключаем состояние выхода на противоположное } break; case S2: // Нажата S2 if (LongPress) { LongPress = 0; // Сбрасываем флаг длительного нажатия // тут что-то делаем если длинное нажатие } else { // тут что-то делаем если короткое нажатие } break; } ButtonPress = 0; // Сбрасываем флаг нажатия кнопки } } }
Без испльзования прерываний от кнопок, дополнительного таймера задержки и антидребезгом на сдвиговом регистре: Спойлер
Код:
//****************************************************************************** // Обработка кнопок с определением короткого и длинного нажатия. // Антидребезг реализован с помощью сдвигового регистра путем сравнения // нескольких последовательных состояний. Определение состояния кнопок // происходит по прерыванию интервального таймера (в данном примере каждые 4ms). // Выполнение действий назначенных на кнопки осущесвляется в основном цикле // программы. //******************************************************************************
#include "msp430g2553.h" #include <stdint.h> // Standard integer types
// Константы для сравнения состояния сдвигового регистра #define PRESS_THRESHOLD 0x3F // Пороговое значение регистра при нажатии кнопки #define RELEASE_THRESHOLD 0xFC // Пороговое значение регистра при отпускании кнопки
#define LONG_PRESS_TIME 700 // Время определяемое как длительное нажатие кнопки (700*4ms = ~ 3s)
ShiftReg >>= 1; // Сдвигаем содержимое регистра на 1 вправо
if (!(P1IN & S1)) BtnMask = S1; // Опрос входов кнопок if (!(P1IN & S2)) BtnMask = S2;
if (!BtnMask) { // Если ни одна кнопка не нажата (или пропал контакт во время дребезга) ShiftReg |= BIT7; // Устанавливаем в 1 старший разряд сдвигового регистра }
if (BtnState == 1) { // Проверяем статус кнопки - если нажата if (!(PressCount >= LONG_PRESS_TIME)){ // Если счетчик уже досчитал, то ничего не деламе, иначе... if (++PressCount >= LONG_PRESS_TIME) { // Увеличиваем счетчик и если досчитал LongPress = 1; // Устанавливаем флаг длинного нажатия ButtonPress = Pressed; // И бит нажатой кнопки } } // Проверяем не отжата ли кнопка if (ShiftReg >= RELEASE_THRESHOLD) { // Если кнопка отжата BtnState = 0; // Устанавливаем статус кнопки в отжата (0) } } else { // Если статус кнопки - отжата if (Pressed) { // Но было зафиксировано нажатие if (PressCount < LONG_PRESS_TIME) { // И если время нажатия меньше чем заданное как длительное LongPress = 0; // Сбрасываем флаг длинного нажатия ButtonPress = Pressed; // Сохраняем бит нажатой кнопки } PressCount = 0; // Обнуляем счетчик длинного нажатия Pressed = 0; // Обнуляем флаг нажатой кнопки } // Проверяем не нажата ли кнопка if (ShiftReg <= PRESS_THRESHOLD) { // Если кнопка нажата BtnState = 1; // Устанавливаем статус кнопки в нажата (1) Pressed = BtnMask; // Сохраняем бит нажатой кнопки } } }
while(1) { if (ButtonPress) { // Если была нажата кнопка switch (ButtonPress & (S1 + S2)) { case S1: // Нажата S1 if (LongPress) { // Если длинное нажатие P1OUT ^= LED_2; // Переключаем состояние выхода на противоположное } else { // Если короткое нажатие P1OUT ^= LED_1; // Переключаем состояние выхода на противоположное } break; case S2: // Нажата S2 if (LongPress) {
Хорошая подборка идей! От себя добавлю, что основной цикл в приведенных реализациях молотит все время и сводит на нет все преимущества обработки нажатий и обработки дребезга через прерывания. Лучше отправлять МК в сон. Кроме того, определенным недостатком программ является частая обработка прерываний от таймера - каждые 4 мс даже если кнопки не нажаты.
Улучшить ситуацию можно несколько модифицировав алгоритм. Именно, разрешать прерывания по совпадению в самом начале обработки дребезга (получения первого прерывания от кнопки) и запрещать их по окончании обработки (в момент когда опять разрешаются прерывания от кнопки). Моменты совпадения нужно будет каждый раз пересчитывать в прерывании по совпадению (добалять одну и ту-же константу к счетчику), что не проблема. Так сделано, например, в моей конструкции http://radiokot.ru/circuit/digital/measure/71/ В этой реализации, правда, каждый канал совпадения таймера обслуживает только одну кнопку. Но это не сильное ограничение, поскольку в современных моделях семейства MSP430 имеется несколько таймеров и у каждого 3-7 каналов сравнения.
Согласен. Если нужен экономичный режим, то вы предлагаете хороший вариант. Передо мной такая задача не стояла. Эти примеры просто заточены под мой проект лабораторного БП, поэтому и 16МГц и 4мс (там не только кнопки), это я думаю каждый настроит под себя. Перепробовав много способов борьбы с дребезгом, я остановился на самом первом варианте (с задержкой на таймере WDT), из тех примеров, что я привел на мой взгляд он менее всего загружает контроллер. Вот еще один рабочий код обработки кнопок с защитой от дребезга (это мне на easyelectronics.ru ShadS предложил): Спойлер
Код:
//****************************************************************************** // // Пример работы с кнопками // // Определение короткого и длинного нажатия. Антидребезг реализован с помощью // задержек на нажатие/отпускание кнопок. // Организовать вызов из прерывания с частотой 100Гц - функцию BtnExe(); // Чтение значения состояния флагов кнопок производится с помощью // глобальной переменной BtnFlags например так (в главном цикле): // if (BtnFlags) { // if (BtnMask & BTN_SHRT_S1) {....ветка короткого нажатия кнопки S1} // if (BtnMask & BTN_SHRT_S2) {....ветка короткого нажатия кнопки S1} // if (BtnMask & BTN_LONG_S1) {....ветка длинного нажатия кнопки S1} // и т.д. // BtnFlags = 0 //Обнулить байт флагов нажатия кнопок // } // //******************************************************************************
#include "msp430g2553.h" #include <stdint.h> // Standard integer types
//настройка параметров работы функций #define BTN_LOCK_TIME 30 //время обработки дребезга в милисекундах (10-100) #define BTN_LONG_TIME 1000 //время фиксации длинного нажатия в милисекундах (1000 - 2500)
Опять-таки, прерывание происходит каждые 10 мс независимо от того нажата кнопка или нет. Если это прерывание еще для чего-то нужно (как у Вас в проекте) то сойдет. В противном случае процессор будет слишком часто и понапрасну отвлекаться на обработку прерывания.
Я всегда делаю обработку нажатий кнопок на основе прерываний порта, регистра сдвига, и отключаемых прерываний каналов сравнения таймера. Сейчас заканчиваю проект с участием кнопок, где вышеупомянутый алгоритм адаптирован с FR57xx для MSP430G2332. Выложу его сюда на форум с исходником скорее всего после конкурса. Кстати, Bujhm666, может напишите сюда статью про Ваш блок питания или дадите ссылку если она уже опубликована?
Сейчас заканчиваю проект с участием кнопок, где вышеупомянутый алгоритм адаптирован с FR57xx для MSP430G2332
Ну можно было бы только код обработки кнопок выложить. Желательно на Си, если можно конечно. Насчет моего блока питания, статью не напишу (не силен я в этом), а код и схему покажу, как доведу до ума (он хоть уже в корпусе и работает, но пока в стадии доводки). В схемотехнике там ничего нового, просто вместо обычных здесь пиков или меги управление от MSP430. Вот фотографии я выкладывал на схем.нет http://forum.cxem.net/index.php?showtopic=41521&st=1560#entry1622650
просто вместо обычных здесь пиков или меги управление от MSP430
Вот это и похвально. Не понимаю, чего остальные ждут. Вообще, конструкция выглядит добротной. Насчет моего кода, он на АСМе. Вместо того, чтобы вырезать куски кода, вот ссылка на весь код: http://mcs.uwsuper.edu/sb/Electronics/BigLCD/clock.s43
Приложения, нуждающиеся в генерации периодических колебаний, могут получить преимущества от использования контроллера DMA с ЦАП12. К примеру, приложение, вырабатывающее синусоидальное колебание может сохранит значения синуса в таблице. Контроллер DMA может непрерывно автоматически переносить эти значения в ЦАП12 через заданные интервалы, создавая синусоиду без участия ЦПУ
Не подскажете, где бы поглядеть рабочий пример по работе ЦАП и DMA?
Сейчас этот форум просматривают: Google [Bot] и гости: 6
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения