Интернет-магазин

Просмотр корзины
В корзине:

товаров - 0 шт.



§ 48. 10-ти разрядный АЦП на основе PIC16F877

Иванов Дмитрий, Апрель 2007
Статья обновлена 26 Мая 2014

Файлы к статье скачать

Эта статья я думаю, будет немного поинтереснее. Здесь мы сделаем АЦП на основе МК PIC16F877. АЦП этот будет 10-ти разрыдным, что очень неплохо ибо позволяет получать хорошую точность преобразования. При диапозоне входных напряжений АЦП 0-5 В получаем шаг квантования 5/(210) = 0.00488 В


Начнем, пожалуй со схемы, чтоб был более понятным код. В МК PIC16F877 есть аж целых 8 линий, на котроые, при соответствующих программных настройках, можно подавать аналоговое напряжение на вход АЦП. В этом примере я использую линию RA0/AN0 (вывод 2). Диапозон рабочих АЦП этого МК составляет 0 - 5 В . Не превышайте этот порог - можно МК сжечь. Еще одним схемным изменением стало появление еще двух светодиодов - нам же надо как-то показать результат работы АЦП. Т.к. 10-ти разрыдный, то нам и нужны 10 светодиодов для отображения результата преобразования.

Для упрощения этого примера, я решил не использовать еще один источник напряжения для входа АЦП, а запитал его через переменый резистор от общей шины питания схемы. Теперь изменяя положение движка резистора можно будет изменять подаваемое на вход АЦП напряжение - от 0 до 5 В.

Теперь рассотрим код для МК, который позволяет использовать АЦП и отображает результат его работы на светодиодах. Готовый проект приложения MPLAB можно найти в файлах к этой статье. Здесь я решил показать помимо работы с модулем АЦП еще и обработку прерываний в МК. Схема функционирования программы следующая: сначала проводим инициализацию АЦП и настраиваем т.н. таймер. После этого входим в бесконечный цикл. Таймер срабатывает с определенной частотой и при каждом его срабатывании управление в МК переходит на нашу специализированную функцию, в которой мы проводим обработку результатов работы АЦП. После того как функция-обработчик прерывания от таймера завершит свою работу, управление передается обратно на тот участок, откуда мы перешли на функцию обработчик. Потом снова сработает таймер и т.д.

Рассмотрим что здесь происходит. Начнем с функции main, ведь имено с нее начнется выполнение программы. Сначала мы присваиваем значение счетчику таймера равным 0 (TMR0=0). Это нужно для того, чтобы таймер не успел сработать, пока мы проводим начальную инициализацию (до входа в бесконечный цикл). Тут необходимо сказать пару слов об этом самом таймере. Это обычный 8-ми разрядный регистр, значение которго при каждом машинном такте увеличивается на еденицу. Как только значение в нем будет равно 256, он сбрасывается и в определенном регистре устанавливается флаг, говорящий о том что произошло переполнение таймера. (вот тут то управление и перейдет на нашу функцию обработчик прерывания). Перодом срабатывания таймера можно управлять, указав через сколько прошедших машинных тактов значение регистра таймера увеличивается на 1. Ругилировать можно в пределах 1:2, 1:4, 1:8, 1:16, 1:32, ..., 1:256. Т.е. в последнем случае, чтобы регистр увеличился на еденицу должно пройти 256 машинных тактов. Тогда для срабатывания таймера потребуется 256*256 = 65536 машинных тактов. Зная длительность машинного такта можно однозначно опрделеить период срабатывания таймера в секудах. Для МК PIC один машинный такт = 4 тактам кварца. Тогда, если у нас стоит кварц на 20 МГц, длительность одного машинного такта будет равна 1/(5 МГц) = 0.2 * 10-6 сек = 0.2 мкс.

Слующей строчкой в коде мы как раз и настраиваем работу таймера. Для этого служит спецальный регистр, каждый бит в котором предназначен для определенной настройки какого-либо свойства. Полное описание этого регистра советую прочитать в описании к этому МК, которое можно было найти в 3-тьей статье этого раздела.

То числовое значение которое загружается в него (регистр) в это примере означает что таймер будет работать с предделителем 1:2 (увеличение счетчика таймера происходит после двух машинных тактов). Далее устанавливая спец. бит настройки T0IE в еденицу мы разрешаем прерывания от таймера. GIE=1 - разрешает обработку прерываний в МК глобально. Потом настраиваем порт B и D для работы на выход и помещаем в них 0 (светодиоды подключенные к ним будут погашены).

Далее проводим настройку работы АЦП. Для его настроек предназначенны два регистра ADCON1 и ADCON0. Более подробно про их содержимое расписано в описаниии МК.

На что хотел обратить Ваше внимание, так это на т.н. выравнивание результата преобразования. Результат то 10-ти разрядный, а регистры в МК PIC 8-ми разрядные. Значит нужны два регистра. Размещением в них этого результата (с какой сторны они выровнены, т.е. откуда начинаются) можно устанавливать самомтоянтельно. В этом примере я указал правое выравнивание. Это значит что 8 младших бит результата будут находиться в одном регистре а оставшиеся 2 будут находится в двух младших битах другогог регистра.

После того как все настройки сделаны, запускаем бесконечный цикл и ждем кагда сработает таймер. Как только это происходит, управление переходит на специальнцю функцию с ключевым словом interrupt. В ней мы проверяем бит T0IF, в которм указывается что произошло прерывание таймера. Если это так, то мы его сбрасываем в ноль (чтоб таймер дальше мог работать) и запускаем процесс преобразования входного аналогового напряжения в цифровой код установкой бита управления АЦП ADGO. Как только преобразование АЦП будет сделано, этот бит станет равным 0. Поэтому с помощью while мы ждем этого события. Теперь нам нужно прочесть результат преобразования. Он храниться в двух регистрах с именами ADRESL и ADRESH. В первом из них храняться 8 младших бит результата и мы сразу же их отсылаем в порт B (красные светодиоды). В ADRESH находятся 2 старших бита результата. Т.к. на схеме я хотел чтобы эти два бита отображались на выводах 2,3 порта D (чтоб все светодиды были по одну сторону от МК) то нужно содержимое этого регистра сдвинуть на два разряда влево. После этого то что сдвинули записываем в порт D.

#include <pic.h>

__CONFIG(0x03F72);

unsigned char b=0;

void interrupt IntFun(void)
{
	if(T0IF)
	{
		T0IF=0;
		ADGO=1;

		while(ADGO==1)
		{
		}

		PORTB=ADRESL;	
		b=ADRESH;
		PORTD=b<<2;
		GIE=1;	
	}
}


void main(void)
{
	TMR0=0;
	OPTION= 0b11010000; //таймер 1:2
	T0IE=1;             //разрешаем прерывания от таймера
	GIE=1;	

	TRISB=0;
	PORTB=0;
	TRISD=0;
	PORTD=0;

	/*
		правое выравнивание
		RA0 - аналог, все остальные из PORTA - цифра
	*/

	ADCON1=0b10001110; 

	/*
		тактовый сигнал Fosc/32
		канал 0 (RA0)
		GO-/DONE = 0
		АЦП включен
	*/

	ADCON0=0b10000001;


	while(1==1)
	{		
	
	}	
}

Внешне полученная схема может выглядеть например вот так.



© Иванов Дмитрий
Апрель 2007
http://www.kernelchip.ru



© KERNELCHIP 2006 - 2017