Перейти к содержанию
    

MSP430 - снова вопросы от чайника

ЗКак быть? Может, установить сначала режим "установка", в прерываниях от CCR0 вести счетчик, а в последнем переключить режим на "сброс". В следующем за ним прерывании опять "установка". Можно так сделать? Вы об этом говорите? :)
Да, режим сброс/установка только для формирования сигнала длительность которого меньше периода перезагрузки таймера и для более точного формирования времянки сигнала. Хотя. если задержка на вход в прерывание от таймера у вас детерминирована и по времени вполне устраивает, то вовсе не обязательно формировать сигнал аппаратно. Можно оставить все как у вас сейчас уже работает. И запуск АЦП делать прямо в таймерном прерывании.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно оставить все как у вас сейчас уже работает. И запуск АЦП делать прямо в таймерном прерывании.

Сейчас не очень хорошо. Понадобилось вот стыковаться, а у меня с синхронностью выявились большие проблемы :) Надо, чтобы все было четко-пречетко. И без камазов с кирпичами :biggrin: То есть, можно сделать так, как я говорю?

а вот по поводу АЦП:

Мне сказали, что цикл while(ADC12IFG & BIT3); - это некорректное использование процесссора. :) типа, чего он будет столько тиков в пустую ждать. Надо работать с прерываниями. и вот вопрос -

Прерывания. как я понимаю, приходят после установки флагов ADC12IFGx, которые устанавливаются после заполнения ADCMEMx. Если режим повторно-последовательный, то прерывания будут после обработки каждого канала?

А вот в найденном примере в прерывании пишется

static unsigned int index;

resault[index] = ADC12MEM0;

resault[index] = ADC12MEM1;

resault[index] = ADC12MEM2;

index=(index+1)%8;

как же так? :) ADCMEM0 заполнен. пришло прерывание, а в прерывании считывается и ADC12MEM1, и ADC12MEM2... они же могут быть еще не заполнены? Нужно было бы по идее писать

if (ADC12IFG & BIT0)

resault[index] = ADC12MEM0;

if (ADC12IFG & BIT1)

resault[index] = ADC12MEM1;... разъясните, пожалуйста.

И вот еще вопрос - index объявляю глобальным, массивы СV1[], CV2[] - тоже. В прерывании веду счетчик(index++), заполняю массивы. В теле проги, если index>=10, ADC12CTL0 &= ENC;

Отправляю сразу по заполнению себе на COM элементы массива - вроде все нормально, заполняются. А после остановки АЦП они пустые, и счетчик 0. В чем тут дело? :05:

Подскажите, помогите.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а вот по поводу АЦП:

Мне сказали, что цикл while(ADC12IFG & BIT3); - это некорректное использование процесссора. :) типа, чего он будет столько тиков в пустую ждать.

Верно. Глупый простой получается.

Надо работать с прерываниями. и вот вопрос -

Прерывания. как я понимаю, приходят после установки флагов ADC12IFGx, которые устанавливаются после заполнения ADCMEMx. Если режим повторно-последовательный, то прерывания будут после обработки каждого канала?

Количество прерываний зависит от установленных флагов разрешения прерываний в регистре ADC12IE. Если вы используете непрерывный режим преобразования по кольцу, то достаточно установить только один бит, соответствующий последнему каналу. И при возникновении прерывания одним чохом считывать все регистры ADC12MEMx. Одно преобразование ADC12 занимает 13 тактов ADC12CLK. Да плюс еще время сэмплирования каждого канала. Максимальное количество каналов преобразования у ADC12 - 16, время на считывание одного канала не более 5 тактов MCLK, так что если частота MCLK не слишком низкая (у вас вроде 8Мгц была?), то вполне можно успеть считать результаты всех преобразований до того, как обновится результат преобразования ADC самого первого в очереди. Если же не будете успевать (например, MCLK значительно ниже ADC12CLK), то можно два, три бита разрешения прерываний в ADC12IE установить, но с некоторым интерливом. Частоту вызова прерываний надо стараться делать поменьше и время нахождения в прерывания соответственно тоже.

И вот еще вопрос - index объявляю глобальным, массивы СV1[], CV2[] - тоже. В прерывании веду счетчик(index++), заполняю массивы. В теле проги, если index>=10, ADC12CTL0 &= ENC;

Отправляю сразу по заполнению себе на COM элементы массива - вроде все нормально, заполняются. А после остановки АЦП они пустые, и счетчик 0. В чем тут дело? :05:

Не совсем понял суть проблемы. Видимо опять на код нужно взглянуть. :cranky: Могу только предположить, что вы неправильно управляете остановом АЦП. Прочитайте внимательно в User's Manual как нужно корректно останавливать преобразование когда используется непрерывный режим преобразования последовательности каналов. Просто сбросить бит ENC в этом случае недостаточно. Останов произойдет, только после завершения всей последовательности преобразований

http://www.gaw.ru/html.cgi/txt/doc/micros/msp430/arh/17.htm

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Количество прерываний зависит от установленных флагов разрешения прерываний в регистре ADC12IE. Если вы используете непрерывный режим преобразования по кольцу, то достаточно установить только один бит, соответствующий последнему каналу.

Ага, ясно. Спасибо :)

 

Не совсем понял суть проблемы. Видимо опять на код нужно взглянуть. :cranky: Могу только предположить, что вы неправильно управляете остановом АЦП. Прочитайте внимательно в User's Manual как нужно корректно останавливать преобразование когда используется непрерывный режим преобразования последовательности каналов. Просто сбросить бит ENC в этом случае недостаточно. Останов произойдет, только после завершения всей последовательности преобразований

да читала, читала, и не один раз. Соображение, видимо, хромает. Как говорил Винни-Пух - "оно хорошее. Только почему-то хромает" :biggrin: Ну и пусть останов произойдет после завершения последовательности, этого и хочу- последний канал обработал и остановился. А прямо из прерывания остановить нельзя? А то как-то неудобно получается. Хочу считать только десять выборок. если вести счетчик в прерываниях, а потом if index>=10, то реально больше считает, пока проверит, пока остановится. понятно, что если массивы задать жестко [10], то остальные значения по фиг. Но зачем же лишнее время работать. Или тогда уж не повторно-последовательный режим делать, а просто однократный последовательный, и ровно десять раз запускать? тоже как-то странно.

Подскажите! :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и пусть останов произойдет после завершения последовательности, этого и хочу- последний канал обработал и остановился. А прямо из прерывания остановить нельзя?
Можно. Первой же командой в прерывании установите CONSEQ=0 и ENC=0. Преобразование остановится немедленно.

Или тогда уж не повторно-последовательный режим делать, а просто однократный последовательный, и ровно десять раз запускать? тоже как-то странно.
А режим однократной последовательности каналов вас не устраивает? Там правда битом ENC нужно "тогглить" после окончания каждой последовательности.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так. Ну вот, как-то не выходит ничего :(

Если в прерывании тормозить

#pragma vector=ADC_VECTOR

__interrupt void ADC12ISR (void)

{

CV1[cindex] = ADC12MEM3;

CV2[cindex] = ADC12MEM4;

ADC12CTL0 &= ENC;

index++;

if (index==9)

{ ADC12CTL1 &= CONSEQ_3;

ADC12CTL0 &= ENC;

 

}

}

То все равно долго тормозится, несмотря на сброс ENC. успевает прийти еще куча прерываний. Ну и, естественно, если в теле проги сбрасывать, то тоже долго останавливается. Как быть?

И, главное

if (flag==2)

{

ADC12CTL0 |= ADC12SC;

 

if (index>=9)

{

//АDC12CTL0 &= ENC;

flag=0;

CVx[cindex]=filter(CV1,10);

CVy[cindex]=filter(CV2,10);

index=0;

cindex++;

 

}

}

if (cindex>3)

cindex=0;

После старта АЦП до того, как успевает прийти 10-е прерывание, условие if (index>=9) уже проверяется, после остановки АЦП выход из последнего прерывания на строке if (cindex>3), потом - к началу проги, попадая сверху-вниз снова на строку if (flag==2), входит в if и запускает АЦП :05: То есть в условие if (index>=9) просто никогда не попадает.

Как быть? Подскажите темной непросвещенной женщине, как грамотно это написать :biggrin: - нужно набирать массив, останавливать АЦП и усреднять данные набранных массивов. Блин, с циклами while все было просто и понятно :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может так?

#pragma vector=ADC_VECTOR
{
if ( ! (index<9))  { //если уже насобирал скока надо
  ADC12CTL1 &= CONSEQ_3; //остановить
  ADC12CTL0 &= ENC;
  }
CV1[cindex] = ADC12MEM3; //последний байт то-же бы надо обработать
CV2[cindex] = ADC12MEM4;
ADC12CTL0 &= ENC;
index++; //станет на один больше, ну и пусть.
}

Что такое cindex++ и почему не в прерывании? Можно его заменить на index++ ?

.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все дело в том, что вы маски неверно накладываете. Команда

ADC12CTL1 &= CONSEQ_3;

сбрасывает все биты кроме CONSEQ0 и CONSEQ1, а нужно наоборот - сбросить только эти два бита. Вот так

ADC12CTL1 &= ~CONSEQ_3;

или вот так

ADC12CTL1 &= CONSEQ_3^0xFFFF;

Следовательно ваш обработчик прерывания будет выглядеть так.

#pragma vector=ADC_VECTOR
__interrupt void ADC12ISR (void)
{ CV1[cindex] = ADC12MEM3;
  CV2[cindex] = ADC12MEM4;
  if (index<9)
    index++;
  else    
  { ADC12CTL1 &= ~CONSEQ_3;
    ADC12CTL0 &= ~ENC;
    ADC12IFG = 0;
  }
}

Насчет остального не совсем понятно. Что за index, что за cindex и что за flag? Опишите реализованный вами алгоритм более полно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как быть? Подскажите темной непросвещенной женщине, как грамотно это написать :biggrin: - нужно набирать массив, останавливать АЦП и усреднять данные набранных массивов. Блин, с циклами while все было просто и понятно :biggrin:

 

Daria,

(хм, мою внучку так зовут :biggrin: ),

предлагаю идею алгоритма.

 

Главное правило - ничего не усложнять, и не делать сложных условий и ожиданий.

У MSP430 быстрый АЦП, хорошо работающий в режиме последовательного измерения всех каналов.

Инициализируется вот так (у меня тактируется от таймера B, в качестве опорного берется напряжение питния):

 

void ADCconfiguration(void)

//SMCLK = 7372800;  T=0,136 us
//tsample =100 us;  Nsample = 100/0,136 = 735
// SHT1_11 gives 768 cycles

{    ADC12CTL0=    SHT1_11+SHT0_11+ADC12ON; //    Vref off
    ADC12CTL1=    CONSEQ_3        //     repeat sequence of channels
                +ADC12SSEL_3    //     SMCLK
//                +ADC12DIV_7        //
                +SHS_3        //start when TimerB.Out1
                +SHP;        //    
    ADC12MCTL0=    INCH_0+SREF_0;        //    Vr+ = +AVcc, Vr- = AVss
    ADC12MCTL1=    INCH_1+SREF_0;
    ADC12MCTL2=    INCH_2+SREF_0;
    ADC12MCTL3=    INCH_3+SREF_0;
    ADC12MCTL4=    INCH_4+SREF_0;
    ADC12MCTL5=    INCH_5+SREF_0;
    ADC12MCTL6=    INCH_6+SREF_0;
    ADC12MCTL7=    INCH_7+SREF_0+EOS;
    ADC12CTL0|=    ENC;               //;start of ADC
};

 

После этой инициализации в регистрах ADC12MEM0...ADC12MEM7 результат последнего измерения соответствующего канала. Берите его в любой момент времени и используйте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

После этой инициализации в регистрах ADC12MEM0...ADC12MEM7 результат последнего измерения соответствующего канала. Берите его в любой момент времени и используйте.

Хм. Серьезно? :) Вот просто так и ничего больше не надо? :biggrin: Надо попробовать, большое спасибо. А прерывания АЦП запретить?

Но вот по поводу прерываний - я переделала прогу и получилось гораздо хуже, чем с циклами while :)

Вот код:

Настройка АЦП(еще раз, на всякий случай)

ADC12CTL0 = ADC12ON + SHT0_8+ MSC;

ADC12CTL1 = CSTARTADD0 + CSTARTADD1 + ADC12SSEL_1+ CONSEQ_1 + SHS_1 + SHP ;

ADC12MCTL3 = INCH_3;

ADC12MCTL4 = INCH_4 + EOS;

ADC12CTL1|= ENC;

После всех настроек

for(;;)

{send_int(azimut);

}

}

 

#pragma vector=TIMERA0_VECTOR

__interrupt void TimerA0(void)

{ _BIC_SR(GIE);

i++;

if (i >= 2000)

 

{ i = 0;

P1OUT = 0;

TACCR0 = 0;

 

ADC12CTL0 |= ENC;

Vs[0] = ADC12MEM3;

Vs[1] = ADC12MEM4;

ADC12CTL0 &= ENC;

TACCR0 = 2000;

}

if (i == 1)

{

TACCR0 = 0;

P1OUT = BIT5;

TACCR0 = 5000;

}

 

_BIS_SR(GIE);

}

 

#pragma vector=ADC_VECTOR

__interrupt void ADC12ISR (void)

{_BIC_SR(GIE);

if (P1OUT & BIT5)

{

ADC12CTL0 |= ENC;

 

while(ADC12IFG&BIT3);

Vr[0]= ADC12MEM3;

while(ADC12IFG&BIT4);

Vr[1] = ADC12MEM4;

 

ADC12CTL0 &= ~ENC;

 

 

offset[0] = (Vs[0] -Vr[0])/2;

offset[1] = (Vs[1] -Vr[1])/2;

 

Vx = Vr[0] - offset[0];

Vx = Vr[1] - offset[1];

 

float F[2];

azimut = calculation (Vx,Vy,F);

 

 

}

 

_BIC_SR(GIE);

}

Делается то же. что и всегда :) Вывод в единице, постоянно по переключению таймера снимаются показания с датчика Vr и ведется счетчик прерываний. после 2000-го прерывания вывод переключается в ноль и снимаются показания Vs. Вычисляются смещения и calculation - основное вычисление.

в чем проблема - получается, что постоянно сижу в прерываниях, работает все очень медленно и глючно :07: Индексы глобальные. но если попытаться перенести все эти if в цикл for(;;), то ничего не работает. Может оттого, что выход из прерывания происходит в то место, из которого в это прерывание ушли, и проверка условий просто постоянно "проскакивает". :( Короче попытка перенести любой из if в цикл for не работает, а так, как у меня - работает, но ужасно :05: Да, наверное не обязательно постоянно дергать битом ENC, но без этого тоже не работает :) беда, да и только :)

Вот то, что Вы, уважаемый Dog Pawlowa, сказали про АЦП - это оч хорошо, проблема только в том, что надо четко отличать, когда преобразование АЦп относится к короткому импульсу(P1OUT=0), а когда rк длинному (P1OUT= BIT5)/

Вот такой огромный вопрос :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Daria, извините за откровенность, но у вас какой-то бред получается :( Вы вообще понимаете суть и механизм работы прерываний? Я не знаю вашего возраста и семейного статуса, но надеюсь что "детская" ассоциация разъяснения сути прерываний будет вам понятна. :)

Представте себе, что вы - мама. Сидите на лавочке с подругой и беседуете. Рядом в песочнице ковыряется и бегает возде нее ваш малыш. И вот в произвольный момент времени малыш подбегает к вам и, прерывая ваш разговор с подругой, спрашивает: "мама, а правда, что море мокрое?" "Правда", отвечаете вы. Малыш, удовлетворенный ответом, убегает, а вы возвращаетесь к разговору с подругой. Через некоторое (опять недетерменированное время) малыш снова подбегает к вам и, прерывает разговор, очередным вопросом: "мама, а небо голубое?" "Конечно голубое, сынок. Подними голову и убедись сам", отвечаете вы. Малыш, задрав высоко голову, долго рассматривает проплывающие в голубом небе облака, а вы по-прежнему продолжаете отложенный разговор с подругой.

Такая аналогия вам понятна? ;)

Развиваю мысль дальше.

Запрет прерываний. "Сынок, перестань отвлекать маму вопросами. Дай маме с тетей спокойно поговорить."

Разрешение прерываний. "Сынок, у тебя там все нормально? Никто тебя не обижает? Ну если что-то случится сразу беги ко мне и скажи."

Тот исходник, что вы привели можно переложить на детский сюжет так.

Мама, вместо того, чтобы разговаривать с подругой, отпускает малыша в песочницу и внимательно следит, чтобы он не упал и не перепачкался. Как только ребенок падает, она, отряхнув его одежду, говорит: "Ну вот, смотри как ты перепачкался! Не ходи больше в песочницу, поиграй рядом с мамой, пока я с этой тётей побеседую". Усадив ребенка рядом, продолжает беседу.

А эта аналогия понятна?

Вы запускаете преобразование АЦП и, не выходя из прерывания, ждете окончания преобразования и установки бита готовности. Спрашивается ЗАЧЕМ? :07: Факт возникновения прерывания УЖЕ является свидетельством о том, что преобразование выполнено и в регистре ADC12MEMx находится готовое значение. После перехода по вектору прерывания вам нужно только считать это значение и при необходимости (пере)запустить или остановить цикл последующих преобразований АЦП. Ждать готовности преобразования, находясь прямо в прерывании нет никакой необходимости!

 

По структуре всей программы. У вас есть основной цикл, где вы что-то там вычисляете, усредняете и при необходимости передаете наружу. У вас есть таймер, по которому вычисляются временные интервалы и идет управление переключением выходного сигнала и работой АЦП. Работа таймера происходит асинхронно (НЕсинхронно) работе основного цикла. АЦП в принципе тоже работает асинхронно и основному циклу и таймеру, но запуск цикла преобразований АЦП происходит синхронно с таймером. Поэтому запуск АЦП после переключения выходного сигнала должен производится из таймерного прерывания. А останов уже в прерывании АЦП. Обмен между прерываниями и основным циклом можно реализовать посредством семафоров (флагов). В прерывании устанавливается семафор, сигнализирующий. например, о том, что цикл измерений был завершен. В основном цикле этот семафор постоянно опрашивается и как только обнаруживается, что он установлен, результаты измерения обрабатываются, а семафор завершения цикла измерений сбрасывается. Таким образом производится взаимодействие асинхронных процессов. Ну насчет буферов, как средства синхронизации потоков данных для асинхронных процессов, по-моему вы уже знаете.

 

И еще просьба. Оформляйте, пожалуйста, ваш текст исходников в теги code. Это такая решеточка code.gif над полем редактирования сообщения. Так сохраняются все отступы и код получается более удобным для восприятия.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Rezident, циклы while совершенно случайно оказались в прерывании! Просто копировала и ... дело было вечером... :05: Так что совершенно зря разразились такой тирадой :) Впрочем, не зря, долго еще могла не заметить. А история про маленького мальчика - супер. :biggrin: Но - запрещение прерываний в прерывании таймера и АЦП делаю осознанно :) , при переключении вывода должен пройти переходной процесс, прежде чем можно разрешать преобразование АЦП. Так что переключение вывода и старт АЦП должны совершенно точно делаться в разные моменты времени. Такие дела. А вообще - как всегда, спасибо :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но - запрещение прерываний в прерывании таймера и АЦП делаю осознанно :) , при переключении вывода должен пройти переходной процесс, прежде чем можно разрешать преобразование АЦП.
Если вы еще раз заглянете в User's Guide и внимательно прочитаете главу 2.2.3 Interrupt Processing -> Interrupt Acceptance, то там пункт №6 гласит

6) The SR is cleared with the exception of SCG0, which is left unchanged.

This terminates any low-power mode. Because the GIE bit is cleared,

further interrupts are disabled.

Бит GIE находится к статусном регистре SR, который при переходе по вектору прерывания очищается (за исключением бита SCG0). Т.е. переход на программу обработки прерывания запрещает все маскируемые прерывания автоматически. Поэтому дополнительно запрещать все прерывания в обработчике прерывания нет необходимости. Находясь в прерывании можно разрешить прерывания, если вы контролируете размер стека и готовы к ситуации с вложенными прерываниями.

Так что переключение вывода и старт АЦП должны совершенно точно делаться в разные моменты времени. Такие дела.
Вы можете запустить преобразование АЦП синхронно с переключением выхода, но выкинуть из расчета результат первого преобразования, используя время, затраченное на это преобразование, как временнУю паузу. Либо использовать этот же таймер (CCR2, например) для генерации временнОй отметки запуска преобразования АЦП. Ожидать в прерывании возможности запуска АЦП имеет смысл только, если требуемая пауза совсем небольшая, не более полусотни тактов MCLK. ИМХО.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...