|
|
  |
MSP430 - снова вопросы от чайника, Вопросы от чайника про MSP и магнитный компас |
|
|
|
Oct 5 2008, 15:42
|
Местный
  
Группа: Участник
Сообщений: 229
Регистрация: 24-02-08
Пользователь №: 35 345

|
Опять я  теперь нужен еще буфер - для АЦП. посмотрите, пожалуйста, нормально ли написана функция чтения? Та же структура Код typedef struct CharBuffer { unsigned char* Data; int NData; int cData; int pWrite; int pRead; } CharBuffer; #define sizeADCBufR 100 struct CharBuffer stADCBufR; unsigned char ADCBufR[sizeADCBufR];
stADCBufR.NData = sizeADCBufR; stADCBufR.Data = ADCBufR; BufferReset(&stADCBufR); Функция записи - записывает по байтам два int числа, функции записи и чтения байта описаны выше Код int WriteADCbuf(CharBuffer* pBuffer, int* data, int size) { if((pBuffer->NData-pBuffer->cData)<2*size+1)return 1; for( int j = 0; j < size; j++) { BufferWrite(pBuffer, (data[j]&0xFF)); BufferWrite(pBuffer, (data[j]>>8)); } return 0; } Чтение в две переменных Код void ReadADCbuf(CharBuffer* pBuffer, int* data0, int* data1) { unsigned char Dat[4]; BufferRead(pBuffer, &Dat[0]); BufferRead(pBuffer, &Dat[1]); *data0=((Dat[0]&0x00FF)|((Dat[1]<<8)&0xFF00)); BufferRead(pBuffer, &Dat[2]); BufferRead(pBuffer, &Dat[3]); *data1=((Dat[2]&0x00FF)|((Dat[3]<<8)&0xFF00)); } Вызов ReadADCbuf(&stADCBufR, &Vr0, &Vr1) Правильно ли склеиваю? И вообще - что-то с ней, по-моему, не то Еще вопрос - как правильно работать с WDT? Я просто останавливаю его при начальной инициализации, и все. Но говорят, что это не правильно, нужно постоянно обращаться к нему, чтобы избежать зависания процессора. Как это делать - обращаться постоянно в цикле for(;;)?
|
|
|
|
|
Oct 6 2008, 06:04
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Daria @ Oct 5 2008, 22:35)  И еще  Мне нужно обмениваться с двумя устройствами. Обычно при обмене кто-то главный (master), а кто-то подчиненный (slave). Как старшинство распределено среди этого трио?
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Oct 6 2008, 17:45
|
Местный
  
Группа: Участник
Сообщений: 229
Регистрация: 24-02-08
Пользователь №: 35 345

|
Цитата(Dog Pawlowa @ Oct 6 2008, 10:04)  Обычно при обмене кто-то главный (master), а кто-то подчиненный (slave). Как старшинство распределено среди этого трио? одно устройство принимает команды с компьютера(от оператора) и на основании их руководит вторым устройством(передает команды и принимает ответные данные).  Как-то так Вопрос про функцию снимается, а вот про WDT? Что, если перезапускать его в прерываниях таймера через каждые сколько-то мс? Как вообще обычно им пользуются?
|
|
|
|
|
Oct 6 2008, 19:04
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Daria @ Oct 6 2008, 23:45)  одно устройство принимает команды с компьютера(от оператора) и на основании их руководит вторым устройством(передает команды и принимает ответные данные).  Как-то так Раз есть второй аппаратный UART, то грешнО его не использовать. Цитата(Daria @ Oct 6 2008, 23:45)  а вот про WDT? Что, если перезапускать его в прерываниях таймера через каждые сколько-то мс? Как вообще обычно им пользуются? Лично я его обычно использую как таймер системных тиков, т.к. у него приоритет прерывания один из самых высоких  Если же вас интересует теория, то где бы вы не сбрасывали WatchDog он должен сбрасываться только после анализа нескольких флагов, которые устанавливаются в разных ответственных местах программы. Вы можете сбрасывать WDT в прерывании таймера, но не просто по факту попадания в это прерывания, а только если выполняются все условия "попадания" в различные другие части программы. В те, куда программный код обязательно должен привести в промежутках между сбросом WDT. Кстати, от "защелкивания" или экстремальных случаев воздействия статики на MSP430 внутренний WatchDog не спасает.
|
|
|
|
|
Oct 7 2008, 17:09
|
Местный
  
Группа: Участник
Сообщений: 229
Регистрация: 24-02-08
Пользователь №: 35 345

|
Цитата(rezident @ Oct 6 2008, 23:04)  Лично я его обычно использую как таймер системных тиков, т.к. у него приоритет прерывания один из самых высоких  Если же вас интересует теория, то где бы вы не сбрасывали WatchDog он должен сбрасываться только после анализа нескольких флагов, которые устанавливаются в разных ответственных местах программы. Вы можете сбрасывать WDT в прерывании таймера, но не просто по факту попадания в это прерывания, а только если выполняются все условия "попадания" в различные другие части программы. В те, куда программный код обязательно должен привести в промежутках между сбросом WDT. Кстати, от "защелкивания" или экстремальных случаев воздействия статики на MSP430 внутренний WatchDog не спасает. Ага, а я вот как раз хотела сначала настроить в сторожевом режиме, а потом просто сбрасывать WDTCNTCL в прерываниях таймера  Не все так просто... То есть, вы не используете WDT в сторожевом режиме, и ничего страшного не случается? И вот еще более важные вопросы - У меня куча массивов, если объявлять их в main, они начинают забивать стек, если как глобальные - то ведь память, отведенная под глобальные константы ограничена. Как быть? Можно ли как-то программно увеличить размер стека? Нужно либо увеличивать стек, либо как-то хитро объявлять все эти массивы... подскажите. и не ругайтесь, если опять сморозила глупость
|
|
|
|
|
Oct 7 2008, 17:41
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Daria @ Oct 7 2008, 23:09)  Ага, а я вот как раз хотела сначала настроить в сторожевом режиме, а потом просто сбрасывать WDTCNTCL в прерываниях таймера  Не все так просто... То есть, вы не используете WDT в сторожевом режиме, и ничего страшного не случается?  А что там должно "страшного" случиться?  Режим интервального таймера для WDT является штатным и документированным. Если вы сомневаетесь в помехоустойчивости, то вообще-то помехоустойчивость устройства в бОльшей степени определяется конструктивными и схемотехническими (трассировка платы, расположение и подключение внешних и внутренних цепей и т.п.) особенностями устройства, а не использованием WatchDog  Цитата(Daria @ Oct 7 2008, 23:09)  И вот еще более важные вопросы - У меня куча массивов, если объявлять их в main, они начинают забивать стек, если как глобальные - то ведь память, отведенная под глобальные константы ограничена. Как быть? Можно ли как-то программно увеличить размер стека? Нужно либо увеличивать стек, либо как-то хитро объявлять все эти массивы... подскажите. и не ругайтесь, если опять сморозила глупость  В Plain C и ANSI C используются четыре типа переменных: 1. register (регистровые), размещаются в регистрах (хотя компиляторы чаще всего плюют на это указание). Область "видимости" текущая функция/контейнер. При выходе из функции/контейнера не сохраняются. 2. auto (автоматические или локальные), размещаются на стеке (или в регистрах, опять же по прихоти компилятора). Область "видимости" текущая функция, контейнер. При выходе из функции/контейнера не сохраняются. 3. global (глобальные), размещаются на постоянной основе в ОЗУ, в области данных. Область видимости весь текущий модуль. А объявленные с квалификатором extern могут быть "видны" в любом другом модуле проекта. 4. static (статические), размещаются на постоянной основе в ОЗУ, в области данных. Область "видимости" текущая функция (если объявление внутри функции) или текущий модуль (если объявление как глобальной снаружи какой-либо функции). При выходе из функции сохраняются. Но статические переменные не могут быть использованы в других модулях проекта и квалификатор extern к ним неприменим. В IAR для MSP430 принято, что область данных (глобальных и статических переменных) располагается "снизу" ОЗУ, а стек "сверху" и "растет" ей навстречу. Для того, чтобы хоть как-то контролировать стек в Plain C, вы можете сами организовать "кучу" (HEAP). Для этого создайте большой глобальный массив и располагайте свои временные "массивчики" внутри его. Но для этого нужно будет научиться (если еще не научились) пользоваться указателями, обязательно контролируя выходы их (указателей) за границы выделенных "массивчиков" и глобального массива кучи. А вообще в map-файле, который можно генерировать с помощью конфигурирования опций IAR, указан размер стека при использовании каждой функции.
|
|
|
|
|
Oct 7 2008, 18:12
|
Местный
  
Группа: Участник
Сообщений: 229
Регистрация: 24-02-08
Пользователь №: 35 345

