AVR Урок 22. Изучаем АЦП. часть 3

 

 

 

 

Урок 22

Часть 3

 

Изучаем АЦП

 

 

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

Только происходило это ручным способом и мы раз в 500 милисекунд постоянно вручную вызывали процесс преобразования, ждали результат, что заметно тратит ресурсы нашего контроллера.

Для того. чтобы этого избежать, существует другой режим работы модуля АЦП в контроллерах AVR — это режим прерываний. Также есть ещё режим не ручного вызова преобразования, а циклического.

Вот такой режим мы сегодня и попробуем реализовать с помощью нашего кода.

Проект мы создадим новый с именем MyADCISRLCD, а код в главный модуль весь скопируем с предыдущего проекта, также все файлы включим те же. Это делается для того, чтобы у нас был отдельный проект для прерываний и отдельный для ручного режима.

Удалим полностью функцию запуска конвертирования из файла adc.c, а также из хедера её прототип за её дальнейшей ненадобностью ибо данный процесс у нас будет автоматизирован.

Немного перенастроим регистры в функции инициализации

 

void ADC_Init(void)

{

  ADCSRA |= (1<<ADEN) // Разрешение использования АЦП

  |(1<<ADSC)//Запуск преобразования

  |(1<<ADFR)//Непрерывный режим работы АЦП

  |(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)//Делитель 128 = 64 кГц

  |(1<<ADIE);//Разрешение прерывания от АЦП

  ADMUX |= (1<<REFS1)|(1<<REFS0); //Внутренний Источник ОН 2,56в, вход ADC0

}

 

Вообщем, тут, я думаю также всё понятно, так как в 1 части нашего занятия мы все регистры и их биты изучили. Также не забываем что весь код, кроме последней строки — это одна единая большая строка кода.

Над данной функцией добавим функцию-обработчик прерывания от АЦП

 

//—————————————-

ISR(ADC_vect)

{

}

//—————————————-

 

Для этого у контроллера существует вот такой вектор

 

image21

 

Здесь мы видим, что данное прерывание вызывается в момент окончания аналого-цифрового преобразования.

Также в файле adc.c нам потребуются две глобальне переменные для временного хранения старшей и младшей части регистровой пары adc

 

#include "adc.h"

//—————————————-

char high_adc=0,low_adc=0;

 

Заполним данные переменные значениями из регистра в обработчике прерывания

 

ISR(ADC_vect)

{

  low_adc = ADCL;

  high_adc = ADCH;//Верхняя часть регистра ADC должна быть считана последней, иначе не продолжится преобразование

 

Здесь есть хитрость. Читать нужно сначала младшую часть, так как следующее преобразование автоматически начинается именно в случае такого порядка считывания регистров.

 

image22

 

 

Из функции main() удалим объявление переменной adc_value, но инициализацию оставим

 

float n;

adc_value=0;

 

и запишем её в main.h, так как данная переменная у нас теперь будет глобальная и она должна быть видна в других модулях

 

#include <stdlib.h>

unsigned int adc_value;

 

Сегодня мы с вами впервые попытаемся использовать глобальные переменные, объявленные в одном модуле проекта, в других модуля.

Тут физика такая. Если мы просто попытаемся в другом модуле обратится к такой переменной, то она всё равно будет не видна. Её необходимо в модуль подключить, для этого существует специальный оператор extern. Вот с помощью него мы и подключим нашу переменную в файл adc.h

 

#include "adc.h"

//—————————————-

extern unsigned int adc_value;

//—————————————-

char high_adc=0,low_adc=0;

 

Теперь данная переменная будет видна везде и изменения в ней тоже.

Занесём в неё считанные значения из двух переменных в обработчике прерывания от АЦП

 

high_adc = ADCH;//Верхняя часть регистра ADC должна быть считана последней, иначе не продолжится преобразование

adc_value=high_adc*256+low_adc;

 

Можно здесь было также использовать и битовые сдвиги, но мы пока поступим просто.

В функции main() удалим вызов преобразоания, так как прерывание нам вызывать не придется, оно происходит автоматически, а можно и закомментировать

 

while(1)

{

  //adc_value = ADC_convert(); //Вызовем преобразование

 

Также нужно не забыть нам включить ещё прерывания глобальные после инициализации АЦП

 

ADC_Init(); //Инициализируем АЦП

sei();

clearlcd(); //Очистим дисплей

 

Соберём код, прошьём контроллер и попробуем работу нашего кода

 

image23 image24  image25

 

Вот такой вот упрощённый механизм использования АЦП по прерываниям.

 

Предыдущая часть Программирование МК AVR Следующий урок

 

Исходный код

 

Программатор и дисплей можно приобрести здесь:

Программатор (продавец надёжный) USBASP USBISP 2.0

Дисплей LCD 16×2

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR Изучаем АЦП

6 комментариев на “AVR Урок 22. Изучаем АЦП. часть 3
  1. Евгений:

    Здравствуйте.

    Спасибо за материалы и огромное спасибо за их подачу. Учусь многому из цикла статей и видео.

    П.С.:Опечатка?

    /*

    Тут физика такая. Если мы просто попытаемся в другом модуле обратится к такой переменной, то она всё равно будет не видна. Её необходимо в модуль подключить, для этого существует специальный оператор extern. Вот с помощью него мы и подключим нашу переменную в файл adc.h

    */

    Изменить в конце adc.h на adc.c ?

    • Дмитрий:

      Возможно ответ запоздал. Но только недавно нашел этот сайт.

      Можно прописать extern и в adc.c, но глобальные переменные обычно прописываются в хедер файлах. 

  2. Андрей:

    Только открыл в протеусе, показует тока до 0200 0.5 ((( что не так? Атмель 7

  3. Андрей:

    Прочитал коммент из 2й части подал питание на AVCC всё заработало

  4. Роман:

    Как настроить сразу два АЦП ? Мне нужно сделать два вольтметра на одной атмеге.

  5. freebits:

    Спасибо за статью. Изложено все доступно и понятно.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*