Перейти к содержанию
    

Кнопки, таймеры, АЦП, взрыв мозга

Здравствуйте!

Есть у меня задачка, которую никак не могу решить. У меня есть 6 кнопок (картинка прилагается), подключены они по две штуки к одному пину. Необходимо сделать так, чтобы при нажатии на каждую кнопку, происходило какое-то своё действие: светодиод мигал с разной чистотой, или динамик гудел различными тонами. И, вот, если одну пару кнопок я уже научился контролировать, то другие никак не могу. Подробности в комментариях к коду.

Сам я программировать и разбираться с МК начал меньше месяца назад. Прошу не судить строго за любые возможные глупые ляпы. Буду благодарен вам за любую помощь! Мозг уже разрывается на части :wacko:

Прогаю в IAR EW на MSP430f2112.

 

#include "msp430f2112.h"

#define RED_LEDS   (BIT0) //красненький светодиодик
#define GREEN_LED  (BIT2) //зелёненький

#define SPKR       (BIT3) // Динамик (здесь я смотрю результат через осциллограф)

#define BUTTON1    (BIT0) // Две кнопки (SB1 и SB2), подсоединённые к P2.0
#define BUTTON2    (BIT3) // Две кнопки (SB3 и SB4), подсоединённые к P2.3
#define BUTTON3    (BIT4) // Две кнопки (SB5 и SB6), подсоединённые к P2.4

volatile char flash  = 0;
volatile char flash2 = 0;

  void TA_init(void);
  void ADC_init(void);

//***********************Главная функция*************************

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD; // Останавливаем сторожевой таймер

  BCSCTL3 = LFXT1S1; // Источником сигнала ACLK будет низкочастотный встроенный генератор со сверхнизким
                     // энергопотреблением VLO. Частота ACLK = 12 кГц

  P1DIR |=  GREEN_LED; // Устанавливаем порт на выход
  P1OUT &= ~GREEN_LED; // Отключаем диод
  P1DIR |=  RED_LEDS;
  P1OUT &= ~RED_LEDS;
  P1DIR |=  SPKR;
  P1REN |=  SPKR;     // Устанавливаем резистор подтяжки, в нашем случае он уменьшает громкость динамика в ~4раза
  P1OUT &= ~SPKR;

  TA_init();
  ADC_init();

  __bis_SR_register(GIE); // Разрешаем прерывания

while(1)
   {
    /*ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_4;
    ADC10CTL0 |= ENC + ADC10SC;          // Если здесь снять комментарии, то мигать светодиод будет
    LPM3;                                // только при нажатии трёх! кнопок одновременно.
    ADC10CTL0 &= ~ENC;                   // Т.е., допустим, чтобы мигать по таймеру А0, нужно
    ADC10CTL1 = INCH_3;                  // нажать SB1, SB3 и SB5. По отдельности они вызывают
    ADC10CTL0 |= ENC + ADC10SC;          // какие-то отдельные колебания, которые только складываясь
    LPM3;*/                              // вместе, дают желаемый сигнал.
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_0;
    ADC10CTL0 |= ENC + ADC10SC;
    LPM3;
    }
}

//***********************Инициализируем АЦП*************************

void ADC_init(void)
{
  ADC10CTL0 = MSC + SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE;  // настраиваем и включаем АЦП, разрешаем прерывания
  ADC10CTL1 = ADC10SSEL_1 + CONSEQ_0; // Буду благодарен, если кто-нибудь объянит мне, что меняет,
                                      // и на практике делает CONSEQ, т.к. в моём случае, его изменение ни к чему не приводит.
                                      // и я не понимаю чего люди пытаются им добиться.
  ADC10AE0 |= BUTTON1 + BUTTON2 + BUTTON3; // Пины с кнопками как входы АЦП
}

//***********************Инициализируем Таймер*************************

void TA_init(void)
{
  //Создаём таймер для удобного моргания через прерывания
  TA0CCR0 = 56;
  TA0CCR1 = 28;
  TA0CCTL0 = CCIE;    // Разрешаем прерывание таймера по достижении CCR0
  TA0CCTL1 = OUTMOD_3 + CCIE;
  TA0CTL = TASSEL_1 + MC_1 + TAIE;  // ACLK, Прямой счёт
}

//***********************Инициализируем Прерывания*************************

#pragma vector = TIMER0_A0_VECTOR
__interrupt void T0_A0(void)
{
        P1OUT ^= flash;                 // если flash == 0, светодиод не горит
                                        // если flash == GREEN_LED, мигаем светодиодом
        LPM3_EXIT;

}

#pragma vector = TIMER0_A1_VECTOR
__interrupt void T0_A1(void)
{
   P1OUT ^= flash2;                    // если flash2 == 0, светодиод не горит
                                       // если flash2 == GREEN_LED, мигаем светодиодом

   TA0IV = 0x00;  //чистим регистр вектора
   LPM3_EXIT;
}

#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
      if (0x03FC < ADC10MEM && ADC10MEM < 0x0400)  // Если нажата SB1
      {
      P1OUT &= ~RED_LEDS;
      //flash  =  GREEN_LED; //мигает светодиод по таймеру A0
      flash = SPKR; // или гудит динамик
      flash2 = 0;
      }
      else if (0x025A < ADC10MEM && ADC10MEM < 0x03FA) // Если кнопки не нажаты
      {
       P1OUT &= ~GREEN_LED;
       P1OUT &= ~RED_LEDS;
       flash = 0;
       flash2 = 0;
      }
      else if (0x0246 < ADC10MEM && ADC10MEM < 0x025A) // Если обе кнопки нажаты
      {
       P1OUT &= ~GREEN_LED;
       P1OUT |=  RED_LEDS;
       flash = 0;
       flash2 = 0;
      }
      else if (0x017F < ADC10MEM && ADC10MEM < 0x0193) // Если нажата SB2
      {
       P1OUT &= ~RED_LEDS;
       //flash2 =  GREEN_LED; //мигает светодиод по таймеру A1
       flash2 = SPKR; //или гудит динамик
       flash = 0;
      }
      LPM3_EXIT;
  }

post-77769-1375433333_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Прошу прощения, в комментариях немного ошибся: Что делает CONSEQ я знаю, я OUTMOD имел ввиду.

 

Добавил ещё один таймер, и сделал небольшой опрос в прерывании АЦП. Теперь работают две пары кнопок. Но какую частоту выдаёт мне TAxCCR1? Явно не ту, которую я ожидаю. Если динамик и гудит различными тонами, то светодиод ведёт себя неадекватно. (Когда вывожу на диод, то TACCR задаю, естественно, выше)

 

//Создаём ещё один таймер для удобного моргания через прерывания
 //TA1R = 112;// смещение относительно первого - не знаю нужно или нет
 TA1CCR0 = 14;   // Задержка таймера для мигания
 TA1CCR1 = 7;
 TA1CCTL0 = CCIE;   // Разрешаем прерывание таймера по достижении CCR0
 TA1CCTL1 = OUTMOD_0 + CCIE;
 TA1CTL = TASSEL_1 + MC_1 + TAIE; // + TACLR; // ACLK, Прямой счёт, обнуление таймера
//*******************************
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
   if ((ADC10CTL1 & INCH_3) == INCH_3)
   {
     if (0x03FC < ADC10MEM && ADC10MEM < 0x0400)  // Если нажата SB1
     {                              
     P1OUT &= ~RED_LEDS;
     //flash3  =  GREEN_LED;
     flash3 = SPKR;
     flash4 = 0;
     } 
     else if (0x025A < ADC10MEM && ADC10MEM < 0x03FA) // Если кнопки не нажаты
     {
      P1OUT &= ~GREEN_LED;
      P1OUT &= ~RED_LEDS;
      flash3 = 0;
      flash4 = 0;
     }
     else if (0x0246 < ADC10MEM && ADC10MEM < 0x025A) // Если обе кнопки нажаты
     {
      P1OUT &= ~GREEN_LED;
      P1OUT |=  RED_LEDS;
      flash3 = 0;
      flash4 = 0;
     }
     else if (0x017F < ADC10MEM && ADC10MEM < 0x0193) // Если нажата SB2
     {
      P1OUT &= ~RED_LEDS;
      //flash3 =  GREEN_LED;
      flash4 = SPKR;
      flash3 = 0;
     }
 }
 else if ((ADC10CTL1 & INCH_0) == INCH_0)
 {
     if (0x03FC < ADC10MEM && ADC10MEM < 0x0400)  // Если нажата SB1
     {                              
     P1OUT &= ~RED_LEDS;
     //flash  =  GREEN_LED;
     flash = SPKR;
     flash2 = 0;
     } 
     else if (0x025A < ADC10MEM && ADC10MEM < 0x03FA) // Если кнопки не нажаты
     {
      P1OUT &= ~GREEN_LED;
      P1OUT &= ~RED_LEDS;
      flash = 0;
      flash2 = 0;
     }
     else if (0x0246 < ADC10MEM && ADC10MEM < 0x025A) // Если обе кнопки нажаты
     {
      P1OUT &= ~GREEN_LED;
      P1OUT |=  RED_LEDS;
      flash = 0;
      flash2 = 0;
     }
     else if (0x017F < ADC10MEM && ADC10MEM < 0x0193) // Если нажата SB2
     {
      P1OUT &= ~RED_LEDS;
      //flash2 =  GREEN_LED;
      flash2 = SPKR;
      flash = 0;
     }
 }
       LPM3_EXIT;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я может чего то не понимаю, но как микроконтроллер поймет, что нажата та или иная кнопка, каждая из которых подключена к одному и тому же пину?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я может чего то не понимаю, но как микроконтроллер поймет, что нажата та или иная кнопка, каждая из которых подключена к одному и тому же пину?

АЦП. При помощи него я измеряю напряжение на пине. На схеме, которую я прикрепил, видно, что напряжение будет меняться при различных вариантах нажатия. Кнопки две - варианта четыре. Это всё находится у меня в прерывании АЦП - взгляните.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще-то, на один вход АЦП можно повесить все ваши кнопки, используя резистивную матрицу

Запараллелив на вход компаратора, можно будет получать прерывание по нажатию/отпусканию (но не по смене комбинации)

 

dz35.gif

 

Статью гуглите сами.

 

Хотя, вот она.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще-то, на один вход АЦП можно повесить все ваши кнопки, используя резистивную матрицу

Запараллелив на вход компаратора, можно будет получать прерывание по нажатию/отпусканию (но не по смене комбинации)

 

dz35.gif

 

Статью гуглите сами.

 

Хотя, вот она.

 

Это здорово, что можно повесить все, но у меня всё именно так, как на схеме, которую я приложил в самом начале. И это не исправить. Простите, из вашего ответа не пойму: АЦП или компаратор? Я понимаю, что компаратор тоже АЦП, но в моём случае это 10-битное АЦП, и в ссылке, что вы мне скинули, тоже АЦП. Там лишь небольшое упоминание о компараторе в конце. Но он не имеет регистра, в котором хранит текущее значение, которое (ADC10MEM) я так удобно сравниваю, дабы выискать нажатую кнопку))) Тогда как? Сопротивление измерять? Буду очень рад, если дообъясните)

И, да, да, насчёт "прерывание по нажатию/отпусканию (но не по смене комбинации)" - Какие комбинации? Я вроде через нажатие/отпускание делаю... :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там лишь небольшое упоминание о компараторе в конце. Но он не имеет регистра, в котором хранит текущее значение, которое (ADC10MEM) я так удобно сравниваю, дабы выискать нажатую кнопку))) Тогда как? Сопротивление измерять? Буду очень рад, если дообъясните)

И, да, да, насчёт "прерывание по нажатию/отпусканию (но не по смене комбинации)" - Какие комбинации? Я вроде через нажатие/отпускание делаю... :(

Компаратор фиксирует момент нажатия (переход через порог), формирует прерывание, а дальше запускается АЦП.

Это альтернатива постоянному опросу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Компаратор фиксирует момент нажатия (переход через порог), формирует прерывание, а дальше запускается АЦП.

Это альтернатива постоянному опросу.

 

Идея хороша, НО:

Вы имеете ввиду, если напряжение, которое фиксируется компаратором больше некоего порога, то -> АЦП прерывание, верно?

Если я понял верно, ТО: у меня напряжение при нажатии 2й кнопки < напряжения при нажатии обеих кнопок < напряжения при не нажатых кнопках < напряжения при нажатой 1й. -> у меня не порог, а некие определённые значения, которые мне как раз и приходится опрашивать при помощи АЦП.

Если я понял неверно, то простите мне мою тупость, и я подумаю тщательнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В принципе, проблему мне удалось решить. Все диоды мигают по-разному. Правда, с динамиками так не выходит. Всё равно пробелы в знаниях и навыках остались..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ADC10CTL1 = ADC10SSEL_1 + CONSEQ_0; // Буду благодарен, если кто-нибудь объянит мне, что меняет,
                                      // и на практике делает CONSEQ, т.к. в моём случае, его изменение ни к чему не приводит.
                                      // и я не понимаю чего люди пытаются им добиться.

CONSEQ - это режим выборки. От него зависит однократный/многократный запуск и распределение данных по регистрам ADC_MEM.

Но поскольку здесь регистр данных всего один, назначение не столь очевидно. А вот в ADC12 забавные вещи можно делать. Например, за один проход последовательно опросить все входы и разложить данные в соответствующие регистры. Или оцифровать подряд несколько раз один вход и по прерыванию получить уже не одну, а несколько выборок, разложенных в разные регистры. Ну и всякие промежуточные комбинации.

С ADC10, как я понял, подобные вещи можно делать, используя модуль DTC, который каждую выборку автоматически переносит из ADC10MEM в заданные ячейки памяти

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ADC10CTL1 = ADC10SSEL_1 + CONSEQ_0; // Буду благодарен, если кто-нибудь объянит мне, что меняет,
                                      // и на практике делает CONSEQ, т.к. в моём случае, его изменение ни к чему не приводит.
                                      // и я не понимаю чего люди пытаются им добиться.

CONSEQ - это режим выборки. От него зависит однократный/многократный запуск и распределение данных по регистрам ADC_MEM.

Но поскольку здесь регистр данных всего один, назначение не столь очевидно. А вот в ADC12 забавные вещи можно делать. Например, за один проход последовательно опросить все входы и разложить данные в соответствующие регистры. Или оцифровать подряд несколько раз один вход и по прерыванию получить уже не одну, а несколько выборок, разложенных в разные регистры. Ну и всякие промежуточные комбинации.

С ADC10, как я понял, подобные вещи можно делать, используя модуль DTC, который каждую выборку автоматически переносит из ADC10MEM в заданные ячейки памяти

 

Спасибо. Надо бы внимательнее изучить ADC12. Любопытные вещи.

А можете человеческим языком объяснить что OUTMOD в TACCTL1 означает? :a14:

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А можете человеческим языком объяснить что OUTMOD в TACCTL1 означает? :a14:

Означает, что можно управлять соответствующими ногами "железно" по совпадению TA и TACCRx, без входа в прерывание и соответственно без джиттера и накладных расходов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Означает, что можно управлять соответствующими ногами "железно" по совпадению TA и TACCRx, без входа в прерывание и соответственно без джиттера и накладных расходов.

 

Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ребят, ещё такой вопрос: Как сделать короткий ШИМ сигнал? Нужно, чтобы динамик пикнул на секунду, одновременно с нажатием кнопки. Подскажите свои идеи, пожалуйста.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ребят, ещё такой вопрос: Как сделать короткий ШИМ сигнал? Нужно, чтобы динамик пикнул на секунду, одновременно с нажатием кнопки. Подскажите свои идеи, пожалуйста.

1. Включить ШИМ.

2. Подождать 1 сек

3. Выключить ШИМ.

Как-то так наверное :laughing:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...