Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: задержка aka Delay
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
CAHTA_1939
начал программировать жки ака MT-12864J. и столкнулся с необходимостью задержки на несколько нс.
for'ом уже не катит. пришла в голову мыслю использования прерывания, но вот как... хз.
нашел несколько примеров, но мне они показались странными...

напишите, кто как реализует задержку на несколько нс (сек)?
Dog Pawlowa
Цитата(CAHTA_1939 @ Aug 18 2007, 21:08) *
напишите, кто как реализует задержку на несколько нс (сек)?

Так несколько нс или несколько с?
CAHTA_1939
Цитата(Dog Pawlowa @ Aug 19 2007, 00:31) *
Так несколько нс или несколько с?



нс =)
Dog Pawlowa
Цитата(CAHTA_1939 @ Aug 18 2007, 23:42) *
нс =)

Несколько нс (наносекунд) как-то сами образуются, там не только прерывания не нужны, там вообще ничего не нужно. smile.gif
CAHTA_1939
Цитата(Dog Pawlowa @ Aug 19 2007, 00:52) *
Несколько нс (наносекунд) как-то сами образуются, там не только прерывания не нужны, там вообще ничего не нужно. smile.gif



это если нужно 10нс...
мне нужно 140нс - 450нс - 1000нс
Dog Pawlowa
Цитата(CAHTA_1939 @ Aug 18 2007, 23:57) *
это если нужно 10нс...
мне нужно 140нс - 450нс - 1000нс

У меня интервал между прерываниями по таймеру составляет 500 нс, и действительно делаю задержку с такой точностью с помощью прерывания от таймера. То есть 450 нс = Delay(1), 1000нс=Delay(2).
Задержку меньше 500 нс реализую с помощью встроенной в компилятор функции.
CAHTA_1939
а примерчик можешь дать?
Dog Pawlowa
Цитата(CAHTA_1939 @ Aug 19 2007, 00:55) *
а примерчик можешь дать?

Де жа вю...

//******* DELAY SUPPORT *******//
__no_init int delay_count;

void StartDelay(int t)
{ delay_count=t; }

void Delay(int t)
{ StartDelay(t); while(delay_count>0) CheckTimeAndResetWDT() ; }

void BackgroundService()
{ // Delay service
if (delay_count) delay_count--;
}

void TimerBConfiguration(void)
{ __bic_SR_register OSCOFF;
TBCTL = TBSSEL_2 + TBCLR + MC_0; // Timer B counts SMCLK clocks continuos
TBCCTL0 = CCIE; // module 0 configuration
TBCCR0 = MaxB; // period of timer overflow
TBCTL |= MC_1; // timer start to "UP" mode
};

#pragma vector=TIMERB0_VECTOR
__interrupt void TimerB_modul0()
{ __enable_interrupt();
ResetWDT1;
BackgroundService();
}
CAHTA_1939
эм... чтото не воткну =)
выложи плиз все ф-ции. плиз
rezident
Господа, вы обалдели что ли? 07.gif Судя по тому, что тема в разделе MSP430, то вопрос применительно к нему. Так про какие наносекунды гутарим-то? cranky.gif Ядро MSP430 кроме серии MSP430F2xxx может тактироваться частотой максимум 8МГц. Т.е. период клока - 125нс. Вход в прерывание - 6 тактов (>=750нс), выход из прерывания 5 тактов (>=625нс). О каком формировании интервала меньше 1,2мкс с помощью прерывания может вообще идти речь? Такие задержки на MSP430 только NOP-ами формируются! 1111493779.gif
P.S. на такт ошибся с прерываниями. Исправил.
CAHTA_1939
вот блин... то есть задержки нужно мутить NOD'ами и осциллографом?
rezident
Цитата(CAHTA_1939 @ Aug 19 2007, 05:06) *
вот блин... то есть задержки нужно мутить NOD'ами и осциллографом?

Можно и без осциллографа обойтись. Количество тактов за которое выполняется каждая команда в User's Manual описано. команда NOP за 1 такт выполняется. Если тактовая 8МГц, то два NOP дадут задержку 250нс, 4 NOP - 500нс. Формировать задержку с помощью прерываний имеет смысл только при временах в десятки-сотни мкс или больше.
CAHTA_1939
ну лан, с "нс" я понял , а что делать с "мс" ? как их мутить? нужна задержка от 100мс до 1000мс с шагом примерно 20-50мс

помогите плиз
VAI
Цитата
как их мутить? нужна задержка от 100мс до 1000мс с шагом примерно 20-50мс

У меня тикает прерывание каждую милисекунду и есть глобальная переменная
Код
volatile unsigned long tick_ms;        // милисекундные тики, хватит на 49 дней непрерывной работы прибора

тогда милисекундная задержка выглядит так
Код
void delay( unsigned long del )
{
  for ( del += tick_ms; del > tick_ms; )
;
}

получается от 1мс до 49 дней, с шагом 1 мс
rezident
Цитата(VAI @ Aug 19 2007, 19:48) *
У меня тикает прерывание каждую милисекунду и есть глобальная переменная
Код
volatile unsigned long tick_ms;        // милисекундные тики, хватит на 49 дней непрерывной работы прибора

тогда милисекундная задержка выглядит так
Код
void delay( unsigned long del )
{
  for ( del += tick_ms; del > tick_ms; )
;
}

получается от 1мс до 49 дней, с шагом 1 мс

+1. Только у меня в зависимости от задачи тикает с периодом от 1мс до 32мс. Но отсчет времени все равно в мс идет. Просто инкремент тиков на величину периода происходит.
Код
#define SYSTEM_TICK_MS 10UL  //период системных тиков 10мс

tick_ms+=SYSTEM_TICK_MS; //инкремент счетчика системных тиков

Сформировать задержку очень просто
Код
unsigned long tmp=tick_ms;
while ((tick_ms-tmp)<5000); //задержка на 5 сек

При таком способе даже момент переполнения счетчика tick_ms не влияет на отсчет временного интервала, т.к. в цикле ожидания вычитание беззнаковых величин происходит.
Dog Pawlowa
Цитата(rezident @ Aug 19 2007, 01:57) *
Господа, вы обалдели что ли? 07.gif

ни фига себе пьяный был sad.gif Нс с мкс перепутал 05.gif Пойду лучше, а то уже пиво открыто...
Господа, делать забор на даче так приятно... Это не микроконтроллеры программировать smile.gif

Аффтар, те фукнции, что не описаны, можно считать пустыми.
CAHTA_1939
а можно поподробней. как настроить тикание =) ибо я чтото представить не могу что и как...
имею ввиду прерывание
помогите плиз +)
rezident
Для кварца 8Мгц используемого в качестве источника тактирования SMCLK

Код
#define SYSTEM_TICK_MS 1UL  //период системного тика

unsigned long tick_ms;  //счетчик системных тиков

//===================================//
// функция инициализации TimerA      //
//===================================//
void initTimerA(void) //инициализация таймераА на период счета 1мс
{ TACTL=TASSEL_2 | TACLR; //TACLK=SMCLK
  TACCR0=7999; //период (7999+1)/8000000=1мс
  TACCTL0=CCIE; //разрешим прерывание от регистра сравнения CCR0
  TACTL|=MC_1;  //запускаем в режиме счета CountUp
}
//===================================//
// обработчик прерывания CCR0 TimerA //
//===================================//
#pragma vector=TIMERA0_VECTOR
#pragma type_attribute=__interrupt
void TIMERA0_ISR(void)
{ tick_ms += SYSTEM_TICK_MS; //инкремент переменной системных тиков на заданную величину
}
//===================================//
// обработчик прерывания ошибки      //
// осциллятора                       //
//===================================//
#pragma vector=NMI_VECTOR
#pragma type_attribute=__interrupt
void osc_fault(void)
{ BCSCTL2=SELM_0|DIVM_0|DIVS_0;  //MCLK=DCO, SMCLK=DCO
  DCOCTL=DCO2|DCO1|DCO0;
  BCSCTL1=DIVA_0|RSEL2|RSEL1|RSEL0;  //ACLK=LFXT
  while ((IFG1&OFIFG)!=0) IFG1&=~OFIFG;   //Ожидаем стабилиз. колебаний кварца XT2
  BCSCTL2=SELM_0|DIVM_0|DIVS_0|SELS;  //MCLK=DCO, SMCLK=XT2/1=8МГц
  IE1|=OFIE;                  //разр. прерывание от детектора ошибки
}

//===================================//
// основной суперцикл программы      //
//===================================//
#pragma type_attribute=__task
void main(void)
{ WDTCTL=WDTPW+WDTHOLD; //остановим WDTimer
  IFG1|=OFIFG; //принудительно установим флаг ошибки осциллятора
  IE1|=OFIE;  //разрешим прерывание от детектора ошибки осциллятора
  initTimerA(); //вызов функции инициализации TimerA
//
// тут ваш код
//
}
CAHTA_1939
ппц как мудрено. а попроше нет ничего? я же тока начинаю осваивать =)
rezident
Куда уж проще-то? 07.gif И так ничего лишнего. Только main, функция инициализации таймера, функция инициализации источников тактирования (совмещенная с обработчиком прерывания от детектора ошибки осциллятора) и обработчик прерывания от таймера.
aag
По идее можно код обработки прерывания ошибки кварца выкинуть.

Вообще это критично или нет? Я то обычно без него обходился, но правильно ли это?
rezident
Цитата(aag @ Aug 24 2007, 12:38) *
По идее можно код обработки прерывания ошибки кварца выкинуть.

Вообще это критично или нет? Я то обычно без него обходился, но правильно ли это?

Выкинуть-то можно, но только в случае если какая-нибудь помеха собьет генерацию, то MCLK перейдет на тактирование от DCO (и скорее всего с понижением частоты тактирования, если кварц на частоту выше 5,5МГц стоит), а SMCLK не будет вообще, если его источником был кварцевый генератор.
FREEKER
Вот очень элементарный пример задержки smile.gif
Функция Delay() - небольшая задержка в 550мкс и функция Big_Delay() - несколько секунд, а мож и больше smile.gif зависит от Delay() также. При кварце 8MHz.

Код
void Delay(void)
{
unsigned int t;
for (t=730; t>0; t--);          //(4 такта For)
}

void Big_Delay(void)
{
unsigned int y;
for (y=5000; y>0; y--)
Delay();
}


Но с таймером мне тоже не всё понятно. Разъясните. Как сделать следующее. Допустим тикает таймер. Нужно остановить его и замерить время по приходу на порт P2.2 логической "1", т.е. по перепаду с 0 на 1. или наоборот.
Flag = P2IFG & 0x04; //Устанавливается флаг при перепаде 1>0
Либо замерить время единичного импулься. т.е. по перепадам 0-1 и 1-0.
Можно пример!? На примере понятней, особенно с коментами.
beer.gif
Rezident. Вам отдельная благодарность.
rezident
Цитата(FREEKER @ Sep 13 2007, 01:25) *
Но с таймером мне тоже не всё понятно. Разъясните. Как сделать следующее. Допустим тикает таймер. Нужно остановить его и замерить время по приходу на порт P2.2 логической "1", т.е. по перепаду с 0 на 1. или наоборот.

Ну для этого таймер останавливать не обязательно. Используйте функцию захвата таймера.
Код
#define CAP_TICKOVFCNTR 0x00010000

volatile unsigned long smplTime, smplOvfCntr;

//================================================//
// Инициализация таймера захвата входной частоты  //
//------------------------------------------------//
//аргументы :нет                                  //
//возвращает:нет                                  //
//================================================//
void initTimerCAP(void)
{ TACTL=TASSEL_2|ID_0|TAIE|TACLR;                 //TACLK=SMCLK/1, прерыв. от переполнения
                                                  //разрешено
  TACCR0=0;                                       //результат захвата
  TACCTL0=CM_1|CCIS_1|CAP;                        //режим захвата по нараст. фронту
                                                  //вход захвата CCI0B (P2.2)
  P2SEL|=BIT2;                                    //P2.2 - CCI0B
  P2DIR&=~BIT2;                                   //P2.2 - вход
  TACTL|=MC_2;                                    //пуск в режиме Continous
}
//================================================//
// Запуск таймера сэмплирования                   //
//------------------------------------------------//
//аргументы :нет                                  //
//возвращает:текущую метку времени                //
//================================================//
unsigned long fStartTimerCap(void)
{ unsigned int buf;
  TACCTL0=CM_3|CCIS_3|CAP;                        //режим захвата по любому фронту
                                                  //вход захвата=VCC
  TACCTL0^=CCIS0;                                 //формируем программно перепад
  buf=TACCR0;                                     //получаем текущее значение TAR
  TACCTL0=CM_1|CCIS_1|CAP;                        //режим захвата по нараст. фронту
  smplTime=smplOvfCntr+buf;                       //получим текущую временную метку
  TACCTL0|=CCIE;                                  //разрешим прерывание при захвате
  return(smplTime);
}
//================================================//
// Обработчик прерывания таймера сэмплирования    //
//------------------------------------------------//
//аргументы :нет                                  //
//возвращает:нет                                  //
//================================================//
#pragma vector=TIMERA0_VECTOR
#pragma type_attribute=__interrupt
void TimerA0_ISR(void)
{ unsigned int buf;
  buf=TACCTL0;                                    //временная метка захвата
  smplTime=smplOvfCntr+buf;                       //просуммирует с таймером переполнений
  TACCTL0&=~CCIE;                                 //сбросим разреш. прерывания захвата
}
//================================================//
// Обработчик прерывания переполнений таймера     //
//------------------------------------------------//
//аргументы :нет                                  //
//возвращает:нет                                  //
//================================================//
#pragma vector=TIMERA1_VECTOR
#pragma type_attribute=__interrupt
void TimerA1_ISR(void)
{ switch(TAIV)
  { default:
    case 0x02:
    case 0x04:
      break;
    case 0x0A:
      smplOvfCntr+=CAP_TICKOVFCNTR;               //инкремент счетчика переполнений
      break;
  }
}

Таймер в моем примере считает постоянно на максимальной частоте SMCLK c переполнением (от 0 до 0xFFFF и дальше). Чтобы расширить измеряемый временной интервал введена 32-битная переменная smplTime, которая суммируется с 32-битным счетчиком переполнений smplOvfCntr. Максимальный временной интервал измеряемый при этом может быть вычислен как число 0xFFFFFFFF деленное на значение частоты SMCLK. Для SMCLK=8MHz этот интервал составляет почти 9 минут.
initTimerCAP - функция начальной инициализации ТаймераА
fStartTimerCap - функция запуска периода ожидания срабатывания ловушки перехода 0->1 на входе P2.2. Она возвращает начальную метку времени. После ее запуска нужно ожидать сброса бита разрешения прерывания CCIE в регистре TACCTL0. Сброс бита будет означать, что ловушка сработала и в переменной smplTime мы имеет соответствующую метку времени. Разница между текущим значением smplTime и значением которая вернула функция fStartTimerCap будет искомым интервалом ожидания от момента запуска до срабатывания ловушки. Для пересчета этой величины в привычные секунды smplTime нужно поделить на значение тактирующей частоты SMCLK.
P.S. еще пояснение. "Хитрая" манипуляция в функции fStartTimerCap
Код
  TACCTL0=CM_3|CCIS_3|CAP;
  TACCTL0^=CCIS0;

обсуловлена тем, что в общем случае MCLK и SMCLK могут быть асинхронными. Например, MCLK от DCO тактируется, а SMCLK от кварцевого генератора. Если при таких условиях попытаться впрямую считать значение TAR без останова таймера, то можно получить неверное значение.
a1ex
Вот я задержку пишу так:

void delay(unsigned int a)
{unsigned int k;
for(k=0;k!=a;++k)
{
}

Ну и соответсвенно, чтобы точно задержку задать, приходиться смотреть осцилографом, и все время значение а подгонять.. Может кто знает как вычислить сколько такой цикл занимает тактов?
Пример: а =10000;(MCLK) DCO = ~800kHz;
Сергей Борщ
Цитата(a1ex @ Dec 3 2007, 18:47) *
Может кто знает как вычислить сколько такой цикл занимает тактов?
Во-первых объявлять k как volatile (иначе при высоком уровне оптимизации цикл может быть выкинут вообще). Во-вторых сгенерить листинт, посмотреть, из каких команд складывается цикл, в даташите посмотреть количество тактов, за которое выполняется каждая команда, дальше простая арифметика.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.