Страница 14 из 23
Re: TI MSP430 Launch Pad
Добавлено: Чт июл 25, 2013 19:54:11
VLeshka
С кодом "while ((P1IN & BIT3) == 0) ;" в обработке прерывания нажатия кнопки, работает прекрасно.
Но дальше я захотел пойти дальше и проверить свою теорию, а именно организовать временную задержку, используя второй таймер (это чисто из интереса). Проблема - при отладке работает, а в реальности зависает при первом же нажатии на кнопке.
Сделал простейший проект, где по второму таймеру меняется состояние светодиодов - работает прекрасно.
Прочитал мануал про таймеры А и В - не нашёл никакого предложения, говорящего о нюансах их совместной работе. Яндекс помучал - не нашёл. Плохо ищу.
В чём проблема, не подскажете?
Re: TI MSP430 Launch Pad
Добавлено: Чт июл 25, 2013 22:20:28
YS
Более классически можно записать так:
"!" - логическое отрицание (его следует отличать от побитового - "~"). Если его аргумент не ноль, он превратит его в ноль. Если ноль - превратит в не ноль.

А все условия в С проверяются на не_ноль/ноль.
В чём проблема, не подскажете?
Видимо, в архитектуре взаимодействия двух прерываний.
Re: TI MSP430 Launch Pad
Добавлено: Чт июл 25, 2013 22:34:51
VLeshka
YS писал(а):Видимо, в архитектуре взаимодействия двух прерываний.
вот полный код, проверено многократно - при отладке работает, при реальном полёте зависает при первом же нажатии на кнопку. Может, подскажете на какую-то некорректность.
Спойлер
#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
while(1);
}
//прерывание по таймеру используем для вкл/выкл с/диодов
#pragma vector = TIMER0_A0_VECTOR //приоритет 0xFFF0
__interrupt void TIMER0_A0_PRE (void)
{
i_time += i_delitel;
if (i_time >= maxPause)
{
P1OUT ^= (BIT0 + BIT6);
i_time = 0;
}
}
//прерывание по кнопке используем для игр с паузой
#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
}
#pragma vector = TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_PRE (void)
{
P1IE |= BIT3; // Разрешение прерываний на P1.3
TA1CTL = 0; //останов таймера B
}
Re: TI MSP430 Launch Pad
Добавлено: Чт июл 25, 2013 22:52:08
YS
TA1CCTL0 = CCIE; //разрешаем прерывание по переполнению счётчика-таймера B
Неверно. CCIE разрешает прерывание от блока сравнения. За прерывание от переполнения отвечает бит TAIE в регистре TACTL. Стр. 368 - 370 User's Guide.
Re: TI MSP430 Launch Pad
Добавлено: Пн июл 29, 2013 14:30:19
VLeshka
YS [добрался до MSP430] да, я неправильно вставил комментарии.
Теперь работают два таймера, только одно НО: до одной точки прерывания [часто] выполнение программы доходит 2 раза, скриншот прилагаю. У меня только одно соображение - таймер останавливается не сразу? Если я неправ, то каким образом выполнение программы доходит до точки прерывания (на скриншоте отмечен) 2 раза?

Re: TI MSP430 Launch Pad
Добавлено: Пн июл 29, 2013 18:51:35
YS
Э-э-э, это надо смотреть в пошаговом режиме. Так я, честно говоря, не совсем понял, в чем дело.
Re: TI MSP430 Launch Pad
Добавлено: Пн июл 29, 2013 20:54:04
VLeshka
Возня вознёй с отладкой проблемы (суть: 2 раза запускается процедура прерывания таймера В и 2 раза - [почти полностью

] процедура прерывания нажатия кнопки), привела к:
- источник проблемы исходит из процедуры обработки прерывания нажатия кнопки;
- в этой процедуре прерывания нажатия кнопки интересно: точка остановки срабатывает 2 раза, только если поставил эту самую точку останова на:
или следующих строчках.
Спойлер
//используем таймер B для борьбы с дребезгом
TA1CCTL0 = CCIE; //Разрешение прерывания захвата/сравнения счётчика-таймера B/* Timer1_A3 Capture/Compare Control 0 */
TA1CTL = (TASSEL_2 + MC_2 + ID_2); //ставим источник тактов на SMCLK, и режим таймера - continuous, и делитель =4 (1 2 4 
Отсюда напрашивается вывод: прерывание таймера В вызывается, когда разрешаешь прерывание этого самого таймера. Я не прав?
Re: TI MSP430 Launch Pad
Добавлено: Пн июл 29, 2013 21:39:53
Кефир
Какой отладчик используете?
Re: TI MSP430 Launch Pad
Добавлено: Вт июл 30, 2013 08:55:43
Psych
YS писал(а):Отсюда напрашивается вывод: прерывание таймера В вызывается, когда разрешаешь прерывание этого самого таймера. Я не прав?
Не должно.
У вас нет таймера В...у вас два таймера А.
В эррате на ваш кристалл ТА16 говорится, что после TACLR вызывается дополнительное прерывание. Попробуйте остановить таймер MC=0, не трогая TACLR.
PS Че то глюканула цитата с автором

