Апр 272012
 

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

В проекте, описанном в предыдущей статье, тактовая частота микроконтроллера формировалась от внутреннего генератора MSI (настройки по умолчанию) и была равна 2,097 МГц. Теперь попробуем использовать в качестве источника тактирования внутренний генератор HSI с частотой 16 Мгц.

Для смены источника допишем в процедуру инициализации следующий код:

//Функция ининиализации периферии 
void InitPeriph()
 {
  RCC->CR |= RCC_CR_HSION; //Включаем тактовый генератор HSI
  while(!(RCC_CR_HSION)); //Ждем его стабилизации
  RCC->CFGR |= RCC_CFGR_SW_HSI; //Выбираем источником тактовой частоты SYSCLK генератор HSI
  RCC->CR &= ~RCC_CR_MSION; //Отключаем генератор MSI. 

 //Настройка порта А 
... 
...

Генератор MSI можно и не отключать, конечно. Но если работаем от батарейного питания и боремся за каждый микроампер, лучше взять за правило — лишних потребителей сразу отключать. Хотя, конечно, “кушает” тактовый генератор очень мало. Запустим программу и сравним результат.

Выходная осциллограмма при тактовом генераторе MSI. Частота выходного сигнала около 3 кГц:

DAC_msi

На следующей осциллограмме выходной сигнал при тактировании от HSI (16 МГц). Выходная частота уже около 23 кГц:

dac_hsi

Обратите внимание, на осциллограммах разная временная шкала! На нижней она уменьшена в 10 раз.

Теперь попробуем еще немного увеличить частоту выходного сигнала. Отключим внешний запуск преобразования. Как в таком случае будет происходить запуск? Автоматически. Как только мы запишем данные в любой из промежуточных регистров хранения DAC_DHRx, сразу же произойдет пересылка данных в выходной регистр DORx и начнется преобразование! И задержка между процедурой записи в DAC_DHRx и началом преобразования будет равна всего одному периоду тактовой частоты! К слову сказать, такая же задержка будет при “ручном” (программном) запуске преобразования. В других случаях, то есть при запуске от таймеров или с внешнего входа EXTI_9, задержка составит уже 3 периода тактовой частоты. Итак, делаем следующее. Для начала отключим разрешение внешнего запуска и выбор его источника, закомментировав строки инициализации:

 //DAC->CR |= DAC_CR_TEN2; //Разрешаем запуск преобразования в канале 2 DAC 
//DAC->CR |= DAC_CR_TSEL2; //Выбираем источник запуска - программный


Затем в цикле for() основной функции main() отключим и сам программный запуск преобразования, закомментировав строку:

//DAC->SWTRIGR |= DAC_SWTRIGR_SWTRIG2; //Запуск преобразования

В итоге, всего на одну последнюю строку укоротили цикл. Посмотрим, что получилось:

dac_hsi_without_trigger

Неплохо! Сравнивая две последние осциллограммы, видим, что период сигнала сократился с 44мкс до 30мкс приблизительно.

Теперь сформируем треугольный сигнал. Режимы формирования “белого шума” или треугольного сигнала выбираются в разрядах WAVE2[1:0] управляющего регистра DAC_CR:

  • 00: генерация запрещена
  • 01: Разрешена генерация шума
  • 1x: Разрешена генерация треугольного сигнала

Примечание: используется, если бит TEN2=1 (разрешен внешний запуск в канале 2)

В разрядах MAMP2[3:0] того же регистра выбирается амплитуда сигнала в режиме формирования “пилы”. Здесь просто задается число, до которого будет считать счетчик, формируя сигнал. Ниже код программы с комментариями:

#include "stm32l1xx.h" 

//Объявление функции инициализации периферии 
void InitPeriph(void);

 int main()
 { 
  InitPeriph(); //Вызываем функцию инициализации периферии
  while(1) //Бесконечный цикл
  { 
   DAC->SWTRIGR |= DAC_SWTRIGR_SWTRIG2; //Запуск преобразования
  }
 } 

//Функция ининиализации периферии 
void InitPeriph()
 {
  RCC->CR |= RCC_CR_HSION; //Включаем тактовый генератор HSI
  while(!(RCC_CR_HSION)); //Ждем его стабилизации
  RCC->CFGR |= RCC_CFGR_SW_HSI; //Выбираем источником тактовой частоты SYSCLK генератор HSI
  RCC->CR &= ~RCC_CR_MSION; //Отключаем генератор MSI.

  //Настройка порта А
  RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //Включаем тактирование порта А
  GPIOA->MODER |= GPIO_MODER_MODER5; //Аналоговый вход/выход линии PA5
  GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5; //Отключаем подтягивающие резисторы

  //Настройка цифро-аналогового преобразователя
  RCC->APB1ENR |= RCC_APB1ENR_DACEN; //Включаем тактирование DAC
  DAC->CR |= DAC_CR_EN2; //Включаем канал 2 DAC
  //DAC->CR |= DAC_CR_BOFF2; //Использование выходного буфера
  DAC->CR |= DAC_CR_TEN2; //Разрешаем запуск преобразования в канале 2 DAC
  DAC->CR |= DAC_CR_TSEL2; //Выбираем источник запуска - программный
  DAC->CR |= DAC_CR_WAVE2; //Генерация "пилы"
  DAC->CR |= DAC_CR_MAMP2; //Амплитуда "пилы" - 4095 отсчетов
  //DAC->CR |= DAC_CR_MAMP2_3 | DAC_CR_MAMP2_1; //Амплитуда "пилы" - 2047 отсчетов
  //DAC->CR |= DAC_CR_MAMP2_3; //Амплитуда "пилы" - 511 отсчетов
  //DAC->CR |= DAC_CR_MAMP2_2 | DAC_CR_MAMP2_1| DAC_CR_MAMP2_0; //Амплитуда "пилы" - 255 отсчетов
 }


Как видим, в основной функции main() остался только бесконечный цикл с программным запуском преобразования. Настройки порта не изменились. В функцию инициализации DAC добавились команды выбора режима формирования треугольного сигнала и выбор его амплитуды. Строки с выбором амплитуды сигнала DAC->CR |= DAC_CR_MAMP… закомментированы все, кроме одной, нужной в данный момент. Можно скомпилировать и запустить проект. Далее, выбирая поочередно нужную амплитуду, посмотрим, что получается на выходе:

DAC->CR |= DAC_CR_MAMP2; //Амплитуда "пилы" - 4095 отсчетов


Triangle_4095

DAC->CR |= DAC_CR_MAMP2_3 | DAC_CR_MAMP2_1; //Амплитуда "пилы" - 2047 отсчетов

Triangle_2047

Как видим, вместе с уменьшением амплитуды увеличивается частота сигнала. Этого и следовало ожидать – счет теперь идет до меньшего значения.  Пойдем дальше:

DAC->CR |= DAC_CR_MAMP2_3; //Амплитуда "пилы" - 511 отсчетов

Triangle_511

При задании слишком малых уровней, сигнал у меня потонул в шумах. Использовать короткую пружинку на щупе осциллографа для контакта с выводом GND не получилось – слишком большое расстояние между ним и выводом PA5. А более длинный “земляной” проводок щупа уже вовсю ловил помехи. Цифровой осциллограф с полосой пропускания 100 МГц, к наводкам он очень чувствителен. Минимально различимый сигнал я получил при уровне сигнала эквивалентном 255 отсчетам.

DAC->CR |= DAC_CR_MAMP2_2 | DAC_CR_MAMP2_1| DAC_CR_MAMP2_0; //Амплитуда "пилы" - 255 отсчетов

Triangle_255_buffer_on

Вот тут то хорошо видно, что уровень сигнала до нуля не доходит! Даже на сигналах с большой амплитудой это было заметно, если присмотреться, а теперь четко видно. Документация сообщает, что по умолчанию на выходе включен буфер с низким выходным сопротивлением. Это для того, чтобы не задействовать внешний усилитель. Отключается буфер установкой единицы в разряд BOFFx (x – номер канала) регистра DAC_CR. Раскомментируем строку

DAC->CR |= DAC_CR_BOFF2; //Использование выходного буфера

и посмотрим на результат

Triangle_255_buffer_off

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

На очереди использование DMA в DAC, а может и еще что-то. Ждите продолжения темы…

Другие статьи: