|
Подружить ADC12 и TimerB |
|
|
|
Jul 11 2007, 08:09
|
Группа: Новичок
Сообщений: 11
Регистрация: 30-06-07
Пользователь №: 28 801

|
Здравствуйте. Я пишу программу, которая должна периодически просыпаться и передавать по UART значения с ADC с метками времени от TimerB.
По отдельности всё работает, но как только всё собирается воедино... Сразу после включения ADC12 у меня перестаёт прерываться таймерБ. Как быть?
|
|
|
|
|
Jul 11 2007, 09:06
|

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

|
Цитата Как быть? Понять, что здесь не общество телепатов. Код выкладывать надо. Если будете вставлять в сообщение, не забывайте соответственно обрамлять его, чтоб сохранилось форматирование. (кнопка "Код" в расширеной форме ответа)
--------------------
Если зайца бить, его можно и спички научить зажигать Сколько дурака не бей - умнее не будет. Зато опытнее
|
|
|
|
|
Jul 12 2007, 06:29
|
Группа: Новичок
Сообщений: 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 никак не изменяют частоту срабатывания прерывания АЦП. И вообще может кто знает как задавать период срабатывания прерывания АДЦ?
|
|
|
|
|
Jul 12 2007, 06:46
|

тут может быть ваша реклама
    
Группа: Свой
Сообщений: 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 (тот же пункт). Поэтому покажите как вы таймер инитите. Вообще я не понял, вам таймерБ нужен зачем? Запускать АЦП от него или передавать его значения по УАРТ?
|
|
|
|
|
Jul 12 2007, 07:35
|
Группа: Новичок
Сообщений: 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 не нашёл)
|
|
|
|
|
Jul 12 2007, 09:07
|

тут может быть ваша реклама
    
Группа: Свой
Сообщений: 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; Не проверял. Не гарантирую.
|
|
|
|
|
Jul 12 2007, 09:45
|

Профессионал
    
Группа: Модераторы
Сообщений: 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(); // Дальнейшая обработка, должна успеть закончится до следующего вызова } первый пробел съедается при форматировании....
--------------------
Если зайца бить, его можно и спички научить зажигать Сколько дурака не бей - умнее не будет. Зато опытнее
|
|
|
|
|
Jul 13 2007, 20:28
|
Группа: Новичок
Сообщений: 11
Регистрация: 30-06-07
Пользователь №: 28 801

|
Всем спасибо. То что я хотел решилось стартом прерывания АЦП из прерываия таймера.
|
|
|
|
|
Jul 17 2007, 11:49
|

тут может быть ваша реклама
    
Группа: Свой
Сообщений: 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. Я несколько неправильно понял доку поначалу. Ясно выразился?
|
|
|
|
|
Jul 17 2007, 12:15
|

Частый гость
 
Группа: Свой
Сообщений: 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
|
|
|
|
|
Jul 17 2007, 12:44
|

тут может быть ваша реклама
    
Группа: Свой
Сообщений: 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 не передать Кроме того (ADC12MEM1 << 8): в 16 битовом числе вы младшие 12 бит сдвигаете на 8 влево. Что получите? 2. Цитата но вот то что я написал не работает Что не работает то конкретно? Приведите обязательно все то что касается настройки таймера и АЦП.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|