Пятница, 19.04.2024, 14:05
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Меню сайта
Реклама Google
Форма входа
Категории раздела
Это нужно знать! [17]
Изучаем AVR [30]
Программаторы [12]
Необходимое ПО [8]
Готовые устройства [73]
Справочная [38]
Инструмент [0]
Технология [8]
Литература [0]
Arduino скетчи [18]
Поиск
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Микроконтроллеры - это просто!
Главная » Статьи » Готовые устройства

Цифровой вольтметр 0 - 25V на Atmega8

Продолжим изучать аналого-цифровой преобразователь микроконтроллеров AVR на примере цифрового вольтметра постоянного напряжения, с пределами измерения от 0 до 25V. Измеряемое напряжение будет отображаться на трехразрядном семисегментном индикаторе с общим анодом. В этом примере применим динамическую индикацию о которой подробней рассказано на одном из предыдущих занятий, кусок исходного кода возьмем от туда же. Микроконтроллер Atmega8 тактируется от внутреннего генератора частотой 8MHz.

Далее займемся настройкой АЦП. В этот раз попробуем использовать внутренний источник опорного напряжения 2,56V, т.к. выход Aref микроконтроллера соединен с ИОН, для обеспечения стабильности ИОН подключаем к выводу Aref конденсатор. Резистор R3 - подстроечный, он служит для регулировки номинального уровня напряжения, желательно многооборотный.

Входом АЦП является линия PC0(ADCO), т.к. вольтметр у нас должен измерять напряжение до 25V, а 25V для порта контроллера это очень много, в таких случаях используют делитель напряжения. Например, если напряжение на входе будет меняться от 0 до 25V, то на выходе оно будет меняться от 0 до 5V.

Рассчитаем максимальное напряжение Uemax подаваемое на вход АЦП по формуле:

Uemax = 1023*Uref/1024

Uemax = 1023*2.56/1024 = 2,5575V

Рассчитаем максимальное входное напряжение делителя, исходя из параметров: R1=100k, R2=10k, Uemax=2,5575, применим такую формулу:

Uemax = Uin*R2/R1+R2

,где Uin максимальное напряжение подаваемое на вход делителя.

Uin = 2,5575*110k/10k = 28,1325V

Из этого мы знаем, что больше 28,1325V на вход вольтметра подавать нельзя. Также надо знать какой результат будет сохраняться в регистре ADC при изменении напряжения на входе АЦП. Результат преобразования вычисляется по формуле:

ADC = 1024*Uemax/Uref

Например при максимальном напряжении на входе 2,5575V результат преобразования будет таким:

ADC = 1024*2,5575/2,56 = 1023

При напряжении на входе 2V результат будет таким:

ADC = 1024*2/2.56 = 800

Чтобы на индикаторе получить реальные цифры в Вольтах результат преобразования надо умножить на коэффициент равный отношению максимального напряжения(4 разряда) подаваемого на вход делителя к максимальному результату преобразования АЦП.

k = 2813/1023 = 2,75

В программе обработчика прерываний от АЦП результат преобразования перемножаем на этот коэффициент и получаем величину напряжения подаваемого на вход делителя, т.к для операции умножения на дробное число микроконтроллеру потребуется много памяти, существует способ представить число 2,75 по другому, например: (ADC*11)/4. Настраиваем регистры АЦП и Таймера2, глобально разрешаем прерывания, так же в коде вычисляем средний показатель результата преобразования и выводим данные на индикатор. Полный текст программы ниже.


// Использование АЦП. Цифровой вольтметр
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h> 
 
//------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9----dp
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x80};
 
volatile unsigned char segcounter = 0;
volatile int display = 0;
 
// Прерывание по переполнению T2, динамическая индикация
ISR(TIMER2_OVF_vect)
{    
PORTD = 0xFF;
PORTB = (1 << segcounter);
  
switch (segcounter)
{    
case 0:
PORTD = ~(SEGMENTE[display % 10000 / 1000]);
break; 
case 1:
PORTD = ~((SEGMENTE[display % 1000 / 100])|0x80); // добавляем десятичную точку
break;    
case 2:
PORTD = ~(SEGMENTE[display % 100 / 10]);
break;        
}
if ((segcounter++) > 2) segcounter = 0;    
}
 
volatile unsigned long value;
volatile unsigned int adc_counter;
 
// Прерывание по окончанию преобразования АЦП
ISR (ADC_vect)
{
value = value + (ADC*11/4);
adc_counter++;
}
 
// Главная функция
int main (void) 

DDRD = 0xFF;
DDRB |= (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3);
PORTD = 0x00;
PORTB = 0x00; 
DDRC = 0x00;   
 
TIMSK |= (1 << TOIE2); // разрешение прерывания по таймеру2
TCCR2 |= (1 << CS21);  //предделитель на 8 
  
ADCSRA |= (1 << ADEN) // разрешение АЦП
 |(1 << ADSC) // запуск преобразования
 |(1 << ADFR) // непрерывный режим работы АЦП
 |(1 << ADPS2)|(1 << ADPS1)|(0 << ADPS0) // предделитель на 64 (частота АЦП 125kHz)
 |(1 << ADIE); // разрешение прерывания
 
ADMUX |= (1 << REFS1)|(1 << REFS0) // внутренний ИОН 2,56V
 |(0 << MUX3)|(0 << MUX2)|(0 << MUX1)|(0 << MUX0); // вход ADC0
  
_delay_ms(50);
 
sei(); //глобально разрешаем прерывания
  
while(1)

if (adc_counter > 300) // вычисляем среднее значение АЦП
{
display = value/adc_counter;
adc_counter = 0;
value = 0;
}     
_delay_ms(50);
}
}


Исходный код для индикатора с общим катодом


// Использование АЦП. Цифровой вольтметр
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h> 
 
//------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9----dp
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x80};
 
volatile unsigned char segcounter = 0;
volatile int display = 0;
 
// Прерывание по переполнению T2, динамическая индикация
ISR(TIMER2_OVF_vect)
{    
PORTD = 0x00;
PORTB = ~(1 << segcounter);
  
switch (segcounter)
{    
case 0:
PORTD = SEGMENTE[display % 10000 / 1000];
break; 
case 1:
PORTD = (SEGMENTE[display % 1000 / 100])|0x80; // добавляем десятичную точку
break;    
case 2:
PORTD = SEGMENTE[display % 100 / 10];
break;        
}
if ((segcounter++) > 2) segcounter = 0;    
}
 
volatile unsigned long value;
volatile unsigned int adc_counter;
 
// Прерывание по окончанию преобразования АЦП
ISR (ADC_vect)
{
value = value + (ADC*11/4);
adc_counter++;
}
 
// Главная функция
int main (void) 

DDRD = 0xFF;
DDRB |= (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3);
PORTD = 0x00;
PORTB = 0x00; 
DDRC = 0x00;   
 
TIMSK |= (1 << TOIE2); // разрешение прерывания по таймеру2
TCCR2 |= (1 << CS21);  //предделитель на 8 
  
ADCSRA |= (1 << ADEN) // разрешение АЦП
 |(1 << ADSC) // запуск преобразования
 |(1 << ADFR) // непрерывный режим работы АЦП
 |(1 << ADPS2)|(1 << ADPS1)|(0 << ADPS0) // предделитель на 64 (частота АЦП 125kHz)
 |(1 << ADIE); // разрешение прерывания
 
ADMUX |= (1 << REFS1)|(1 << REFS0) // внутренний ИОН 2,56V
 |(0 << MUX3)|(0 << MUX2)|(0 << MUX1)|(0 << MUX0); // вход ADC0
  
_delay_ms(50);
 
sei(); //глобально разрешаем прерывания
  
while(1)

if (adc_counter > 300) // вычисляем среднее значение АЦП
{
display = value/adc_counter;
adc_counter = 0;
value = 0;
 }     
_delay_ms(50);
}
}

Категория: Готовые устройства | Добавил: Alex (11.07.2014)
Просмотров: 9383 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Copyright MyCorp © 2024