Параллельный АЦП и Ардуино.
- Войдите на сайт для отправки комментариев
Втр, 26/01/2016 - 16:11
Привет коллеги.
Подскажите кто имел опыт прикручивания параллельного АЦП к Ардуино, возможно есть готовые библиотеки или просто у вас был проект такой.
Если есть поделитесь ссылочной или кодом.
Про то что можно прописать все на С я знаю но мы же на форуме по Ардуино! Про АЦП работающие по SPI не писать с ними все и так ясно.
Всем ко не пройдет мимо заранее спасибо!
Да прикрутить то его несложно. Соеденяешь выход АЦП (8 разрядов) с одним портом ардуины, например В и читаешь весь порт в переменную, например а =PortB. В переменной имеешь число от 0 до 255. Все остальное как частота тактирования, уровень входного напряжения и т.д. смотрим в даташите на АЦП.
Да прикрутить то его несложно. Соеденяешь выход АЦП (8 разрядов) с одним портом ардуины, например В и читаешь весь порт в переменную, например а =PortB. В переменной имеешь число от 0 до 255. Все остальное как частота тактирования, уровень входного напряжения и т.д. смотрим в даташите на АЦП.
Отличный совет!
--от 0 до 255 если АЦП восьмибитный.
--собирать данные АЦП в порт нужно только если преобразование завершено, для этого есть специальный сигнал.
--Как прикрутить АЦП и собирать данные стандартным способом используя язык С знаю и написал об этом.
Хотел и хочу увидеть возможно есть именно Ардуино реализация в виде проектов или библиотек!
Не встречалось мне пока проектов имеено для ардуино, да и билиотеки тут впринципе не нужны. От С+ в скетче то будет всего лишь будет кусочек например:
Засада в другом
Засад тут много. Например может попасть считывание данных на момент переключения результата АЦП и получим мусор. Но редко.
Если надо
как эти данные быстро обработать и вывести например на графический дисплей
Быстро вводим, складируем в буфер. Потом не так быстро обрабатываем и выводим на дисплей. Сильно быстро выводить на дисплей без толку, у него частота обновления низкая, не отобразит все, отобразит - так глаз не увидит, а увидит глаз - так мозг не поймет ))))
Сомневаюсь, что какой дибо ацп будет на шину выдавать промежуточные (мусорные значения)
но что гадать на кофейной гуще? Давайте название чипа
Сомневаюсь, что какой дибо ацп будет на шину выдавать промежуточные (мусорные значения)
Какие такие промежуточные?! Нет конечно. Одно корректное значение 01111111 меняет второе корректное 10000000 и именно в этот момент нас угораздило считать. Что получим?
В даташите пишут что считывать по наростанию клока, что требуется учитывать.
но что гадать на кофейной гуще? Давайте название чипа
Какое такое название? ... хмм мерзкий, пакостный, черный, диповский, видеозаточеный (если Вы про TDA8708A)
К стати, если Вы с ним знакомы то немного вопросов. Чем TDA8708A от B отличается? На али есть воще без буквы, а он чем отличен? Смотрю схема выходов АЦП имеет отдельное питание причем с странной нижней границей в 4,2В (чип вообще довольно странный из за заточки на видеосигнал, зато цена хорошая) это намек на совместимость с 3,3В, не знаете, не пробовали? Это интересует потому как для приема с него 30МГц avr безнадежен, прикидую на STM, а он 3,3В. Заточка чипа на видео не мешает общему применению как АЦП? А может полезна чем?
Сомневаюсь, что какой дибо ацп будет на шину выдавать промежуточные (мусорные значения)
Какие такие промежуточные?! Нет конечно. Одно корректное значение 01111111 меняет второе корректное 10000000 и именно в этот момент нас угораздило считать. Что получим?
В даташите пишут что считывать по наростанию клока, что требуется учитывать.
но что гадать на кофейной гуще? Давайте название чипа
Какое такое название? ... хмм мерзкий, пакостный, черный, диповский, видеозаточеный (если Вы про TDA8708A)
К стати, если Вы с ним знакомы то немного вопросов. Чем TDA8708A от B отличается? На али есть воще без буквы, а он чем отличен? Смотрю схема выходов АЦП имеет отдельное питание причем с странной нижней границей в 4,2В (чип вообще довольно странный из за заточки на видеосигнал, зато цена хорошая) это намек на совместимость с 3,3В, не знаете, не пробовали? Это интересует потому как для приема с него 30МГц avr безнадежен, прикидую на STM, а он 3,3В. Заточка чипа на видео не мешает общему применению как АЦП? А может полезна чем?
Если еще не заказали то мой совет не берите.
Лучше возьмите такой AD9280 он немного дешевле, по скорости такой же и собственных шумов мало дает, и с подбором ОУ будет проще, так как у него рабочий диапазон больше.
Мне лично он очень понравился! Рекомендую!
А считывать показания быстрее всего прямым копированием состояния порта в регистр памяти асемблером, если лень с асмом разбираться то можно писать на С но на компиляторе нужно выбоать максимальную оптимизацию по скорости.
Максимум что можно выжать с Атмега328 при кварце 16МГц это скорость записи 8МГц с АЦП-проверял.
Наполняете массив значений затем их обрабатываете, четко нужно разделять процессы чтоб считку не тормозить.
Если еще не заказали то мой совет не берите. Лучше возьмите такой AD9280 он немного дешевле, по скорости такой же и собственных шумов мало дает, и с подбором ОУ будет проще, так как у него рабочий диапазон больше. Мне лично он очень понравился! Рекомендую!
Спасибо, не заказывал, смотрю на AD9280. У меня пока предварительное рассмотрение задачи - т.е. стоит ли вообще в это влазить.
А считывать показания быстрее всего прямым копированием состояния порта в регистр памяти асемблером, если лень с асмом разбираться то можно писать на С но на компиляторе нужно выбоать максимальную оптимизацию по скорости. Максимум что можно выжать с Атмега328 при кварце 16МГц это скорость записи 8МГц с АЦП-проверял. Наполняете массив значений затем их обрабатываете, четко нужно разделять процессы чтоб считку не тормозить.
А считывать показания быстрее всего прямым копированием состояния порта в регистр памяти асемблером, если лень с асмом разбираться то можно писать на С но на компиляторе нужно выбоать максимальную оптимизацию по скорости. .
Та ладно! Добится того, чтоб за две команды считать порт и сохранить не так и сложно. Можна даже адрес инерементить если в стек сохранять.
Максимум что можно выжать с Атмега328 при кварце 16МГц это скорость записи 8МГц с АЦП-проверял. Наполняете массив значений затем их обрабатываете, четко нужно разделять процессы чтоб считку не тормозить.
+1
С учетом того что я разгоняю Атмегу до 27МГц можно будет получить максимум 15 мегасемплов в секунду.Это не плохо, плохо то что оперативки у Атмеги мало и получается собрать до 1500 выборок и с ними работать а это мало.
Посмотрел AD9280. В целом симпатичный, только непонятка с переполнением, выход сигнализации есть, а какой код при этом выдаст не понятно. Я правда даташит подиагонали читал, может пропустил.
Только по цене он в 2 раза дороже, но что радует, у продавца на али на этот АЦП даже есть заказы, аж два!! Ну один понятно - Ваш. Но получается ещё кто-то на Земле этим занимается ))) И не признается! ))))
Я его в УА покупал за 2.5бакса, а ТДА у нас 3бакса стоит.
Вот мне форумчанин показал где есть дешевые
2штуки
http://www.ebay.com/itm/2-PCS-AD9280ARSZ-SSOP-28-AD9280ARS-AD9280-8-Bit-...
К нему еще нужен толковый ОУ, т.к. входное сопротивление низковато. Кто что использует. Так чтоб 30МГц и сс запасом. И питание 0-5В.
Ого как ветка оживилась!
TDA8708A действительно заказывать не стоит, лучше уж AD9280. Я ее покупал для проекта на http://www.stanson.ch/index.php?page=proj&proj=USB-oscope, но не совладал с линуксом так и осталась. А так если очень хочется, то она в Вольмастере есть.
Вот тут Атмегу32 разогнали до 32МГц http://bezkz.su/publ/shemy/oscillografy/page,1,2,700212-oscillograf-na-mikrokontrollere-atmega32a.html, а в комментариях один товарищ пишет, что у него замечательно работает и на 40Мгц. С учетом того, что частота дискретизации там 1\3 то получается довольно неплохо, можно спокойно смотреть сигналы до мегагерца, что в большинстве случаев вполне достаточно.
Быстро вводим, складируем в буфер. Потом не так быстро обрабатываем и выводим на дисплей.
Я пока в программировании не силен можно пояснить алгоритм? Допустим заполнили буфер, начали обрабатывать, а куда девать данные которые идут во время обработки? Или просто их игнорируем, или делаем большой буфер, тогда насколько большой?
Или просто их игнорируем, или делаем большой буфер, тогда насколько большой?
Игнорируем, если задача позволяет, разумеется. Т.е. для задач типа осцилографа, эквалайзера и т.д. где результатов заведомо больше, чем человек может воспринять.
Быстро вводим, складируем в буфер. Потом не так быстро обрабатываем и выводим на дисплей.
Я пока в программировании не силен можно пояснить алгоритм? Допустим заполнили буфер, начали обрабатывать, а куда девать данные которые идут во время обработки? Или просто их игнорируем, или делаем большой буфер, тогда насколько большой?
Забили буфер, после этого игнорируем АЦП обрабатываем данные и выводим на экран, после сразу забиваем новые данные. На скоростях выше 20МГц и оперативке 2Кб вы этого не заметите.
[ Максимум что можно выжать с Атмега328 при кварце 16МГц это скорость записи 8МГц с АЦП-проверял. Наполняете массив значений затем их обрабатываете, четко нужно разделять процессы чтоб считку не тормозить.
Заинтриговало, решил попробывать. Достал лежавший без дела АЦП, подцепил к Атмега328 и ....
надежды на такую скорость быстро растаяли, больше 200 кГц нормально видимого сигнала получить не удалось.
Решил проверить насколько быстро Атмега может заполнить массив отсчетов и в принципе результаты совпали с этой частотой. Взял вот такой скетч и посмотрел за сколько пишется 10, 100 и 1000 элементов массива
01
unsigned
int
Read[10];
02
03
void
setup
() {
04
DDRD = 0xff;
// Настройка порта D на выход
05
PORTD = 0xff;
06
DDRC = 0x00;
// Настройка порта С на вход
07
PORTC = 0x00;
08
}
09
10
void
loop
() {
11
12
int
i;
13
for
(i=0; i<10; i++) {
// читаем порт в массив
14
Read[i] = PINC;
15
}
16
for
(i=0; i<10; i++) {
// имитируем работу программы
17
PORTD = 0x00;
18
PORTD = 0xff;
19
}
20
}
Потом проделал тоже самое в Атмел студии , получилось что массив из 10 элементов пишется в память при кодировании в Аrduino IDE - 8.188 мкс, в Атмел студии - 3.688 мкс, то бишь реальная частота при которой можно реально увидеть какойто сигнал (10 отсчетов), а не просто 2 точки - 122кГц и 266кГц соответственно. Возможно на асемблере получится еще немного быстрее но я в нем не шарю вообще. Может кто проверит ради интереса.
Реально код в чистом С работает в 2 с лишним раза быстрее. Отсюда вывод - надо что то шустрее например STM32. Хотя ремонтировать импульсные БП вполне.
Вот результаты
И шож Вы исследуете при
unsigned
int
Read[10]; и
int
i;
Ну елы палы! Просто диссертация, и при таких типах данных. А про 8МГц - таки не похоже на правду. скорей выйдет что надо 3 такта, т.е. 16/3=5.33Мгц. Потому как загрузка с порта однотактовая а сохранение с инкрементом адреса двутактная, и PUSH (это если на стеке делать) тоже. И понятно, цикл развернуть.Кстати 3.688мкс на 10 элементов - это 6 тактов, 3 на ввод и сохранение, 1 проверка индекса и 2 переход. Похоже в студии у Вас типы данных правильные- оди байт а не int.
Про АЦП на 200КГц - это Вы его порядком загрубили, 10 бит оно честно дает за 13мкс, т.е. около 76КГц.
Мужики ser-vasin, ser-vasin есть у меня Хамелион, он на Atmega32 которая тактируется 15МГц делает 6Мегасемплов в секунду, реальный прибор в железе там код на ассемблере.
Atmega328 от кварца 27МГцсможет вдвое быстрее.
Как и что писали вы не знаю но в Атмел студии можно посмотреть ассемблерную расшифровку вашего кода и там видно что каждое десйствие занимает вместо одного такта четыре и так по разному везде, это зависит от настроек опритмизации компилятора, но на асме все равно быстрее всего.
Как и что писали вы не знаю но в Атмел студии можно посмотреть ассемблерную расшифровку вашего кода и там видно что каждое десйствие занимает вместо одного такта четыре и так по разному везде, это зависит от настроек опритмизации компилятора, но на асме все равно быстрее всего.
Посмотреть можна и в ардуинке. Код. Три варианта ввода , цикл на int, на byte, и без цикла.
01
unsigned
int
Read[10];
02
byte
Readbyte[10];
03
void
setup
()
04
{
05
int
i;
06
for
(i=0; i<10; i++) {
// читаем порт в массив
07
Read[i] = PINC;
08
}
09
for
(
byte
i=0; i<10; i++) {
// читаем порт в массив
10
Readbyte[i] = PINC;
11
}
12
Readbyte[i++] = PINC;
13
Readbyte[i++] = PINC;
14
Readbyte[i++] = PINC;
Дизассемблировано
01
00000c82 <
setup
>:
02
c82: ec e5 ldi r30, 0x5C ; 92
03
c84: f2 e0 ldi r31, 0x02 ; 2
04
c86: 86 b1
in
r24, 0x06 ; 6
05
c88: 80 83 st Z, r24
06
c8a: 11 82 std Z+1, r1 ; 0x01
07
c8c: 32 96 adiw r30, 0x02 ; 2
08
c8e: 82 e0 ldi r24, 0x02 ; 2
09
c90: e0 37 cpi r30, 0x70 ; 112
10
c92: f8 07 cpc r31, r24
11
c94: c1 f7 brne .-16 ; 0xc86 <
setup
+0x4>
12
c96: e0 e7 ldi r30, 0x70 ; 112
13
c98: f2 e0 ldi r31, 0x02 ; 2
14
c9a: 86 b1
in
r24, 0x06 ; 6
15
c9c: 81 93 st Z+, r24
16
c9e: 82 e0 ldi r24, 0x02 ; 2
17
ca0: ea 37 cpi r30, 0x7A ; 122
18
ca2: f8 07 cpc r31, r24
19
ca4: d1 f7 brne .-12 ; 0xc9a <
setup
+0x18>
20
ca6: 86 b1
in
r24, 0x06 ; 6
21
ca8: 80 83 st Z, r24
22
caa: 86 b1
in
r24, 0x06 ; 6
23
cac: 81 83 std Z+1, r24 ; 0x01
24
cae: 86 b1
in
r24, 0x06 ; 6
25
cb0: 82 83 std Z+2, r24 ; 0x02
Число циклов смотрим в описании МК. Для in-1 для st,std-2...
Без цикла (последние 6 строк) все просто in и std, ввод каждого значения за 3 цикла, т.е 5,33МГц
В циклах видно наличие связки in и st, а все остальное - на организацию цикла. Для инта цикл 8 команд, для байта 6. Циклы считать лень, но в общем издержки больше чем я думал. Если цикл перевернуть так - for ( i=10; i; i--) будет лучше. Наверно. Если есть из студии дизассемблер - выкладуйте, посмотрим различия завтра.
Очень сомниваюсь что здесь настройки компилятора чего либо поменяют. GCC штука проверенная, лишнего не лепит. На всяк случай напомню - именно gcc компилирует из си, ИДЕ только гадости в исходниках сишных делает ;))) своим препроцессором, к компиляции она никоим боком.
Отличный совет!
--от 0 до 255 если АЦП восьмибитный.
--собирать данные АЦП в порт нужно только если преобразование завершено, для этого есть специальный сигнал.
--Как прикрутить АЦП и собирать данные стандартным способом используя язык С знаю и написал об этом.
Хотел и хочу увидеть возможно есть именно Ардуино реализация в виде проектов или библиотек!
Какое нафиг преобразование в параллельном АЦП? Оно же не путём приближения работает. И данне в порту у него не пляшут в момент изменения - там регистр-защёлка должен быть буфферный.
Посмотреть можна и в ардуинке. Код. Три варианта ввода , цикл на int, на byte, и без цикла.
01
unsigned
int
Read[10];
02
byte
Readbyte[10];
03
void
setup
()
04
{
05
int
i;
06
for
(i=0; i<10; i++) {
// читаем порт в массив
07
Read[i] = PINC;
08
}
09
for
(
byte
i=0; i<10; i++) {
// читаем порт в массив
10
Readbyte[i] = PINC;
11
}
12
Readbyte[i++] = PINC;
13
Readbyte[i++] = PINC;
14
Readbyte[i++] = PINC;
Дизассемблировано
01
00000c82 <
setup
>:
02
c82: ec e5 ldi r30, 0x5C ; 92
03
c84: f2 e0 ldi r31, 0x02 ; 2
04
c86: 86 b1
in
r24, 0x06 ; 6
05
c88: 80 83 st Z, r24
06
c8a: 11 82 std Z+1, r1 ; 0x01
07
c8c: 32 96 adiw r30, 0x02 ; 2
08
c8e: 82 e0 ldi r24, 0x02 ; 2
09
c90: e0 37 cpi r30, 0x70 ; 112
10
c92: f8 07 cpc r31, r24
11
c94: c1 f7 brne .-16 ; 0xc86 <
setup
+0x4>
12
c96: e0 e7 ldi r30, 0x70 ; 112
13
c98: f2 e0 ldi r31, 0x02 ; 2
14
c9a: 86 b1
in
r24, 0x06 ; 6
15
c9c: 81 93 st Z+, r24
16
c9e: 82 e0 ldi r24, 0x02 ; 2
17
ca0: ea 37 cpi r30, 0x7A ; 122
18
ca2: f8 07 cpc r31, r24
19
ca4: d1 f7 brne .-12 ; 0xc9a <
setup
+0x18>
20
ca6: 86 b1
in
r24, 0x06 ; 6
21
ca8: 80 83 st Z, r24
22
caa: 86 b1
in
r24, 0x06 ; 6
23
cac: 81 83 std Z+1, r24 ; 0x01
24
cae: 86 b1
in
r24, 0x06 ; 6
25
cb0: 82 83 std Z+2, r24 ; 0x02
Число циклов смотрим в описании МК. Для in-1 для st,std-2...
Без цикла (последние 6 строк) все просто in и std, ввод каждого значения за 3 цикла, т.е 5,33МГц
В циклах видно наличие связки in и st, а все остальное - на организацию цикла. Для инта цикл 8 команд, для байта 6. Циклы считать лень, но в общем издержки больше чем я думал. Если цикл перевернуть так - for ( i=10; i; i--) будет лучше. Наверно. Если есть из студии дизассемблер - выкладуйте, посмотрим различия завтра.
Очень сомниваюсь что здесь настройки компилятора чего либо поменяют. GCC штука проверенная, лишнего не лепит. На всяк случай напомню - именно gcc компилирует из си, ИДЕ только гадости в исходниках сишных делает ;))) своим препроцессором, к компиляции она никоим боком.
Одна из фишек, дающая корявость кода, но помогающая компилятору - объявление переменной где попало. Объявите счётчик в заголовке цикла и его оптимировать компилятор сможет: for ( int i=0...
Пока мой АЦП не приедет и я не вытравлю плату тестовую с АЦП+МК и обвязка, ничего кодить и выкладывать темболее не собираюсь!)
Дурное это дело виртуальные приборы ускорять, вот если не получится быстро сделать хотя-бы 10-12мегасемплов в секунду выложу что есть и скажу прямо,-" Хотелось как лучше, а получилось вот так!)"
Похоже в студии у Вас типы данных правильные- оди байт а не int.
Про АЦП на 200КГц - это Вы его порядком загрубили, 10 бит оно честно дает за 13мкс, т.е. около 76КГц.
Да нет в студии код тот же самый код, оптимизаций никаких не влючал - не умею пока, может она сама оптимизирует.
01
int
main(
void
)
02
{
03
unsigned
int
Read[10];
04
DDRD = 0xFF;
05
PORTD = 0x00;
06
DDRC = 0x00;
07
PORTC = 0x00;
08
while
(1)
09
{
10
int
i;
11
for
(i=0; i<10; i++) {
12
Read[i] = PORTC;
13
}
14
for
(i=0; i<10; i++) {
15
PORTD = 0x00;
16
PORTD = 0xff;
17
}
18
}
19
}
Про АЦП не понял, АЦП внешний - многострадальная TDA8708A тактируется теми же 16 МГц, что и контроллер через вывод CLKO.
А как тогда правильно объявить массив, bate студия не понимает, может тогда
unsigned char ?
И, что означает "Если цикл перевернуть так - for ( i=10; i; i--) будет лучше. Наверно. "
Чем лучше?
Мужики ser-vasin, ser-vasin есть у меня Хамелион, он на Atmega32 которая тактируется 15МГц делает 6Мегасемплов в секунду, реальный прибор в железе там код на ассемблере.
Atmega328 от кварца 27МГцсможет вдвое быстрее.
Как и что писали вы не знаю но в Атмел студии можно посмотреть ассемблерную расшифровку вашего кода и там видно что каждое десйствие занимает вместо одного такта четыре и так по разному везде, это зависит от настроек опритмизации компилятора, но на асме все равно быстрее всего.
Да все по тесту получается правильно, просто мы говорим маленько о разном. Тактировать АЦП можно хоть 100 МГЦ весь вопрос в том сколько сможет переварить Атмега и сколько нам нужно для нормального отображения сигнала. А нужно хотя бы 10 отсчетов, ну 5 для треугольника.
Вот Logik пояснил, что 3.688мкс на 10 элементов - это 6 тактов, 3 на ввод и сохранение, 1 проверка индекса и 2 переход.
Если уложить это на Ассемблере в 3 такта то получим ~ 500 кГц нормально видимого сигнала, о чем честно и написано разработчиком Хамелиона на Радиокоте,
цитата
А как тогда правильно объявить массив, bate студия не понимает, может тогда
unsigned char ?
да.
И, что означает "Если цикл перевернуть так - for ( i=10; i; i--) будет лучше. Наверно. "
Чем лучше?
А тем что проверка i!=0 выполняется быстрей чем i<10. Старый програмистский фокус. Но реально, если нужно предельно быстро - нужно цикл раскрывать. Хотите ввести десять значений - 10 раз пишем Read[i++] = PORTC; разницы с ассемблером не будет. Цикл даже предельно оптимально, на ассемблере будит хуже в 2-3 раза.
Я так вижу по теме блуждает некоторое расхождение в трактовке слова "паралельный". Одни имеют в виду способ его подключения к МК - паралельно к порту, не по I2C как бывает, другие про тип АЦП - АЦП паралельного преобразования. Я так понимаю нам его тип пофигу, лиш бы быстро, а подключение и есть предмет темы.
И данне в порту у него не пляшут в момент изменения - там регистр-защёлка должен быть буфферный.
Они конечно есть. И данные не пляшут, но периодически изменяют значения на новые. И если ввод пройдет именно в этот момент, получим отсчет с мусором. Но это редко будет, а при тактировании от одного генератора может и не проявлятся.
А тем что проверка i!=0 выполняется быстрей чем i<10. Старый програмистский фокус. Но реально, если нужно предельно быстро - нужно цикл раскрывать. Хотите ввести десять значений - 10 раз пишем Read[i++] = PORTC; разницы с ассемблером не будет. Цикл даже предельно оптимально, на ассемблере будит хуже в 2-3 раза.
Вот спасибо за подсказку. То бишь должно выглядеть примерно так?
01
unsigned
char
Read[10];
02
03
void
setup
() {
04
05
DDRC = 0x00;
06
PORTC = 0x00;
07
}
08
09
void
loop
() {
10
11
unsigned
char
i = 0;
12
13
// читаем порт в массив
14
Read[i++] = PINC;
// пишем 10 раз
15
........
16
Read[i++] = PINC;
17
18
}
....
Да все по тесту получается правильно, просто мы говорим маленько о разном. Тактировать АЦП можно хоть 100 МГЦ весь вопрос в том сколько сможет переварить Атмега и сколько нам нужно для нормального отображения сигнала. А нужно хотя бы 10 отсчетов, ну 5 для треугольника.
.....
Я писал о тактировании Атмеги, если при тактировании 15МГц Хамелион может оцифровывать данные со скоростью 6Мегасемплов, то тактируя Атмегу от 27МГц она будет быстрее сохранять данные и можно добиться 10-12Мегасемплов оцифровки.
Все данные есть в даташите, четко написано сколько тактов нужно на сохранения состояния порта в регистр памяти, точных цифр не помню кому нужно найдет, но если пишу что можно ускорить значит я посчитал и рассчитываю на это.
Нам нужно НИ НА ЧТО не отвлекая контроллер на максимальной скорости забить отведенные регистры памяти состояниями порта на котором АЦП, дальше прекратить сбор обработать и вывести и опять сбор и так по кругу.
А тем что проверка i!=0 выполняется быстрей чем i<10. Старый програмистский фокус. Но реально, если нужно предельно быстро - нужно цикл раскрывать. Хотите ввести десять значений - 10 раз пишем Read[i++] = PORTC; разницы с ассемблером не будет. Цикл даже предельно оптимально, на ассемблере будит хуже в 2-3 раза.
Вот спасибо за подсказку. То бишь должно выглядеть примерно так?
да.
Да все по тесту получается правильно, просто мы говорим маленько о разном. Тактировать АЦП можно хоть 100 МГЦ весь вопрос в том сколько сможет переварить Атмега и сколько нам нужно для нормального отображения сигнала. А нужно хотя бы 10 отсчетов, ну 5 для треугольника.
Я так понимаю, это Вы про сглаживание входных сигналов? Так можна и проще.
Получили с АЦП очередной отсчет А. Считаем так S=S+A-S/n, и сглаженый Асгл=отсчет S/n, где n - величина характеризующая степень сглаживания, удобно брать в виде степени двойки. По умному это ФНЧ с БИХ первого порядка. Для первого отсчета полезно делать S=A*n. Разрядность S надо брать больше чем А на степень двойки в n.
Зря я сразу код не писал, эти формулы в тексте 8(
пределы 2мкс,5мкс,10мкс,20мкс,50мкс,100мкс,200мкс,500мкс,1мс,2мс,5мс,10мс,20мс,50мс."
Не густо ли пределы? ИМХО лучше реже. И еще добавить типа режим захвата - сигнал запомнили в буфере и перешли в режим просмотра, а при просмотре его можна сжимать и растягивать в несколько раз. Полезно и для редких событий и пределы не надо часто щелкать.
К примеру на STM я могу запомнить около 10000 отсчетов, при вводе с АЦП порядка 1мкс получу хранение 10мс. А далее я при просмотре сжимаю и растягиваю как хочу, перемещаюсь влево и вправо. Обмен по всяким i2c так удобней рассматривать. Собственно без этого его толком не посмотриш.
Нам нужно НИ НА ЧТО не отвлекая контроллер на максимальной скорости забить отведенные регистры памяти состояниями порта на котором АЦП, дальше прекратить сбор обработать и вывести и опять сбор и так по кругу.
Причем даже прерывания запретить. Но такая логика хороша только на высоких частотах. Если диапазон мс и более, то логика нужна другая. Там и на одну точку много отсчетов АЦП, и прорисовывать можна и нужно сразу и т.д.
Я писал о тактировании Атмеги, если при тактировании 15МГц Хамелион может оцифровывать данные со скоростью 6Мегасемплов, то тактируя Атмегу от 27МГц она будет быстрее сохранять данные и можно добиться 10-12Мегасемплов оцифровки.
Да с этим я и не спорю, что если ее разогнать то она будет сохранять данные быстрее. Я пока пытаюсь понять как быстро она сохраняет на стандартной частоте, так как пока только разбираюсь в программировании на С, а про Асемблер вообще сказать нечего. За плечами только начальный курс Бейсика средней школы.
Я так понимаю, это Вы про сглаживание входных сигналов? Так можна и проще.
Получили с АЦП очередной отсчет А. Считаем так S=S+A-S/n, и сглаженый Асгл=отсчет S/n, где n - величина характеризующая степень сглаживания, удобно брать в виде степени двойки. По умному это ФНЧ с БИХ первого порядка. Для первого отсчета полезно делать S=A*n. Разрядность S надо брать больше чем А на степень двойки в n.
Не, про это я вообще пока не задумывался. Я про то, что имееем например на входе меандр с периодом 10мкс, а в массив можем сохранять со скоростью не больше 2мкс, вот и получим всего 5 отсчетов даже если АЦП может больше и в итоге увидим не меандр а теугольник. Вот как то так.
Не густо ли пределы? ИМХО лучше реже.
Ну это вопрос не ко мне, а к разработчику Хамелиона, у меня данного прибора нет. Я просто привел его характеристики.
К примеру на STM я могу запомнить около 10000 отсчетов, при вводе с АЦП порядка 1мкс получу хранение 10мс. А далее я при просмотре сжимаю и растягиваю как хочу, перемещаюсь влево и вправо. Обмен по всяким i2c так удобней рассматривать. Собственно без этого его толком не посмотриш.
А вот тут можно немножко подробней. Я пыталься играться с пересчетом координат точек при выводе на дисплей, но что то путного ничего не получилось. Не придумал ничего лучшего кроме задержки в цикле при чтении данных с АЦП. Но что то мне подсказывает это есть не совсем правильно. Да и отсчетов у меня всего 100, а у вас вон сколько. Может натолкнете на путь истинный.
Но реально, если нужно предельно быстро - нужно цикл раскрывать. Хотите ввести десять значений - 10 раз пишем Read[i++] = PORTC; разницы с ассемблером не будет.
Проверил на практике. Результаты довольно интересные, если в Ардуино IDE все оказалось довольно пресказказуемо, то в студии как то немного непонятно.
При замене массива int на char, прибавка в скорости около 25-30%, а при раскрытии цикла скорость в IDE увеличилась еще в 2 раза, а вот в студии аж почти в 3 раза и массив из 100 элементов почти в 5 раз.
Перепроверил перепрошил несколько раз, результат один, почти 1мкс на массив из 10 элементов.
Это реально или что то не так? Вот код из студии
01
int
main(
void
) {
02
03
unsigned
char
Read[10];
04
unsigned
char
i = 0;
05
DDRD = 0xFF;
06
PORTD = 0x00;
07
DDRC = 0x00;
08
PORTC = 0x00;
09
10
while
(1) {
11
12
i = 0;
13
14
Read[i++] = PORTC;
// пишем 10 раз
15
Read[i++] = PORTC;
16
Read[i++] = PORTC;
17
Read[i++] = PORTC;
18
Read[i++] = PORTC;
19
Read[i++] = PORTC;
20
Read[i++] = PORTC;
21
Read[i++] = PORTC;
22
Read[i++] = PORTC;
23
24
for
(i=0; i<5; i++) {
// имитируем работу
25
PORTD = 0x00;
26
PORTD = 0xff;
27
}
28
}
29
}
Вот результаты
И данне в порту у него не пляшут в момент изменения - там регистр-защёлка должен быть буфферный.
Они конечно есть. И данные не пляшут, но периодически изменяют значения на новые. И если ввод пройдет именно в этот момент, получим отсчет с мусором. Но это редко будет, а при тактировании от одного генератора может и не проявлятся.
Не бывает. Это не дунькин софт, с микросхемах всё предусмотрено - их аккуратные и умные люди делают.
Параллельный порт имеет регистр-защёлку вход-выход. Когда АЦП нашёл значение, он его готовое имеет на своём выходе, подключенном к защёлке, даёт сигнал записи и все разряды одновременно улетают в защёлку (на, с какими-то там мгновениями терагерцовыми). Если порт последовательный, то передача осуществляется через регистр, который заполняется в начале чтения - пока буфер не улетит, изменения показателя значения пофигу. Тайминти по всем микросхемам всегда приводятся в даташитах. Иверяю Вас - ни один даже самый офигительный процессор не успеет отловить разницу в скорости записи разрядов защёлки.
При замене массива int на char, прибавка в скорости около 25-30%, а при раскрытии цикла скорость в IDE увеличилась еще в 2 раза, а вот в студии аж почти в 3 раза и массив из 100 элементов почти в 5 раз.
Перепроверил перепрошил несколько раз, результат один, почти 1мкс на массив из 10 элементов.
Это реально или что то не так? Вот код из студии
Тенденции верные, а цифры - не все понятно. Но с другой стороны у Вас в раскрытом цикле не 10 вводов а 9 ;) Ввод 10 значений за 1мкс при тактовой частоте 16МГц выглядит невероятно прекрасно.
Не бывает. Это не дунькин софт, с микросхемах всё предусмотрено - их аккуратные и умные люди делают.
Ой да ладно. Пивал я с ними пиво. А как бутылки суютсуют потом в диффузионные печи для осаждения фосфоросиликатного стекла на кремний , так тоже лично видел. Но не о том вопрос.
Параллельный порт имеет регистр-защёлку вход-выход. Когда АЦП нашёл значение, он его готовое имеет на своём выходе, подключенном к защёлке, даёт сигнал записи и все разряды одновременно улетают в защёлку (на, с какими-то там мгновениями терагерцовыми). Если порт последовательный, то передача осуществляется через регистр, который заполняется в начале чтения - пока буфер не улетит, изменения показателя значения пофигу. Тайминти по всем микросхемам всегда приводятся в даташитах. Иверяю Вас - ни один даже самый офигительный процессор не успеет отловить разницу в скорости записи разрядов защёлки.
Суть вопроса правильно передана. Но не терагерцы, а десятки наносекунд, а пороги срабатывания+монтажные емкости+многократный ввод превращает маловероятную вещ в реальную проблему. Так вот по таймингам из даташитов, именно там и есть привязка к тому или иному фронту тактирующего сигнала, и её надо соблюдать. Если АЦП тактировать от того же генератора, что и МК, то скорей всего проблему не увидим. Но не факт, что нам не "повезет". Если от разных генераторов - периодически получим.
Тенденции верные, а цифры - не все понятно. Но с другой стороны у Вас в раскрытом цикле не 10 вводов а 9 ;) Ввод 10 значений за 1мкс при тактовой частоте 16МГц выглядит невероятно прекрасно.
Да это по ходу я код криво скопировал, посмотрелв студии там 10 вводов. Да еще забыл написать что в студии это не Атмега328Р, а Атмега64А может поэтому такой результат, хотя ядра то у них вроде одинаковые. Извиняюсь что не написал сразу. Вот дизассемблированный код из самой студии
01
00000046 CLR R1 Clear Register
02
00000047 OUT 0x3F,R1 Out to I/O location
03
00000048 SER R28 Set Register
04
00000049 LDI R29,0x10 Load immediate
05
0000004A OUT 0x3E,R29 Out to I/O location
06
0000004B OUT 0x3D,R28 Out to I/O location
07
0000004C CALL 0x00000052 Call subroutine
08
0000004E JMP 0x00000069 Jump
09
00000050 JMP 0x00000000 Jump
10
00000052 SER R24 Set Register
11
00000053 OUT 0x11,R24 Out to I/O location
12
00000054 OUT 0x12,R24 Out to I/O location
13
00000055 OUT 0x14,R1 Out to I/O location
14
00000056 OUT 0x15,R1 Out to I/O location
15
00000057 LDI R18,0x05 Load immediate
16
00000058 SER R25 Set Register
17
00000059 IN R24,0x15 In from I/O location
18
0000005A IN R24,0x15 In from I/O location
19
0000005B IN R24,0x15 In from I/O location
20
0000005C IN R24,0x15 In from I/O location
21
0000005D IN R24,0x15 In from I/O location
22
0000005E IN R24,0x15 In from I/O location
23
0000005F IN R24,0x15 In from I/O location
24
00000060 IN R24,0x15 In from I/O location
25
00000061 IN R24,0x15 In from I/O location
26
00000062 IN R24,0x15 In from I/O location
27
00000063 MOV R24,R18 Copy register
28
00000064 OUT 0x12,R1 Out to I/O location
29
00000065 OUT 0x12,R25 Out to I/O location
30
00000066 SUBI R24,0x01 Subtract immediate
31
00000067 BRNE PC-0x03 Branch
if
not equal
32
00000068 RJMP PC-0x000F Relative jump
33
00000069 CLI Global Interrupt Disable
34
0000006A RJMP PC-0x0000 Relative jump
Ой шото оно плохо в студии выходит. Смотрим строки 17-26, видим 10 вводов с порта, но не видим сохранения. Почему так - скорей всего компилятор перестарался с оптимизацией. Он увидел, что после ввода массив Read ни где не задействован и решил, зачем сохранять то, что никому не нужно. Остальных опытов это тоже касается. Вот так вот, чисто эксперементальный факт - замеры времени, может оказатся совершенно неверным! Отличный пример в плане приобретения опыта! В мемориз!!!
И легко допустить, что человек в подобных случаях начинает говорить в стиле "Так я же все на практике проверил, а вы тут теории разводите". Вот как оно бывает. И холиварим по 100 страниц потом)))
ПС. Лечить этим - http://arduino.ru/Reference/Volatile
Отличный пример в плане приобретения опыта! В мемориз!!!
И легко допустить, что человек в подобных случаях начинает говорить в стиле "Так я же все на практике проверил, а вы тут теории разводите". Вот как оно бывает. И холиварим по 100 страниц потом)))
+1000000000
Вот вот! И опыт сын ошибок трудных .... Терзало меня смутное сомнение, что здесь что-то не так.
Хорошо когда есть кто то, кто может подсказать что не так, а так же придется маленько почитать про ассемблер
Ну что ж, повторим опыт в связи с вновь открывшимися обстоятельствами.
ПС: А кстати студия выдавала предупреждение что массив нигде не используется, но я по малограммотности ее проигнорировал.
Конкурирующая фирма - http://mysku.ru/blog/aliexpress/39326.html
Конкурирующая фирма - http://mysku.ru/blog/aliexpress/39326.html
Интересная поделка наших китайских друзей, скопиастили наверное с какого нибудь форума.
По ходу стоит Атмега64 и TLC5510, интересно только, а что там рядом делает еще одна 32 ногая атмега( а может и не атмега, но очень похожа). Меандр на 500Кгц какой то уже печальный... что опять же наводит на мысли о скорости записи в память атмеги, т.к. TLC5510 вполне приличный АЦП, бельгийцы в свои Vallemanы их ставили
Но за цену в 6 килорублей ..... они нам не конкуренты!
ПС. Лечить этим - http://arduino.ru/Reference/Volatile
Вылечил, вот код, если в коде все верно то время чтения 10 элементов получилось - 2.25 мкс, частота 444,4кГц, что очень похоже на правду
01
00000044 JMP 0x00000050 Jump
02
00000046 CLR R1 Clear Register
03
00000047 OUT 0x3F,R1 Out to I/O location
04
00000048 SER R28 Set Register
05
00000049 LDI R29,0x10 Load immediate
06
0000004A OUT 0x3E,R29 Out to I/O location
07
0000004B OUT 0x3D,R28 Out to I/O location
08
0000004C CALL 0x00000052 Call subroutine
09
0000004E JMP 0x0000007D Jump
10
00000050 JMP 0x00000000 Jump
11
00000052 PUSH R28 Push register on stack
12
00000053 PUSH R29 Push register on stack
13
00000054 IN R28,0x3D In from I/O location
14
00000055 IN R29,0x3E In from I/O location
15
00000056 SBIW R28,0x0A Subtract immediate from word
16
00000057 IN R0,0x3F In from I/O location
17
00000058 CLI Global Interrupt Disable
18
00000059 OUT 0x3E,R29 Out to I/O location
19
0000005A OUT 0x3F,R0 Out to I/O location
20
0000005B OUT 0x3D,R28 Out to I/O location
21
0000005C SER R24 Set Register
22
0000005D OUT 0x11,R24 Out to I/O location
23
0000005E OUT 0x12,R24 Out to I/O location
24
0000005F OUT 0x14,R1 Out to I/O location
25
00000060 OUT 0x15,R1 Out to I/O location
26
00000061 LDI R18,0x05 Load immediate
27
00000062 SER R25 Set Register
28
00000063 IN R24,0x15 In from I/O location
29
00000064 STD Y+1,R24 Store indirect with displacement
30
00000065 IN R24,0x15 In from I/O location
31
00000066 STD Y+2,R24 Store indirect with displacement
32
00000067 IN R24,0x15 In from I/O location
33
00000068 STD Y+3,R24 Store indirect with displacement
34
00000069 IN R24,0x15 In from I/O location
35
0000006A STD Y+4,R24 Store indirect with displacement
36
0000006B IN R24,0x15 In from I/O location
37
0000006C STD Y+5,R24 Store indirect with displacement
38
0000006D IN R24,0x15 In from I/O location
39
0000006E STD Y+6,R24 Store indirect with displacement
40
0000006F IN R24,0x15 In from I/O location
41
00000070 STD Y+7,R24 Store indirect with displacement
42
00000071 IN R24,0x15 In from I/O location
43
00000072 STD Y+8,R24 Store indirect with displacement
44
00000073 IN R24,0x15 In from I/O location
45
00000074 STD Y+9,R24 Store indirect with displacement
46
00000075 IN R24,0x15 In from I/O location
47
00000076 STD Y+10,R24 Store indirect with displacement
48
00000077 MOV R24,R18 Copy register
49
00000078 OUT 0x12,R1 Out to I/O location
50
00000079 OUT 0x12,R25 Out to I/O location
51
0000007A SUBI R24,0x01 Subtract immediate
52
0000007B BRNE PC-0x03 Branch
if
not equal
53
0000007C RJMP PC-0x0019 Relative jump
54
0000007D CLI Global Interrupt Disable
55
0000007E RJMP PC-0x0000 Relative jump
Конкурирующая фирма - http://mysku.ru/blog/aliexpress/39326.html
Прибор не стоит своего, за эти деньги у тех же китайцев есть DSO068 он делает честные 20Мегасемплов.
Вылечил, вот код, если в коде все верно то время чтения 10 элементов получилось - 2.25 мкс, частота 444,4кГц...
Как вы получили 444кГц?
Если 10 значений пишет за 2.25мкс
1000 000 /2.25=444 444×10= 4 444 444sps или 4.4Msps.
Ну вот, опять про мегасемплы... Хоороший трюк придумали наши китайские друзья - вместо максимальной измеряемой частоты сигнала, писать количество мегасемплов АЦП.
Я исхожу из того, что мы оба имеем в виду осциллограф, поэтому количество мегасемплов АЦП играет конечно важную роль, но вторую. На первом месте, стоит как раз скорость записи этих мегасемплов в память.
В идеальном варианте, при идеальном меандре, и 10 отсчетах мы должны увидеть примерно вот это,
но это только в идеальном, а на практике..., ну сможем получить лишь примерное представление о сигнале ведь отсчетов то у нас всего 10 и сигнал не идеальный..., впрочем об этом много написано в интернете.
Увеличиваем частоту измеряемого сигнала в 2 раза, и получаем уже всего 5 захваченных точек, видим на экране вместо сигнала корявый треугольник, удивляемся и спрашиваем себя, - а где же мои МЕГАСЕМПЛЫ? И тут же начинаем плохо думать о коварных китайцах.
Ну да ладно, вот эти 444 кГЦ и и есть максимальная измеряемая частота сигнала, при которой мы сможем увидеть хоть что то от исходного сигнала, и чтобы ее измерить от АЦП как раз и требуется 444 кГЦ × 10отсчетов = 4.4 Mегасемпла. Будет АЦП выдавать 10Msps или 20Msps роли уже не играет, нужно именно столько, сколько мы сможем захватить, остальные будут пропущены.
Можно конечно попробывать поиграться с разогоном, попытка не пытка как говорится.
Ну вот, опять про мегасемплы... Хоороший трюк придумали наши китайские друзья - вместо максимальной измеряемой частоты сигнала, писать количество мегасемплов АЦП.
Я исхожу из того, что мы оба имеем в виду осциллограф, поэтому количество мегасемплов АЦП играет конечно важную роль, но вторую. На первом месте, стоит как раз скорость записи этих мегасемплов в память.
В идеальном варианте, при идеальном меандре, и 10 отсчетах мы должны увидеть примерно вот это,
но это только в идеальном, а на практике..., ну сможем получить лишь примерное представление о сигнале ведь отсчетов то у нас всего 10 и сигнал не идеальный..., впрочем об этом много написано в интернете.
Увеличиваем частоту измеряемого сигнала в 2 раза, и получаем уже всего 5 захваченных точек, видим на экране вместо сигнала корявый треугольник, удивляемся и спрашиваем себя, - а где же мои МЕГАСЕМПЛЫ? И тут же начинаем плохо думать о коварных китайцах.
Ну да ладно, вот эти 444 кГЦ и и есть максимальная измеряемая частота сигнала, при которой мы сможем увидеть хоть что то от исходного сигнала, и чтобы ее измерить от АЦП как раз и требуется 444 кГЦ × 10отсчетов = 4.4 Mегасемпла. Будет АЦП выдавать 10Msps или 20Msps роли уже не играет, нужно именно столько, сколько мы сможем захватить, остальные будут пропущены.
Можно конечно попробывать поиграться с разогоном, попытка не пытка как говорится.
При чем здесь китайцы!?
Я имею ввиду и опираюсь всегда на Мегасемплы которые может захватить прибор.
В цифровых осциллографах стоит обращать внимание на три параметра, а остальное опционально.
-количество захватываемых семплов в секунду
-размер буфера этих семплов
-ширина канала.
Кстати о том сколько точек нужно для отображения сигнала это сугубо личный критерий, мне чтоб рассмотреть сигнал 50 точек минимум нужно, для 400КГц это 20Msps, что вы с десятью точками увидите? Только форму.
В цифровых осциллографах стоит обращать внимание на три параметра, а остальное опционально.
-количество захватываемых семплов в секунду
Ну я про что написал?
-размер буфера этих семплов
-ширина канала.
Зависит от предыдущего пункта
Кстати о том сколько точек нужно для отображения сигнала это сугубо личный критерий, мне чтоб рассмотреть сигнал 50 точек минимум нужно, для 400КГц это 20Msps, что вы с десятью точками увидите? Только форму.
.....
Вы для кого эти посты с разъяснениями и картинками пишете, еще и с неправильными?
Если для меня, то не трудитесь.
Тему создал в надежде что проявятся люди кто использовал именно в ардуино среде параллельный АЦП или писал под него библиотеки.
Все остальное о подключении и о том как собирать данные-знаю.