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

 
 
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
aag
сообщение Jul 18 2007, 03:23
Сообщение #16


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

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



считывание значения заменил такой строкой:
Код
adc_value = ADC12MEM0;

(изначально я думал, что ADC12MEMx 8-битные, а раз ацп 12 разрядов, то соответственно первые 8 лежат в ADC12MEM(x), а оставшиеся 4 - в ADC12MEM(x+1) )

установки такие:
Код
ADC12CTL0 = ADC12ON | MSC | ENC | REF2_5V;
ADC12CTL1 = SHP;
P6SEL = 0x01;
ADC12IE = 0x01;


функция ADC12CTL0 |= ADC12SC; срабатывает по нажжатию кнопки.

вроде все должно нормально работать, только вот значения ADC12MEM0 не зависят от приложенного к пину напряжения почему-то. значение всегда равно 0x04D8
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jul 18 2007, 05:29
Сообщение #17


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

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



Цитата(aag @ Jul 18 2007, 07:23) *
считывание значения заменил такой строкой:
Код
adc_value = ADC12MEM0;

(изначально я думал, что ADC12MEMx 8-битные, а раз ацп 12 разрядов, то соответственно первые 8 лежат в ADC12MEM(x), а оставшиеся 4 - в ADC12MEM(x+1) )

установки такие:
Код
ADC12CTL0 = ADC12ON | MSC | ENC | REF2_5V;
ADC12CTL1 = SHP;
P6SEL = 0x01;
ADC12IE = 0x01;


функция ADC12CTL0 |= ADC12SC; срабатывает по нажжатию кнопки.

вроде все должно нормально работать, только вот значения ADC12MEM0 не зависят от приложенного к пину напряжения почему-то. значение всегда равно 0x04D8


По моему вы невнимательно читаете документацию. Доки от ТИ заслуживают уважения к себе biggrin.gif a14.gif

1. Я не вижу где вы настраиваете непосредственно канал (регистр ADC12MCTL0).

2. Читайте в самом верху на регистры ADC12CTL1, ADC12CTL0, ADC12MCTL0 : Modifiable only when ENC = 0
Это значит, что
Код
ADC12CTL0 |= ENC;
вы должны сделать в самом конце. Вообще полезно после инициализации всех регистров проверить, а приинитились ли они как надо.

3. Прерывания от таимера и от АЦП происходят??? Точку останова поставте в обработчиках.

4. Если прерывания есть, в дебуггере сбросте значение ADC12MEM0 в 0 и посмотрите на следующем прерывании оно 0x04D8? Если нет, то это значит, что значение не меняется, а не неправильное.
Go to the top of the page
 
+Quote Post
aag
сообщение Jul 18 2007, 06:21
Сообщение #18


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

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



Цитата
2. Читайте в самом верху на регистры ADC12CTL1, ADC12CTL0, ADC12MCTL0 : Modifiable only when ENC = 0
Это значит, что


Блин..

после того как сделал так:
Код
ADC12CTL0 = ADC12ON | MSC | REF2_5V;
ADC12CTL1 = SHP;
P6SEL = 0x01;
ADC12IE = 0x01;

ADC12CTL0 |= ENC;

все заработало. теперь при изменении напряжения, ADC12MEM0 принимает значения от 0x00 до 0x0F39
smile.gif
больше не хочет принимать, видимо недостаточно напряжения.

Вобщем, проблема решена. Спасибо огромное

Сообщение отредактировал aag - Jul 18 2007, 06:26
Go to the top of the page
 
+Quote Post
jorikdima
сообщение Jul 18 2007, 07:10
Сообщение #19


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

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



Цитата(aag @ Jul 18 2007, 10:21) *
теперь при изменении напряжения, ADC12MEM0 принимает значения от 0x00 до 0x0F39
smile.gif
больше не хочет принимать, видимо недостаточно напряжения.



Настройте канал!!! Регистр ADC12MCTL0, по умолчанию там может быть черт знает что.
Go to the top of the page
 
+Quote Post

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

 


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


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