3. Аппаратный ШИМ (PWM).
3.1. Таймеры/счетчики и регистры управления.
ШИМ (широтно импульсная модуляция) в микроконтроллере реализуется с использованием аппаратных таймеров. Теорию ШИМ рассматривать не будем. Рассмотрим лишь получение плавного изменения напряжения/тока на основе ШИМ. Для начала разберемся как управлять таймерами.
Имеется три таймера два по 8 бит (TC0, TC2) и один 16 бит (TC1). Настройка происходит регистрами TCCRxA, TCCRxB(x – означает выбранный таймер 0, 1 или 2).
Разберем чуточку подробнее на примере таймера TC1 в режиме 8 бит:
Регистр TCCR1A
бит |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
COM1A1 |
COM1A0 |
COM1B1 |
COM1B0 |
– |
– |
WGM11 |
WGM10 |
Бит 7, 6 (COM1A1, COM1A0)- настройка поведения вывода A по событию.
Бит 5, 4 (COM1B1, COM1B0)- настройка поведения вывода B по событию.
COM1A1/ COM1B1 |
COM1A0/ COM1B0 |
События |
0 |
0 |
Нормальная работа порта, таймер отключен от вывода. |
0 |
1 |
Переключение порта с 0 на 1 или обратно при совпадении. |
1 |
0 |
Сброс на 0 при совпадении. |
1 |
1 |
Установка 1 при совпадении. |
Бит 3, 2 — зарезервированы.
Бит 1, 0 (WGM11, WGM10) — позволяют настроить ШИМ, подробно рассматривать не будем из-за объемности описания.
Регистр TCCR1B
бит |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
FOC1A |
FOC1B |
– |
– |
WGM12 |
CS12 |
CS11 |
CS10 |
Бит 7, 6 (FOC1A, FOC1B)- при использовании ШИМ должны быть установлены в 0.
Бит 5, 4 — зарезервированы.
Бит 3 — используется совместно с WGM11, WGM10 для настройки ШИМ.
Бит 2, 1, 0 (CS12, CS11, CS10) — выбор источника тактирования таймера.
CS12 |
CS11 |
CS10 |
Событие |
0 |
0 |
0 |
Нет тактового сигнала (таймер остановлен) |
0 |
0 |
1 |
CLK |
0 |
1 |
0 |
CLK/8 |
0 |
1 |
1 |
CLK/64 |
1 |
0 |
0 |
CLK/256 |
1 |
0 |
1 |
CLK/1024 |
1 |
1 |
0 |
Внешний тактовый импульс по заднему фронту. |
1 |
1 |
1 |
Внешний тактовый импульс по переднему фронту. |
Регистр TCNT1
бит |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
– |
– |
– |
– |
– |
– |
– |
– |
Из регистра TCNT1 можно считать значение или записать начальное значение для таймера.
Регистры OCN1A и OCN1B
бит |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
– |
– |
– |
– |
– |
– |
– |
– |
Регистры OCN1A и OCN1B содержат значение сравнения связанные с соответствующими выводами микроконтроллера.
Есть еще два регистра TIMSK1 и TIFR1 – они предназначены для настройки маски прерываний и флагов прерываний.
Все перечисленные регистры можно использовать для всех трех таймеров. Для таймера TC1 есть возможность использовать расширенные настройки в связи с его 16-битной структурой.
Данный раздел не претендует на полноту описания работы с таймерами и ШИМ.
3.1. Программа с ШИМ
Для начала построим в Proteus схему и дальше применим ее для моделирования
Теперь программа.
#include <avr/io.h> //Подключаем библиотеку ввода/вывода AVR #include <util/delay.h> //Подключаем библиотеку формирования задержки выполнения int main(void) { DDRB |= 1<<PB1; //Устанавливаем как вывод регистр 1 порта B TCCR1A |= 1<<(COM1A1) | 1<<(WGM10); //В регистре TCCR1A устанавливаем биты COM1A1 и WGM10 в 1 TCCR1B |= 1<<(CS10) | 1<<(WGM12); //В регистре TCCR1B устанавливаем биты CS10 и WGM12 в 1 int pwm = 0; //Объявляем переменную для значения сравнения int up = 1; //Создаем флаг для увеличения или уменьшения скважности ШИМ while(1) { OCR1A = pwm; //Заносим значение в регистр сравнения pwm += up ? 1 : -1; //В зависимости от флага uo увеличиваем или уменьшаем значение сравнения pwm if (pwm == 255) //Проверяем pwm на достижение 255 и переключаем флаг uo в 0 up = 0; else if (pwm == 0) //Проверяем pwm на достижение 0 и переключаем флаг uo в 1 up = 1; _delay_ms(10); //Задержка выполнения 10мс } return 0; }
Программа подключает ШИМ к регистру 1 порта B и плавно увеличивает а затем уменьшает ток.
4. Обмен данными по SPI
Вот и добрались до обмена данными между микроконтроллером и внешним миром. Рассмотрим это на связке AVR >> SPI >> MAX7221 >> семисегментные индикаторы.
4.1. SPI
Работу с протоколом обмена SPI на ATmega328 начнем с рассмотрения регистров управления. Всего используется три регистра SPCR, SPSR и SPDR.
Регистр SPCR
бит |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
SPIE |
SPE |
DORD |
MSTR |
CPOL |
CPHA |
SPR1 |
SPR0 |
Бит 7 (SPIE)- разрешает прерывания.
Бит 6 (SPE)- включает аппаратный SPI.
Бит 5 (DORD) — определяет порядок передачи данных (0 — старший бит вперед, 1 — младший бит вперед).
Бит 4 (MSTR) — режим работы master/slave (1/0).
Бит 3 и 2 (CPOL, CPHA) — режим работы SPI.
Mode |
CPOL |
CPHA |
SPI Mode 0 |
0 |
0 |
SPI Mode 1 |
0 |
1 |
SPI Mode 2 |
1 |
0 |
SPI Mode 3 |
1 |
1 |
Бит 1 и 0 (SPR1, SPR0) — частота тактирования SPI.
SPI2X |
SPR1 |
SPR0 |
Частота тактирования |
0 |
0 |
0 |
f/4 |
0 |
0 |
1 |
f/16 |
0 |
1 |
0 |
f/64 |
0 |
1 |
1 |
f/128 |
1 |
0 |
0 |
f/2 |
1 |
0 |
1 |
f/8 |
1 |
1 |
0 |
f/32 |
1 |
1 |
1 |
f/64 |
Регистр SPSR
бит |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
SPIF |
WCOL |
- |
- |
- |
- |
- |
SPI2X |
Бит 7 (SPIF)- флаг прерываний SPI.
Бит 6 (WCOL)- флаг ошибки записи.
Бит 5, 4, 3, 2, 1 — зарезервированы.
Бит 6 (SPI2X)- бит удвоения скорости записи.
Регистр SPDR
бит |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
MSB |
- |
- |
- |
- |
- |
- |
LSB |
Регистр SPDR предназначен для записи/чтения в сдвиговый регистр что приводит к активации передачи данных по SPI.
4.2. Использование SPI.
Рассмотрим передачу данных по SPI на примере вывода информации на семисегментные индикаторы. Для начала создадим схему в Proteus для эмуляции процесса.
Программировать будем вывод данных на 5 семисегментных индикатора через микросхему MAX7221, которая принимает данные по 16 бит по протоколу SPI.
/* Использование семисегментного индикатора с общим катодом и сдвиговым регистром по протоколу SPI */ #include <avr/io.h> //подключаем библиотеки #include <util/delay.h> #define SPI_DDR DDRB //назначаем имя для изменеия направления на порту B #define SPI_PORT PORTB //назначаем имя для используемого порта #define SPI_SS PB2 //назначаем имя выхода SS #define SPI_MOSI PB3 //назначаем имя выхода MOSI #define SPI_MISO PB4 //назначаем имя выхода MISO #define SPI_SCK PB5 //назначаем имя выхода SCK char d[18] ={ //кодирование знаков для семисегментного индикатора 0x7E, //0 0x30, //1 0x6D, //2 0x79, //3 0x33, //4 0x5B, //5 0x5F, //6 0x70, //7 0x7F, //8 0x7B, //9 0x77, //a 0x1F, //b 0x4E, //c 0x3D, //d 0x4F, //e 0x47, //f 0x80, //. 0x00 //пусто }; void spi(char cmd,char data) //Функция передачи двух пакетов по 8 бит по протоколу SPI { SPI_PORT &= ~(1<<SPI_SS); //сбрасываем SS в 0 SPDR = cmd; //отправляем данные по SPI адрес while(!(SPSR&(1<<SPIF))); //ждем окончания отправки SPDR = data; //отправляем данные по SPI данные while(!(SPSR&(1<<SPIF))); //ждем окончания отправки SPI_PORT |= (1<<SPI_SS); //устанавливаем SS в 1 } void clrdig () //Функция очистки индикаторов { spi(0x01,d[17]); spi(0x02,d[17]); spi(0x03,d[17]); spi(0x04,d[17]); spi(0x05,d[17]); } int main() { SPI_DDR = (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS); //настраиваем MOSI, SCK, SS как выходы SPI_PORT |=(1<<SPI_SS); //устанавливаем SS в 1 SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0); //через регистр SPCR настраиваеи аппаратное SPI //Инициализация MAX7221 spi(0x0C,0x00); //Отключение индикаторов spi(0x09,0x00); //Отключение декодирования spi(0x0A,0x0A); //Интенсивность свечения индикаторов spi(0x0B,0x04); //Количество индикаторов начиная с 0 spi(0x0F,0x00); //Отключение теста индикаторов spi(0x0C,0x01); //Включение индикаторов clrdig(); //Очистка всех индикаторов int i=0; //Переменная перебора выводимых символов int j=1; //Переменная осчета номера индикатора while(1){ //Бесконечный цикл spi(j,d[i]); //Вывод на индикатор j символа i _delay_ms(1000); //Задержка выполнения 1000мс i++; if(i>17)i=0; j++; if(j>5)j=1; } return 0; }
Перед использованием MAX7221 не забываем провести инициализацию.
Передача по SPI проходит по следующей схеме:
-
Выставляем SS в 0;
-
Заносим данные в регистр SPDR данные;
-
Каждый бит по очереди передается по тактам SCK;
-
Завершаем передачу установкой SS в 1.
Прикрепленные файлы:
- proteus_pwm.zip (14 Кб)
- CB_pwm.zip (6 Кб)
- spi_P.zip (16 Кб)
- s_sg_katod.zip (31 Кб)
Комментарии (2) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
[Автор]