Turbo_enot 0 2 августа, 2013 Опубликовано 2 августа, 2013 · Жалоба Здравствуйте! Есть у меня задачка, которую никак не могу решить. У меня есть 6 кнопок (картинка прилагается), подключены они по две штуки к одному пину. Необходимо сделать так, чтобы при нажатии на каждую кнопку, происходило какое-то своё действие: светодиод мигал с разной чистотой, или динамик гудел различными тонами. И, вот, если одну пару кнопок я уже научился контролировать, то другие никак не могу. Подробности в комментариях к коду. Сам я программировать и разбираться с МК начал меньше месяца назад. Прошу не судить строго за любые возможные глупые ляпы. Буду благодарен вам за любую помощь! Мозг уже разрывается на части Прогаю в 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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 2 августа, 2013 Опубликовано 2 августа, 2013 · Жалоба Прошу прощения, в комментариях немного ошибся: Что делает 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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
d7d1cd 0 2 августа, 2013 Опубликовано 2 августа, 2013 · Жалоба Я может чего то не понимаю, но как микроконтроллер поймет, что нажата та или иная кнопка, каждая из которых подключена к одному и тому же пину? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 5 августа, 2013 Опубликовано 5 августа, 2013 · Жалоба Я может чего то не понимаю, но как микроконтроллер поймет, что нажата та или иная кнопка, каждая из которых подключена к одному и тому же пину? АЦП. При помощи него я измеряю напряжение на пине. На схеме, которую я прикрепил, видно, что напряжение будет меняться при различных вариантах нажатия. Кнопки две - варианта четыре. Это всё находится у меня в прерывании АЦП - взгляните. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 17 5 августа, 2013 Опубликовано 5 августа, 2013 · Жалоба Вообще-то, на один вход АЦП можно повесить все ваши кнопки, используя резистивную матрицу Запараллелив на вход компаратора, можно будет получать прерывание по нажатию/отпусканию (но не по смене комбинации) Статью гуглите сами. Хотя, вот она. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 5 августа, 2013 Опубликовано 5 августа, 2013 · Жалоба Вообще-то, на один вход АЦП можно повесить все ваши кнопки, используя резистивную матрицу Запараллелив на вход компаратора, можно будет получать прерывание по нажатию/отпусканию (но не по смене комбинации) Статью гуглите сами. Хотя, вот она. Это здорово, что можно повесить все, но у меня всё именно так, как на схеме, которую я приложил в самом начале. И это не исправить. Простите, из вашего ответа не пойму: АЦП или компаратор? Я понимаю, что компаратор тоже АЦП, но в моём случае это 10-битное АЦП, и в ссылке, что вы мне скинули, тоже АЦП. Там лишь небольшое упоминание о компараторе в конце. Но он не имеет регистра, в котором хранит текущее значение, которое (ADC10MEM) я так удобно сравниваю, дабы выискать нажатую кнопку))) Тогда как? Сопротивление измерять? Буду очень рад, если дообъясните) И, да, да, насчёт "прерывание по нажатию/отпусканию (но не по смене комбинации)" - Какие комбинации? Я вроде через нажатие/отпускание делаю... :( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 17 5 августа, 2013 Опубликовано 5 августа, 2013 · Жалоба Там лишь небольшое упоминание о компараторе в конце. Но он не имеет регистра, в котором хранит текущее значение, которое (ADC10MEM) я так удобно сравниваю, дабы выискать нажатую кнопку))) Тогда как? Сопротивление измерять? Буду очень рад, если дообъясните) И, да, да, насчёт "прерывание по нажатию/отпусканию (но не по смене комбинации)" - Какие комбинации? Я вроде через нажатие/отпускание делаю... :( Компаратор фиксирует момент нажатия (переход через порог), формирует прерывание, а дальше запускается АЦП. Это альтернатива постоянному опросу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 5 августа, 2013 Опубликовано 5 августа, 2013 · Жалоба Компаратор фиксирует момент нажатия (переход через порог), формирует прерывание, а дальше запускается АЦП. Это альтернатива постоянному опросу. Идея хороша, НО: Вы имеете ввиду, если напряжение, которое фиксируется компаратором больше некоего порога, то -> АЦП прерывание, верно? Если я понял верно, ТО: у меня напряжение при нажатии 2й кнопки < напряжения при нажатии обеих кнопок < напряжения при не нажатых кнопках < напряжения при нажатой 1й. -> у меня не порог, а некие определённые значения, которые мне как раз и приходится опрашивать при помощи АЦП. Если я понял неверно, то простите мне мою тупость, и я подумаю тщательнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 5 августа, 2013 Опубликовано 5 августа, 2013 · Жалоба В принципе, проблему мне удалось решить. Все диоды мигают по-разному. Правда, с динамиками так не выходит. Всё равно пробелы в знаниях и навыках остались.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 17 5 августа, 2013 Опубликовано 5 августа, 2013 · Жалоба ADC10CTL1 = ADC10SSEL_1 + CONSEQ_0; // Буду благодарен, если кто-нибудь объянит мне, что меняет, // и на практике делает CONSEQ, т.к. в моём случае, его изменение ни к чему не приводит. // и я не понимаю чего люди пытаются им добиться. CONSEQ - это режим выборки. От него зависит однократный/многократный запуск и распределение данных по регистрам ADC_MEM. Но поскольку здесь регистр данных всего один, назначение не столь очевидно. А вот в ADC12 забавные вещи можно делать. Например, за один проход последовательно опросить все входы и разложить данные в соответствующие регистры. Или оцифровать подряд несколько раз один вход и по прерыванию получить уже не одну, а несколько выборок, разложенных в разные регистры. Ну и всякие промежуточные комбинации. С ADC10, как я понял, подобные вещи можно делать, используя модуль DTC, который каждую выборку автоматически переносит из ADC10MEM в заданные ячейки памяти Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 6 августа, 2013 Опубликовано 6 августа, 2013 · Жалоба ADC10CTL1 = ADC10SSEL_1 + CONSEQ_0; // Буду благодарен, если кто-нибудь объянит мне, что меняет, // и на практике делает CONSEQ, т.к. в моём случае, его изменение ни к чему не приводит. // и я не понимаю чего люди пытаются им добиться. CONSEQ - это режим выборки. От него зависит однократный/многократный запуск и распределение данных по регистрам ADC_MEM. Но поскольку здесь регистр данных всего один, назначение не столь очевидно. А вот в ADC12 забавные вещи можно делать. Например, за один проход последовательно опросить все входы и разложить данные в соответствующие регистры. Или оцифровать подряд несколько раз один вход и по прерыванию получить уже не одну, а несколько выборок, разложенных в разные регистры. Ну и всякие промежуточные комбинации. С ADC10, как я понял, подобные вещи можно делать, используя модуль DTC, который каждую выборку автоматически переносит из ADC10MEM в заданные ячейки памяти Спасибо. Надо бы внимательнее изучить ADC12. Любопытные вещи. А можете человеческим языком объяснить что OUTMOD в TACCTL1 означает? :a14: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 17 6 августа, 2013 Опубликовано 6 августа, 2013 · Жалоба А можете человеческим языком объяснить что OUTMOD в TACCTL1 означает? :a14: Означает, что можно управлять соответствующими ногами "железно" по совпадению TA и TACCRx, без входа в прерывание и соответственно без джиттера и накладных расходов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 6 августа, 2013 Опубликовано 6 августа, 2013 · Жалоба Означает, что можно управлять соответствующими ногами "железно" по совпадению TA и TACCRx, без входа в прерывание и соответственно без джиттера и накладных расходов. Спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turbo_enot 0 9 августа, 2013 Опубликовано 9 августа, 2013 · Жалоба Ребят, ещё такой вопрос: Как сделать короткий ШИМ сигнал? Нужно, чтобы динамик пикнул на секунду, одновременно с нажатием кнопки. Подскажите свои идеи, пожалуйста. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Terkin 0 9 августа, 2013 Опубликовано 9 августа, 2013 · Жалоба Ребят, ещё такой вопрос: Как сделать короткий ШИМ сигнал? Нужно, чтобы динамик пикнул на секунду, одновременно с нажатием кнопки. Подскажите свои идеи, пожалуйста. 1. Включить ШИМ. 2. Подождать 1 сек 3. Выключить ШИМ. Как-то так наверное :laughing: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться