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

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

:) Здравствуйте. Кто читал предыдущую мою тему "MSP430 - вопросы от чайника", тот поймет - это снова я :biggrin: Тему закрыли, слишком долго висела. А вопрсов все больше. :)

Если кому-то вдруг окажется не влом разбираться, то

Вот кусок проги:

int flag;//глобальные переменные

int cindex;

испульзуемые функции(write_flash - пишет число во flash, read_flash - считывает)

void write_flash(float* value, float *addr)

{ while(FCTL1 & BUSY);

_BIC_SR(GIE);

FCTL1 = FWKEY + ERASE;

FCTL3 = FWKEY;

*addr = 0;

 

while(FCTL1 & BUSY);

FCTL1 = FWKEY + WRT; for (int i=0;i<=3;i++)

{ *addr = value;

addr++;

}

 

_BIS_SR(GIE);

while(FCTL1 & BUSY);

FCTL1 = FWKEY;

FCTL3 = FWKEY + LOCK;

}

 

void read_flash(float* addr, float* pfO)

{

for (int i=0;i<=3;i++)

{ pfO=*addr;

addr++;

}

}

Чего хочу сделать - Если присылаю 0, то должны считаться два показания с выводов P6.3 и P6.4, присылается 0хАА - т.е. "считалось", записываются первые элементы двух массивоы данных.

Когда набирается по четыре элемента, индекс сбрасывается

Если присылаю 0xFF, то должна выполнится функция calibrovka_hmc, если она выполняется неверно, то присылается 0хСС, иначе из flash считывается и присылается вычисленная с помощью этой функции константа.

Внутри функции main

ADC12CTL0 = ADC12ON + REFON + SHT0_8; //настройка АЦП

ADC12CTL1 = CSTARTADD0 + CSTARTADD1 + ADC12SSEL_1+ CONSEQ_1;

ADC12MCTL3 = INCH_3;

ADC12MCTL4 = INCH_4 + EOS;

 

float temp[4];

flag=0;

cindex=0;

for(;;)

{

for(delay = 0; delay <20000; delay++);

if( flag==0 )

{send_int(0x0);

}

if( flag==1 )

{

 

if (calibrovka_hmc(CVx, CVy, temp)==0)//calibrovka_hmc - имеет параметрами два массива и вычисляет четыре константы(нужные для калибровки устройства)

 

{

send_int(0xCC);

flag=0;

}

else

{

float pfO[4];

read_flash((float*)0x1000,pfO);

r=(int)(pfO[0]+0.5);

send_int®;

flag=0;

}

 

flag=4;

}

 

if (flag==2)

{

ADC12CTL0 |=ADC12SC + ENC; CVx[cindex] = ADC12MEM3; CVy[cindex] = ADC12MEM4;

ADC12CTL0 &= ENC;

cindex++;

send_int(0xAA);

flag=0;

}

 

if (cindex>3)

cindex=0;

}

}

#pragma vector=UART0RX_VECTOR

__interrupt void usart0_rx ( void)

{

if( RXBUF0==0xFF)

flag = 1;

if (RXBUF0==0x0)

flag = 2;

}

В ЧЕМ ПРОБЛЕМА:

Перед выполнением калибровки присылаю элементы массива, полученного при считывании показаний с выводов, - оказывается, что в массив записываются по два-три раза одно значение, хотя этого не может быть. Соответственно, из-за этого не работает и все остальное :crying:

Может, неправильно настроен АЦП? Или в чем может быть дело?

И, если кому-то вдруг не влом разбираться - функции записи во flash и чтения flash - можно ли сделать как-то поумнее?

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


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

Некоторое (продолжительное) время не заглядывал в форум, а когда заглянул оказалось, что вашу тему прикрыли. :cranky:

По поводу Flash.

Проверять готовность к записи во Flash (бит BUSY) при выполнении программы записи прямо из Flash нет необходимости. Вот такая вот продвинутая технология у MSP430 :) Почему так, объяснять еще раз не буду. Читайте внимательно User's Manual. Проверка готовности нужна только в том случае, если ваша функция записи исполняется из ОЗУ (SRAM), а не из Flash.

Запись во внутреннюю Flash MSP430 может производится 16-и разрядными словами и/или байтами. float имеет размерность 32 бита, т.е. 2 слова/4 байта. Так что, для записи переменной float нужно как минимум две команды записи 16-и битных слов или четыре команды записи байта. У вас указатели value и addr указывают на тип float. Поэтому команды типа addr++; увеличивают значение такого указателя на 4 байта и во Flash пишется какая-то фигня. Пишите тогда уж пословно, делая явное приведение типа к 16-и битному целому.

for (int i=0; i<(4*2); i++) // здесь я явно выделил удвоение числа элементов записи
((unsigned short *)addr)[i] = ((unsigned short *)value)[i];

Назначение функции чтения из Flash я вообще не очень понимаю. У MSP430 фон-Неймановская архитектура с общим адресным пространством для команд и данных. Встроенного EEPROM тоже нет. Так что выделять копирование в отдельную функцию (если только она не вызывается несколько раз) я не вижу смысла. Да и ее тоже можно оптимизировать на одну команду (выкинув addr++; ), если в теле цикла писать

pfO[i]=addr[i];

Насчет всего остального.

Может у меня сложилось неверное впечатление, но похоже вы не осознаете, что такое синхронные и асинхронные события. Просто не владеете таким уровнем абстракций. Попробую объяснить на бытовом примере.

Вы когда-нибудь видели как подъемный кран работает? Внизу на земле стоит стропальщик, который крепит к крюку крана груз, а наверху в кабине крана сидит крановщик, который управляет движением крюка, стрелы и платформы крана. Причем крановщик не сам-по-себе управляет, а подчиняется управляющим командам стропальщика. Только после того как груз

- прицеплен,

- надежность крепления проверена,

- стропальщик подал команду "вира!"

крановщик включает двигатель, приводящий к движению крюка и стрелы крана. До подачи команды "вира!" крановщик просто ждет готовности груза.

У вас в системе присутствуют асинхронные процессы (измерение АЦП, прием/передача UART), а вы работаете с ними как Бог на душу положит. :( Стропальщик убил бы просто такого крановщика, если бы остался жив после его несанкционированных действий. ;)

Эта иллюстрация синхронных действий. Для иллюстрации же асинхронных процессов к картине работы башенного крана нужно добавить несколько КАМАЗов с кирпичем, которые приезжают на стройку асинхронно работе крана, когда у них получится, и сваливают кирпич в общую кучу. Которую потом стропальщик с крановщиком общими синхронными действиями перемещают на строящийся уровень дома :)

Эта моя пространная тирада относится в частности к строке

ADC12CTL0 |=ADC12SC + ENC; CVx[cindex] = ADC12MEM3; CVy[cindex] = ADC12MEM4;

Где вы запускаете преобразование АЦП и тут же, не дожидаясь окончания выполнения преобразования, считываете результаты оцифровки непонятно чего. Раз вы не используете прерывание от АЦП, ну подождите для приличия установки флага готовности что ли :laughing:

ADC12CTL0 |=ADC12SC|ENC;
while ((ADC12IFG&(1<<3))!=0);
CVx[cindex]=ADCMEM3;
while ((ADC12IFG&(1<<4))!=0);
CVy[cindex] = ADC12MEM4;

То же самое относится к модификации флага в прерывании UART. Если вы посылаете последовательности из двух команд 0xFF и 0x00, и снова 0xFF и 0x00, но не успели считать значение какого-то флага, то его значение потеряется и вы получите дублирование команды 0xFF или 0x00. Потому, что прием через UART асинхронен выполнению основного тела программы, где эти флаги анализируются. Для того чтобы команды, принятые через UART не терялись, их нужно буферизировать, т.е. складывать в некий массив из которого в основном теле программы они будут извлекаться.

