STM Урок 30. HAL. DAC. Sinus. DMA

Урок 30

DAC. Sinus. DMA

 

Сегодня мы попробуем также посредством технологии DMA создать колебания синусоидальной формы также из данных, заранее подготовленных в массиве в виду того, что синусоидальные колебания вообще не предусмотрены аппаратно в МК. Также по многочисленным просьбам в различных уроках мы попытаемся измерить частоту колебаний и период в тактах полного синусоидального колебания. Для вывода данных на экран также используем LCD 20х4, который мы подключим через переходник I2C.

Проект создаём из проекта DAC_TRIANGLE2. Назовем его DAC_SIN. Запустим проект в Cube и включим там I2C1

 

image00

 

В 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 */

 

Соберем код, прошьем контроллер и посмотрим результат.

Попробуем поиграться с таймером

Поставим сначала такие данные

 

image01

 

Уменьшим период вдвое до 50

Пока можно всё это проделать в Keil.

Соберем, прошьем и посмотрим.

Попробуем уменьшить ещё вдвое до 25

Соберем, прошьем и посмотрим.

Убавим до 12

Соберем, прошьем и посмотрим.

 

 

 

Исходный код

 

 

Отладочную плату можно приобрести здесь STM32F4-DISCOVERY

 

 

Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)

STM HAL. DAC. Sinus. DMA

 

Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)

STM HAL. DAC. Sinus. DMA

6 комментариев к “STM Урок 30. HAL. DAC. Sinus. DMA

  1. Добрый день! А как можно при помощи того же дма быстро вкл.выкл. генерацию на выходе ЦАП?
    Я так понимаю что нужно только раз запускать дма командой? :
    HAL_DAC_Start_DMA (&hdac, DAC_CHANNEL_1,(uint32_t*)buf_sin,60,DAC_ALIGN_12B_R);

    И потом раз останавливать командой:
    HAL_DAC_Stop_DMA(***);

    • Как это правильно сделать?

      И ещё вопросик:
      Как регулировать амплитуду того же синуса на выходе? Математически , введя буфер в ОЗУ таким же размером как буфер синуса и пересчитывать синусоиду потом динамически в цикле?

  2. Подскажите, пожалуйста, почему значения счётчика получаются больше на 53-54 такта (6053, 3053, 1553,…), чем казалось бы должно быть: 6000 = 100*60, 3000 = 50*60 и т.д.
    Где происходит добавление тактов?

  3. Интересно, если в строке вывода времени периода всё умножить на 2, а в строке вывода частоты разделить всё на 2, то это уже будет больше соответствовать действительности. Сигнал смотрел на осциллографе.

  4. Здравствуйте, если бы Вы замерили данный синусоидальный сигнал на обычном осциллографе, то увидели бы что частота синусоиды не 26,7 кГц, а 13,33кГц. Реализованный вами счетчик clk_counter почему-то считает такты на частоте HCKL/2, при условии если у вас тоже HCLK=84МГц.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*