Урок 30
DAC. Sinus. DMA
Сегодня мы попробуем также посредством технологии DMA создать колебания синусоидальной формы также из данных, заранее подготовленных в массиве в виду того, что синусоидальные колебания вообще не предусмотрены аппаратно в МК. Также по многочисленным просьбам в различных уроках мы попытаемся измерить частоту колебаний и период в тактах полного синусоидального колебания. Для вывода данных на экран также используем LCD 20х4, который мы подключим через переходник I2C.
Проект создаём из проекта DAC_TRIANGLE2. Назовем его DAC_SIN. Запустим проект в Cube и включим там I2C1
В Configuration оставим пока всё как было.
Сгенерируем, запустим и соберём проект. Настроим программатор. Скопируем файлы lcd.c и lcd.h из проекта I2CLCD80. Подключим файл lcd.c в проект, а также файл lcd.h подключим в файле main.h
#include «stm32f4xx.h»
#include «lcd.h»
Заменим массив uint16_t buf_tr[64] на вот такой
uint16_t buf_sin[60]={
11,45,100,177,274,391,526,678,
844,1024,1215,1415,1622,1834,2048,2262,
2474,2681,2881,3072,3252,3418,3570,3705,
3822,3919,3996,4051,4085,4095,4085,4051,
3996,3919,3822,3705,3570,3418,3252,3072,
2881,2681,2474,2262,2048,1834,1622,1415,
1215,1024,844,678,526,391,274,177,
100,45,11,0
};
Соответственно здесь также произведем некоторые изменения
HAL_TIM_Base_Start(&htim6);
HAL_DAC_Start_DMA (&hdac, DAC_CHANNEL_1,(uint32_t*)buf_sin,60,DAC_ALIGN_12B_R);
/* USER CODE END 2 */
Также нам потребуется счётчик и строковая переменная
/* Private variables ———————————————————*/
uint32_t clk_counter=0;
char str[20];
uint16_t buf_sin[60]={
Также для организации счёта тактов МК нам потребуется определенный код в main.c тут
#include «main.h»
#define DWT_CYCCNT *(volatile unsigned long *)0xE0001004
#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
/* USER CODE END Includes */
и тут
/* USER CODE BEGIN 2 */
uint32_t frq = HAL_RCC_GetHCLKFreq();
SCB_DEMCR |= 0x01000000;
DWT_CONTROL|= 1;
DWT_CYCCNT = 0;
HAL_TIM_Base_Start(&htim6);
Также внесем определенные изменения в файл stm32f4xx_it.c, практически повторив там всё из файла main.c за некоторым исключением (extern)
/* USER CODE BEGIN 0 */
#define DWT_CYCCNT *(volatile unsigned long *)0xE0001004
#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
extern uint32_t clk_counter;
/* USER CODE END 0 */
В обработчике прерывания от DMA в этом же файле мы сосчитаем такты
void DMA1_Stream5_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Stream5_IRQn 0 */
clk_counter=DWT_CYCCNT;
DWT_CYCCNT=0;
/* USER CODE END DMA1_Stream5_IRQn 0 */
Инициализируем дисплей в файле main.c
HAL_DAC_Start_DMA (&hdac, DAC_CHANNEL_1,(uint32_t*)buf_sin,60,DAC_ALIGN_12B_R);
LCD_ini();
LCD_Clear();
А в бесконечном цикле отобразим то, что мы сосчитали
while (1)
{
sprintf((char*)str,»%u»,clk_counter);//количество тактов на период
LCD_SetPos(0, 0);
LCD_String(str);
sprintf((char*)str,»%u»,(clk_counter*1000)/(frq/1000));//время периода в микросекундах
LCD_SetPos(0, 1);
LCD_String(str);
sprintf((char*)str,»%u»,frq/clk_counter);//частота в герцах
LCD_SetPos(0, 2);
LCD_String(str);
HAL_Delay(1000);
/* USER CODE END WHILE */
Соберем код, прошьем контроллер и посмотрим результат.
Попробуем поиграться с таймером
Поставим сначала такие данные
Уменьшим период вдвое до 50
Пока можно всё это проделать в Keil.
Соберем, прошьем и посмотрим.
Попробуем уменьшить ещё вдвое до 25
Соберем, прошьем и посмотрим.
Убавим до 12
Соберем, прошьем и посмотрим.
Предыдущий урок Программирование МК STM32 Следующий урок
Купить отладочную плату можно здесь STM32F4-DISCOVERY
Смотреть ВИДЕОУРОК
Добрый день! А как можно при помощи того же дма быстро вкл.выкл. генерацию на выходе ЦАП?
Я так понимаю что нужно только раз запускать дма командой? :
HAL_DAC_Start_DMA (&hdac, DAC_CHANNEL_1,(uint32_t*)buf_sin,60,DAC_ALIGN_12B_R);
И потом раз останавливать командой:
HAL_DAC_Stop_DMA(***);
Как это правильно сделать?
И ещё вопросик:
Как регулировать амплитуду того же синуса на выходе? Математически , введя буфер в ОЗУ таким же размером как буфер синуса и пересчитывать синусоиду потом динамически в цикле?
Подскажите, пожалуйста, почему значения счётчика получаются больше на 53-54 такта (6053, 3053, 1553,…), чем казалось бы должно быть: 6000 = 100*60, 3000 = 50*60 и т.д.
Где происходит добавление тактов?
Интересно, если в строке вывода времени периода всё умножить на 2, а в строке вывода частоты разделить всё на 2, то это уже будет больше соответствовать действительности. Сигнал смотрел на осциллографе.
Добрый день! А возможно вообще переменный выход организовать с отрицательной полуволной?
Здравствуйте, если бы Вы замерили данный синусоидальный сигнал на обычном осциллографе, то увидели бы что частота синусоиды не 26,7 кГц, а 13,33кГц. Реализованный вами счетчик clk_counter почему-то считает такты на частоте HCKL/2, при условии если у вас тоже HCLK=84МГц.