Буферы бывают линейные (типа FIFO) и циклические. По-моему для вашего случая больше подходит циклический буфер. Пример.

#define UART_MAXBUFSIZE 8  //здесь задается размер выделяемого UART буфера
struct cbuf
{ unsigned char *pBuf;  //указатель на начало буфера
  unsigned int rIdx;   //индекс для чтения элемента из буфера
  unsigned int wIdx;  //индекс для записи элемента в буфер
  unsigned int cntr;  //счетчик общего количества элементов в буфере, чтобы знать о его заполнении
} cbuf;
unsigned char uartBuf[UART_MAXBUFSIZE]; // собственно сам буфер UART

 

где-то в начале программы нужно инициализировать структуру этого буфера

...
cbuf.pBuf=&uartBuf[0];
cbuf.rIdx=0;
cbuf.wIdx=0;
cbuf.cntr=0;
...

В прерывании от приемника UART запись в буфер

#pragma vector=UART0RX_VECTOR
__interrupt void usart0_rx ( void)
{ if (cbuf.cntr<UART_MAXBUFSIZE)
  { cbuf.pBuf[cbuf.wIdx]=U0RXBUF;
    if (cbuf.wIdx<(UART_MAXBUFSIZE-1))
      cbuf.wIdx++;
    else
      cbuf.wIdx=0;
    cbuf.cntr++;
  }
}

В теле программы считывание из буфера. Для атомарности доступа к буферу на время доступа к нему временно запрещаем прерывание от приемника UART

...
if (cbuf.cntr>0)
{ IE1&=~URXIE0;
  uCmd=cbuf.pBuf[cbuf.rIdx];
  cBuf.cntr--;
  IE1|=URXIE0;
  if (cbuf.rIdx<(UART_MAXBUFSIZE-1))
    cbuf.rIdx++;
  else
    cbuf.rIdx=0;
}
// дальше значение переменной uCmd можно использовать как текущую команду, полученную через UART
...

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


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

Ага, все же заглянули :) спасибо за комментарии и критику, все подробно и пространно. :)

По поводу АЦП я уже сама доперла, установку флагов жду, режим использую последовательный, и бит MSC ставлю :biggrin: Теперь работает. По поводу read_flash - ну да, но это так, для понта отдельная функция :)

А по поводу write_flash - хм. но она работает. я проверяла, во flash пишется не фигня :) может это мне просто везет? :biggrin:

Про буфер - спасибо, попробую.

Вообще спасибо, что не забыли :)

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


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

А по поводу write_flash - хм. но она работает. я проверяла, во flash пишется не фигня :) может это мне просто везет?

 

Пока везет. В данном случае строка:

 

*addr = value;

скорее всего, транслируется компилятором как

 

MOV.W @R12+, 0(R13)

MOV.W @R12+, 2(R13)

 

т.е. реально происходит именно последовательная запись двух слов по очереди, но никто не гарантирует, что это будет всегда, при любых настройках. Причем там лежат еще одни незаметные грабли, на которые легко наступить. Точно также строка

 

*addr = 0;

 

транслируется в

 

MOV.W #0x0, 0(R13)

MOV.W #0x0, 2(R13)

 

что два раза подряд вызовет стирание сегмента, причем без пауз между ними. В лучшем случае это вызовет удвоенный износ флешки, в худшем - неизвестно (поскольку до подобных действий наверняка еще никто не додумался :) )

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


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

*addr = 0;

 

транслируется в

 

MOV.W #0x0, 0(R13)

MOV.W #0x0, 2(R13)

 

что два раза подряд вызовет стирание сегмента, причем без пауз между ними. В лучшем случае это вызовет удвоенный износ флешки, в худшем - неизвестно (поскольку до подобных действий наверняка еще никто не додумался :) )