|
Цитата(rezident @ Oct 7 2008, 21:41)  В IAR для MSP430 принято, что область данных (глобальных и статических переменных) располагается "снизу" ОЗУ, а стек "сверху" и "растет" ей навстречу. Для того, чтобы хоть как-то контролировать стек в Plain C, вы можете сами организовать "кучу" (HEAP). Для этого создайте большой глобальный массив и располагайте свои временные "массивчики" внутри его. Но для этого нужно будет научиться (если еще не научились) пользоваться указателями, обязательно контролируя выходы их (указателей) за границы выделенных "массивчиков" и глобального массива кучи. А вообще в map-файле, который можно генерировать с помощью конфигурирования опций IAR, указан размер стека при использовании каждой функции. Все же пока не ясно  Есть массивы, которые объявлены в main, они висят в стеке, потом при вызове какой-нибудь функции, создаются еще локальные - и забивают в этот момент стек. я вижу размер стека, вижу, что заполнен, но как же быть, если массив нужен? Объявить большой глобальный - да, но если не хватит памяти, отведенной под глобальные переменные? Кстати, в руководстве, которое вы часто поминаете, сказано, что при начальной инициализации, нужно инициализировать указатель стека(указав вершину ОЗУ). Как записывается инициализация SP?
Сообщение отредактировал Daria - Oct 7 2008, 18:21
|
|
|
|
|
Oct 7 2008, 19:07
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Daria @ Oct 8 2008, 00:12)  Все же пока не ясно  Есть массивы, которые объявлены в main, они висят в стеке, потом при вызове какой-нибудь функции, создаются еще локальные - и забивают в этот момент стек. Пример из программы можете привести, где по-вашему создаются локальные копии массивов локальных переменных? Цитата(Daria @ Oct 8 2008, 00:12)  я вижу размер стека, вижу, что заполнен, но как же быть, если массив нужен? Объявить большой глобальный - да, но если не хватит памяти, отведенной под глобальные переменные? Либо вы не совсем аккуратно программируете, либо выбранный кристалл (размер имеющегося у него ОЗУ) не соответствует вашей задаче. Цитата(Daria @ Oct 8 2008, 00:12)  Кстати, в руководстве, которое вы часто поминаете, сказано, что при начальной инициализации, нужно инициализировать указатель стека(указав вершину ОЗУ). Как записывается инициализация SP?  Поскольку вы программируете на Си, а не на ассемблере, то задачей инициализации указателя стека и очисткой/инициализацией глобальных и статических переменных, находящихся в сегменте DATA_Z, занимается сам компилятор. Все это делается в процедуре StartUp, которая выполняется ДО вызова функции main. Надеюсь вы в курсе, что main это тоже функция и у нее есть пролог и эпилог, как и у подавляющего большинства других функций? Вот если бы вы писали программу полностью на ASM, то инициализацию указателя стека и инициализацию/очистку глобальных переменных пришлось бы писать тоже вам. Вручную
|
|
|
|
|
Oct 10 2008, 20:23
|
Местный
  
Группа: Участник
Сообщений: 229
Регистрация: 24-02-08
Пользователь №: 35 345

|
Цитата(rezident @ Oct 7 2008, 23:07)  Либо вы не совсем аккуратно программируете, либо выбранный кристалл (размер имеющегося у него ОЗУ) не соответствует вашей задаче. Однозначно, первое  ОЗУ = 2 КВ. Но я поняла, в чем дело - это не стек забивался, а размер stack heap был по умолчанию задан 50 байт.  Я не тормоз, я медленный газ  Но теперь все вроде в порядке.
|
|
|
|
|
Oct 14 2008, 21:54
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Daria @ Oct 14 2008, 21:27)  Как быть - возможен ли такой вариант - писать что-то (например, массивы ко-тов фильтров) во flash, чтобы они не висели в стеке? Возможен. Объявляйте их с квалификатором const. Но при этом они становятся неизменяемыми. Цитата(Daria @ Oct 14 2008, 21:27)  Еще про WDT  Что, если в программе будет какой-то невыявленный при испытаниях глюк, который выявится уже в процессе использования? Проц зависнет где-нибудь в прерывании... и будет висеть. А WDT это дело предотвратит. Так или не так?  Так. Именно для этого его и придумали. Надо лишь Придумать алгоритм его периодического сбрасывания, чтобы он не сбросил вашу штатно работающую программу и чтобы при подвисании одной части он не продолжал успешно сбрасываться в другой.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 18 2008, 16:50
|
Местный
  
