Введение
В устройствах на микроконтроллерах иногда требуется генерировать аналоговый сигнал. В зависимости от частоты аналогового сигнала, требуемого разрешения и типа используемого микроконтроллера, выполнить это можно несколькими способами. А именно: с помощью широтно-импульсной модуляции, используя функционал аппаратных таймеров или программную реализацию, с помощью встроенного цифроаналогового преобразователя (ЦАП`а), с помощью внешних схем цифроаналоговых преобразователей на дискретных элементах или с помощью внешних микросхем цифроаналоговых преобразователей.
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 мкФ. При таких номиналах фильтра мы получим уже похожий аналоговый сигнал.
Однако, как правило, одного звена пассивного фильтра будет не достаточно. Потому что после него аналоговых сигнал все еще будет содержать большое количество гармоник.
Comments
2. Таймера с прерываниями лучше настраивать в хрестоматийной последовательно сти. Такой подход никогда не подведёт, ни когда глобальные прерывания при этом процессе уже разрешены, ни когда запрещены:
- остановка таймера,
- задать режим работы(не стартуя),
- задать регистры TCNT, OCR, ICR......
- TIFR = (сбрасить флаг, возможно, от предыдущих запусков этого таймера),
- задать TIMSK,
- старт таймера операцией |= (CSii)
2. Запомню.
Лучше операцией =
Code:
TCCR0 = (1<<WGM01)|(1<<WGM00)|(1<<COM01)|(0<<COM00)| \
(0<<CS02)|(1<<CS01)|(0<<CS00);
Могу сказать как именно Ваш случай привел однажды к трудноуловимому глюку у моего коллеги. Я башку сломал пока понял в чем дело. Представьте: Tаймер. Задается СТС режим с ТОРом, определяемым регистром ICR. Шаги:
-останов,
-задание режима в TCCRnA,
-задание TCNT,
-задание ICR (внимание!!!!!)
-задание TIFR,TIMSK...
- TCCRnB = (режим и запуск) Сэкономили!
Поехали!
Блин - ПЕРИОД ТАЙМЕРА отрабатывается НЕ ТОТ! Нулевой почему-то стал, период-то! (Счастье еще, что быстро заметили это)
Какого хрена?
А вот какого: Вход захвата таймера ICn отключается от захватничества только тогда, когда режим с TOP=ICR задан! А пипл решил сэкономить, режим был задан не полностью, а только в TCCRnA. Парень спокойно суёт ICR=XX, думая что это надёжно сохранится, а на вход IC извне подавалась некая частота. И фронт этой частоты иногда успевал переписать TCNT в ICR пока дело доходило до TCCRnB! Вот откуда получался "нулевой" период. А если б парень нормально задал бы режим, и в TCCRnA и в TCCRnB, то такого бы не произошло.
AVR шуток не любит. Ошибок не прощает))
Шаги объдинять не нужно, но лучше делать их с минимальными затратами.
Quoting Peter:
Пока есть только AVR Mega/ AVR Xmega/ LPC11 CM-0/ EFM32 и когда-то давно были x51 и Sx52. Но что-то к разделению сущностей не прихожу, а скорей ухожу.
Quoting Peter:
Да, бывают случаи...разные. Навочно не придуиаешь.
Quoting Peter:
Ригистр для сброса таймера в исходное состояние очень бы не помешал.
Quoting Peter:
:)
Мне будет интересно реализовать DTMF сигнал в проекте с матричной клавой 4*4.Ждем вторую часть...
"Хотя существуют специальные микроконтроллер ы специально "заточенные" для генерации большого количества ШИМ сигналов."
какие именно можете указать ?
i = (i + 1) & 31;
& 31 - зачем ?
RSS feed for comments to this post