АЦП ATmega16 |
us4ilq | Дата: Понедельник, 09.11.2009, 20:35 | Сообщение # 31 |
Группа: Пользователи
Сообщений: 48
Статус: Offline
|
А вот у меня такой avr910_usb_programmer. уже давненько есть Ну примерно пару месяцев. Вот только я его почемуто неиспользую а постоянно шью Пони Прогом. И до сих пор все было оч. хорошо, пока меня не поволокло на изучение программирования. Вообщето он все (вроде) нормально зашивает. Ну вот к примеру Ваш код (откомпелированный) шьет же, и все работает. Добавлено (09.11.2009, 20:35) --------------------------------------------- Я его пробовал подключать через программер КОДЕВИЖЕНА, просто чтоб проверить увидит ли его КОДЕВИЖЕН? Увидел на КОМ.3 Ну на том я и успокоился.
| |
|
|
|
eugenemcu | Дата: Понедельник, 09.11.2009, 20:38 | Сообщение # 32 |
Группа: Администраторы
Сообщений: 89
Статус: Offline
|
Ну тогда за чем дело встало? Зачем Вам старая лошадь? С таким программером никаие фюзы не страшны По установке отдельных фьюзов в CVAVR советовать не буду. Скачайте AvrStudio он абсолютно бесплатный, в AVRPROG все режимы выбираются из списков: Подключите устройство. Запустите C:\Program Files\Atmel\AVR Tools\AvrProg\AvrProg.exe. Выберите тим микроконтроллера и hex-файл. Далее нажмите кнопку Advansed... и для внешнего кварца выберите из списка источник тактирования - Ext XTAL, High frequency. Для записи фьюзов нажмите "Write". Далее "Close" и в первом окне в разделе Flash нажмите кнопку "Program" для записи HEX.
8619073.jpg(57Kb) · 1322658.jpg(90Kb)
| |
|
|
|
us4ilq | Дата: Вторник, 10.11.2009, 16:14 | Сообщение # 33 |
Группа: Пользователи
Сообщений: 48
Статус: Offline
|
ОБАЛДЕТЬ!!!! Заработало! А знаете что надо было сделать? Создать заново проект !!! Видать я что то , в каком то файле напорол.
0633283.jpg(65Kb) · 6011670.jpg(80Kb)
| |
|
|
|
eugenemcu | Дата: Среда, 11.11.2009, 20:51 | Сообщение # 34 |
Группа: Администраторы
Сообщений: 89
Статус: Offline
|
Здравствуйте, Сергей. Посмотрел Ваш код в письме и понял - нужны дополнительные разъяснения по вычислению и отображению напряжения. По порядку: Переменная AdcCode в программе хранит выходной код АЦП, который по сути равен количеству 1024-ых долей опорного напряжения во входном. Я вносил в код строку AdcCode=AdcCode>>2;, убирающую из переменной AdcCode два младших разряда как недостоверные. Теперь решил отказаться от этой идеи - пусть в результате будет всё, что намеряло АЦП. Тогда AdcCode - это выходной код АЦП, как он есть, то есть в 1024-ых долях от опоры. Чтобы преобразовать код АЦП в реальное напряжение нужно ввести в программу переменную с плавающей точкой способную хранить дробные числа - тип float и рассчитать напряжение: Code float Volt; // Напряжение в вольтах. Volt=(AdcCode)*(5.0/1024); Далее уже переменную Volt можно отобразить на ЖК с помощью функции sprintf как число с плавающей точкой (она это вроде умеет). Но у меня почему-то ничего не вывелось, поэтому я решил выделить разряды единиц, десятых и сотых долей и отобразить их поотдельности. Чтобы не возиться с дробными числами, которые в несколько раз снижают быстродействие кода, умножим напряжение на сто: AdcCode=100.0*(AdcCode)*(5.0/1024); после выполнения этой строки в переменной AdcCode окажется Uвх*100, например 325 при 3,25В, далее остаётся только выделить сотни, десятки и единицы переменной. Это можно сделать простым вычитанием из AdcCode чисел 100, 10 и 1 с подсчётом числа таких вычитаний. В итоге получился такой код: В начале программы нужно объявить переменные: Code unsigned char St,Ds,Ed; // Десятичные разряды выходного напряжения - единицы, десятые и сотые доли. и ветка расчёта и отображения: Code if (Status==3) // Если АЦП завершил преобразование... { AdcCode=100.0*(AdcCode)*(5.0/1024); St=0; // Сброс разряда сотен перед очередным подсчётом. while (AdcCode>100) { AdcCode=AdcCode-100; St++; } // Вычитать из числа 100 пока, в нём не останется сотен и считать количество проходов. Ds=0; // Сброс разряда десятков перед очередным подсчётом. while (AdcCode>10) { AdcCode=AdcCode-10; Ds++; } // Вычитать из числа 10 пока, в нём не останется десятков и считать количество проходов. Ed=0; // Сброс разряда единиц перед очередным подсчётом. while (AdcCode>0) {AdcCode=AdcCode-1; Ed++; } // Вычитать 1 пока не останется целой части, считать количество проходов. lcd_clear(); // Очистить экран. lcd_gotoxy(0,0); sprintf (lcd_buffer,"V =%u,%u%u",St,Ds,Ed); lcd_puts(lcd_buffer); Status=0; }
| |
|
|
|
us4ilq | Дата: Четверг, 12.11.2009, 16:20 | Сообщение # 35 |
Группа: Пользователи
Сообщений: 48
Статус: Offline
|
Здравствуйте Евгений! Попробовал изменения что Вы предложили в последний раз, получилось! Однако всеже непонятно , почему ничего не вышло вот с этим - Code AdcCode=(AdcCode>>2); // Убрать два младших разряда из результата. AdcCode=AdcCode*(5/256); Почему нельзя при 8ми разрядах АЦП осуществить преобразование из двоичного в десятичный. Почему-то мне кажется что можно. Просто я незнаю как. Может я просто неправильно это описал? Если я Вам еще не очень надоел, то может (при наличии времени ) разжуете мне как это сделать? Опять же наш диалог (если это можно так назвать) читают и другие такиеже как и я начинающие. А значит будет помощь кому то еще. Спасибо Сергей.
| |
|
|
|
eugenemcu | Дата: Четверг, 12.11.2009, 20:22 | Сообщение # 36 |
Группа: Администраторы
Сообщений: 89
Статус: Offline
|
Здравствуйте, Сергей. Это ошибка вполне простительная. Связана она с достаточно хитрым моментом - приведением типов в языке Си. Дело в том, что Си приводит тип результата любого выражения к типу наиболее точного члена в этом выражении. Например, если Вы делите дробное число на целочисленное, то результат тоже будет дробным числом. Ближе к делу. В той форме записи, которую Вы применили (без десятичной точки), константы 5 и 256 будут восприняты Си как целочисленные и результат он тоже приведёт к целочисленному типу. То есть вместо числа 5/256 = 0,0195, вы получите 5/256 = 0. Избежать этого можно, записав любую из двух констант с десятичной точкой, например 5.0/256 или 5/256.0, тогда она будет воспринята Си как константа с плавающей точкой и отброса дробной части не произойдёт. AdcCode=AdcCode*(5.0/256); Но и это пол беды. Переменная AdcCode объявлена целым типом int и в момент присвоения результата выражения (AdcCode*(5.0/256)) переменной AdcCode тоже произойдет утрата дробной части и на экране ЖК Вы увидите только целые числа 1, 2...5В. Поэтому результат нужно записывать в новую переменную с типом float (см. мои примеры выше). Со временем Вы научитесь следить за преобразованием типов по ходу программы, хотя первый случай достаточно хитрый, его легко пропустить даже, имея определённый опыт в программировании.
| |
|
|
|
us4ilq | Дата: Суббота, 14.11.2009, 16:10 | Сообщение # 37 |
Группа: Пользователи
Сообщений: 48
Статус: Offline
|
Здравствуйте Евгений! Поигрался немного с программой учтя Ваши последние рекомендации. Все равно ничего неполучается - компилятор возмущается при попытке использования переменной float в sprintf. Показывает ошибку , мол нельзя использовать переменную float с "%". И еще хотелось бы немного вернутся назад вы рекомендовали вот такую запись: при необходимости изменить один бит в регистре, не затрагивая состояние остальных. Безусловно я с Вами согласен, но ведь (как мне кажется) и такая запись PORTB.2=1 будет равнозначна Вашей, ведь так мы тоже изменяя бит №2 в регистре PORTB незатрагиваем остальные? Или я опять "торможу"? Спасибо. Сергей.
| |
|
|
|
eugenemcu | Дата: Суббота, 14.11.2009, 20:16 | Сообщение # 38 |
Группа: Администраторы
Сообщений: 89
Статус: Offline
|
Здравствуйте, Сергей! Давайте по порядку. Если мне не изменяет память, речь шла о выборе между Code TCCR1B|=(1<<CS12); и TCCR1B=4; Вторая запись сбрасывает все биты кроме второго... это очевидно. Язык Си не содержит операций по установке или сбросу отдельных битов! И этим вообще-то всё сказано. Записи типа PORTB.2=1 - это макросы, то есть простые замены текста через директиву #define на другой текст. Для различных сред разработки существуют встроенные макросы, например в IAR: Code если написать SETBIT (TCCR1B,2); то макрос #define SETBIT(ADDRESS,BIT) ((ADDRESS) |= (1<<(BIT))) заменит такую запись на TCCR1B|=(1<<CS12); То же самое делают встроенные макросы CodeVision, сами понимаете, что сути происходящего такая замена не меняет. Зато код, написанный в CV невозможно будет сходу перенести в другие компиляторы. А, если разработчик начнёт писать свои макросы, коих можно накатать сколь угодно, читаемость кода другими людьми ухудшиться ещё больше и им самим кстати тоже, когда он начнёт забывать что и каким образом заменяют его макросы. Но это моё личное мнение. Я стараюсь писать на чистом Си, ничего более хитрого по сути для сброса или установки битов просто не существует. По поводу отображения float в sprintf. Я говорил, что у меня тоже не получилось вывести её. Поэтому я выделил разряды и отобразил их отдельно. Как не крути, функции sprintf всё равно пришлось бы этим заниматься. Разбираться со встроенными функциями CVAVR особого желания нет, они пожирают слишком много кода. Да и вам, как начинающему программисту, полезнее сделать некоторые вещи вместо библиотечной функции
| |
|
|
|
us4ilq | Дата: Воскресенье, 15.11.2009, 04:13 | Сообщение # 39 |
Группа: Пользователи
Сообщений: 48
Статус: Offline
|
Вы писали: "Да и вам, как начинающему программисту" Да мне аж стыдно стало - какой же я (хоть и начинающий) программист!??? Да я всего лиш пытаюсь начать учиться!!! К стати. Заметил интересный момент - когда индикатор показывает, скажем 4,11 вольт, то справа добавляется ИНОГДА еще и 0 (4,110). Тоесть если после запятой 11 то может появится еще и 0. Может это из за наводок на провода? ведь всетаки на макетке собрано? И еще один момент - решл я попробовать замерить напряжение батарейки от часов (электронных), что то вроде SC21. Так вот ничего из этой затеи невышло. Подозреваю что на входе должен присутствовать какой нибудь высокоомный резистор, на общий провод. Но тогда он будет искажать показания, как тут быть? Спасибо Сергей.
| |
|
|
|
eugenemcu | Дата: Воскресенье, 15.11.2009, 19:17 | Сообщение # 40 |
Группа: Администраторы
Сообщений: 89
Статус: Offline
|
Здравствуйте, Сергей. Это не помеха, это моя ошибка Не правильно прописал условия в циклах while, в результате возможны значения при которых некоторые разряды досчитывают до 10 вместо 9. Исправьте, пожалуйста: while (AdcCode>100) на while (AdcCode>=100) while (AdcCode>10) на while (AdcCode>=10) while (AdcCode>0) на while (AdcCode>=1) и всё будет нормально. Случай с батарейкой объяснить не могу. Входное сопротивление канала АЦП около 100 МОм. А значит входные токи на уровне десятков наноампер. Никаких существенных падений напряжения при таких токах в нормальной батарейке быть не должно
| |
|
|