Re: TI MSP430 Launch Pad
Добавлено: Сб авг 03, 2013 13:42:17
ANALOG
Всю тему не читал, наверняка уже был такой вопрос:
Можно ли этот лаунчпад использовать тупо как переходник USB - UART?
И если да то куда подключаться для приема данных с него?
Re: TI MSP430 Launch Pad
Добавлено: Сб авг 03, 2013 21:55:39
YS
Можно ли этот лаунчпад использовать тупо как переходник USB - UART?
Да. Подключаться к пинам, помеченным как RXD и TXD.
Пинхедер J3. Перемычки, естесственно, надо снять.
Re: TI MSP430 Launch Pad
Добавлено: Сб авг 03, 2013 21:57:03
Ser60
Да, можно. Нужно только правильно выставить 2 джампера на плате. Именно, этими джамперами можно подключть преобразователь к МК нз плате, или наоборот отключить от него. В последнем случае преобразователь можно будет использовать и с внешними устройствами вне платы. Какие именно
джамперы написано в инструкции пользователя для платы.
Re: TI MSP430 Launch Pad
Добавлено: Вт авг 13, 2013 20:44:42
VLeshka
Добрался до MSP430 (прошу прощенья за паузу).
Дело я 29го июля закончил тем, что заместо кода:
Код: Выделить всё
//используем таймер 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кб.
Re: TI MSP430 Launch Pad
Добавлено: Пт авг 16, 2013 14:14:44
Bujhm666
Вот рабочий пример обработки кнопок и борьбы с дребезгом. Различаются короткое и длинное нажатие кнопок. В качестве таймера задержки на нажатие/отпускание используется сторожевой таймер WDT. Легко делается на любое количество кнопок. Идея взята отсюда:
http://bennthomsen.wordpress.com/ti-msp ... -switches/
Спойлер
Код: Выделить всё
//******************************************************************************
// Обработка кнопок с определением короткого и длинного нажатия.
// Антидребезг реализован с помощью задержки на нажатие/отпускание кнопки.
// Определение состояния кнопок происходит по прерываниям на портах i/o.
// Длительность нажатия определяется по счетчику в интервальном таймере
// (в данном примере каждые 4ms). Задержка выполнена на строжевом таймере (WDT)
// переводимом на это время в режим интервального таймера.
// Выполнение действий назначенных на кнопки осущесвляется в основном цикле
// программы.
//******************************************************************************
#include "msp430g2553.h"
#include <stdint.h> // Standard integer types
#define LED_1 BIT6 // Зеленый светодиод
#define LED_2 BIT0 // Красный светодиод
#define S1 BIT3 // Кнопка 1
#define S2 BIT4 // Кнопка 2
#define LONG_PRESS_TIME 700 // Продолжительность нажатия клавиши определяемая как "долгое нажатие"
volatile uint8_t Pressed = 0; // Флаг состояния кнопки
volatile uint8_t ButtonPress = 0; // Флаг нажатия кнопки (содержит установленный бит нажатой кнопки)
volatile uint8_t LongPress = 0; // Флаг длинного нажатия кнопки
volatile uint16_t PressCount = 0; // Счетчик времени нажатия
// Обработчик прерывания от PORT1
#pragma vector = PORT1_VECTOR
__interrupt void Port1_ISR(void)
{
uint8_t btn; // Буфер для P1IFG
if(P1IFG & S1 || P1IFG & S2)
{
btn = P1IFG;
P1IE &= ~(S1 + S2); // Запрещаем прерывания от кнопки
WDTCTL = WDT_ADLY_16; // Запуск сторожевого таймера (WDT) в режиме интервального с периодом 48ms
IFG1 &= ~WDTIFG; // Очистка флага прерывания WDT
IE1 |= WDTIE; // Разрешаем прерывания от WDT
if (P1IES & btn)
{ // Если спадающий фронт
Pressed |= btn; // Устанавливаем флаг нажатия кнопки
PressCount = 0; // Сбрасываем счетчик длинного нажатия
}
else
{ // Если нарастающий фронт
if (PressCount < LONG_PRESS_TIME) // Если короткое нажатие на кнопку
{
ButtonPress = btn;
}
Pressed = 0; // Сброс флага состояния кнопки
}
P1IES ^= btn; // Прерывание по нарастающему фронту
P1IFG &= ~(S1 + S2); // Сброс флага прерывания кнопки
btn = 0; // Обнуляем буфер
}
}
// Обработчик прерываний от Timer A1
#pragma vector = TIMER1_A0_VECTOR
__interrupt void TimerA1_ISR(void) {
if (Pressed) // Проверка, нажата ли кнопка
{
if (++PressCount == LONG_PRESS_TIME) // Зафиксировано длительное нажатие 700*4ms = ~3s
{
ButtonPress = Pressed; // Устанавливаем флаг нажатой кнопки
LongPress = 1; // Устанавливаем флаг длительного нажатия кнопки
Pressed = 0; // Сброс флага состояния кнопки
}
}
}
// Обработчик прерываний от таймера WDT
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
IE1 &= ~WDTIE; // Запрет прерываний от WDT
IFG1 &= ~WDTIFG; // Очистка флага прерывания WDT
WDTCTL = WDTPW + WDTHOLD; // Отключение таймера WDT
P1IFG &= ~(S1 + S2); // Сброс флага прерывания кнопки
P1IE |= S1 + S2; // Разрешаем прерывания от кнопки
}
void main(void) {
WDTCTL = WDTPW + WDTHOLD; // WatchDog off
BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
DCOCTL = CALDCO_16MHZ;
BCSCTL2 |= DIVS_3; // SMCLK = DCO / 8 = 2MHz
BCSCTL3 |= LFXT1S_2; // Set ACLK -> VLOCLK = 12kHz
// *** led ***
P1DIR |= LED_1 + LED_2;
P1OUT &= ~(LED_1 + LED_2);
// *** button ***
P1DIR &= ~(S1 + S2); // Установка вывода кнопки как входного
P1OUT |= S1 + S2; // Подтяжка к питанию
P1REN |= S1 + S2; // Включение подтягивающего резистора
P1IES |= S1 + S2; // Прерывание по спадающему фронту
P1IE |= S1 + S2; // Разрешаем прерывание
P1IFG = 0x00; // Очистка регистра прерываний
// *** Timer1 ***
TA1CTL = TASSEL_2 + ID_3 + MC_1 + TACLR; // SMCLK/8, upmode
TA1CCR0 = 1000; // sample every 4ms
TA1CCTL0 = CCIE; // CCR0 interrupt enabled
__bis_SR_register(GIE); // Разрешаем прерывания
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
#define LED_1 BIT6 // Зеленый светодиод
#define LED_2 BIT0 // Красный светодиод
#define S1 BIT3 // Кнопка 1
#define S2 BIT4 // Кнопка 2
#define LONG_PRESS_TIME 700 // Продолжительность нажатия клавиши определяемая как "долгое нажатие"
#define LOCK_PRESS_TIME 10 // Продолжительность блокироки нажатия кнопки
volatile uint8_t Pressed = 0; // Флаг состояния кнопки
volatile uint8_t ButtonPress = 0; // Флаг нажатия кнопки (содержит установленный бит нажатой кнопки)
volatile uint8_t LongPress = 0; // Флаг длинного нажатия кнопки
volatile uint8_t LockPress = 0; // Флаг блокировки нажатия кнопки
volatile uint8_t LockPressCount = 0; // Счетчик времени блокировки нажатия
volatile uint16_t PressCount = 0; // Счетчик времени нажатия
// Обработчик прерывания от PORT1
#pragma vector = PORT1_VECTOR
__interrupt void Port1_ISR(void)
{
uint8_t btn; // Буфер для P1IFG
if(P1IFG & S1 || P1IFG & S2)
{
btn = P1IFG; // Состояние регистра P1IFG в буфер
P1IE &= ~(S1 + S2); // Запрещаем прерывания от кнопки
LockPressCount = 0; // Обнуляем счетчик времени блокировки кнопки
LockPress = 1; // Устанавливаем флаг блокировки нажатия клавиши
if (P1IES & btn)
{ // Если спадающий фронт
Pressed |= btn; // Устанавливаем флаг нажатия кнопки
PressCount = 0; // Сбрасываем счетчик длинного нажатия
}
else
{ // Если нарастающий фронт
if (PressCount < LONG_PRESS_TIME) // Если короткое нажатие на кнопку
{
ButtonPress = btn;
}
Pressed = 0; // Сброс флага состояния кнопки
}
P1IES ^= btn; // Прерывание по нарастающему фронту
P1IFG &= ~(S1 + S2); // Сброс флага прерывания кнопки
btn = 0; // Обнуляем буфер
}
}
// Обработчик прерываний от Timer A1
#pragma vector = TIMER1_A0_VECTOR
__interrupt void TimerA1_ISR(void) {
if (LockPress) // Если установлен флаг блокировки кнопки
{
if (++LockPressCount == LOCK_PRESS_TIME) // Если время блокировки истекло (10*4ms = 40ms)
{
P1IFG &= ~(S1 + S2); // Сброс флага прерывания кнопки
P1IE |= S1 + S2; // Разрешаем прерывания от кнопки
LockPress = 0; // Сбрасываем флаг блокировки нажатия кнопки
}
}
if (Pressed) // Проверка, нажата ли кнопка
{
if (++PressCount == LONG_PRESS_TIME) // Зафиксировано длительное нажатие 700*4ms = ~3s
{
ButtonPress = Pressed; // Устанавливаем флаг нажатой кнопки
LongPress = 1; // Устанавливаем флаг длительного нажатия кнопки
Pressed = 0; // Сброс флага состояния кнопки
}
}
}
void main(void) {
WDTCTL = WDTPW + WDTHOLD; // WatchDog off
BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
DCOCTL = CALDCO_16MHZ;
BCSCTL2 |= DIVS_3; // SMCLK = DCO / 8 = 2MHz
// *** led ***
P1DIR |= LED_1 + LED_2;
P1OUT &= ~(LED_1 + LED_2);
// *** button ***
P1DIR &= ~(S1 + S2); // Установка вывода кнопки как входного
P1OUT |= S1 + S2; // Подтяжка к питанию
P1REN |= S1 + S2; // Включение подтягивающего резистора
P1IES |= S1 + S2; // Прерывание по спадающему фронту
P1IE |= S1 + S2; // Разрешаем прерывание
P1IFG = 0x00; // Очистка регистра прерываний
// *** Timer1 ***
TA1CTL = TASSEL_2 + ID_3 + MC_1 + TACLR; // SMCLK/8, upmode
TA1CCR0 = 1000; // sample every 4ms
TA1CCTL0 = CCIE; // CCR0 interrupt enabled
__bis_SR_register(GIE); // Разрешаем прерывания
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 LED_1 BIT6 // Зеленый светодиод
#define LED_2 BIT0 // Красный светодиод
#define S1 BIT3 // Кнопка 1
#define S2 BIT4 // Кнопка 2
// Константы для сравнения состояния сдвигового регистра
#define PRESS_THRESHOLD 0x3F // Пороговое значение регистра при нажатии кнопки
#define RELEASE_THRESHOLD 0xFC // Пороговое значение регистра при отпускании кнопки
#define LONG_PRESS_TIME 700 // Время определяемое как длительное нажатие кнопки (700*4ms = ~ 3s)
uint8_t LongPress = 0; // флаг длительного нажатия кнопки
volatile uint8_t ButtonPress = 0; // Бит нажатой кнопки
// - - - - - - - - - - - - - - - - - - - - -
// PRESS_THRESHOLD = 0x3F = 0 b00111111
// RELEASE_THRESHOLD = 0xFC = 0 b11111100
// - - - - - - - - - - - - - - - - - - - - -
#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A(void)
{
uint8_t BtnMask = 0; // Бит нажатой кнопки
static uint16_t PressCount = 0; // Время нажатия кнопки
static uint8_t BtnState = 0; // Флаг устйчивого состояния кнопки (после дребезга)
static uint8_t Pressed = 0; // Флаг - кнопка была нажата
static uint8_t ShiftReg = 0xFF; // Сдвиговый регистр для хранения состояния кнопки
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; // Сохраняем бит нажатой кнопки
}
}
}
void main (void)
{
WDTCTL = WDTPW | WDTHOLD; // Останавливаем сторожевой таймер
BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
DCOCTL = CALDCO_16MHZ;
BCSCTL2 |= DIVS_3; // SMCLK = DCO / 8 = 2MHz
// *** led ***
P1DIR |= LED_1 + LED_2;
P1OUT &= ~(LED_1 + LED_2);
// *** button ***
P1DIR &= ~(S1 + S2); // Установка вывода кнопки как входного
P1OUT |= S1 + S2; // Подтяжка к питанию
P1REN |= S1 + S2; // Включение подтягивающего резистора
// *** Timer1 ***
TA1CTL = TASSEL_2 + ID_3 + MC_1 + TACLR; // SMCLK/8, upmode
TA1CCR0 = 1000; // sample every 4ms
TA1CCTL0 = CCIE; // CCR0 interrupt enabled
__bis_SR_register(GIE); // Разрешаем прерывания
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) {
} else {
}
break;
}
ButtonPress = 0; // Сбрасываем флаг нажатия кнопки
}
}
}
Re: TI MSP430 Launch Pad
Добавлено: Пт авг 16, 2013 18:29:59
Ser60
Хорошая подборка идей! От себя добавлю, что основной цикл в приведенных реализациях молотит все время и сводит на нет все преимущества обработки нажатий и обработки дребезга через прерывания. Лучше отправлять МК в сон. Кроме того, определенным недостатком программ является частая обработка прерываний от таймера - каждые 4 мс даже если кнопки не нажаты.
Улучшить ситуацию можно несколько модифицировав алгоритм. Именно, разрешать прерывания по совпадению в самом начале обработки дребезга (получения первого прерывания от кнопки) и запрещать их по окончании обработки (в момент когда опять разрешаются прерывания от кнопки). Моменты совпадения нужно будет каждый раз пересчитывать в прерывании по совпадению (добалять одну и ту-же константу к счетчику), что не проблема. Так сделано, например, в моей конструкции
http://radiokot.ru/circuit/digital/measure/71/
В этой реализации, правда, каждый канал совпадения таймера обслуживает только одну кнопку. Но это не сильное ограничение, поскольку в современных моделях семейства MSP430 имеется несколько таймеров и у каждого 3-7 каналов сравнения.
Re: TI MSP430 Launch Pad
Добавлено: Сб авг 17, 2013 07:18:51
Bujhm666
Согласен. Если нужен экономичный режим, то вы предлагаете хороший вариант. Передо мной такая задача не стояла. Эти примеры просто заточены под мой проект лабораторного БП, поэтому и 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 LED_1 BIT6 // Зеленый светодиод
#define LED_2 BIT0 // Красный светодиод
#define S1 BIT3 // Кнопка 1
#define S2 BIT4 // Кнопка 2
//настройка параметров работы функций
#define BTN_LOCK_TIME 30 //время обработки дребезга в милисекундах (10-100)
#define BTN_LONG_TIME 1000 //время фиксации длинного нажатия в милисекундах (1000 - 2500)
//глобальные переменные
volatile uint8_t BtnFlags; //байт флагов нажатия кнопки
#define BTN_SHRT_S1 (1<<0) //бит короткого нажатия кнопки S1
#define BTN_SHRT_S2 (1<<1) //бит короткого нажатия кнопки S2
#define BTN_LONG_S1 (1<<2) //бит длинного нажатия кнопки S1
#define BTN_LONG_S2 (1<<3) //бит длинного нажатия кнопки S2
void BtnExe (void);
// Обработчик прерываний от Timer A1
#pragma vector = TIMER1_A0_VECTOR
__interrupt void TimerA1_ISR(void) {
BtnExe();
}
void main(void) {
WDTCTL = WDTPW + WDTHOLD; // WatchDog off
BCSCTL1 = CALBC1_1MHZ; // 1MHz clock
DCOCTL = CALDCO_1MHZ;
// *** led ***
P1DIR |= LED_1 + LED_2;
P1OUT &= ~(LED_1 + LED_2);
// *** button ***
P1DIR &= ~(S1 + S2); // Установка вывода кнопки как входного
P1OUT |= S1 + S2; // Подтяжка к питанию
P1REN |= S1 + S2; // Включение подтягивающего резистора
// *** Timer1 ***
TA1CTL = TASSEL_2 + ID_3 + MC_1 + TACLR; // SMCLK/8, upmode
TA1CCR0 = 2000; // sample every 10ms
TA1CCTL0 = CCIE; // CCR0 interrupt enabled
__bis_SR_register(GIE); // Разрешаем прерывания
while(1)
{
if (BtnFlags) { // Если была нажата кнопка
if (BtnFlags & BTN_SHRT_S1) { // Ветка короткого нажатия кнопки S1
P1OUT ^= LED_1; // Переключаем состояние выхода на противоположное
}
if (BtnFlags & BTN_SHRT_S2) { // Ветка короткого нажатия кнопки S2
}
if (BtnFlags & BTN_LONG_S1) { // Ветка длинного нажатия кнопки S1
P1OUT ^= LED_2; // Переключаем состояние выхода на противоположное
}
if (BtnFlags & BTN_LONG_S2) { // Ветка длинного нажатия кнопки S2
}
BtnFlags = 0;
}
}
}
//-----------------------------------------------------------------------------------------------------------------------
//ФУНКЦИЯ ОБРАБОТКИ НАЖАТИЙ КЛАВИШ (вызывать в прерывании с частотой 100 Гц)
//короткое нажатие устанавливает бит BTN_SHRT_X глобальной переменной BtnFlags
//длинное нажатие устанавливает бит BTN_LONG_X глобальной переменной BtnFlags
void BtnExe (void)
{
static uint8_t BtnLockBit; //защелка (защита от дребезга)
static uint8_t BtnLockCoun; //счетчик защелки (защита от дребезга)
static uint8_t BtnLongCoun; //счетчик длинного нажатия
static uint8_t BtnLastState; //последнее состояние кнопок перед отпусканием
uint8_t mask = 0;
if (!(P1IN & S1)) mask = BTN_SHRT_S1;
if (!(P1IN & S2)) mask = BTN_SHRT_S2;
if (mask){ //опрос состояния кнопки
if (BtnLockCoun < (BTN_LOCK_TIME/10)){ //клавиша нажата
BtnLockCoun++;
return; //защелка еще не дощитала - возврат
}
BtnLastState = mask;
BtnLockBit =1; //нажатие зафиксировано
if (BtnLongCoun >= (BTN_LONG_TIME/10))
return; //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше
if (++BtnLongCoun >= (BTN_LONG_TIME/10))
BtnFlags |= (BtnLastState<<2); //счетчик досчитал до максимума - устанавливаем биты длинного нажатия
}
else{ //клавиша отжата
if (BtnLockCoun){
BtnLockCoun --;
return; //защелка еще не обнулилась - возврат
}
if (! BtnLockBit) //СТАТИЧЕСКИЙ ВОЗВРАТ
return;
BtnLockBit =0; //отжатие зафиксировано
if (BtnLongCoun < (BTN_LONG_TIME/10))
BtnFlags |= BtnLastState; //установка бита короткого нажатия
BtnLongCoun = 0; //сброс счетчика длительности нажатия
}
}
Re: TI MSP430 Launch Pad
Добавлено: Сб авг 17, 2013 19:43:58
Ser60
Опять-таки, прерывание происходит каждые 10 мс независимо от того нажата кнопка или нет. Если это прерывание еще для чего-то нужно (как у Вас в проекте) то сойдет. В противном случае процессор будет слишком часто и понапрасну отвлекаться на обработку прерывания.
Я всегда делаю обработку нажатий кнопок на основе прерываний порта, регистра сдвига, и отключаемых прерываний каналов сравнения таймера. Сейчас заканчиваю проект с участием кнопок, где вышеупомянутый алгоритм адаптирован с FR57xx для MSP430G2332. Выложу его сюда на форум с исходником скорее всего после конкурса. Кстати, Bujhm666, может напишите сюда статью про Ваш блок питания или дадите ссылку если она уже опубликована?
Re: TI MSP430 Launch Pad
Добавлено: Вс авг 18, 2013 11:34:07
Bujhm666
Ser60 писал(а):Сейчас заканчиваю проект с участием кнопок, где вышеупомянутый алгоритм адаптирован с FR57xx для MSP430G2332
Ну можно было бы только код обработки кнопок выложить. Желательно на Си, если можно конечно.
Насчет моего блока питания, статью не напишу (не силен я в этом), а код и схему покажу, как доведу до ума (он хоть уже в корпусе и работает, но пока в стадии доводки). В схемотехнике там ничего нового, просто вместо обычных здесь пиков или меги управление от MSP430. Вот фотографии я выкладывал на схем.нет
http://forum.cxem.net/index.php?showtop ... try1622650
Re: TI MSP430 Launch Pad
Добавлено: Пн авг 19, 2013 08:05:26
Ser60
Bujhm666 писал(а):просто вместо обычных здесь пиков или меги управление от MSP430
Вот это и похвально. Не понимаю, чего остальные ждут. Вообще, конструкция выглядит добротной. Насчет моего кода, он на АСМе. Вместо того, чтобы вырезать куски кода, вот ссылка на весь код:
http://mcs.uwsuper.edu/sb/Electronics/BigLCD/clock.s43
Re: TI MSP430 Launch Pad
Добавлено: Пн авг 19, 2013 10:29:55
prinv
Читаю
здесь о ЦАП
Приложения, нуждающиеся в генерации периодических колебаний, могут получить преимущества от использования контроллера DMA с ЦАП12. К примеру, приложение, вырабатывающее синусоидальное колебание может сохранит значения синуса в таблице. Контроллер DMA может непрерывно автоматически переносить эти значения в ЦАП12 через заданные интервалы, создавая синусоиду без участия ЦПУ
Не подскажете, где бы поглядеть рабочий пример по работе ЦАП и DMA?