Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/11: Рейтинг темы: голосов - 11, средняя оценка - 5.00
7 / 7 / 0
Регистрация: 03.04.2015
Сообщений: 45
1

Может кто сталкивался с таким? ATxmega256A3U

04.03.2016, 23:10. Показов 2138. Ответов 20

Author24 — интернет-сервис помощи студентам
Суть такая, есть некое устройство, где используется АЦП AD7795. АЦП настроено на биполярное преобразование и выдаёт значение результата преобразования как 32790 ( что является значением находящимся около нуля (т.е. максимальное отрицательное значение равно 0, измеренный НУЛЬ 32768, максимальное измеренное значение 65535). В результате, при пересчёте кода результата преобразования в напряжение на входе, контроллер зависает. Вот код по которому происходит преобразование:

C
1
2
3
4
5
double convertAdcCountdownTomV(long int *valueForConvert)
{
    double mV = (*valueForConvert/32768.0 [B]- 1[/B])*1.17; //Выведено из datasheet а AD7794/AD7795
    return mV;
}
Если убрать вычитание единицы -1, контроллер, работает, но результат преобразования не верен. Если вычитание изменить на сложение работает исправно, но опять же результат не верен. Была попытка заменить, вычитание, сложением с помощью дополнительного кода значение 1. Результат тот же - зависание контроллера.

Путём экспериментов, было найдено решение:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
double convertAdcCountdownTomV(long int *valueForConvert)
{
    if (*valueForConvert >= 32768)
    {
        *valueForConvert &= 0x7FFF;
    }
    else
    {
        *valueForConvert = 32768 - (*valueForConvert);
    }
    double mV = (((*valueForConvert)*1.17) / 32768.0);
    //double mV = (*valueForConvert/32768.0 - 1)*1.17;
    return mV;
}
Работает, но хочется докопаться до истины. Может есть у кого мысли по этому поводу?
PS: сильно не пинайте, программирование железа изучаю сам, профильное образование совершенно другое и готов выслушать конструктивную критику. Спасибо.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.03.2016, 23:10
Ответы с готовыми решениями:

может кто сталкивался с таким ?
intel corei7950@3.06ghz s.1366asus rampage111gene ddr3 4gb nvidia 480gtx бп 750w 2...

Файл во вложении может содержать вирус? Кто-нибудь сталкивался с таким типом рассылки?
Приветствую, форумчане! Кто-нибудь сталкивался с формой неконтролируемой рассылки doc-файла с...

Кто-то сталкивался с таким заданием?
Распечатать список учеников,фамилии которых начинаются на букву В, с указанием даты их рождения. ...

Кто-нибудь с таким сталкивался?
У меня уже второй раз такая ерунда - сайт находится в ТОП-е на 3-5 позиции по определенному ВЧ....

Кто сталкивался с таким в drupal 7 ?
http://mebellmoskva.ru/kupit-krovat Заходя по ссылке вы увидите что пропали скрипты и стили А...

20
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
08.03.2016, 07:43 2
попробуй вот так
C
1
float mv=((*valueForConvert-32768)/32768.0)*1.17;
или попробуй вообще уйти от чисел с плавающей запятой
все дело в том что нет аппаратной поддержки, все реализуется библиотеками от производителя а там возможны глюки, и для микроконтроллеров float все же ближе чем double
2
techpriest
634 / 213 / 57
Регистрация: 27.02.2014
Сообщений: 1,180
09.03.2016, 01:37 3
Можно попробовать добавить явное приведение типа:
C++ (Qt)
1
float mV = (((float)*valueForConvert)/32768.0 [B]- 1[/B])*1.17;
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
09.03.2016, 06:37 4
вот еще что подумал
а чему равно
Цитата Сообщение от 3050mAh Посмотреть сообщение
long int *valueForConvert
?
размерность? в каждом компиляторе это свое и если размерность 16 бит то будем иметь проблемы с приведением
так как при 0xFFFF (65535) будем иметь -1 а не максимум 0х8000 будем иметь минимум(-32768) а не середину
между 0x7FFF и 0x8000 разница не 1, а 65535

для начала сделай аргумент беззнаковым
C
1
double convertAdcCountdownTomV(long unsigned int *valueForConvert)
0
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
09.03.2016, 17:24 5
Цитата Сообщение от 3050mAh Посмотреть сообщение
значение результата преобразования как 32790
сдается мне, вы просто получаете на "середину шкалы", а просто знаковое значение. 32790 - это может быть "-24". Попробуйте изменить объявление переменной на тип "signed int" (или signed short, здесь действительно зависит от компилятора и его настроек типов).
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
09.03.2016, 17:53 6
Цитата Сообщение от Voland_ Посмотреть сообщение
signed int
signed допускается опускать int по умолчанию signed, в отличии от char который может быть unsigned/signed в зависимости от настроек
причем самое смешное? что на микроконтроллерах char чаще всего настроен unsigned а на больших компах signed
0
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
09.03.2016, 20:32 7
Цитата Сообщение от ValeryS Посмотреть сообщение
int по умолчанию signed
да я ж не против. У ТС данные объявлены как указатель на тип long, как известно 32-битный. Это значит, что его знак лежит в 31м бите, а не 15м, как все нормальные знаковые биты в этом случае.
Я открывал даташит на этот АЦП, но при беглом изучении не нашел описание выходных данных, но из тех АЦП, с которыми я сталкивался, знак был в 90% случаев. Поэтому, вопрос его использования весьма актуален.
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
09.03.2016, 21:19 8
Цитата Сообщение от Voland_ Посмотреть сообщение
У ТС данные объявлены как указатель на тип long, как известно 32-битный.
в том то и дело что неизвестно
стандарт гарантирует что char<=short<=int<=long
о размерности ни слова, все на откуп компилятору,а про компилятор я у ТС не увидел
можешь себе представить все эти типы 128 бит, по стандарту допускается
вот тебе живой пример AVR и STM32 у одной int 16 у другой 32 бит
Цитата Сообщение от Voland_ Посмотреть сообщение
Это значит, что его знак лежит в 31м бите, а не 15м, как все нормальные знаковые биты в этом случае.
вот посему я и предложил работать ему с беззнаковыми
есть такой тип данных,не помню как называется, встречался со звуковыми АЦПухами
все что от 0 до средины диапазона( допустим 0-0x8000) это отрицательные а все что выше положительные значения, а сам 0 это средина(0x8000), и перевод в дополнительный код (signed), приведет к еще большему геморою
0
7 / 7 / 0
Регистрация: 03.04.2015
Сообщений: 45
10.03.2016, 22:43  [ТС] 9
Цитата Сообщение от Voland_ Посмотреть сообщение
сдается мне, вы просто получаете на "середину шкалы", а просто знаковое значение. 32790 - это может быть "-24". Попробуйте изменить объявление переменной на тип "signed int" (или signed short, здесь действительно зависит от компилятора и его настроек типов).

Цитата Сообщение от ValeryS Посмотреть сообщение
все что от 0 до средины диапазона( допустим 0-0x8000) это отрицательные а все что выше положительные значения, а сам 0 это средина(0x8000)
Именно так и есть,
When the ADC is configured for bipolar operation, the output
code is offset binary with a negative full-scale voltage resulting
in a code of 000...000, a zero differential input voltage resulting
in a code of 100...000, and a positive full-scale input voltage
resulting in a code of 111...111.
Спасибо всем за помощь, как вернусь к этому вопросу, буду пробовать варианты. Если что-то получится, отпишусь.

По поводу явного приведения типов, такой вариант не сработал.
ЗЫ: Среда Atmel Studio 7, С99.
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
10.03.2016, 23:10 10
Цитата Сообщение от 3050mAh Посмотреть сообщение
Именно так и есть,
так вот если используешь int (по умолчанию знаковый) и получаешь все что отрицательное у АЦПухи в переменной положительное и наоборот, тута старший бит знак означает 1 значит минус
вот так тебе нужно переводить
C
1
2
unsigned int  DataADC=Read();// считываешь значение
int Data=DataADC-0x8000;// получаешь знаковую переменную с плюсами и минусами
1
7 / 7 / 0
Регистрация: 03.04.2015
Сообщений: 45
11.03.2016, 00:44  [ТС] 11
Цитата Сообщение от ValeryS Посмотреть сообщение
так вот если используешь int (по умолчанию знаковый) и получаешь все что отрицательное у АЦПухи в переменной положительное и наоборот, тута старший бит знак означает 1 значит минус
вот так тебе нужно переводить
Я согласен, что int по умолчанию знаковый. где старший разряд, отвечает за знак. int (он же вроде как short int) занимает 2 байта памяти и меет значения от -32768 до 32367. Но я то использовал long int (ну или можно было использовать unsigned int от 0 до 65535), который занимает 4 байта и имеет диапазон от -2 147 483 648 до 2 147 483 647. Следовательно, от АЦП я при любом раскладе принимаю исключительно положительное число.
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
11.03.2016, 01:00 12
Цитата Сообщение от 3050mAh Посмотреть сообщение
Следовательно, от АЦП я при любом раскладе принимаю исключительно положительное число.
не факт
смотри вот мы имеем -1 в char и копируем его в int
C++
1
2
char a=-1;
int b=a;
в b тоже -1,они содержат 0xFF и 0xFFFF соответственно, знаковый бит размножается
и это правильно иначе при приведении из меньшего в больший числа бы волшебным образом менялись
но в данной задаче это не приемлемо
выход использовать беззнаковые, они то просто копируют бит в бит
C++
1
2
char a=-1;
unsigned int b=a;
будет 0xFF и 0x00FF
1
7 / 7 / 0
Регистрация: 03.04.2015
Сообщений: 45
11.03.2016, 08:06  [ТС] 13
Цитата Сообщение от ValeryS Посмотреть сообщение
не факт
смотри вот мы имеем -1 в char и копируем его в int

C
1
2
char a=-1;
int b=a;
в b тоже -1,они содержат 0xFF и 0xFFFF соответственно, знаковый бит размножается
и это правильно иначе при приведении из меньшего в больший числа бы волшебным образом менялись
но в данной задаче это не приемлемо
выход использовать беззнаковые, они то просто копируют бит в бит
C
1
2
char a=-1;
unsigned int b=a;
будет 0xFF и 0x00FF
Не знал про это, спасибо. Буду пробовать.

А ещё такой вопрос, можно ли как то получить доступ к глобальным переменным, не используя ключевого слова volatile при объявлении переменной?
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
11.03.2016, 08:45 14
Цитата Сообщение от 3050mAh Посмотреть сообщение
А ещё такой вопрос, можно ли как то получить доступ к глобальным переменным,
берешь и вызываешь если переменная объявлена в другой единице трансляции (файл С) то нужно добавить слово extern чтобы компилятор её увидел
например так
file1.c
C
1
2
3
4
int a;
 
.........
a=5;
file2.c
C
1
2
3
extern int a;
.............
a=10;
Цитата Сообщение от 3050mAh Посмотреть сообщение
не используя ключевого слова volatile при объявлении переменной?
это несколько другое
слово volatile запрещает компилятору её оптимизировать

например
C
1
2
int a=5;
while(a!=5)
и где то в другом файле, в процедуре, допустим, прерывания есть такое
C
1
a=10;
компилятор видя что условие цикла ложное, и не зная что в другом месте переменная меняется, вполне может этот цикл выбросить, понимая что это пустой код
так вот слово volatile запрещает ему такие вольности
0
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
11.03.2016, 09:54 15
Цитата Сообщение от 3050mAh Посмотреть сообщение
Следовательно, от АЦП я при любом раскладе принимаю исключительно положительное число.
вдобавок к сказанному еще хочу отметить, что вы передаете в функцию указатель на long, но не само число. Это значит, что если вы при вызове функции дадите указатель на переменную short, то функция вообще может сбеситься, т.к. вполне возможно после этой переменной память будет содержать еще данные, в данном случае являющиеся старшими разрядами переменной. То есть вы в этом случае должны передавать указательно только на тип long и более.

Что касается АЦП - то я в курсе
Цитата Сообщение от ValeryS Посмотреть сообщение
есть такой тип данных,не помню как называется, встречался со звуковыми АЦПухами
все что от 0 до средины диапазона( допустим 0-0x8000) это отрицательные а все что выше положительные значения, а сам 0 это средина(0x8000), и перевод в дополнительный код (signed), приведет к еще большему геморою
глянул таки ДШ, принцип вы правильный указали. Но здесь немного не так (стр.25):
The offset register is a 16-bit register on the AD7795 and a 24-bit
register on the AD7794. The offset register holds the offset
calibration coefficient for the ADC and its power-on reset value
is 0x8000/0x800000, for the AD7794/AD7795, respectively.
То есть смещение нуля и задается этим регистром. А выходные данные идут без знака. По умолчанию нулем задается середина диапазона, что вполне логично.
1
7 / 7 / 0
Регистрация: 03.04.2015
Сообщений: 45
11.03.2016, 15:23  [ТС] 16
Цитата Сообщение от Voland_ Посмотреть сообщение
вдобавок к сказанному еще хочу отметить, что вы передаете в функцию указатель на long, но не само число. Это значит, что если вы при вызове функции дадите указатель на переменную short, то функция вообще может сбеситься, т.к. вполне возможно после этой переменной память будет содержать еще данные, в данном случае являющиеся старшими разрядами переменной. То есть вы в этом случае должны передавать указательно только на тип long и более.
переменная которая хранит данные от АЦП имеет тип тип long int, адрес которой я потом передаю в функцию по указателю.

C
1
2
3
long int result[MAX_CHANNEL];                   //результат преобразования для каждого канала
void AD779x_GetConversionData(long int *pDataForReceive, uint8_t dataNumber); //функция для приёма данных от АЦП
double convertAdcCountdownTomV(long int *valueForConvert); // собственно расчёт значения напряжения
0
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
11.03.2016, 15:40 17
ну я понимаю, вроде бы не было замечено банальных ошибок. Просто 32битная арифметика даже цилочисленная довольно громоздкая в AVR. У нее ж даже команд деления нет, не то что float-сопроцессора. А вы ему постоянно double и long подсовываете. Я бы пересмотрел код в плане ухода от double и float, и работы в целочисленном поле, но, скажем, с умноженными на 1000 числами. Это заметно сэкономит процессорное время и убережет от ошибок.

ЗЫ: в каком-то проекте я слыхал, что тригонометрические вычисления (3d-координат, ничего заморского) в AVR занимали ~0,5c (!), хотя в выражениях там 3-4 строчки по 5-6 действий в каждой. Так что я бы сделал выражение
C
1
double a = (adc/32768.0) * 1.17;
в виде
C
1
signed long a = (((unsigned long)adc)-offs)*1170)>>15;
При этом в переменной "a" вы получите результат умноженный на 1000 (то есть по факту с тремя знаками после запятой). Считаться будет ну просто "на лету", учитывая всю сложность операции. В принципе вы можете в числитель еще 10 добавить (то есть умножать на 11700), чтобы получить 4 знака после запятой.

