В данной статье будет рассмотрен принцип использования встроенного аналого-цифрового преобразователя (АЦП или по англ. ADC - Analog-to-digital converter) в микроконтроллерах AVR на примере attiny13
АЦП в Attiny13 может использовать 3 порта ADC1-ADC2. Также при соответствующих настройках фьюзов в качестве четвертого порта ADC0 можно задействовать порт RESET.
Для управления АЦП используются регистры ADMUX и ADCSRA, а для хранения результата – 16-битный регистр ADC, состоящий из двух восьмибитных ADCH и ADCL. Теперь об этом немного попрдробней:
ADMUX – ADC Multiplexer Selection Register
Где:
REFS0 – Выбор источника опорного напряжения. 0 – используется напряжение питания Vcc, 1 - внутреннее опорное напряжение величиной 1.1В
ADLAR – задает способ вывода результата в регистр ADC (ADCH и ADCL)
Если ADLAR = 0, то в регистре число в формате, удобном для 10-битной работы АЦП (в ADC – 16-битное значения сигнала на входе (0-1023)):
а если ADLAR = 1, то число в удобном формате для 8-ми битной работы АЦП (В регистре ADCH – 8-битное значения сигнала на входе (0-255)):
MUX1:0 – задает порт ADC0-ADC3, с которым будет работать АЦП:
ADCSRA – ADC Control and Status Register A
Где:ADEN: ADC Enable – запись в него 1 разрешает работу АЦП
ADSC: ADC Start Conversion – запись в него 1 запускает старт преобразования
ADIF: ADC Interrupt Flag – бит, который используется для контроля процесса преобразования. По окончанию преобразования данный бит устанавливается в 1.
Bits 2:0 – ADPS[2:0]: Выбор предделителя для подачи тактирования. Диапазон тактирования от 50 до 200кГц. Для получения частоты тактирования в 75кГц нужно выбрать коэффициент 128 (9 600 000/128 = 75 000)
Пример использования:
Инициализация АЦП.
// Выбираем внутренний источник опорного напряжения и ADC3 ADMUX|=(1<< REFS0) | (1<<MUX0) | (1<<MUX1); //Разрешаем работу АЦП и устанавливаем делитель на 128 ADCSRA|=(1<< ADEN) | (1<<ADPS0) |(1<<ADPS1) | (ADPS2);
Чтение результата АЦП:
ADCSRA|=(1<<ADSC); //Запуск преобразования While((ADCSRA&(1<<ADSC))); //Ожидаем окончания преобразования
После этого 16 битный результат находится в регистре ADC, который можно сохранить в переменную
Пример программы с 10 битным преобразованием (результат 0-1023):
/* * ADC-tm1637.c * * ============================================ * H A R D W A R E I N F O R M A T I O N S * ============================================ * Attiny13a ___________ * 1 /____ |8 * o--|RESET Vcc|--o +5V * ADC o--|PB3/ADC3 PB2|--o * o--|PB4/ADC2 PB1|--o CLK_PIN * GND o--|GND PB0|--o DIO_PIN * |_____________| * * Author : Vyacheslav */ #define F_CPU 1200000L #include <avr/io.h> #include <util/delay.h> #include "tm1637.h" unsigned short numb_b, digit_tmp; int main(void) { //Инициализация АЦП ADMUX|= (1<<MUX0) | (1<<MUX1); //Выбираем для работы АЦП порт ADC3 ADCSRA|= (1<<ADEN) | (1<<ADPS2); // Разрешаем работу АЦП и устанавливаем делитель на 16 (1.2MHz/16=75kHz) TM1637_init(1, 6); TM1637_clear(); TM1637_display_colon(0); while (1) { ADCSRA|=(1<<ADSC); //Запуск преобразования while(!(ADCSRA&(1<<ADIF))); //Ожидание окончания преобразования numb_b = ADC; for (unsigned char i = 1; i <= 4; ++i) { digit_tmp = numb_b % 10; TM1637_display_digit(4-i,digit_tmp); numb_b = numb_b / 10; } _delay_ms(1000); } }
Чтоб преобразование было не 10 битным, а 8 (результат 0-255) нужно бит ADLAR регистра ADMUX установить в 1 и результат взять не с ADC, а с ADCH:
/* * ADC-TM1637-8bit.c * ============================================ * H A R D W A R E I N F O R M A T I O N S * ============================================ * Attiny13a ___________ * 1 /____ |8 * o--|RESET Vcc|--o +5V * ADC o--|PB3/ADC3 PB2|--o * o--|PB4/ADC2 PB1|--o CLK_PIN * GND o--|GND PB0|--o DIO_PIN * |_____________| * * Author : Vyacheslav */ #define F_CPU 1000000L #include <avr/io.h> #include <util/delay.h> #include "tm1637.h" unsigned short numb_b, digit_tmp; int main(void) { //Инициализация АЦП ADMUX|= (1<<ADLAR) | (1<<MUX0) | (1<<MUX1); //Выбираем для работы АЦП порт ADC3 ADCSRA|= (1<<ADEN) | (1<<ADPS2); // Разрешаем работу АЦП и устанавливаем делитель на 16 (1.2MHz/16=75kHz) TM1637_init(1, 6); TM1637_clear(); TM1637_display_colon(0); while (1) { ADCSRA|=(1<<ADSC); //Запуск преобразования while(!(ADCSRA&(1<<ADIF))); //Ожидание окончания преобразования numb_b = ADCH; for (unsigned char i = 1; i <= 4; ++i) { digit_tmp = numb_b % 10; TM1637_display_digit(4-i,digit_tmp); numb_b = numb_b / 10; } _delay_ms(1000); } }
И еще вариант программы, где АЦП реализовано в виде функции ADC_read с возможностью задания порта при вызове функции. Т.к. в качестве примера выбран порт 2 (ADC2), а к нему подключена кнопка, то на индикаторе отображается напряжение на кнопке (5В = 1023 единицы):
/* * ADC-tm1637-func.c * * ============================================ * H A R D W A R E I N F O R M A T I O N S * ============================================ * Attiny13a ___________ * 1 /____ |8 * o--|RESET Vcc|--o +5V * ADC o--|PB3/ADC3 PB2|--o * o--|PB4/ADC2 PB1|--o CLK_PIN * GND o--|GND PB0|--o DIO_PIN * |_____________| * * Author : Vyacheslav */ #define F_CPU 1200000L #include <avr/io.h> #include "tm1637.h" #include <util/delay.h> unsigned int ADC_read (unsigned char ch_adc) { if (ch_adc & (1<<0)) {ADMUX|= (1<<0);}; //Т.к. значение MUX1:0 соответствует номеру порта ADCx if (ch_adc & (1<<1)) {ADMUX|= (1<<1);}; // то записываем в них номер порта ADCSRA|=(1<<ADSC); //Запуск преобразования while(!(ADCSRA&(1<<ADIF))); //Ожидание окончания преобразования return (ADC); //Возврат в основною программу со значением 8-битного АЦП } int main(void) { ADCSRA|= (1<<ADEN) | (1<<ADPS2); // Разрешаем работу АЦП и устанавливаем делитель на 16 (1.2MHz/16=75kHz) TM1637_init(1, 6); TM1637_display_colon(0); int numb_b, digit_tmp; while (1) { numb_b = ADC_read(1); //Считываем в переменную значение ADC for (unsigned char i = 1; i <= 4; ++i) { // выводим значение ADC на дисплей digit_tmp = numb_b % 10; TM1637_display_digit(4-i,digit_tmp); numb_b = numb_b / 10; } _delay_ms(500); } }
Комментариев нет:
Отправить комментарий