:( а как тогда написать? Такая строка была в примере, который я скачала с ИАРовского сайта, - "фиктивная запись". Как тогда написать фиктивную запись ?:)

И вот еще ВОПРОС- понимаю, что, наверное, глупый, но -

Когда гружу прогу с помощью IAR Kickstart - работает нормально, считает четко все - я проверяла. Но так как код уже превышает 4кБ, гружу с помощью полной версии - на COM приходит полная ересь. С чем это может быть связано? Код такой же - один в один.

Я думала, может дело в доступе к библиотекам, но не ругается же на код, на #include <math.h>, работает, считает, пишет... только фигню :05:

Вот. Не ругайтесь! - уж такая я глупая :biggrin:

Вот сама функция, она принимает два массива и на их основании вычисляет и пишет во flash 4 четыре константы

int calibrovka_hmc( float* V1, float* V2, float* calibr)

{

 

float x[4], a[3][3],d[4];

float Ox,k,Oy,kx,ky;

for (int i=0;i<4;i++)

{ a[0]=2*(V1-V1[i+1]);

a[1]=2*(V2-V2[i+1]);

a[2]= -((V2)*(V2)-(V2[i+1])*(V2[i+1]));

a[3]= ((V1)*(V1)-(V1[i+1])*(V1[i+1]));

d=((V1)*(V1)-(V1[i+1])*(V1[i+1]));

}

 

if (gauss(x,a,d,3)==0) return 0;

else

{

Ox=x[0];

k=x[2];

if (x[2]!=0) Oy=x[1]/x[2];

else Oy=0;

}

kx=sqrt((V1[3]-Ox)*(V1[3]-Ox)+k*(V2[3]-Oy)*(V2[3]-Oy));

ky=sqrt((kx)*(kx)/k);

calibr[0]=Ox;

calibr[1]=Oy;

calibr[2]=kx;

calibr[3]=ky;

write_flash( calibr, (float*) 0x1080);

return 1;

}

 

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

Такие вопросы :laughing:

Изменено пользователем Daria

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


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

:( а как тогда написать? Такая строка была в примере, который я скачала с ИАРовского сайта, - "фиктивная запись". Как тогда написать фиктивную запись ?:)
Конечно фиктивная запись, вот только в примере скорее всего был указатель другого типа (unsigned int или unsigned char). Как поступить в данной ситуации я вам уже выше подсказал - используйте явное приведение типа. Раз у вас указатель на float, то при фиктивной записи преобразуйте его к указателю на unsigned int.

*((unsigned int *)addr)=0;

И вот еще ВОПРОС- понимаю, что, наверное, глупый, но -

Когда гружу прогу с помощью IAR Kickstart - работает нормально, считает четко все - я проверяла. Но так как код уже превышает 4кБ, гружу с помощью полной версии - на COM приходит полная ересь. С чем это может быть связано? Код такой же - один в один.

Версии IAR одинаковы? Настройки проекта одинаковы? И вообще, спрашивается зачем использовать KickStart при наличии полной версии? :07: Если вы не пользуетесь дебаггером, то для загрузки прошивки в кристалл использовать IAR вообще не обязательно. Пользуйтесь специальными программами. MSPFET Programmer от Kurt-а или FET-Pro430 Lite от Elprotronic или вот тут же в форуме zltigo свою утилиту AT430 предлагает.

А вообще правильность работы алгоритма программы можно проверить в симуляторе. Тем более, если у вас есть в наличии результаты работы алгоритма по известным данным.

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


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

И версии, и настройки. А кикстарт - потому что сначала был только он :)

FET-Pro430 Lite у меня есть. но не очень-то удобно компилироваться, а потом грузить через нее - проще и быстрее же все делать в ИАРе :)

Дебаггером, кстати, пользуюсь, но проверить алгоритм не получается - он не показывает текущие значения моих переменных, только регистры контроллера :05: - то же касается симулятора

 

Кстати, если настройка АЦП

ADC12CTL0 = ADC12ON +REFON + SHT0_8+MSC;

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

ADC12MCTL3 = INCH_3;

ADC12MCTL4 = INCH_4 + EOS;

а потом

ADC12CTL0 |=ADC12SC;

ADC12CTL0 |=ENC;

while(ADC12IFG & BIT3);

CVx[cindex] = ADC12MEM3;

while(ADC12IFG & BIT4);

CVy[cindex] = ADC12MEM4;

ADC12CTL0 &= ENC;

так нормально? Или опять грузовики с кирпичами понаехали? :biggrin:

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


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

И версии, и настройки. А кикстарт - потому что сначала был только он :)

FET-Pro430 Lite у меня есть. но не очень-то удобно компилироваться, а потом грузить через нее - проще и быстрее же все делать в ИАРе :)

Не проще. C-Cpy грузит "дебажную" версию прошивки, а в реальное устройство вы будете компилировать другую версию, без дебаговских примочек. Не нравится FET-Pro430, используйте программатор Курта. Её (программу) кстати можно интегрировать в IAR, т.к. в ней имеется поддержка командной строки. Tools->Configure Tools->New обзываете ее и заполняете необходимые поля параметрами запуска программы MSPFET Programmer. Только для нее нужно использовать Release-ную настройку с форматом выходного файла TI-TXT или HEX.

Дебаггером, кстати, пользуюсь, но проверить алгоритм не получается - он не показывает текущие значения моих переменных, только регистры контроллера :05: - то же касается симулятора
Ну здрасте! А ручками в окно View->Watch имя интересуемых переменных или структур забить лень что ли? Или окно View->Locals открыть и наблюдать за автоматическими переменными.

Кстати, если настройка АЦП

ADC12CTL0 = ADC12ON +REFON + SHT0_8+MSC;

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

ADC12MCTL3 = INCH_3;

ADC12MCTL4 = INCH_4 + EOS;

а потом

ADC12CTL0 |=ADC12SC;

ADC12CTL0 |=ENC;

while(ADC12IFG & BIT3);

CVx[cindex] = ADC12MEM3;

while(ADC12IFG & BIT4);

CVy[cindex] = ADC12MEM4;

ADC12CTL0 &= ENC;

так нормально? Или опять грузовики с кирпичами понаехали? :biggrin:

А зачем вы включаете опору, если ее не использует е при измерении? А так... сойдет :) Только я бы перед запуском преобразования флаги ADC12IFG почистил бы на всякий пожарный.

Опс! Тока сейчас заметил, неверно все-таки. Нужно так.

while((ADC12IFG & BIT3)==0);

Пока флаг не установлен, нужно ждать. А у вас инверсное условие. В моем примере выше я тоже ошибся, но поправить уже не могу. :(

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


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

Дебаггером, кстати, пользуюсь, но проверить алгоритм не получается - он не показывает текущие значения моих переменных, только регистры контроллера :05: - то же касается симулятора

Галочка в project->options->linker->output "debug information for C-Spy" стоит?

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


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

Ну здрасте! А ручками в окно View->Watch имя интересуемых переменных или структур забить лень что ли? Или окно View->Locals открыть и наблюдать за автоматическими переменными.

rezident, ну вы меня уж за совсем-пресовсем тупую держите! :05: :) Конечно, не лень! Но состояние переменных почему-то не отображается, вместо этого error стоит. Только состояние регистров. Я думала, это так всегда :biggrin:

 

Опс! Тока сейчас заметил, неверно все-таки. Нужно так.

while((ADC12IFG & BIT3)==0);

Пока флаг не установлен, нужно ждать. А у вас инверсное условие. В моем примере выше я тоже ошибся, но поправить уже не могу. :(

не, это я тоже ошиблась, когда вам писала - на самом деле я, конечно, while(!(ADC12IFG & BIT3)) пишу. Ага? Тож на тож ведь. или все же не очень корректно? :)

 

 

 

Галочка в project->options->linker->output "debug information for C-Spy" стоит?

А вот не знаю. Посмотрю, спасибо :)

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


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

rezident, ну вы меня уж за совсем-пресовсем тупую держите! :05: :)
Ну зачем же сразу такие эпитеты? Я просто делаю скидку на женскую альтернативную логику. Извините, если обидел.

Но состояние переменных почему-то не отображается, вместо этого error стоит. Только состояние регистров. Я думала, это так всегда :biggrin:
=DS=, указал вероятную причину.

не, это я тоже ошиблась, когда вам писала - на самом деле я, конечно, while(!(ADC12IFG & BIT3)) пишу. Ага? Тож на тож ведь. или все же не очень корректно? :)
Да пишите себе на здоровье, раз вам такой стиль нравится! Просто я лично при проверке условий предпочитаю явное сравнение с нулем. Для меня так нагляднее и понятнее. Но в свою "религию" я никого насильно не обращаю :biggrin:

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


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

Так вот. Галочка стоит. А состояние переменных все равно error :05:

По поводу ошибок в программе - у меня, кстати, все-таки разные версии, Kickstart 5.0, a Evolution 4.0. :) Но разве это может повлиять.? Ведь не ругается, все считает... Что-то не так с #include <math.h>? А, еще - они стоят вместе. Могут, перепуться библиотеки?

Теперь такие вопросы:

rezident, вы вот давно обещали помочь разобраться с таймером ;) Так, как я это делаю(по переключению флага ) - не пойдет :biggrin: "Камазы с кирпичами", да и только :biggrin: При большой скорости пересчета, в принципе, можно забить на некоторые неточности, но, когда нужно выполнять что-то четко по команде...

Вы говорили, что можно использовать выход таймера. Как? :) Ведь мне не нужно постоянно переключать вывод, нужно долго держать его в единице, а потом короткое время в ноле.

Еще- если я запущу еще и таймер В - это не будет излишней перегрузкой программы? Дело в том, что мне надо постоянно фиксировать состояние переменной azimut и где-то раз в секунду смотреть, не изменилась ли она, если изменилась - отсылать команду на COM. Что, если делать это по таймеру В?

Короче - помогите, спасите :)

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


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

Так вот. Галочка стоит. А состояние переменных все равно error :05:
Ну я не знаю. :laughing: Попробовал я в своем текущем проекте убирать "птички" в опциях проекта везде, где только встретил "Generate debug ...". В режиме отладки пропала возможность "шагать" по Сишному исходнику. Только по ASM-овому тексту теперь шагает. Но значения глобальных переменных в окне Watch и локальных переменных в окне Locals все равно показывает. Может вы пытаетесь в окне Watch значение локальной переменной посмотреть? Тогда понятно почему ошибку выдает.

По поводу ошибок в программе - у меня, кстати, все-таки разные версии, Kickstart 5.0, a Evolution 4.0. :) Но разве это может повлиять.? Ведь не ругается, все считает... Что-то не так с #include <math.h>? А, еще - они стоят вместе. Могут, перепуться библиотеки?
В один каталог крайне не рекомендуется устанавливать разные версии одного продукта. Если только с одинаковой версией IDE, но для разных целевых платформ (например, EWAVR и EW430). Устанавливайте версии KickStart и Evalution в разные каталоги, тогда путаницы не будет.

rezident, вы вот давно обещали помочь разобраться с таймером ;) Так, как я это делаю(по переключению флага ) - не пойдет :biggrin: "Камазы с кирпичами", да и только :biggrin: При большой скорости пересчета, в принципе, можно забить на некоторые неточности, но, когда нужно выполнять что-то четко по команде...

Вы говорили, что можно использовать выход таймера. Как? :) Ведь мне не нужно постоянно переключать вывод, нужно долго держать его в единице, а потом короткое время в ноле.

У таймеров MSP430 имеется режим compare (сравнения), в котором содержимое регистра TAR/TBR (которое постоянно инкрементируется по тактовым импульсам TACLK/TBCLK) сравнивается с capture-регистрами CCRx. При совпадении CCRx и TAR/TBR происходит установка флага CCIFG в соответствующем регистре CCTLx, а если разрешено прерывание для этого регистра (установлен бит CCIE), то еще и генерируется вызов прерывания по соответствующему вектору. Векторов для каждого таймера по две штуки. Один для CCR0, второй вектор расшарен для всех остальных CCRx. Манипулируя содержимым CCRx, вы можете генерировать прерывания для разных отметок времени. Кроме этого, для каждого блока compare имеется выходной модуль, который по возникающим событиям таймера может управлять состоянием бита OUT в CCTLx и ассоциированного с ним пина (или пинов, т.к. для TimerA эта функция выведена на несколько пинов) TAx/TBx. По событию совпадения TAR/TBR и CCRx бит OUT может быть сброшен, установлен, проинвертирован. Совпадение TAR/TBR и CCR0 действует на состояния всех битов OUT во всех выходных модулях таймера. По этому событию (от CCR0) бит OUT также может быть сброшен, установлен, проинвертирован. Таким образом можно генерировать ШИМ. Например, если для TA1 выбрать режим выходного модуля "сброс/установка", то по совпадению TAR и CCR1 вывод TA1 сброситься в лог.0, а по совпадению TAR и CCR0 установиться в лог.1. Режим выходного блока задается для каждого регистра индивидуально. Исключение составляет только CCR0, т.к. он действует сам на себя дважды за период, если выбран режим счета CountUp или Up/Down в которых период счета определяется содержимым этого CCR0.

Я предлагал вам использовать TimerA в режим счета Continious (с переполением). Выходной модуль TA0 или TA1 использовать для генерации выходного управляющего импульса, который одновременно запускает преобразование АЦП в непрерывном режиме последовательности каналов. Вам нужно только в прерывании от CCR0 или CCR1 вести счетчик и при достижении предпоследнего интервала отсчета импульса перепрограммировать режимы выходного блока и вовремя остановить АЦП для нового запуска по другому фронту TA0 или TA1.

Вот. Утомился я что-то "на пальцах" пересказывать содержимое User's Manual. :) Если еще непонятно, то пояснения будут уже завтра.

Кстати, не помню, давал ли я ссылку на русскоязычный переводной вариант User's Manual? На всякий случай продублирую ссылку на Компэловскую библиотеку.

Еще- если я запущу еще и таймер В - это не будет излишней перегрузкой программы? Дело в том, что мне надо постоянно фиксировать состояние переменной azimut и где-то раз в секунду смотреть, не изменилась ли она, если изменилась - отсылать команду на COM. Что, если делать это по таймеру В?
Нет особой разницы на какой таймере вести счет временных отметок (пауз). Если вам так удобно, то задействуйте TimerB. Хотя необходимости в этом я не вижу. У вас уже имеется счетчик на TimerA. Просто добавьте в процедуру прерывания еще один счетчик с удобным весовым коэффициентом. Я предпочитаю вести счет времени в миллисекундах. Например, используя WDTimer и ACLK от часового таймера.

#define SYSTIME_TICKPERIOD_MS  16 //весовой коэффициент системных тиков

volatile unsigned int TMTick;

//================================================//
// Инициализация таймера системных тиков          //
//------------------------------------------------//
//аргументы :нет                                  //
//возвращает:нет                                  //
//================================================//
void initSysTickTimer(void)
{ TMTick=0;
  WDTCTL=WDT_ADLY_16;                             //интервальный таймер тиков, тик=15,625мс
  IFG1&=~WDTIFG;                                  //сбросим флаг
  IE1|=WDTIE;                                     //разр. прерывание
}

const unsigned int SysTickCorrTbl[8]={0,0,1,0,0,1,0,1};  //корректировочная таблица

//================================================//
// Обработчик прерываний системного таймера       //
//------------------------------------------------//
//аргументы :нет                                  //
//возвращает:нет                                  //
//================================================//
#pragma vector=WDT_VECTOR
#pragma type_attribute=__interrupt
void SysTickTimer_ISR(void)
{ static unsigned int sysCntr=0;                     //вспомогательная переменная сист.тиков
//--- системные тики [мс] ---
  if (sysCntr<7)
    sysCntr++;
  else
    sysCntr=0;
  TMTick+=SYSTIME_TICKPERIOD_MS-SysTickCorrTbl[sysCntr];//инкремент сист. тиков (мс)
}

В основном теле программы я беру абсолютную разницу (беззнаковую разность) между двумя считанными значениями переменной TMTick и получаю прошедший интервал времени. Учитывая необходимость атомарности доступа к переменной системных тиков, выбираю ее тип unsigned int. Этот тип позволяет определять интервал времени до 65,5 секунд (период переполнения переменной). Если нужны бОльшие интервалы времени, то нужно брать 32-х битную переменную, но тогда придется запретом/разрешением прерывания или другими способами обеспечить атомарность доступа к ней.

Еще замечание насчет примененной корректировочной таблицы. Поскольку период частоты, полученной от деления частоты часового кварца (32768Гц) на делитель WDTimer (512), не является целой величиной миллисекунд (15,625мс), то я корректирую точность системных тиков с помощью таблицы. И на периоде 250мс получаю целое число миллисекунд.

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


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

Ну я не знаю. :laughing: Попробовал я в своем текущем проекте убирать "птички" в опциях проекта везде, где только встретил "Generate debug ...". В режиме отладки пропала возможность "шагать" по Сишному исходнику. Только по ASM-овому тексту теперь шагает. Но значения глобальных переменных в окне Watch и локальных переменных в окне Locals все равно показывает. Может вы пытаетесь в окне Watch значение локальной переменной посмотреть? Тогда понятно почему ошибку выдает.

Ничего подобного :) Все же не совсем, не совсем я даунито, я уже говорила. Локальные переменные смотрю, где надо :)

Об остальном - rezident, какой же вы все-таки хороший! :biggrin: Так все подробно и хорошо. Та функция, которую хотела сделать, вроде работает, а про таймеры... В принципе я пыталась сделать нечто подобное, но возникли проблемы :) Какие именно, напишу чуть позже, когда еще раз попробую переделать, руководствуясь вашими комментариями :) Спасибо, конечно, огромное. буду разбираться :)

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


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

Здравствуйте, снова я :)

Например, если для TA1 выбрать режим выходного модуля "сброс/установка", то по совпадению TAR и CCR1 вывод TA1 сброситься в лог.0, а по совпадению TAR и CCR0 установиться в лог.1.

...Я предлагал вам использовать TimerA в режим счета Continious (с переполением). Выходной модуль TA0 или TA1 использовать для генерации выходного управляющего импульса, который одновременно запускает преобразование АЦП в непрерывном режиме последовательности каналов. Вам нужно только в прерывании от CCR0 или CCR1 вести счетчик и при достижении предпоследнего интервала отсчета импульса перепрограммировать режимы выходного блока и вовремя остановить АЦП для нового запуска по другому фронту TA0 или TA1.

Все же я какая-то непонятливая :( допустим, режим Continious и режим "сброс/установка", по совпадению TAR и CCR1 вывод TA1 сброситься в лог.0, а по совпадению TAR и CCR0 установиться в лог.1. Но максимальное число. которое я могу записать в CCR0 - FFFF. А мне нужно держать лог. 1 долго. Как быть? Может, установить сначала режим "установка", в прерываниях от CCR0 вести счетчик, а в последнем переключить режим на "сброс". В следующем за ним прерывании опять "установка". Можно так сделать? Вы об этом говорите? :)

Да, а по поводу версий IAR - дело было просто в глючности самой ломаной версии 3.2 :)

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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