PS: только в моем варианте надо будет проследить насчет сдвига знака. Если он движется вместе со всеми байтами, то придется сдвиг втянуть внутрь выражения, дважды умножив adc и offs на множитель, сдвинуть их, а потом вычесть.
0
7 / 7 / 0
Регистрация: 03.04.2015
Сообщений: 45
11.03.2016, 17:11  [ТС] 18
Цитата Сообщение от ValeryS Посмотреть сообщение
компилятор видя что условие цикла ложное, и не зная что в другом месте переменная меняется, вполне может этот цикл выбросить, понимая что это пустой код
так вот слово volatile запрещает ему такие вольности
Т.е. для приёма данных от АЦП не обязательно при объявлении переменной использовать volatile, но если переменная участвует где-то в условии, то её надо обозвать volatile?

Добавлено через 1 час 25 минут
Цитата Сообщение от Voland_ Посмотреть сообщение
А вы ему постоянно double и long подсовываете.
Пока я приостановил это дело и вернусь к нему в ближайшее время. Большие типы данных были выбраны, с целью избежать нехватки места и избежать переполнения. Так сказать для первого приближения.
0
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
11.03.2016, 19:06 19
Цитата Сообщение от Voland_ Посмотреть сообщение
олько в моем варианте надо будет проследить насчет сдвига знака. Если он движется вместе со всеми байтами,
а он движется, а на место его приходит опять он же( во завернул)
например число 10001000 (двоичное)надо сдвинуть на 2 вправо
так вот для знакового результат сдвига будет 1110 0010
а для безнакового 0010 0010
в ассемблере различают сдвиг вправо арифметический( с копированием знакового бита) и логический( без копирования оного) при сдвиге влево оба сдвига ведут себя одинаково

Добавлено через 54 минуты
Цитата Сообщение от 3050mAh Посмотреть сообщение
Т.е. для приёма данных от АЦП не обязательно при объявлении переменной использовать volatile,
вот тут подробно про эту volatile http://we.easyelectronics.ru/S... atile.html
2
techpriest
634 / 213 / 57
Регистрация: 27.02.2014
Сообщений: 1,180
13.03.2016, 01:29 20
... Я где-то года два назад проводил исследование вопроса арифметики с плавающей точкой. К сожалению результатов не сохранилось, но вывод был следующим.

На контроллерах имеющих умножитель операции над float выполняются приблизительно с той же скоростью, как и над int32_t.
Так что особых причин отказываться от float в пользу 4-х байтной целочисленной арифметики... На самом деле нет...

А ошибок с целочисленной арифметикой наляпать можно преизрядно.

И... Вообще говоря, 8МГц и 2Кб оперативки позволяют развернуть неслабую операционную систему... Такой комп на луну летал.
А вы такты и байты считаете.
0
13.03.2016, 01:29
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.03.2016, 01:29
Помогаю со студенческими работами здесь

Друзья, я в шоке! Кто с таким сталкивался?
Уйма времени было потрачено на отладку Multimerch (партнёрская программа продавцов) в Opencart...

Сокет 942. кто с таким сталкивался?
Всем привет. решил сменить кулер. на плате там где он стоит написано &quot;socket 942&quot; а рядом с...

Кто сталкивался с таким? Бьюсь уже три часа
Похоже, я сделал искусственный интеллект :-D Как бы я ни пытался исправить. (оставил только циклы,...

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

может кто сталкивался
Всем привет. Подскажи плиз. Стоит сервак на базе ОС Server 2008. Поднят сервер терминалов. Стоит...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru