реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Подружить ADC12 и TimerB
Salazar
сообщение Jul 11 2007, 08:09
Сообщение #1





Группа: Новичок
Сообщений: 11
Регистрация: 30-06-07
Пользователь №: 28 801



Здравствуйте. Я пишу программу, которая должна периодически просыпаться и передавать по UART значения с ADC с метками времени от TimerB.

По отдельности всё работает, но как только всё собирается воедино...
Сразу после включения ADC12 у меня перестаёт прерываться таймерБ.
Как быть?
Go to the top of the page
 
+Quote Post
VAI
сообщение Jul 11 2007, 09:06
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



Цитата
Как быть?

Понять, что здесь не общество телепатов. Код выкладывать надо.
Если будете вставлять в сообщение, не забывайте соответственно обрамлять его, чтоб сохранилось форматирование. (кнопка "Код" в расширеной форме ответа)


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jul 11 2007, 10:21
Сообщение #3


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



меня тоже это все очень интересует biggrin.gif Как раз сейчас тоже мучаюсь с запуском конвертациии по таймеру. Приведите код плиз
Go to the top of the page
 
+Quote Post
Salazar
сообщение Jul 12 2007, 06:29
Сообщение #4





Группа: Новичок
Сообщений: 11
Регистрация: 30-06-07
Пользователь №: 28 801



Вот так я инициализирую АЦП:
Код
...
ADC12CTL0 = SHT0_0 + MSC + ADC12ON + ADC12OVIE;
ADC12CTL1 = SHS_0 + SHP + ADC12DIV_0 + ADC12SSEL_0 + CONSEQ_2;
ADC12MCTL0 = INCH_0 + SREF_6;    // ref+=AVcc, channel = A0
ADC12MCTL1 = INCH_1 + SREF_1 + EOS;   // ref+=AVcc, channel = A1
...


Меня интересует, почему параметры ADC12DIV_x и ADC12SSEL_x никак не изменяют частоту срабатывания прерывания АЦП.
И вообще может кто знает как задавать период срабатывания прерывания АДЦ?
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jul 12 2007, 06:46
Сообщение #5


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



Цитата(Salazar @ Jul 12 2007, 10:29) *
Вот так я инициализирую АЦП:
Код
...
ADC12CTL0 = SHT0_0 + MSC + ADC12ON + ADC12OVIE;
ADC12CTL1 = SHS_0 + SHP + ADC12DIV_0 + ADC12SSEL_0 + CONSEQ_2;
ADC12MCTL0 = INCH_0 + SREF_6;    // ref+=AVcc, channel = A0
ADC12MCTL1 = INCH_1 + SREF_1 + EOS;   // ref+=AVcc, channel = A1
...


Меня интересует, почему параметры ADC12DIV_x и ADC12SSEL_x никак не изменяют частоту срабатывания прерывания АЦП.
И вообще может кто знает как задавать период срабатывания прерывания АДЦ?


Период стабатывания можно определять по выходу OUT таймераА или Б (пункт 17.2.5). Либо вручную, по ADC12SC (тот же пункт). Поэтому покажите как вы таймер инитите.

Вообще я не понял, вам таймерБ нужен зачем? Запускать АЦП от него или передавать его значения по УАРТ?
Go to the top of the page
 
+Quote Post
Salazar
сообщение Jul 12 2007, 07:35
Сообщение #6





Группа: Новичок
Сообщений: 11
Регистрация: 30-06-07
Пользователь №: 28 801



Например:
(ACLK = 32768)

TimerB срабатывает 100 раз в секунду:
Код
  TBCTL = CNTL_0 + TBSSEL_1 + MC_1;
  TBCCR0 = 328;
  TBCCTL0 = CCIE;


АЦП инициализирую на TimerB:
Код
ADC12CTL0 = SHT0_0 + MSC + ADC12ON + ADC12OVIE;
ADC12CTL1 = SHS_2 + SHP + ADC12DIV_0 + ADC12SSEL_1 + CONSEQ_2;


Модуль тактирования настроен так:
Код
BCSCTL2 = SELM_3 + DIVM_3 + DIVS_3 + DCOR;
BCSCTL1 = XT2OFF + DIVA_0;


В итоге, таймерБ работает как надо (в его обработчике прерывания инкрементируется RTC) а прерывание от адц не вызывается вообще.

А если работать через ADC12SC, то в какой регистр установить период? (в 17.2.5 не нашёл)
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jul 12 2007, 09:07
Сообщение #7


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



Если через ADC12SC то периода нету как такового - это одноразовый запуск сэмплирования. Есть вариант (наскока я понимаю), поставить ADC12SC в обработчик прерывания таймера (там где у вас часы инкрементятся ), но это не по-человечески, ибо все равно придется обрабатывать прерывания от АЦП, когда данные будут готовы (через несколько тактов после ADC12SC)

Попробуйте так.

Код
//TimerB.OUT0, АЦП тактируется от встроенного осциллятора, только один канал и один раз (в том смысле, что начинать преобразоввание мы будем САМИ по прерыванию в таймере)
ADC12CTL1 = SHS_0 + SHP + ADC12DIV_0 + ADC12SSEL_0 + CONSEQ_0;

ADC12CTL0 = SHT0_0 + ENC + ADC12ON;


//И это не забываем
ADC12IE = BIT0;


//В обработчик таймера ставим
ADC12CTL0 |= ADC12SC;



Не проверял. Не гарантирую.
Go to the top of the page
 
+Quote Post
VAI
сообщение Jul 12 2007, 09:45
Сообщение #8


Профессионал
*****

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



Вот так я вызываю Преобразования с определенным периодом по таймеру.
Если нужна еще и передача оцифрованых значений по UART, то можно еще и это добавить, важно, чтоб успело передаться до следующего вызова.
Код
// --- Определения ---------------------------------------------------------------------------------------- **
#define Start_conversion()        { ADC12CTL0 |= ADC12SC; }
#define Enable_conversions()      { ADC12CTL0 |= ENC; }
#define Disable_conversions()     { ADC12CTL0 &= ~ENC; }
#define ADC_SUM                   4     // сколько преобразований суммируем и принимаем за 1 отсчет
#define ADC_MAX                   ( 4095 * ADC_SUM )
#define ADC_NORMA                 ( 3500 * ADC_SUM )


/* --- adc_ini() ------------------------------------------------------------------------------------------ **
*  Инициализация каналов АЦП
* -------------------------------------------------------------------------------------------------------- */
static void adc_ini( void )
{
  P6SEL = BINARY( 11111111 );                                     // весь порт используется, как входы АЦП
  P6DIR = BINARY( 00000000 );

  ADC12CTL0 = ADC12ON                                             // АЦП включено
            | SHT0_2                                              // время установленияния для ADC12MEM0…ADC12MEM7, tsample >= 2 us, сделаем 16/4us
            | SHT1_3                                              // время установленияния для ADC12MEM8…ADC12MEM15 сделаем 32/4us (tsample > 5us)
            | MSC                                                 // обрабатываем последовательность каналов
            | REFON + REF2_5V                                     // опорное напряжение 2.5В включено
          ;

  ADC12CTL1 = CSTARTADD_0                                         // данные будем помещать начиная с ADC12MEM0
            | SHP                                                 // Сигнал SAMPCON берется с таймера защёлки. Передний фронт сигнала Sample-input запускает таймер.
            | ADC12SSEL_2                                         // тактовая частота для ядра АЦП (ADC12CLK) - MCLK
            | ADC12DIV_1                                          // деленая на 2 - итого 4 МГц, время преобразования (13 * 1/4 + tsample)us
            | CONSEQ_1                                            // один цикл измерения последовательности каналов
          ;

// При перестановке каналов при инициализации АЦП не забыть переставить enum variable_resistor
  ADC12MCTL0 = INCH_2  + SREF_1;                                  // канал = A2,               Vr+=Vref+, Vr-=AVSS
  ADC12MCTL1 = INCH_0  + SREF_1;                                  // канал = A0,               Vr+=Vref+, Vr-=AVSS
  ADC12MCTL2 = INCH_3  + SREF_1;                                  // канал = A3,              Vr+=Vref+, Vr-=AVSS
  ADC12MCTL3 = INCH_1  + SREF_1;                                  // канал = A1,              Vr+=Vref+, Vr-=AVSS

  ADC12MCTL4 = INCH_4  + SREF_1;                                  // канал = A4,               Vr+=Vref+, Vr-=AVSS
  ADC12MCTL5 = INCH_6  + SREF_1;                                  // канал = A6,              Vr+=Vref+, Vr-=AVSS
  ADC12MCTL6 = INCH_5  + SREF_1;                                  // канал = A5,              Vr+=Vref+, Vr-=AVSS
  ADC12MCTL7 = INCH_7  + SREF_1 + EOS;                        // канал = A7, Vr+=Vref+, Vr-=AVSS + EOS

// -----------------------------------------------------------------------------------------------------------------
  ADC12IE = 1 << ( adc_cnt - 1 );                                 // Enable ADC12IFG.x - разрешим прерывание от последнего оцифровываемого канала
  Enable_conversions();
}

/* --- Timer_A_isr() -------------------------------------------------------------------------------------- **
*
* -------------------------------------------------------------------------------------------------------- */
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A_isr( void )
{

  tick_ms++;
  Start_conversion();
......
......
}

/* --- ADC12_isr() ---------------------------------------------------------------------------------------- **
*  Конец преобразования АЦП, вызывается по таймеру А с частотой 1000 Гц
* Накапливаем сигнал за ADC_SUM преобразований
* -------------------------------------------------------------------------------------------------------- */
#pragma vector=ADC_VECTOR
__interrupt void ADC12_isr( void )
{
unsigned short *adc_mem_ptr;
static int a_cnt;
int a;

  adc_mem_ptr = (unsigned short *)&ADC12MEM0;
  for ( a = 0; a < adc_cnt; a++ )                                 // остальные из ADC_SUM
    x_adc_t[a] += *adc_mem_ptr++;                                 // сохраним результаты АЦП во временный массив
  if ( ++a_cnt < ADC_SUM )
    return;
// Сюда попадает с частотой ( 1000 / ADC_SUM ) = 250 Гц
  for ( a_cnt = a = 0; a < adc_cnt; a++ )                         // сумма ADC_SUM отсчетов готова, перенесем "куда нада"
  { x_adc[a] = x_adc_t[a];
    x_adc_t[a] = 0;
  }
// Дальше не критично ко времени, лишь бы до следующего прерывания выполнилось, поэтому разрешим прерывания
  __enable_interrupt();
  if ( flag.channel_REF == OFF )                                  // Опорнай канал игнорируется
    x_adc[X_REF] = ADC_NORMA;
  ADC12_isr_add();  // Дальнейшая обработка, должна успеть закончится до следующего вызова
}


первый пробел съедается при форматировании....


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
Salazar
сообщение Jul 13 2007, 20:28
Сообщение #9





Группа: Новичок
Сообщений: 11
Регистрация: 30-06-07
Пользователь №: 28 801



Всем спасибо.
То что я хотел решилось стартом прерывания АЦП из прерываия таймера.
Go to the top of the page
 
+Quote Post
aag
сообщение Jul 17 2007, 09:44
Сообщение #10


Частый гость
**

Группа: Свой
Сообщений: 81
Регистрация: 8-04-06
Из: Новосибирск
Пользователь №: 15 939



2 Salazar:

Напишите, плиз, итоговый код прерывания

Сейчас с аналогичной проблемой борюсь, на примере всеж легче учиться будет..
Go to the top of the page
 
+Quote Post
VAI
сообщение Jul 17 2007, 09:54
Сообщение #11


Профессионал
*****

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



2 aag

А чем мой код не нравится?


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
aag
сообщение Jul 17 2007, 11:47
Сообщение #12


Частый гость
**

Группа: Свой
Сообщений: 81
Регистрация: 8-04-06
Из: Новосибирск
Пользователь №: 15 939



Ваш код нравится.

только я не все в нем понимаю: зачем нужно сохранять результат ацп во временный массив? почему нельзя сразу нельзя в "куда надо" кинуть? (а нельзя действительно - выкинул часть кода, работать перестало, только не понимаю почему)
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jul 17 2007, 11:49
Сообщение #13


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



Цитата(aag @ Jul 17 2007, 15:47) *
Ваш код нравится.

только я не все в нем понимаю: зачем нужно сохранять результат ацп во временный массив? почему нельзя сразу нельзя в "куда надо" кинуть? (а нельзя действительно - выкинул часть кода, работать перестало, только не понимаю почему)

это усреднение у него просто по нескольким выборкам


Проблема, на которую я нарвался заключалась в следующем.

Я хотел по прирыванию от таймера начинать оцифровку. Но при этом не хотел делать SC в обработчике, а хотел, чтоб оно автоматом запускалось по сигналу out от таймера. Но запускался АЦП только однажды и причиной тому был режим CONSEQ_0 а не CONSEQ_2.

Вывод. Если вручную хотите запускать то SC в прерывании таймера и CONSEQ_0. Если автоматом, то настройка таймера на SET/RESET, необрабатывать его прерывания и CONSEQ_2.

Я несколько неправильно понял доку поначалу.

Ясно выразился?
Go to the top of the page
 
+Quote Post
aag
сообщение Jul 17 2007, 12:15
Сообщение #14


Частый гость
**

Группа: Свой
Сообщений: 81
Регистрация: 8-04-06
Из: Новосибирск
Пользователь №: 15 939



В принципе, да.

У мне как раз и хотелось по таймеру А (или В, или просто по нажатию кнопки) однин раз считать значение напряжения на входе АЦП (пока только на одном пине, а не на всех сразу) и передать его куда-нибудь. но вот то что я написал не работает:
Код
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A_isr( void )
{
   if (!read)
   {
      ADC12CTL0 |= ADC12SC;
      read = true;
   }
  
   .....
}

#pragma vector=ADC_VECTOR
__interrupt void ADC12_isr( void )
{
   adc_value = ADC12MEM0 + (ADC12MEM1 << 8);
   read = false;
}


adc_value - глобальная переменная типа unsigned int, откуда потом можно будет считать данные о том, что было на входе АЦП
read - глобальная переменная, необходимая для того чтобы таймер знал, что данные еще не получены и не запускал АЦП заново

p.s. функция ADC12_isr_add() в коде VAI для его нужна? и где ее код взять?

Сообщение отредактировал aag - Jul 17 2007, 12:16
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jul 17 2007, 12:44
Сообщение #15


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



ADC12_isr_add() его "личная" функция и совершенно не важно что она там делает.

1. Я не понял, что вы хотите сделать сторокой

Код
adc_value = ADC12MEM0 + (ADC12MEM1 << 8);


Если вы хотите в adc_value передать значения с 2 входов, то тут как минимум проблемы с разрядностью.
unsigned int - 16 бит
ADC12MEMx - 16 бит

В 16 битах 32 не передать smile.gif

Кроме того (ADC12MEM1 << 8): в 16 битовом числе вы младшие 12 бит сдвигаете на 8 влево. Что получите?

2.
Цитата
но вот то что я написал не работает


Что не работает то конкретно? Приведите обязательно все то что касается настройки таймера и АЦП.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 7th July 2025 - 09:49
Рейтинг@Mail.ru


Страница сгенерированна за 0.0153 секунд с 7
ELECTRONIX ©2004-2016