Daria 0 14 июня, 2008 Опубликовано 14 июня, 2008 · Жалоба 1. если вы хотите задействовать аппаратные возможности таймера по формированию импульсов, то сразу же используйте и аппаратную возможность синхронизации запуска АЦП. Обратите внимание, что вместо того, чтобы программно "дергать" битом ASC12SC можно аппаратно управлять запуском преобразования от сигналов TA1 или TB0, TB1. Т.е. как я и предлагал ранее - формировать времянку с помощью выходного сигнала TA1 и им же управлять запуском АЦП. Спасибо, постараюсь разобраться :) 2. Насчет шумов АЦП и осреднения. Время сэмплирования и преобразования нужно выбирать, исходя в т.ч. из соображений сопротивления источника сигнала. Вы не слишком ли малое время сэмплирования выбрали? Поскольку у вас количество каналов измерения значительно меньше, чем количество каналов АЦП, то усреднение можно сделать полуаппаратно. Запускаете АЦП в режиме последовательности каналов которые сконфигурированы на один и тот же вход АЦП. А затем простым вычислением среднего арифметического значения нескольких значений ADC12MEMx усредняете. А я вот примерно так и собиралась сделать :) даже и не знаю, как по-другому спасибо еще раз. Господа, товарищи, и все же Помогите разобраться с переопределением типов!!! int x,y; переопределяю (float) (х), возвращаю return (int)(x/y), так как пока хочу работать с целыми, и принимающая программка сделана под них. Но отношение получается либо 0, либо 1. В чем тут дело? Объясните, пожалуйста! заранее спасибо. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 15 июня, 2008 Опубликовано 15 июня, 2008 · Жалоба Помогите разобраться с переопределением типов!!! int x,y; переопределяю (float) (х), возвращаю return (int)(x/y), так как пока хочу работать с целыми, и принимающая программка сделана под них. Но отношение получается либо 0, либо 1. В чем тут дело? Я думаю, что дело в том, что x никогда не бывает больше 2y-1. Я предпочитаю работать с целочисленной арифметикой, но при этом нужно держать в памяти диапазоны возможных значений аргументов. Впрочем, как Вы используете float, тоже нужно :) Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 15 июня, 2008 Опубликовано 15 июня, 2008 · Жалоба Помогите разобраться с переопределением типов!!! int x,y; переопределяю (float) (х), возвращаю return (int)(x/y), так как пока хочу работать с целыми, и принимающая программка сделана под них. Но отношение получается либо 0, либо 1. В чем тут дело? Объясните, пожалуйста! Это не переопределение, а приведение типа. Чтобы операция деления производилась с числами именно типа float нужно приведение типов сделать непосредственно в выражении return ((int)((float)x/(float)y)) причем int и второй float можно не указывать, т.к. в операции деления приведение типа к более "высокому" будет сделано автоматически. И результат операции будет приведен к типу int автоматически в соответствии с типом результата, возвращаемым функцией. Но для наглядности можно написать так, как я указал. Второй способ - использовать временные (локальные) переменные требуемого типа. Большого расхода памяти это не вызовет, т.к. компилятор оптимизирует сам обращение к таким переменным. float fTmp; if (y!=0) //проверка исключения "деление на нуль" { fTmp=(float)x; //приведение типа для наглядности fTmp/=(float)y; //опять же здесь приведение типа только для наглядности } else fTmp=0; //вынужденная обработка возникшего исключения return((int)fTmp); Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Daria 0 16 июня, 2008 Опубликовано 16 июня, 2008 · Жалоба Большое спасибо, rezident, теперь все получилось:))) Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 16 июня, 2008 Опубликовано 16 июня, 2008 · Жалоба Я рад вашим успехам :) Кстати, если вам требуется округление, то можно (до преобразования в int) при вычислениях с float прибавлять число 0.5f. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VAI 0 17 июня, 2008 Опубликовано 17 июня, 2008 · Жалоба прибавлять число 0.5f. если число положительное, и вычитать 0.5, если число отрицательное. Примерно, в общем виде, где-то так: /* --- round() -------------------------------------------------------------------------------------------- ** * На выходе получаем округлённый float-результат * value - что округлять * accuracy - с какой точностью округлять (например 2. или 0.03 или 0.1 и т.д.) * -------------------------------------------------------------------------------------------------------- */ float round( float value, float accuracy ) { return( ((long)( value / accuracy + ( value < (float)0. ? (float)-0.5 : (float)0.5 ))) * accuracy ); } Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Daria 0 17 июня, 2008 Опубликовано 17 июня, 2008 · Жалоба Я рад вашим успехам :) Зря иронизируете, я медленно(очень медленно), но верно расту Кстати, если вам требуется округление, то можно (до преобразования в int) при вычислениях с float прибавлять число 0.5f. Спасибо за совет - пригодится :) если число положительное, и вычитать 0.5, если число отрицательное. Примерно, в общем виде, где-то так... Спасибо, VAI. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 18 июня, 2008 Опубликовано 18 июня, 2008 · Жалоба Зря иронизируете, я медленно(очень медленно), но верно расту Никакой иронии! Это чистосердечно. Смайлик неподходящий выбрал. Вот такие надо было. :a14: Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Daria 0 22 июня, 2008 Опубликовано 22 июня, 2008 · Жалоба Здравствуйте, и снова вопросы :) много, много вопросов :) 1.!! Сначала по поводу усреднения отсчетов для уменьшения шума - предлагали использовать бит MSC в регистре ADC12CTL0. Правильно ли я понимаю, что тогда значения выборок будут постоянно(до сброса бита ENC) записываться в регистры ADC12MEMx, и получить усредненное значение можно считывая значения из разных регистров ADC12MEMx и деля на их количество? Но у меня 16 каналов АЦП, задействовано в дальнейшем будет 5. Т.е. я могу использовать для усреднения только три значения из регистров ADC12MEMx - маловато будет... :( ну, или я все же не понимаю, поясните тогда принцип использования бита MSC. Делаю усреднение пока так(знаю, что криво, но) int filter(int r[10])// среднее арифметическое 10 значений { int s, t; s = 0; for(t = 0 ; t < 10 ; t++) s+=r[t]; return s/10; } ... ADC12CTL0 = ADC12ON + REFON + SHT0_8;// настройка АЦП ADC12CTL1 = CSTARTADD0 + CSTARTADD1 + ADC12SSEL_1+ CONSEQ_1+ SHS_1; ADC12MCTL3 = INCH_3; ADC12MCTL4 = INCH_4 + EOS; index = 0; ... И, собственно if (TACCTL0 & CCIFG)// если таймер переключился { if (P1OUT & BIT5)// и, если вывод все еще в единице,т.е. еще идет длинный импулсьс { ADC12CTL0 |= ENC; Vr[0][index] = ADC12MEM3; // записываем в массив значения из ADC12MEMх Vr[1][index] = ADC12MEM4; ADC12CTL0 &= ENC; index++; if (index >= 10)// когда значений в массиве 10 { index = 0; offset[0] = (Vs[0] - filter(Vr[0]))/2; // Вычисление смещений уровня сигнала offset[1] = (Vs[1] - filter(Vr[1]))/2; Vx = filter(Vr[0]) - offset[0]; //вычисление координат вектора маг.индукции Vy = filter(Vr[1]) - offset[1]; azimut = calculation (Vx,Vy); //вычисление азимута } send_int(azimut); } send_int(azimut) - вычисленный азимут посылается на СOM. Описание send_int было выше в теме, да и не в ней суть, на вычисления тоже можно не обращать внимания :) ВОПРОС! - 2.!! В данном случае вычисляю азимут 10 раз, а посылаю только один. т.е. 10 раз посылается одно и то же значение. Если переношу строчку send_int(azimut); под строку azimut = calculation (Vx,Vy); - т.е. сразу после вычисления и отправляю, то программа не работает :( На СOM ничего не приходит! :07: Поясните, пожалуйста, если будет время разобраться - ПОЧЕМУ?! 3.!! Вопрос не по теме MSP430, уж извините, но вдруг кто-нибудь знает - Когда считываю уровень сигнала с датчика, он самопроизвольно "плывет", плата лежит неподвижно, а уровень за минуту убегает довольно прилично, при вычислении азимута получается, что в минуту градусов +/- 5 :07: С чем это может быть связано? Датчик, напоминаю, HMC1002 Вопрос в основном к Курту, если он заглянет. Да, Kurt, отправила Вам письмо - загляните в ящик - там еще куча вопросов по компасу конкретно Ну, Вы сами обещали помочь Ну вот, пока все - помогите, кто может чем сможет Не ругайте за безграмотность и всех с победой сбороной России :yeah: Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 22 июня, 2008 Опубликовано 22 июня, 2008 · Жалоба ну, или я все же не понимаю, поясните тогда принцип использования бита MSC.Бит MSC не имеет прямого отношения к усреднению. Он лишь позволяет автоматически запускать таймер сэмплирования (Sample Timer) после каждого преобразования (если выбран режим последовательности каналов). На блок-схеме из User's Guide хорошо видно, что устройство выборки-хранения (Sample-and-Hold или УВХ в отечественной терминологии), подключенное к входному 16-и канальному мультиплексору управляется сигналом SAMPCON. Лог.1. SAMPCON включает режим выборки, в котором конденсатор УВХ заряжается до напряжения входного сигнала, подключенного к выбранному входу мультиплексора, а лог.0 отключает УВХ от мультиплексора и запускает преобразование. Длительность лог.1 задается таймером сэмплирования, либо внешним сигналом в обход таймера сэмплирования. Сам таймер сэмплирования запускается по фронту сигнала SHI, который формируется либо программно от ADC12SC, либо одним из трех внешних сигналов от модулей таймера A или таймера B. Так вот установка бита MSC позволяет не ждать фронта сигнала SHI для запуска каждого последующего преобразования, а формировать его аппаратно по окончании предыдущего преобразования. Но это все работает только, если выбран режим управления от Sample Timer и режим последовательности каналов. Делаю усреднение пока так(знаю, что криво, но) int filter(int r[10])// среднее арифметическое 10 значений { int s, t; s = 0; for(t = 0 ; t < 10 ; t++) s+=r[t]; return s/10; } Ну некоторая "кривизна" присутствует только при передаче аргумента функции. Передавать следует указатель на массив отсчетов и возможно еще и длину этого массива. int filter(int *ptr, int size) { int s=0, t; for(t=0; t<size; t++) s+=*ptr; ptr++; if (size>0) //проверим на исключение "деление на нуль" return (s/size); else return 0; } Вызов функции будет такой x=filter(r, 10); или x=filter(&r[0], 10); Передавать второй аргумент имеет смысл потому, что если вы неправильно неудачно выбрали времена, то у вас будет заполнен не весь буфер. Т.е. за выбранное время будет меньше 10 преобразований. См. ниже про эту потенциальную ошибку. ... ADC12CTL0 = ADC12ON + REFON + SHT0_8;// настройка АЦП ADC12CTL1 = CSTARTADD0 + CSTARTADD1 + ADC12SSEL_1+ CONSEQ_1+ SHS_1; ADC12MCTL3 = INCH_3; ADC12MCTL4 = INCH_4 + EOS; index = 0; ... Еще раз обращаю внимание, что во избежание ошибок при формировании слова из отдельных битов следует пользоваться побитовым ИЛИ '|', а не оператором сложения '+'. И, собственно if (P1OUT & BIT5)// и, если вывод все еще в единице,т.е. еще идет длинный импулсьс { Здесь возможно имеется потенциальная алгоритмическая ошибка. Проверять нужно не только до начала преобразования, но и после окончания преобразования. И если после окончания преобразования бит сменил свое состояние, то результат последнего преобразования нужно отбрасывать. Следовательно у вас может быть не 10 отсчетов, а меньше. Поэтому выше я предложил передавать в функцию фильтрации еще и реальную длину буфера отсчетов. 2.!! В данном случае вычисляю азимут 10 раз, а посылаю только один. т.е. 10 раз посылается одно и то же значение. Если переношу строчку send_int(azimut); под строку azimut = calculation (Vx,Vy); - т.е. сразу после вычисления и отправляю, то программа не работает :( На СOM ничего не приходит! :07: Поясните, пожалуйста, если будет время разобраться - ПОЧЕМУ?! Затрудняюсь сходу дать однозначный ответ, но думаю, что причиной является факт, что получение значения измерения и передача его через UART это процессы вообще-то асинхронные, но вы их пытаетесь принудительно синхронизировать без использования буферов. Вы используете передачу по опросу бита готовности, а не по прерыванию. А каждая передача "тормозит" измерения на время передачи двух символов. Поэтому за тот же самый интервал времени (который у вас фиксированный и определяется таймером) вы получаете меньше отсчетов, чем предполагаемое вами количество (10). Следовательно условие if (index >= 10) не выполняется, результата azimut вы не получаете, и передача через UART тоже не идет. Для решения этой проблемы рекомендую использовать передачу по прерываниям и формировать для передачи свой собственный буфер, линейный или циклический. По 3-му вопросу ответить не могу. Я не "копенгаген", да и с подобными датчиками я не работал :laughing: Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Daria 0 24 июня, 2008 Опубликовано 24 июня, 2008 (изменено) · Жалоба Здравствуйте снова. Rezident, спасибо за подробный разбор, но вот я начала после Ваших комментов разбираться и окончательно зависла :07: Во-первых, после того, как фильтр сделала по Вашему совету - с делением не на 10, а на index. числа начали получаться жуткими и бессмысленными, вразнобой и без всякой связи с поворотом платы - как это можно объяснить? :07: Во-вторых, я, наивная, полагала, что преобразование АЦП запускается сейчас синхронно с переключением таймера, я ведь вроде не битом ADC12SC "дергаю", а ставлю бит SHS_1 в ADC12CTL1 - т.е использую выход таймера А1... или нет? Проверка if (P1OUT & BIT5) идет не перед стартом преобразования, а перед тем, как записывать новый элемент в массив, т.е. как раз то, о чем Вы говорите... так мне казалось :) В третьих, тут вроде все советовали как раз использовать как можно меньше прерываний, лучше вообще без них, вот и стараюсь без них :) и вообще - Вы обещали рассказать, как в данном случае не программно дергать P1OUT, а использовать выход таймера - как это можно сделать, ведь изменение состояния вывода должно произойти только через 918 переключений таймера :05: И все-таки вопрос - почему send_int(azimut) нельзя перенести в то место, в которое хочется :) ? Если бы условие if (index >= 10) никогда не выполнялось, то и вычисление никогда не происходило бы, а что-то таки вычисляется. Без фильтра работает :) только сильно скачет, что не есть хорошо. Вот такие непонятки :) будет время, ответьте, пожалуйста. Изменено 24 июня, 2008 пользователем Daria Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 24 июня, 2008 Опубликовано 24 июня, 2008 · Жалоба Daria, давайте все исходники (весь проект). Варианты возможных нюансов в многоветвистое дерево вырастают, а телепатия что-то тяжело нынче идет :) Я бы вам посоветовал отладить работу АЦП не с датчиком, а с постоянными напряжениями для начала. Вы еще не до конца разобрались с синхронной работой ADC12 и TimerA и вообще с функционированием ADC12. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Daria 0 25 июня, 2008 Опубликовано 25 июня, 2008 (изменено) · Жалоба Я бы вам посоветовал отладить работу АЦП не с датчиком, а с постоянными напряжениями для начала. да пробовала :) Вроде нормально идет. Правда, пробовала без всяких усреднений... Вы еще не до конца разобрались с синхронной работой ADC12 и TimerA и вообще с функционированием ADC12. Эт точно да и с USART похоже тоже. Видимо все дело в том, как я отправляю число. Функция send_int получилась кривоватая. Вот подскажите, как просто и хорошо отправить целое число, 12бит, чтобы занять как можно меньше времени и получить как можно меньше ошибок при приеме? Пробовала без флажка 0xFF, означающего конец посылки, но при "слеплении" получаются ошибки. вы говорили, что нужно как-то по прерываниям работать, как? :) Да, вот что странно, когда я разрешаю прерывания по передаче, вообще перестает работать. А проект пока маленький совсем, прикладываю текст. Не ругайтесь на "+", я потом обязательно исправлю, все как-то недосуг :) Вообще спасибо за поддержку:) 1.txt Изменено 25 июня, 2008 пользователем Daria Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NoName 0 26 июня, 2008 Опубликовано 26 июня, 2008 · Жалоба Функция send_int получилась кривоватая. Вот подскажите, как просто и хорошо отправить целое число, 12бит, чтобы занять как можно меньше времени и получить как можно меньше ошибок при приеме? Имеет смысл сразу организовать протокол обмена. Пример: адрес получателя 1 или 2 байта идентификатор пакета 2 байта - соответвует идентификатору запроса. длина данных пакета 1 или 2байт данные [] адрес отправителя 1 или 2 байта СRC 2 байт истина прописная, протокол то все равно прийдется организовывать ))) либо воспользоватся общепринятыи протоколом для Вашей конторы ... Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Daria 0 26 июня, 2008 Опубликовано 26 июня, 2008 (изменено) · Жалоба Имеет смысл сразу организовать протокол обмена. либо воспользоватся общепринятыи протоколом для Вашей конторы ... Спасибо. Общепринятого протокола нет - контора большая, кто обменивается, тот между собой обычно и договаривается:) А пока как-нибудь. А имеет смысл писать такой протокол ради того, чтобы просто постоянно отправлять число от 0 до 360 на COM- и больше ничего? Да, rezident, бог с ним. с усреднением - все равно особенно не поможет, нужно делать норамльный цифровой фильтр. А я до него еще не доросла :) Чутка попозже. Пока вот вопрос - записываю число во flash, использую режим записи по словам. т.е. int число пишется легко и без проблем. А как записать float - надо уже режим поблоковой записи? Или нет? Изменено 26 июня, 2008 пользователем Daria Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться