Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.50/6: Рейтинг темы: голосов - 6, средняя оценка - 4.50
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
1

АЦП

18.09.2016, 00:46. Просмотров 1148. Ответов 16
Метки нет (Все метки)

Недавно начал изучать мк AVR. Написал программу для работы с АЦП. Ее работу проверяю в протеусе. При увеличении напряжения на ножке ADC0 от 0 до 0.5В значение, выводимое на дисплей, меняется от 0 до 200. Но при дальнейшем увеличение напряжения значение на LCD не меняется, хотя, насколько я понял, оно должно доходить до 1024, почему это происходит?
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// ATmega8
 
#define F_CPU  8000000
 
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
#define LCD_PORT  PORTD
 
unsigned int res, dec, ed, sot, t;
 
 
void init_ports()
{
    DDRD = 0xff;
    LCD_PORT = 0x00;
}
 
void init_ADC()
{   
    ADCSRA |= (1<<ADEN|0<<ADFR|0<<ADIE); 
    ADCSRA |= (1<<ADPS2|1<<ADPS1|1<<ADPS0); 
    ADMUX  |= (1<<REFS1|1<<REFS0);  
}
 
 
void read_ADC()
{
    ADCSRA |= (1<<ADSC); 
        while ( (ADCSRA & (1<<ADSC)) );
    res = ADC;
    t  =  48 + res/1000;
    sot = 48 + (res%1000)/100;
    dec = 48 + (res%100)/10;
    ed  = 48 + (res%10);
}
 
 
void write_LCD(unsigned int temp)
{
    LCD_PORT &= 0x0f;
    LCD_PORT |= (temp&0xf0);
    LCD_PORT |= 2;
    _delay_us(1);
    LCD_PORT &= ~2;
    LCD_PORT &= 0x0f;
    LCD_PORT |= (temp<<4);
    LCD_PORT |= 2;
    _delay_us(1);
    LCD_PORT &= ~2;
}
 
void com(unsigned int temp) // Передача на LCD команды
{
    LCD_PORT &= ~1;
    write_LCD(temp);
    _delay_ms(1);
}
 
void data(unsigned int temp)  // Передача на LCD данных
{
    LCD_PORT |= 1;
    write_LCD(temp);
    _delay_ms(1);
}
 
void init_LCD()
{
    com(0b00000010);
    com(0b00101000);
    com(0b00001100);
}
 
 
int main(void)
{
    init_ports();
    init_LCD();
    init_ADC();
    ADCSRA |= (1<<ADSC);    
    while(1)
    {
        read_ADC();
 
        com(0x80);
        if(t>48)
        data(t);
        data(sot);
        data(dec);
        data(ed);
        _delay_ms(500);
        ADCSRA |= (1<<ADSC);
    }
}

Снимок.PNG
0
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.09.2016, 00:46
Ответы с готовыми решениями:

Расширение АЦП микроконтроллера и подключение к АЦП датчиков
Здравствуйте. У меня встала задача сделать устройство для элеватора, для контроля температуры в 864...

Mega16 и неиспользуемый АЦП (питание ацп?)
Если я не использую АЦП контроллера нужно ли подавать на АЦП питание? Если нет, то просто оставить...

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

Atmega16 АЦП
Здравствуйте! Пытался запустить АЦП на Atmeag16, с выводом значений на LCD. Что б долго не...

Atmega32A и АЦП
Подскажите, где у меня ошибка в инициализации? Пытаюсь настроить АЦП в режим непрерывного...

16
Витальич
1277 / 1183 / 175
Регистрация: 02.12.2013
Сообщений: 4,886
18.09.2016, 08:45 2
Как вариант:
значение АЦП запишется в регистры ADCL и ADCH. Т.к АЦП 10 битный 1 регистра мало. Значение обоих регистров хранится в ADCW.
Цитата Сообщение от Vitaly7995 Посмотреть сообщение
sot = 48 + (res%1000)/100;
* * dec = 48 + (res%100)/10;
Да и этот кусок смущает. Зачем делим еще на сто и десять?
1
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
18.09.2016, 09:30  [ТС] 3
Спасибо за Ваш ответ. Сделал исправление в коде
res = ADCW;
результат остался тот же. Переменная res имеет тип unsigned int, по идее она должна умещать в себе 10 битное значение.
Да и этот кусок смущает. Зачем делим еще на сто и десять?
(res%100) - деление с остатком, как результат получаем двухзначное число, далее делим на 10 целочисленно, т.е. остаток отбрасывается и как результат получаем значение десятка числа.
0
Витальич
1277 / 1183 / 175
Регистрация: 02.12.2013
Сообщений: 4,886
18.09.2016, 09:48 4
C
1
2
3
4
5
    res = ADC;
    t  =  48 + (res/1000)%10;
    sot = 48 + (res/100)%10;
    dec = 48 + (res/10)%10;
    ed  = 48 + (res%10);
1
18.09.2016, 09:48
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
18.09.2016, 10:06  [ТС] 5
Без изменений
0
ValeryS
Модератор
7960 / 5929 / 785
Регистрация: 14.02.2011
Сообщений: 20,404
Завершенные тесты: 1
18.09.2016, 10:11 6
Цитата Сообщение от Vitaly7995 Посмотреть сообщение
Недавно начал изучать мк AVR.
изучай сразу правильно
Цитата Сообщение от Vitaly7995 Посмотреть сообщение
ADCSRA |= (1<<ADEN|0<<ADFR|0<<ADIE);
что за биты? комментировать надо, какой режим хочешь включить
Цитата Сообщение от Vitaly7995 Посмотреть сообщение
t = 48 + res/1000;
что за число 48?
самодокументирующий код писать надо
C
1
t ='0' + res/1000;
да и имена переменным лучше осмысленные давать
C
1
ths='0' + res/1000;
Цитата Сообщение от Vitaly7995 Посмотреть сообщение
void write_LCD(unsigned int temp)
зачем здесь int ? здесь char за глаза хватит
1
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
18.09.2016, 10:19  [ТС] 7
Цитата Сообщение от ValeryS Посмотреть сообщение
что за биты? комментировать надо, какой режим хочешь включить
Режим одиночного преобразования,(1<<ADEN) - включение ацп.
Цитата Сообщение от ValeryS Посмотреть сообщение
что за число 48?
самодокументирующий код писать надо
48, 0x30 и '0' - одно и то же, насколько я понимаю
Цитата Сообщение от ValeryS Посмотреть сообщение
зачем здесь int ? здесь char за глаза хватит
Вы правы, исправил на char
0
ValeryS
Модератор
7960 / 5929 / 785
Регистрация: 14.02.2011
Сообщений: 20,404
Завершенные тесты: 1
18.09.2016, 10:36 8
Цитата Сообщение от Vitaly7995 Посмотреть сообщение
48, 0x30 и '0' - одно и то же, насколько я понимаю
да
но потом когда будешь читать программу '0' предпочтительней, не надо будет вспоминать, что имелось ввиду под "магическим числом" 48
тоже и с инициализацией
программы пишутся для людей, машина и так разберется
теперь о проблеме
поскольку мы не знаем что врет чтение или вывод на экран то необходимо локализовать проблему
для начала я бы вывел на экран числа от 0 до 1024 (в цикле)
и будет понятно "где собака порылась"
1
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
18.09.2016, 10:47  [ТС] 9
Сделал вывод на экран чисел от 0 до 1024 - все цифры выводятся.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void read_ADC()
{
        res = i;
        ths = 48 + (res/1000)%10;
        sot = 48 + (res/100)%10;
        dec = 48 + (res/10)%10;
        ed  = 48 + (res%10);
        i++;
}
 
int main(void)
{
    init_ports();
    init_LCD();
    init_ADC(); 
    while(1)
    {
        read_ADC();
 
        com(0x80);
        if(ths>48)
        data(ths);
        data(sot);
        data(dec);
        data(ed);
        _delay_ms(50);
 
    }
0
Витальич
1277 / 1183 / 175
Регистрация: 02.12.2013
Сообщений: 4,886
18.09.2016, 10:56 10
ACSR=0x80; компаратор off
Далее настройка АЦП
1
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
18.09.2016, 11:10  [ТС] 11
я еще пробовал,считывать значение АЦП по прерыванию в режиме постоянного преобразования, там то же самое. Значение на LCD не превышает 200.

Добавлено через 4 минуты
все равно выше 200 не подымается

C
1
2
3
4
5
6
7
8
void init_ADC()
{   
    ACSR=0x80;
    
    ADCSRA |= (1<<ADEN|0<<ADFR|0<<ADIE); 
    ADCSRA |= (1<<ADPS2|1<<ADPS1|1<<ADPS0); 
    ADMUX  |= (1<<REFS1|1<<REFS0);  
}
Добавлено через 5 минут
Выбрал для АЦП сначала ножку ADC1 (1<<MUX0), потом ножку ADC3 (1<<MUX0|1<<MUX1) - результат тот же
0
Витальич
1277 / 1183 / 175
Регистрация: 02.12.2013
Сообщений: 4,886
18.09.2016, 11:20 12
http://www.cyberforum.ru/post9311925.html
1
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
18.09.2016, 11:50  [ТС] 13
Автор той темы писал "Действительно, надо было поставить условие и проверять бит окончания работы АЦП."
Но у меня же в коде есть это условие
C
1
2
3
4
5
6
7
8
9
10
11
void read_ADC()
{
    ADCSRA |= (1<<ADSC); 
    while ( (ADCSRA & (1<<ADSC)) );
 
        res = ADCW;
        ths  =  48 + (res/1000)%10;
        sot = 48 + (res/100)%10;
        dec = 48 + (res/10)%10;
        ed  = 48 + (res%10);
}
C
1
while ( (ADCSRA & (1<<ADSC)) ); // пока бит ADSC установлен, ничего делаем
а присвоения результата происходит после окончания преобразования ацп, т.е. после того как бит ADSC сбрасывается в 0. Автор той темы дожидается окончания преобразования ацп установкой в 1 бита ADIF, я тоже попробовал вставить в код его условие
C
1
while ((ADCSRA & (1 << ADIF)) == 0);
Но ничего не изменилось, ведь же нет разницы ждать пока бит ADSC сбросится или бит ADIF установится? Ведь оба этих действия говорят об окончании преобразования. Еще после установки ADIF его придется сбрасывать, чтобы еще раз дождаться оконания преобразования
0
Витальич
1277 / 1183 / 175
Регистрация: 02.12.2013
Сообщений: 4,886
18.09.2016, 11:55 14
Формат выводимых данных есть в настройках АЦП, не помню как называется, попробуйте с ней поиграться.
1
ValeryS
Модератор
7960 / 5929 / 785
Регистрация: 14.02.2011
Сообщений: 20,404
Завершенные тесты: 1
18.09.2016, 11:56 15
Vitaly7995, приведи полностью исправленный код с комментариями
может когда пишешь коменты и сам найдешь ошибку
у меня так часто бывает
1
Vitaly7995
4 / 4 / 2
Регистрация: 01.06.2016
Сообщений: 18
18.09.2016, 12:12  [ТС] 16
Лучший ответ Сообщение было отмечено ValeryS как решение

Решение

Спасибо за помощь, нашел в чем был косяк. Подключил питание в протеусе к выводам AREF и AVCC и все заработало нормально - глупая ошибка
2
ValeryS
Модератор
7960 / 5929 / 785
Регистрация: 14.02.2011
Сообщений: 20,404
Завершенные тесты: 1
18.09.2016, 12:51 17
Цитата Сообщение от Vitaly7995 Посмотреть сообщение
Подключил питание в протеусе к выводам AREF и AVCC и все заработало нормально
мдя а я как то, это дело, не заметил
1
18.09.2016, 12:51
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.09.2016, 12:51

АЦП ATmega8
Доброго времени суток. Написал программу, в которой при выходе из обработчика прерывания по...

АЦП на atmega8515
Здравствуйте, я начинающий программист. совсем ещё как бы чайник, разобрал пока самое простенькое...

АЦП и pt1000
Хочется подцепить к АЦП датчик температуры, для начала мне хватит полуградуса на диапазоне 0-300оС....


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.