
- •Отчет по выполнению лабораторных работ
- •2. Использование таймеров для генерации временных интервалов и тональных сигналов
- •3. Характеристики аналого-цифрового преобразователя
- •4. Генерация сигнала методом прямого цифрового синтеза. Быстрое преобразование Фурье (бпф)
- •4.1. Проверка работы генератора гармонического сигнала и аналого-цифрового преобразования.
- •4.2. Исследование особенностей бпф.
- •4.3. Использование оконной функции.
4. Генерация сигнала методом прямого цифрового синтеза. Быстрое преобразование Фурье (бпф)
4.1. Проверка работы генератора гармонического сигнала и аналого-цифрового преобразования.
Частота дискретизации канала АЦП-ЦАП Fs= 32000 Гц
Частота 4 кГц
Вход АЦП (выход генератора)
Выход ЦАП Спектральная характеристика
Частота 16 кГц
Вход АЦП (выход генератора)
Выход ЦАП Спектральная характеристика
Частота 24 кГц
Вход АЦП (выход генератора)
Выход ЦАП Спектральная характеристика
4.2. Исследование особенностей бпф.
Полный диапазон частот: ...
"Вырезанный" диапазон: ...
Форма выходного сигнала в нескорректированном диапазоне частот.
Частота ... Гц
Форма выходного сигнала внутри скорректированного диапазона частот.
Частота ... Гц
Форма выходного сигнала на границе диапазонов.
Частота ... Гц
Причины "артефактов":
4.3. Использование оконной функции.
Частота сигнала: Частота сигнала:
Спектрограмма без оконной функции Спектрограмма без оконной функции
Спектрограмма с оконной функцией Спектрограмма с оконной функцией
4.4. Измерение времени обработки.
Вид обработки |
Время ввода-вывода, мкс |
Время обработки блока, мкс |
Время ввода-вывода и обработки отсчета, мкс |
FFT+IFFT
|
1.91 |
2089.05 |
|
FFT+IFFT+ частотная коррекция |
1.90 |
2103.05 |
|
FFT+IFFT+ оконная функция |
1.90 |
2555.30 |
|
Расчет максимального коэффициента загрузки процессора:
Текст программы
Исходный модуль D:\ARM\Work\DspLab_fft\main.c
/******************************************************************************
*
* УЧЕБНЫЙ ПРОЕКТ
*
* Генерация сигнала методом прямого цифрового синтеза.
* Прямое, обратное быстрое преобразование Фурье (БПФ).
* Визуализация спектра сигнала. Оконная функция.
*
* Задействовано два переключаемых буфера отсчетов.
* Демонстрируется возникновение переходных помех на стыке временных отсчетов
* после прямого БПФ, коррекции частотных составляющих и обратного БПФ.
*
* Для обработки используется библиотека CMSIS DSP Library.
*
* Copyright (C) 2013 МГТУ МИРЭА
*
* Версия: 1.2
*
******************************************************************************/
/*
ОРГАНЫ УПРАВЛЕНИЯ
Джойстик "вверх/вниз" - увеличение/уменьшение частоты генератора синусоидального сигнала
Джойстик "влево" - переключение между типами входного сигнала: синусоидальный / шум / нет сигнала
Джойстик "вправо" - переключение режимов обработки: без обработки / коррекция отсчетов / оконная функция
Джойстик "выбор" - переключение режимов регистрации: измерение коэф.передачи / нет измерений / спектр
Кнопка TAMPER - вывод меток времени обработки
Кнопка WAKEUP - выход из программы
*/
// Заголовочные файлы
#include "stm32_p407.h" //Файл конфигурации отладочной платы STM32-P407
#include "adcdac.h" //Процедуры работы с АЦП, ЦАП, кодеком
#include "gauge.h" //Процедуры управления и измерения
#include "arm_math.h" //Определения и функции библиотеки CMSIS DSP Library
#include "mathfunc.h" //Прототипы вспомогательных математических функций
//---------------------------------------------------------------------------
// ОБЪЯВЛЕНИЯ ДАННЫХ
#define fftLen 1024 //Длина - число отсчетов - преобразования Фурье
#define BlockSize (fftLen*2) //Размер буфера для отсчетов с учетом мнимых составляющих
float32_t DataIn0[BlockSize]; //Буферы для входных отсчетов
float32_t DataIn1[BlockSize];
float32_t DataOut0[BlockSize]; //Буферы для выходных отсчетов
float32_t DataOut1[BlockSize];
float32_t *DataIn, *DataOut; //Текущие указатели на буферы
arm_cfft_radix4_instance_f32 S; //Структуры для обработки данных
arm_cfft_radix4_instance_f32 iS;
int32_t DataIndex; //Индекс текущего входного/выходного отсчета
int32_t TransferBuf; //Номер (0 или 1) буфера для текущего ввода-вывода
int32_t ProcBuf; //Номер (0 или 1) обрабатываемого (обработанного) буфера
int16_t DataChannel1, DataChannel2; //Входные и выходные отсчеты в формате 1.15 с фиксированной точкой
int16_t DataADC; //Прямой отсчет с АЦП для системы калибровки
int32_t AmplOffset = 0; //Смещение нулевого уровня сигнала с АЦП
int32_t GagingMode = 0; //Режим регистрации:
// 0 - измерение коэффициента передачи
// 1 - нет измерений
// 2 - визуализация спектра
int32_t ProcessMode = 0; //Дополнительный режим обработки (помимо БПФ):
// 0 - нет
// 1 - коррекция частотных составляющих
// 2 - оконная функция
int32_t HardwareMode = 1; //Конфигурация системы:
// 0: цифровой генератор -> ЦАП--(аналоговый сигнал)--> АЦП -> обработка
// 1: цифровой генератор -> обработка
//---------------------------------------------------------------------------
// ГЛАВНАЯ ФУНКЦИЯ
int main()
{
int32_t j;
float K;
//Счетчик для реализации периода изменения тестовой индикации
volatile uint32_t i = 0;
//Инициализация структур параметров для цифровой обработки сигнала
arm_cfft_radix4_init_f32 (&S, fftLen, 0, 1); //Прямое преобразование
arm_cfft_radix4_init_f32(&iS, fftLen, 1, 1); //Обратное преобразование
//Задание 4-х уровней групповых приоритетов и 4-х уровней приоритетов в каждой группе
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//Инициализация тестовых индикаторов
STM_LEDInit(LED1);
STM_LEDInit(LED2);
//Инициализация кнопок
STM_PBInit(BUTTON_TAMPER, BUTTON_MODE_GPIO);
STM_PBInit(BUTTON_WAKEUP, BUTTON_MODE_GPIO);
//Инициализация кодека (ЦАП выходных отсчетов сигнала)
SoundCodecConfig(32000); //Аргумент - частота дискретизации, Гц
SoundCodecInterruptConfig(ENABLE);
//Инициализация АЦП
ADCConfig();
//Инициализация генератора входного сигнала
SignalGenConfig();
//Инициализация графического интерфейса, джойстика, системы измерений
GgInterfaceInit();
//ОСНОВНОЙ ЦИКЛ
while (1)
{
if (TransferBuf != ProcBuf)//Ожидание заполнения буфера
{
TimeMarker3(); //Метка времени выполнения № 3 (НАЧАЛО ОБРАБОТКИ)
DataIn = ProcBuf ? DataIn1 : DataIn0; //Установка указателей на обрабатываемые буферы
DataOut = ProcBuf ? DataOut1 : DataOut0;
// ===== Н а ч а л о о б р а б о т к и =====
STM_LEDOn(LED2);
if (ProcessMode == 2)
for (j = 0; j < fftLen/2; j++) //Взвешивание посредством оконной функции Хемминга
{ K = 0.54f - 0.46f * cosf(2*3.14159f*j/(fftLen-1));
DataIn[j*2] *= K;
DataIn[(fftLen-1-j)*2] *= K;
}
arm_cfft_radix4_f32(&S, DataIn); //ПРЯМОЕ БПФ
for (j = 0; j < BlockSize; j++) //Пересылка частотных отсчетов (без обработки)
DataOut[j] = DataIn[j];
if (ProcessMode == 1)
{ //Тестовая обработка: уменьшение в K раз амплитуд отсчетов
K = 0.1f; // с индексами в заданном диапазоне и симметричных им.
for (j = 64; j <= 128; j++) // Для дискретизации 32 кГц и 1024 отсчетах индексы 64..128
{ // примерно соответствуют частотам сигнала 2..4 кГц.
DataOut[j*2] *= K; //Действительный частотный отсчет
DataOut[j*2+1] *= K; //Мнимый частотный отсчет
DataOut[(fftLen-j)*2] *= K; //Действительный частотный отсчет в отрицательной области
DataOut[(fftLen-j)*2+1] *= K; //Мнимый частотный отсчет в отрицательной области
}
}
SpectrVisualization(DataOut, fftLen); //Визуализация спектра
arm_cfft_radix4_f32(&iS, DataOut); //ОБРАТНОЕ БПФ
STM_LEDOff(LED2);
// ===== К о н е ц о б р а б о т к и =====
ProcBuf ^= 1; //Переключение на другой буфер
TimeMarker4(); //Метка времени выполнения № 4 (КОНЕЦ ОБРАБОТКИ)
}
GgControl(); //Управление частотой и амплитудой генератора сигнала,
// вывод результатов измерений
if (i++ == 0x800) STM_LEDOff(LED1); //Тестовое управление индикатором
if (i == 0x50000) STM_LEDOn(LED1), i = 0;
if (STM_PBGetState(BUTTON_WAKEUP)) break; //Выход из основного цикла, если нажата WAKEUP
}
//ОКОНЧАНИЕ ОСНОВНОГО ЦИКЛА
//Сброс процессора - завершение выполнения данной программы, запуск начального загрузчика
NVIC_SystemReset();
while (1) {}
}
//---------------------------------------------------------------------------
// ОБСЛУЖИВАНИЕ ПРЕРЫВАНИЯ С ЧАСТОТОЙ ДИСКРЕТИЗАЦИИ
// Данная подпрограмма вызывается из обработчика прерывания ..._IRQHandler(),
// реализованного в adcdac.c
// Частота дискретизации формируется интерфейсным модулем процессора SPI/I2S,
// посредством которого по интерфейсу I2S отсчеты сигнала выводятся на внешний звуковой кодек.
// Этот модуль также генерирует прерывания с частотой дискретизации. В обработчике
// прерывания, размещенном здесь, производятся следующие операции:
// - считываются отсчеты входного сигнала с АЦП или цифрового входа;
// - АЦП запускается на следующий цикл преобразования;
// - входные отсчеты размещаются в одном из входных буферов;
// - из выходного буфера с тем же номером извлекаются обработанные отсчеты и передаются кодеку;
// - проверяется заполнение текущего буфера и при необходимости производится переключение на другой.
void Sample_Handler(void)
{
extern int16_t GeneratorSamples; //Цифровой выход генератора сигналов (в доп. коде)
// параметр объявлен в adcdac.c
if (HardwareMode == 0)
{ //Получение данных с АЦП, преобразование смещенного кода в дополнительный,
// коррекция нулевого уровня
DataADC = ADC_GetConversionValue(ADC3) ^ 0x8000;
DataChannel2 = DataChannel1 = DataADC - AmplOffset;
}
//Получение цифрового отсчета входного сигнала (минуя АЦП)
else DataChannel2 = DataChannel1 = GeneratorSamples;
//Перезапуск АЦП
ADC_SoftwareStartConv(ADC3);
//Сохранение входных отсчетов в текущем буфере, чтение выходных отсчетов
if (TransferBuf)
{ DataIn1[DataIndex] = q15_to_float(DataChannel1); DataIn1[DataIndex+1] = 0;
DataChannel2 = DataChannel1 = float_to_q15(DataOut1[DataIndex]); DataIndex += 2;
}
else
{ DataIn0[DataIndex] = q15_to_float(DataChannel1); DataIn0[DataIndex+1] = 0;
DataChannel2 = DataChannel1 = float_to_q15(DataOut0[DataIndex]); DataIndex += 2;
}
//Проверка достижения конца буфера, если да, переключение на другой буфер
if (DataIndex >= BlockSize) DataIndex = 0, TransferBuf ^= 1;
//Обработанные значения - в DataChannel1, DataChannel2
}
Фрагменты исходного модуля D:\ARM\Work\DspLab_fft\adcdac.c
/**
******************************************************************************
* Файл adcdac.c
* Copyright (C) 2013 МГТУ МИРЭА
* Версия 1.2
* Описание: Функции инициализации и обслуживания периферийных устройств
* (АЦП, ЦАП, кодека, таймеров), генерации гармонического сигнала
* для использования в проектах цифровой обработки сигналов.
******************************************************************************
*/
#include "adcdac.h"
#include "arm_math.h"
#include "gauge.h"
#include <stdlib.h> //Для функции rand()
// Объявления данных
extern const q15_t sinTableQ15[]; //Массив отсчетов функции sin (определен в arm_sin_q15.c)
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //Структура конфигурации базового таймера
TIM_OCInitTypeDef TIM_OCInitStructure; //Структура конфигурации таймера с ШИМ
uint16_t DACData1; //Данные для ЦАП в смещенном коде
int16_t GeneratorSamples; //Цифровой выход генератора сигналов (в доп. коде)
uint32_t GenReference = 192000; //Опорная частота DDS, Гц
uint32_t GenFrequencyMax = 24000; //Максимальная выходная частота
uint32_t GenFrequencyMin = 20; //Минимальная выходная частота
uint32_t GenFrequency = 1000; //Текущая частота выходного сигнала генератора, Гц
uint32_t AccumulatorPhase; //Аккумулятор DDS
uint32_t DeltaPhase; //Дискрет изменения фазы DDS
uint16_t GenAmplitude = 1; //Признак: наличие/отсутствие генерации
uint16_t GenNoise = 0; //Признак генерации шумового сигнала
//---------------------------------------------------------------------------
// ИНИЦИАЛИЗАЦИЯ ГЕНЕРАТОРА СИГНАЛОВ
void SignalGenConfig(void)
{
STM_LEDInit(LED3); STM_LEDOff(LED3);
STM_LEDInit(LED4); STM_LEDOff(LED4);
//Инициализация таймера TIM4, как источника тактирования ЦАП
TimerConfig();
//Инициализация ЦАП
DACConfig();
//Инициализация параметров генератора
AccumulatorPhase = 0;
DeltaPhase = UINT32_MAX / GenReference * GenFrequency;
//Разрешение прерываний от таймера
TimerInterruptConfig(ENABLE);
}
//---------------------------------------------------------------------------
// ИЗМЕНЕНИЕ ЧАСТОТЫ ГЕНЕРАТОРА
// Входной параметр: dir = -1 (вниз), 0 - нет, 1 (вверх)
void GenFrequencyChange(int32_t dir)
{
uint32_t dfreq;
if (dir == 0) return;
dfreq = (dir < 0) ? GenFrequency - 1 : GenFrequency;
if (dfreq >= 5000) dfreq = 50;
else if (dfreq >= 2000) dfreq = 20;
else if (dfreq >= 1000) dfreq = 10;
else if (dfreq >= 500) dfreq = 5;
else if (dfreq >= 200) dfreq = 2;
else dfreq = 1;
if (dir > 0)
if (GenFrequency + dfreq > GenFrequencyMax) GenFrequency = GenFrequencyMax;
else GenFrequency += dfreq;
else
if (GenFrequency < GenFrequencyMin + dfreq) GenFrequency = GenFrequencyMin;
else GenFrequency -= dfreq;
DeltaPhase = UINT32_MAX / GenReference * GenFrequency;
}
//---------------------------------------------------------------------------
// ИНИЦИАЛИЗАЦИЯ ТАЙМЕРА ДЛЯ ОПОРНОЙ ЧАСТОТЫ ГЕНЕРАТОРА СИГНАЛОВ (DDS)
/* Таймер 4 подключен к шине APB1, частота тактирования которой в 4 раза ниже системной:
168 МГц / 4 = 42 МГц. Так как коэффициент деления частоты для данной шины не 1,
то на таймеры этой шины поступает удвоенная тактовая частота, т.е. 84 МГц.
Например, для частоты дискретизации 192 кГц:
- предделитель не используется (коэф. деления = 1)
- число, загружаемое в счетчик: TIM_Period = 84 МГц / 192 кГц - 1
Контрольный выход таймера: канал CH4 выведен на разряд порта PB9.
На выходе CH4 используется формирователь с ШИМ, коэффициент заполнения длительности импульса
(duty cycle) = 25%, загружаемое число для этого
TIM_CCR = TIM_Period * duty cycle[%] / 100[%] = TIM_Period / 4
Прерывания от таймера конфигурируются по событию его автоперезагрузки.
*/
void TimerConfig(void)
{
// ... аналогично предыдущим проектам
}
//---------------------------------------------------------------------------
// ИНИЦИАЛИЗАЦИЯ АЦП
void ADCConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //Структура конфигурации портов общего назначения
ADC_CommonInitTypeDef ADC_CommonInitStructure; //Структура общей конфигурации АЦП
ADC_InitTypeDef ADC_InitStructure; //Структура конфигурации АЦП
//Задание общей конфигурации по умолчанию
ADC_CommonStructInit(&ADC_CommonInitStructure);
ADC_CommonInit(&ADC_CommonInitStructure);
//Конфигурирование каналов: ADC3_IN8 (разряд порта PF10)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//Разрешение тактирования порта
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//Номер разряда (маска)
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//Альтернативная функция: аналоговый вход
GPIO_Init(GPIOF, &GPIO_InitStructure);//Функция конфигурирования
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3,ENABLE);//Разрешение тактирования АЦП
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //Разрядность 12 бит
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Режим многоканального сканирования
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Режим непрерывного преобразования
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//Фронт запуска
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4; //Запуск от TIM4_CH4
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; //Выравнивание данных влево
ADC_InitStructure.ADC_NbrOfConversion = 1; //Преобразование одного канала
ADC_Init(ADC3, &ADC_InitStructure); //Функция конфигурирования
ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 1, ADC_SampleTime_56Cycles); //Задание номера канала, числа групп, времени преобразования
ADC_DMACmd(ADC3,DISABLE);//Запрет прямого доступа к памяти
ADC_Cmd(ADC3,ENABLE);//Разрешение работы
}
//---------------------------------------------------------------------------
// ИНИЦИАЛИЗАЦИЯ ЦАП
// Используется DAC1 с выходом на разряд порта PA4
void DACConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //Структура конфигурации портов общего назначения
DAC_InitTypeDef DAC_InitStructure; //Структура конфигурации ЦАП
//Разрешение тактирования порта PA, разряды которого используются как выходы ЦАП
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//Разрешение тактирования ЦАП
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
//Конфигурирование разряда PA.4 как аналогового
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //Номер разряда (маска) для DAC1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //Альтернативная функция: аналоговый вход-выход
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //Без подтягивающих резисторов
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Конфигурирование режимов работы ЦАП
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T4_TRGO; //Запуск: от триггерного выхода TRGO таймера 4
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //Встроенный генератор: не используется
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = 0; //Маска/амплитуда для встроенного генератора (не исп.)
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //Разрешение выходного буфера повышенной мощности
DAC_Init(DAC_Channel_1, &DAC_InitStructure); //Функция конфигурирования
//Общее разрешение работы ЦАП, загрузка начального значения данных ЦАП (код - смещенный)
DAC_Cmd(DAC_Channel_1, ENABLE);
DAC_SetChannel1Data(DAC_Align_12b_L, 0x0000);
}
//---------------------------------------------------------------------------
// ИНИЦИАЛИЗАЦИЯ ЗВУКОВОГО КОДЕКА
void SoundCodecConfig(uint32_t AudioFreq)
{
//Структуры конфигурации
GPIO_InitTypeDef GPIO_InitStructure;
I2S_InitTypeDef I2S_InitStructure;
RCC_PLLI2SConfig(213,2); //Конфигурирование синтезатора ФАПЧ для интерфейса I2S (PLL I2S)
RCC_PLLI2SCmd(ENABLE); //Разрешение работы PLL I2S
while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY)); //Ожидание готовности PLL I2S
RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S); //Задание PLL I2S как источника тактирования I2S
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); //Разрешение тактирования модуля SPI3/I2S3 по шине APB1
SPI_I2S_DeInit(SPI3); //Деинициализация (сброс) интерфейса SPI3/I2S3
//Конфигурирование интерфейса I2S3
I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx; //Режим: _SlaveTx _SlaveRx _MasterTx _MasterRx
I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips; //Стандарт: _Phillips _MSB _LSB _PCMShort _PCMLong
I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b; //Формат: _16b _16bextended _24b _32b
I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable; //Разрешение выдачи на выход тактового сигнала
I2S_InitStructure.I2S_AudioFreq = AudioFreq; //Частота дискретизации: _8k ... _192k
I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low; //Исходный уровень тактового сигнала: _Low _High
I2S_Init(SPI3, &I2S_InitStructure); //Функция конфигурирования
//Запрет прерывания I2S3 TXE
SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, DISABLE);
//Конфигурирование выводов процессора
//Разрешение тактирования портов A, B, C
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
//Конфигурирование PA15 (внешний сигнал I2S3_WS)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_SPI3); //Подключение вывода к I2S
//Конфигурирование PB3 (внешний сигнал I2S3_CK) и PB5 (внешний сигнал I2S3_SD)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI3);
//Конфигурирование PC7 (внешний сигнал I2S3_MCK)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_SPI3);
//Разрешение прерываний при пустом передающем буфере
SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, ENABLE);
//Разрешение работы интерфейса SPI3/I2S3
I2S_Cmd(SPI3, ENABLE);
}
//---------------------------------------------------------------------------
// РАЗРЕШЕНИЕ/ЗАПРЕТ ГЛОБАЛЬНЫХ ПРЕРЫВАНИЙ ОТ SPI3/I2S3 (КОДЕКА)
void SoundCodecInterruptConfig(FunctionalState NewState)
{
NVIC_InitTypeDef NVIC_InitStructure; //Структура конфигурации прерываний
NVIC_InitStructure.NVIC_IRQChannel = SPI3_IRQn; //Номер (линия) прерывания
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //Приоритет группы
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //Приоритет внутри группы
NVIC_InitStructure.NVIC_IRQChannelCmd = NewState; //Разрешение/запрет прерывания
NVIC_Init(&NVIC_InitStructure); //Функция конфигурирования
}
//---------------------------------------------------------------------------
// РАЗРЕШЕНИЕ/ЗАПРЕТ ГЛОБАЛЬНЫХ ПРЕРЫВАНИЙ ОТ ТАЙМЕРА 4
void TimerInterruptConfig(FunctionalState NewState)
{
NVIC_InitTypeDef NVIC_InitStructure; //Структура конфигурации прерываний
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //Номер (линия) прерывания
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //Приоритет группы
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //Приоритет внутри группы
NVIC_InitStructure.NVIC_IRQChannelCmd = NewState; //Разрешение/запрет прерывания
NVIC_Init(&NVIC_InitStructure); //Функция конфигурирования
}
//---------------------------------------------------------------------------
// ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ ТАЙМЕРА 4 - ИСТОЧНИКА ОПОРНОЙ ЧАСТОТЫ DDS
// Вызывается с частотой дискретизации генерируемого сигнала.
// Проверяется флаг типа прерывания (в данном случае это необязательно,
// так как используется один тип), флаг очищается.
// Код для передачи в ЦАП - смещенный.
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
AccumulatorPhase += DeltaPhase;
if (!GenAmplitude) GeneratorSamples = 0;
else
if (GenNoise)
GeneratorSamples = (int16_t)rand() / 2;
else
GeneratorSamples = (sinTableQ15[AccumulatorPhase >> 24] / 2) * GenAmplitude;
DACData1 = GeneratorSamples ^ 0x8000;
DAC_SetChannel1Data(DAC_Align_12b_L, DACData1);
DACData1 += 32;
}
}
//---------------------------------------------------------------------------
// ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ I2S3 (КОДЕКА)
// Вызывается с двойной частотой дискретизации.
// За одно обслуживание передается 16-битный отсчет одного канала.
// Вызов вторичного обработчика Sample_Handler(), формирующего отсчеты
// сразу двух каналов, происходит в 2 раза реже. При этом осуществляется
// фиксация временных меток.
void Sample_Handler(void); //Прототип функции получения отсчетов для кодека (main.c)
extern int16_t DataChannel1, DataChannel2; //Выходные отсчеты (объявлены в main.c)
uint16_t select_chan = 0; //Флаг переключателя каналов
extern volatile uint32_t StartTimeMarker12; //Признак запуска измерений (gauge.c)
void SPI3_IRQHandler(void)
{
if (!select_chan) TimeMarker1(); //Метка времени выполнения № 1 (НАЧАЛО ВВОДА-ВЫВОДА)
if (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) != RESET) //Проверка флага запроса
{
SPI_I2S_ClearFlag(SPI3, SPI_I2S_FLAG_TXE); //Сброс флага запроса прерывания
if (!select_chan)
{
Sample_Handler(); //Вторичный обработчик
SPI_I2S_SendData(SPI3, DataChannel1); //Передача кодеку отсчета первого канала
GgMeasurement(); //Измерение амплитуды сигнала
}
else SPI_I2S_SendData(SPI3, DataChannel2); //Передача кодеку отсчета второго канала
select_chan^= 1;//Переключение каналов
}
if (select_chan) TimeMarker2(); //Метка времени выполнения № 2 (КОНЕЦ ВВОДА-ВЫВОДА)
}
//---------------------------------------------------------------------------
Фрагменты исходного модуля D:\ARM\Work\DspLab_fft\gauge.c
/**
******************************************************************************
* Файл gauge.c
* Copyright (C) 2013 МГТУ МИРЭА
* Версия 1.2
* Описание: Процедуры управления генерацией, измерениями параметров
* сигнала с использованием графического интерфейса.
*
******************************************************************************
*/
#include "lcd.h"
#include "adcdac.h"
#include "gauge.h"
#include "math.h"
const uint32_t RegulDelay1 = 1000; //Начальный период опроса регулятора = 100 мс / 0.1 мс
const uint32_t RegulDelay2 = 200; //Ускоренный период опроса регулятора = 20 мс / 0.1 мс
//---------------------------------------------------------------------------
// ОБРАБОТЧИК ПРЕРЫВАНИЙ ОТ ТАЙМЕРА ПЕРИОДА ОПРОСА РЕГУЛЯТОРА ЧАСТОТЫ
uint32_tButCntr= 0;//Код длительности удержания органа управления
void TIM6_DAC_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
if (STM_EVAL_PBGetState(BUTTON_UP)) //Положение джойстика "Вверх" -
{ // увеличение частоты
if(ButCntr== 0 ||ButCntr> 4)
GenFrequencyChange(1);
ButCntr++;
}
else
if (STM_PBGetState(BUTTON_DOWN)) //Положение джойстика "Вниз" -
{ // уменьшение частоты
if (ButCntr == 0 || ButCntr > 4)
GenFrequencyChange(-1);
ButCntr++;
}
else
if (ButCntr) ButCntr = 0, TIM_SetAutoreload(TIM6, RegulDelay1);
//Увеличение скорости перестройки при длительном удержании
if (ButCntr > 30) TIM_SetAutoreload(TIM6, RegulDelay2);
}
//---------------------------------------------------------------------------