Группа: Участник
Сообщений: 229
Регистрация: 24-02-08
Пользователь №: 35 345

|
Такой вопрос. Почему-то не получается объявить фукнцию, работающую с двумерным массивом, размер которого можно бы было передавать как формальный параметр. На function(float а[][]) ругается, а если писать function (float** a), а потом передавать конкретный массив float m[5][5] как function(m), то функция вообще не выполняется, хотя никаких ошибок не пишет :  Как это вообще делается? И еще - есть уравнение четвертой степени ax^4+bx^3+cx^2+dx+e=0 Как бы можно было реализовать его решение, если коэффициенты a,b,c,d,e будут вычислены по данным АЦП? Это вообще возможно на таком кристалле? Ну, есть методы решения уравнений в общем виде - метод деления отрезка пополам, например. Но во-первых, нужно знать область, на которой функция меняет знак, во-вторых искать пределы последовательностей  Если вдруг кто-нибудь когда-нибудь делал, подскажите. А про массив - обязательно подскажите!
Сообщение отредактировал Daria - Oct 18 2008, 17:17
|
|
|
|
|
Oct 18 2008, 19:17
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Daria @ Oct 18 2008, 22:50)  Такой вопрос. Почему-то не получается объявить фукнцию, работающую с двумерным массивом, размер которого можно бы было передавать как формальный параметр. На function(float а[][]) ругается, а если писать function (float** a), а потом передавать конкретный массив float m[5][5] как function(m), то функция вообще не выполняется, хотя никаких ошибок не пишет :  Как это вообще делается?  Вы поймите, что многомерные массивы это лишь такая человеческая абстракция. В памяти МК многомерные массивы все равно представляются в виде одномерных участков оперативной памяти. У вас многомерный массив переменных типа float. Единичным элементом массива является переменная типа float. Так вот и передавайте в функцию указатель на переменную типа float. Объявление функции Код void func (float *ptr); Вызов функции Код func(&a[0][0]); либо Код float *ptr=&a[0][0]; func(ptr); Если же вы хотите, чтобы в результате выполнения функции передаваемый указатель тоже изменился, только тогда нужно передавать указатель на указатель. Код void func (float **pFptr) { float *ptr=pFptr;
...
*pFptr=ptr; } вызов функции Код float *ptr=&a[0][0]; func(&ptr); Насчет второй части вопроса, увы! не могу подсказать  Не настолько я силен в математике
|
|
|
|
|
Oct 19 2008, 01:36
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
Начиная с 99 года в С стало возможно описывать массивы с переменной длинной, IAR этот стандарт поддерживает. Кстати, в Фортране подобное было с самого начала, не прошло и полвека.  Ниже примеры из текста стандарта ISO/IEC 9899:1999 Код EXAMPLE 3 The following declarations demonstrate the compatibility rules for variably modified types. extern int n; extern int m; void fcompat(void) { int a[n][6][m]; int (*p)[4][n+1]; int c[n][n][6][m]; int (*r)[n][n][n+1]; p = a; // invalid: not compatible because 4 != 6 r = c; // compatible, but defined behavior only if // n == 6 and m == n+1 }
EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or function prototype scope. Array objects declared with the static or extern storage-class specifier cannot have a variable length array (VLA) type. However, an object declared with the static storageclass specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.
extern int n; int A[n]; // invalid: file scope VLA extern int (*p2)[n]; // invalid: file scope VM int B[100]; // valid: file scope but not VM
void fvla(int m, int C[m][m]); // valid: VLA with prototype scope
void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA { typedef int VLA[m][m]; // valid: block scope typedef VLA
struct tag { int (*y)[n]; // invalid: y not ordinary identifier int z[n]; // invalid: z not ordinary identifier }; int D[m]; // valid: auto VLA static int E[m]; // invalid: static block scope VLA extern int F[m]; // invalid: F has linkage and is VLA int (*s)[m]; // valid: auto pointer to VLA extern int (*r)[m]; // invalid: r has linkage and points to VLA static int (*q)[m] = &B; // valid: q is a static block pointer to VLA } Примерно так должно работать (не проверял): Код float func( int i; int j; float a[i][j] ) { float s = 0.0; for( int ii = 0; ii < i; ii++) for( int jj = 0; jj < j; jj++) s += a[ii][jj];
return s; }
float m[5][5]; float mm[25][3];
func( 5, 5, m ); func( sizeof(mm)/sizeof(mm[0]), sizeof(mm[0])/sizeof(mm[0][0]), mm );
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|