Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ATMega16 и АЦП
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
mr_onnik
Имеется МК Mega 163, на вход ADC0 (PA0) которого подается изменяющееся напряжение 0...5 В;
AVcc и AREF соединен с Vcc, AGND соединен с GND.

В CodeVisionAVR пишу такой код:
Код
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | 0xff;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSR|=0x40;
// Wait for the AD conversion to complete
while ((ADCSR & 0x10)==0);
ADCSR|=0x10;
return ADCW;
}

//настройки портов

void main(void)
{ int a = 0;

   while(1)
   {
    a = (int)read_adc;
    PORTC.6 = 1;
    delay_ms(a);
    PORTC = 0x00;
    }
}


в результате светодион на шестом выводе порта С постоянно мигает с частотой примерно 0,5с. Наверное, снимается показание с внутреннего источника опорного напряжения, которое составляет примерно половину 5В.

Что неправильно сделано? Как сделать, чтобы частота мигания светодиода менялась в зависимости от подаваемого напряжения на ADC0?
mdmitry
Цитата(mr_onnik @ Nov 6 2007, 23:15) *
Имеется МК Mega 163, на вход ADC0 (PA0) которого подается изменяющееся напряжение 0...5 В;
AVcc и AREF соединен с Vcc, AGND соединен с GND.

Не очень хорошая идея соединять AVcc и AREF с Vcc и AGND с GND. Это разные питания и желательно заботится о хорошем AREF. Просадка питания означает изменение опорного напряжения, а при маломощных источниках питания это бывает часто. Аналогично и с землями. При правильном проектировании плат аналоговую и цифровую земли соединяют в ОДНОЙ точке на плате. посмотрите осциллографом, что бегает по земле и какая пульсация на питании.
oran-be
А это - так задумано?
Код

ADMUX=adc_input | 0xff;

Согласно даташиту вход АЦП будет всегда подключен к 0. А показания в 0.5 сек - может. стоит проверить, допускает ли функция
delay_ms()
передачу в качестве аргумента 0.
И еще - на Ацпшнике 2.5 В может быть только снаружи. Внутренее проверочное напряжение у него 1.22В
mr_onnik
Цитата(oran-be @ Nov 7 2007, 08:50) *
А это - так задумано?
Код

ADMUX=adc_input | 0xff;

На самом деле нет. На сколько я разобрался в мануалах вместо 0xFF нужно указать адрес входа АЦП. А после неудачных попыток решил - пусть проганяет по всем.

mdmitry, источник питания дает 500мА. Сейчас мне не важна точность. Просто для начала собрал простенькую обвязку, чтобы увидеть работу АЦП. Когда увижу, буду повышать точность wink.gif

P.S. Может, эта строка неправильная?
Код
a = (int)read_adc;
SergeiCh
Цитата(mr_onnik @ Nov 7 2007, 03:15) *
a = (int)read_adc;
(int)read_adc; - это адрес функции (точка входа в функцию), приведенный к целому типу, а не вызов функции. Почитайте какую-нибудь книжку по Си.
IgorKossak
Цитата(SergeiCh @ Nov 7 2007, 11:03) *
(int)read_adc; - это адрес функции (точка входа в функцию), приведенный к целому типу, а не вызов функции. Почитайте какую-нибудь книжку по Си.

Ну и почему бы сразу не посоветовать написать правильно?
Код
a = (int)read_adc(0);
Так ли уж необходимы нравоучения?
oran-be
lol.gif lol.gif
Да - кто первый заметит слона?
mr_onnik
Цитата(IgorKossak @ Nov 7 2007, 11:33) *
Ну и почему бы сразу не посоветовать написать правильно?
Код
a = (int)read_adc(0);
Так ли уж необходимы нравоучения?


Исправил. Светодиод вообще перестал мигать. Что в таком случае может содержаться в переменной read_adc? Бесконечность?
SergeiCh
Цитата(IgorKossak @ Nov 7 2007, 16:33) *
Так ли уж необходимы нравоучения?
Это совет. Когда написал, тоже подумал, что звучит как нравоучение, но, виноват, все-таки оставил.
Код
unsigned int a = 0;
...
a = read_adc(0);
Не желательно без крайней необходимости приводить типы (в С++ для этого вообще три оператора). Это мое мнение smile.gif
oran-be
Цитата(mr_onnik @ Nov 7 2007, 14:09) *
Исправил. Светодиод вообще перестал мигать. Что в таком случае может содержаться в переменной read_adc? Бесконечность?

