Генерация аналоговых сигналов микроконтроллером. Ч1

Введение

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

1. Принцип генерации аналогового сигнала с помощью ШИМ (PWM)

   ШИМ сигнал представляет собой цифровой сигнал, у которого период повторения постоянный, а длительность меняется. Отношение длительности ШИМ сигнала к его периоду называется коэффициентом заполнения. Пропустив такой сигнал через низкочастотный фильтр, что по сути равносильно интегрированию, мы получим на выходе фильтра уровень напряжения пропорциональный коэффициенту заполнения. 


   Таким образом, меня этот коэффициент, можно генерировать аналоговые сигналы произвольной формы. Причем как переменные, например, синусоида, пила или человеческая речь, так и постоянные (произвольный уровень напряжения). 

1.1 Характеристики сигнала

   Максимальная амплитуда выходного аналогового сигнала будет определяться амплитудой логической единицы цифрового ШИМ сигнала. Если микроконтроллер питается от +5 В, то грубо говоря, амплитуда выходного аналогового сигнала будет от 0 до 5 В. 

   Минимальный шаг изменения аналогового сигнала (разрешение) будет определяться выражением:


dUa = Umax/2^n,


где Umax максимальная амплитуда аналогового сигнала (В), а n - разрядность счетчика реализующего ШИМ. 

   Например, ШИМ сигнал формируется с помощью программного 8-ми разрядного счетчика. Количество градаций ШИМ сигнала, которые можно получить с помощью этого счетчика, равно 2^8 = 256. Тогда разрешение аналогового сигнала при Umax = 5 В будет равно 


dUa = 5/256 = 0,0195 В. 


   Частота ШИМ сигнала будет определять так:


Fpwm = Fcpu/(K*2^n),


где Fcpu - тактовая частота микроконтроллера (Гц), K - коэффициент предделителя счетчика, n - разрядность счетчика. 

   Например, тактовая частота микроконтроллера 8 МГц, коэффициент предделителя равен 8, разрядность счетчика 8 бит. Тогда частота выходного ШИМ сигнала будет равна:

Fpwm = 8000000/(8*256) = ~3906 Гц


   Частота выходного аналогового сигнала будет определяться выражением:

Fa = Fpwm/Ns = Fcpu/(K*2^n*Ns),


где Fpwm - частота ЩИМ сигнала, а Ns - количество отсчетов аналогового сигнала. 
   
   Например, ШИМ сигнал реализуется на 8-ми разрядном счетчике с коэффициентом предделителя равным 8 и тактовой частотой микроконтроллера 8 МГц. В памяти микроконтроллера записано 32 отсчета синусоидального сигнала, которые представляют собой один его период. Тогда частота выходной синусоиды будет равна:

Fa = 8000000/(8*2^8 * 32) = ~122 Гц

   Разрядность ЦАП`a сделанного на основе ШИМ эквивалентна разрядности используемого счетчика. 

1.2 Аппаратная реализация ШИМ

   Все современные микроконтроллеры имеют в своем составе таймеры/счетчики. Один или несколько режимов этих таймеров предназначены для генерации ШИМ сигнала. Как правило этот сигнал генерируется на специальных выводах. Например, у микроконтроллера mega16 фирмы Atmel 8-ми разрядный таймер/счетчик Т0 имеет два режима генерации ШИМ сигнала (быстрый ШИМ и ШИМ с точной фазой), а для вывода сигнала используется пин порта B - OC0 (PINB3).

   Достоинство аппаратной реализации ШИМ сигнала - это низкая загрузка микроконтроллера (прерывание вызывается один раз в период ШИМ сигнала), простота использования и точность (если в системе мало прерываний). Из недостатков можно отметить - ограниченное разрешение счетчиков, невысокая частота, ограниченное число каналов, на которых можно генерировать ШИМ сигналы. Хотя существуют специальные микроконтроллеры специально "заточенные" для генерации большого количества ШИМ сигналов.

1.3 Программная реализация ШИМ

   Также можно генерировать ШИМ сигнал программно. Для этого нужно просто создать программный счетчик и по сигналу аппаратного таймера инкрементировать его значение и отслеживать достижение крайних значений счетчика, в которых ШИМ сигнал меняет состояние. 

   Преимущество программной реализации - простота, неограниченное количество каналов, неограниченное разрешение. Конечно, условно неограниченное, с учетом доступной памяти. Недостатки программной реализации - высокая загрузка микроконтроллера. Прерывания должны вызываться на каждый инкремент счетчика и каждый раз нужно проверять не достиг ли он одного из крайних значений. Также программная реализация имеет меньшую точность (большее дрожание фронтов сигнала) и еще меньшую частоту (из-за первого недостатка).

   Однако, несмотря на это, программная реализация ШИМ`а тоже имеет место быть, если требуется генерировать постоянный аналоговый сигнал или переменный, но с невысокой частотой. 

   Ниже приведен пример кода, который выполняет функцию генерацию аналогового сигнала с помощью аппаратной и программной широтно-импульсной модуляции. Код написан для микроконтроллера atmega16, тактовая частота 8 МГц, компилятор IAR. На выходах PB2 и PB3 генерируются две синусоиды (разной частоты) из 32 двух отсчетов. 

#include <ioavr.h>
#include <intrinsics.h>
#include <stdint.h>

#define SPWM_PIN 2

//таблица синуса
__flash uint8_t tableSin[] = 
{
   152,176,198,218,234,245,253,255,
   253,245,234,218,198,176,152,128,
   103, 79, 57, 37, 21, 10, 2, 0,
   2, 10, 21, 37, 57, 79,103,128
};

uint8_t softCount = 0;
uint8_t softComp = 0;

int main( void )
{
 //настройка портов
 PORTB = 0;
 DDRB = 0xff;
 
//разрешение прерывания по совпадению Т0
TIMSK = (1<<OCIE0);
 //режим FastPWM, неинв. шим сигнал, предделитель 8
 TCCR0 = (1<<WGM01)|(1<<WGM00)|(1<<COM01)|(0<<COM00)| \
 (0<<CS02)|(1<<CS01)|(0<<CS00);
 
 //обнуляем счетный регистр
 TCNT0 = 0;
 OCR0 = 0;
 
 __enable_interrupt();
 while(1);
 return 0;
}

//прерывание таймера Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
   static uint8_t i = 0;
   static uint8_t j = 0;
 
   OCR0 = tableSin[i];
   i = (i + 1) & 31;
 
   //программный ШИМ
    softCount++;
    if (softCount == 0){ 
       PORTB |= (1<<SPWM_PIN); 
      softComp = tableSin[j];
      j = (j + 1) & 31; 
   }
 
   if (softCount == softComp){
      PORTB &= ~(1<<SPWM_PIN); 
   }
}


1.4 Фильтр для ШИМ

   Частота среза фильтра должна быть между максимальной частотой генерируемых аналоговых сигналов и частотой ШИМ сигнала. Если частота среза фильтра будет выбрана близко к границе полосы аналогового сигнала, это приведет к его ослаблению. А если частота среза фильтра будет близко к частоте ШИМ сигнала, аналоговый сигнал просто не "выделится". Чем выше частота ШИМ сигнала, тем проще реализовать выходной фильтр.

   Рассмотрим пример. ШИМ сигнал генерируется аппаратным 8-ми разрядным счетчиком с коэффициентом предделителя равным 8, тактовая частота микроконтроллера 8МГц, количество отсчетов аналогового сигнала - 32.

Частота ШИМ сигнала будет равна:


Fpwm = Fcpu/(K*2^n) = 8000000/(8*256) = ~3906 Гц


Частота аналогового сигнала будет равна:


Fa = Fpwm/Ns = 3906/32 = 122 Гц


   Выберем частоту среза равную 200 Гц и рассчитаем номиналы пассивного низкочастотного RC фильтра. Частота среза такого фильтра определяется выражением:


Fc = 1/(2*Pi*R*C),


где R - номинал резистора (Ом), а C -емкость конденсатора (Ф).

   Задавшись номиналом одного из компонентов можно вычислить номинал второго. Для резистора номиналом 1 кОм, емкость конденсатора будет равна:


C = 1/(2*Pi*Fc*R) = 1/(6.28 * 1000*200) = ~0.8 мкФ 


   Выбираем ближайшее значение из ряда E12 - 0.82 мкФ. При таких номиналах фильтра мы получим уже похожий аналоговый сигнал.

   Однако, как правило, одного звена пассивного фильтра будет не достаточно. Потому что после него аналоговых сигнал все еще будет содержать большое количество гармоник.

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

При добавлении в комментарий Си кода, заключайте его между тегами [code] [/code]. Иначе он будет отображаться некорректно.


Защитный код
Обновить