Поскольку
Код
ADMUX=adc_input | 0xff;

то мультиплексор подключен к земле и в значении АЦП должен быть 0.
Функция delay_ms(a) поддерживает 0? Проверьте. Засандальте туда 0 втупую и посмотрите.
SergeiCh
Цитата(mr_onnik @ Nov 7 2007, 17:09) *
Исправил. Светодиод вообще перестал мигать. Что в таком случае может содержаться в переменной read_adc? Бесконечность?
Странно, что раньше он мигал. Вы выводите в порт 0, вызываете функцию read_adc, пока она выполняется, а выполняется она быстро smile.gif, у вас ноль, после опять выводится 1. Т.е. светодиод выключен (другой вывод светодиода не земле?) пока выполняется функция. А где порт настраивается на выход? Или это CV в стартап коде делает? Действительно совет, попробуйте вашу программу погонять в AVR Studio или другом каком симуляторе. Гораздо полезнее разобраться самому. Задача-то простая.
mr_onnik
Цитата(oran-be @ Nov 7 2007, 12:36) *
Поскольку
Код
ADMUX=adc_input | 0xff;

то мультиплексор подключен к земле и в значении АЦП должен быть 0.
Функция delay_ms(a) поддерживает 0? Проверьте. Засандальте туда 0 втупую и посмотрите.


Засандалил. Никаких изменений, пока вообще не убрал строку a = read_adc(0);
Получается, что на ней МК зависает ( Когда убрал ее, при delay_ms(0) светодиод горит, значит, delay работает. Получается, неправильное преобразование.

P.S. А как указать вместо 0xFF адрес ADC0?

Цитата(SergeiCh @ Nov 7 2007, 12:48) *
Странно, что раньше он мигал. Вы выводите в порт 0, вызываете функцию read_adc, пока она выполняется, а выполняется она быстро smile.gif, у вас ноль, после опять выводится 1. Т.е. светодиод выключен (другой вывод светодиода не земле?) пока выполняется функция. А где порт настраивается на выход? Или это CV в стартап коде делает? Действительно совет, попробуйте вашу программу погонять в AVR Studio или другом каком симуляторе. Гораздо полезнее разобраться самому. Задача-то простая.


Подразумевается, что пауза между миганиями прямо пропорциональна подаваемому напряжению. Скажем, при 5В пауза будет около 1с, при 2,5 - 0,5с. Ведь, пока не будет выдержана пауза, АЦП не работает?
SergeiCh
Цитата(mr_onnik @ Nov 7 2007, 17:55) *
Подразумевается, что пауза между миганиями прямо пропорциональна подаваемому напряжению. Скажем, при 5В пауза будет около 1с, при 2,5 - 0,5с. Ведь, пока не будет выдержана пауза, АЦП не работает?
Беда в том, что время свечения светодиода ровно времени оцифровки сигнала. По документации оно должно быть 13 - 260 мкс, что для человеческого глаза очень мало. Еще нужно настроить прескалер АЦП и разрешить работу АЦП (ADEN в ADCSRA). Ни разу не видел CV, порты и т.п конфигурируются ч/з меню/окошки?
GDI
Вот что хорошо в CV, так это мастер нового проекта, он сам и порты настроит если того требуется и АЦП, таймера и прочее сам сконфигурит и разрешит, если надо, то сам сделает вектора прерываний и даже некоторую перифирию может подключить, например символьные ЖКИ, датчики температруры DS18B20, часы DS1307 и 1302 и др., только укажи на каком порту ты их желаешь видеть. Для УАРТа может сам сделать буферизированный прием и/или передачу. Но на этом прелести CV заканчиваются и начинаются суровые глюки, правда в маленьких проектах это не заметно.
oran-be
Цитата(mr_onnik @ Nov 7 2007, 14:55) *
Засандалил. Никаких изменений, пока вообще не убрал строку a = read_adc(0);
Получается, что на ней МК зависает ( Когда убрал ее, при delay_ms(0) светодиод горит, значит, delay работает. Получается, неправильное преобразование.

P.S. А как указать вместо 0xFF адрес ADC0?

Зависать в функции контролле может только в одном месте - на цикле while. Типовой таракан, если неправильно скофигурировано железо и не высставляется флаг. Проверьте инициализацию АЦП.
З.Ы.
В строке
Код
ADMUX=adc_input | 0xff;

надо убрать операцию | 0xff, после которой, какой бы вы аргумент не передавали в функцию, в ADMUX все равно будет 0xff и мультиплексор будет подключен к земле.
singlskv
Цитата(mr_onnik @ Nov 6 2007, 23:15) *
.......................
Господа(товарисчи... кому как больше нравится...), хватит измываться над автором темы...

Автор,
полную схему со ВСЕМИ параметрами, полностью софт, и подробное описание того что Вы хотели
получить, в студию...

Тогда точно найдутся желающие Вам подсказать...
mr_onnik
Цитата(singlskv @ Nov 7 2007, 21:41) *
Автор,
полную схему со ВСЕМИ параметрами, полностью софт, и подробное описание того что Вы хотели
получить, в студию...

Нажмите для просмотра прикрепленного файла
Код
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date    : 02.11.2007
Author  : Freeware, for evaluation and non-commercial use only
Company :
Comments:


Chip type           : ATmega163
Program type        : Application
Clock frequency     : 4,000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/

#include <mega163.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <io.h>
#include <stdint.h>  
#include <delay.h>  

#define F_CPU 4000000UL


// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSR|=0x40;
// Wait for the AD conversion to complete
while ((ADCSR & 0x10)==0);
ADCSR|=0x10;
return ADCW;
}


// ADC initialization
// ADC Clock frequency: 115,200 kHz
// ADC Voltage Reference: Int., cap. on AREF

                      
void init_avr(void)
{

PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x00;

PORTC = 0x00;
DDRC = 0xF0;/* set port C pins 7-4 as outputs, 3-0 as inputs */

PORTD=0x00;
DDRD=0x0F;

// Global enable interrupts
#asm("sei")

}

// Declare your global variables here

void main(void)
{ unsigned int a = 0;
  
PORTD = 0x00;
PORTC = 0x00;
// Declare your local variables here

init_avr();

while (1)
      
      {
                 a = read_adc(0);                  
                 PORTC.6 = 1;  
                 delay_ms(a);
                 PORTC = 0x00;
                 delay_ms(a);
      
      
      };
}


Программа CodeVisionAVR.
Требуется сделать так, чтобы частота мигания светодиода прямопропорционально зависела от напряжения, подаваемого на ADC0. help.gif
sergeeff Jr.
PWM организуй при помощи таймера...
singlskv
Цитата(mr_onnik @ Nov 9 2007, 00:22) *
Код
// ADC initialization
// ADC Clock frequency: 115,200 kHz
// ADC Voltage Reference: Int., cap. on AREF
А где код инициализации ADC ?

Вы там случаем битик ADEN выставить не забыли ?
SergeiCh
Цитата(mr_onnik @ Nov 9 2007, 04:22) *
Код
#include <mega163.h>
Так ATmega16, как в теме, или ATmega163? AVCC желательно подать ч/з резистор 100 Ом или дроссель 10 мкГ, конденсатор 0.1 мкФ на AVCC, светодиод можно напрямую к порту. В симуляторе бит ADEN выставляется?
mr_onnik
Цитата(singlskv @ Nov 9 2007, 01:53) *
А где код инициализации ADC ?

Вы там случаем битик ADEN выставить не забыли ?


Скажу сразу: я не профи в этом деле, поэтому с инициализацией у меня прблемы sad.gif
imho, ADEN выставляется в регистре ADCSR?
mrKirill
Цитата
while (1)
{
a = read_adc(0);
PORTC.6 = 1;
delay_ms(a);
PORTC = 0x00;
delay_ms(a);
};

Почитал посты, тут как я понял мало кто использует CV, добавлю свою каплю, так как в CV работал около 1 года.
Так вот зацитированная выше мною часть ИМХО должна выглядеть так:
Цитата
while (1)
{
read_adc(0); //Запуск преобразования АЦП
a = ADCW; //Считывание преобразованного значения
PORTC.6 = 1; //Установили вывод
delay_ms(a); //Пауза
PORTC.6 = 0; //Сбросили вывод
delay_ms(a); //Пауза
};

Если бы удосужились почитать Help на CV, то поняли бы что строка:
Цитата
a = read_adc(0);

Представляет собой - чушь
Правильность конфигурирования выводов и АЦП не проверяю, Wizard для этого есть
Сергей Борщ
Цитата(mrKirill @ Nov 23 2007, 06:45) *
Если бы удосужились почитать Help на CV, то поняли бы что строка:
Представляет собой - чушь
А если бы удосужились посмотреть приведенный исходник, то поняли бы, что это вовсе не функция из библиотеки CV.
Цитата(mrKirill @ Nov 23 2007, 06:45) *
Правильность конфигурирования выводов и АЦП не проверяю, Wizard для этого есть
"Программирование мышкой"? Ну-ну.

Цитата(mr_onnik @ Nov 22 2007, 23:28) *
Скажу сразу: я не профи в этом деле, поэтому с инициализацией у меня прблемы sad.gif
Ее у вас просто нет sad.gif Возьмите описание АЦП, раздел регистры, выпишите все три описанных там регистра, далее читая описание на каждый из битов регистра решите, какое значение вам нужно записать в этот бит, чтобы АЦП сделало то, что вы хотите. И поставьте запись этих битов в эти регистры в функцию инициализации перед разрешением прерываний.
mrKirill
Цитата(Сергей Борщ @ Nov 23 2007, 16:25) *
А если бы удосужились посмотреть приведенный исходник, то поняли бы, что это вовсе не функция из библиотеки CV.

Если бы удосужились более внимательно прочитать пост #17, который я цитировал, то наверное заметили бы, что там внизу текста приведена фраза "Программа CodeVisionAVR.", вот и привел правильный кусок программы для CV.
Цитата
"Программирование мышкой"? Ну-ну.

Насколько я понял в деле программирования и конфигурирования он не силен, потому пусть тыкается в Визарде, потом может научится все правильно конфигурировать

Лично сам пишу работаю в AVR Studio (для asm), CodeVision и IAR (для С), потому "программирование мышкой" - не ко мне.
Офф-топ закончен.
Сергей Борщ
Цитата(mrKirill @ Nov 23 2007, 13:11) *
Если бы удосужились более внимательно прочитать пост #17, который я цитировал, то наверное заметили бы, что там внизу текста приведена фраза "Программа CodeVisionAVR.",
Удосужился. CodeVisionAVR - это компилятор. Использовать или нет идущие в его комплекте библиотеки - личное дело программиста. В процитированном вами посте #17 библиотеки не используются. Вывод - ссылка на help по библиотекам неуместна.
Цитата(mrKirill @ Nov 23 2007, 13:11) *
вот и привел правильный кусок программы для CV.
Использование библиотек не является ни необходимым, ни тем более достаточным условием правильности программы. Короче - в посте #22 вы вместо ответа на цитируемый пост #17 написали ответ на какие-то свои мысли, да еще с претензией. На что я вам и указал. И это как раз не оффтоп.
defunct
Код
#define ADC_CONTROL (1 << ADEN)|(0 << ADIE)|(0 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)
#define MUX_CONTROL (0 << REFS1)|(0 << REFS0)|(0 << ADLAR) // ARef / 10 bit

int ReadAdc(unsigned char channel)
{
    ADMUX = MUX_CONTROL | channel;
    ADCSR = ADC_CONTROL | (1 << ADSC);

    while ( (ADCSR & (1 << ADIF)) == 0); // wait till conversion completes
    return ADCW;
}
WHALE
defunct,в CV это не пройдет.Почему-то у него нет хидера ioavrxxx.h или как он там в яре называется.
Соответственно,компилятор не поймет атмеловские название битов регистров.
Надо или напрямую в байтах загружать или один раз руками прописать и добавить в библиотеку(или
содрать иаровский smile.gif .
defunct
Цитата(WHALE @ Nov 23 2007, 18:14) *
в CV это не пройдет.Почему-то у него нет хидера ioavrxxx.h или как он там в яре называется.
Соответственно,компилятор не поймет атмеловские название битов регистров.

эх sad.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.