Регулирование скважности сигнала при помощи аналогового потенциометра снастройкой «мертвого времени» на микроконтроллере STM32
Емельянов Александр Александрович, доцент;
Бесклеткин Виктор Викторович, ассистент;
Иванин Александр Юрьевич, студент;
Пестеров Дмитрий Ильич, студент;
Юнусов Тимур Шамильевич, студент;
Иванов Павел Евгеньевич, студент;
Соснин Александр Сергеевич, студент.
Российский государственный профессионально-педагогический университет
(г. Екатеринбург)
Целью данной работы является программирование студентами на лабораторном стенде изменения скважности сигнала при помощи аналогового потенциометра с настройкой «мертвого времени» [1], [2], [3]. Программирование производится в среде CooCox CoIDE.
Для реализации этой цели необходимо решить следующие задачи:
‒ Настройка тактирования микроконтроллера, задействование внешнего кварца (HSE) и включение умножения частоты (PLL), а также расстановка предделителей для шин микроконтроллера;
‒ Включение тактирования периферийных устройств;
‒ Инициализация и настройка прямого доступа к памяти (DMA) для работы с аналогово-цифровым преобразователем (АЦП);
‒ Инициализация и настройка аналогово-цифрового преобразователя (АЦП) для снятия данных с потенциометра;
‒ Ввод функции инициализации:
1) Назначение портов ввода-вывода (GPIO – General Ports Input/Outputs);
2) Инициализация таймера (TIM1);
3) Инициализация ШИМ с обязательным включением комплементарных каналов;
4) Настройка «мертвого времени» (DeadTime);
- Ввод функции для записи данных с потенциометра в регистр сравнения таймера (TIM1).
Алгоритм набора кода в среде разработки CooCox CoIDE состоит в следующем:
- Запускаем среду программирования CooCox CoIDE.
- После запуска CooCox CoIDE в строке меню нажать: Project → New Project.
- В появившемся окне в поле «Project name» ввести имя своему проекту.
- Далее нужно выбрать поле с надписью «Chip».
- Появится окно с выпадающими списками различных фирм микроконтроллеров (рис. 1). Необходимо открыть список ST, затем из выпадающего списка открыть подсписок STM32F103x, после чего найти микроконтроллер STM32F103C8, выбрать его левым щелчком мыши и нажать Finish (рис. 2).
Рис. 1. Выбор фирмы микроконтроллера
Рис. 2. Выбор микроконтроллера
- После проделанных действий появится главное окно с репозиторием для выбора необходимых для проекта библиотек (рис. 3). Необходимо подключить следующие библиотеки:
‒ RCC – для управления тактовым генератором;
‒ GPIO – для управления портами ввода-вывода;
‒ TIM – для управления таймерами;
‒ DMA – для работы с прямым доступом к памяти;
‒ ADC – для работы с аналогово-цифровым преобразователем.
Рис. 3. Выбор библиотек в репозитории
- После выбора библиотек необходимо на панели инструментов выбрать «New file» и создать файлы «ADC to DMA.h» и «main.h». Затем создать файлы «SetToRcc72» и «timerPWM» с расширением «.с», а также аналогичные файлы с расширением «.h» (рис. 4).
Рис. 4. Создание файлов проекта
- Следующим шагом необходимо в панели файлов открыть «SetToRcc72.h», два раза щелкнув по нему левой кнопкой мыши, и с помощью директивы «#include <>» записать в нем заголовочный файл «stm32f10x_rcc.h», необходимый для работы с тактовым генератором (рис. 5).
Рис. 5. Запись заголовочного файла «stm32f10x_rcc.h» в «SetToRcc72.h»
- Далее необходимо открыть файл «SetToRcc72.c» и заполнить его. В нем указываются настройки тактирования микроконтроллера, значение множителя частоты (PLL), а также делители на шинах микроконтроллера (AHB, APB1, APB2). Содержание файла «SetToRcc72.c» представлено в листинге 1.
Листинг 1. Содержание файла «SetToRcc72.c»
#include "SetToRcc72.h"
void rcc_pll(void)
{
ErrorStatus HSEStartUpStatus;
//--Сброс настроек тактирования--//
RCC_DeInit();
//--Включение внешнего кварца на 8 МГц-----//
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS)
{
//---Предделитель на шине AHB---//
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//---Предделитель на шине APB2--//
RCC_PCLK2Config(RCC_HCLK_Div4);
//---Предделитель на шине APB1--//
RCC_PCLK1Config(RCC_HCLK_Div2);
//--Настройка тактирования для АЦП---//
RCC_ADCCLKConfig(RCC_PCLK2_Div2);
//--Умножение частоты на 9-----//
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//--Включение умножения-------//
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource()!=0x08)
{
}
}
else {
while(1)
{
}
}
}
- После написания кода необходимо записать прототип функции в файл «SetToRcc72.h» (рис. 6).
Рис. 6. Прототип функции в файле «SetToRcc72.h»
- Следующим шагом необходимо открыть файл «main.h» и подключить туда все заголовочные файлы (рис. 7), которые будут использоваться в проекте. Это позволит ко всем файлам подключать только «main.h».
Рис. 7. Подключение заголовочных файлов в «main.h»
- Далее необходимо открыть файл «ADC to DMA.h» и с помощью директивы «#include<>» подключить к нему файл «main.h». Затем нужно создать массив с ключевым словом «volatile» (сообщает компилятору, что содержание массива может быть изменено извне), в который будут записываться значения с потенциометра, а также создать функцию для инициализации DMA и АЦП и заполнить ее. Содержание файла «ADC to DMA.h» представлено в листинге 2.
Листинг 2. Содержание файла «ADC to DMA.h»
#include "main.h"
//---Массив для сохранения данных с потенциометра---//
volatile uint16_t ADCBuffer[] = {0xAAA};
void adc_to_dma(void)
{
//----Настройка DMA для работы с регистром АЦП---//
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_Struct;
DMA_Struct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_Struct.DMA_MemoryBaseAddr = (uint32_t)ADCBuffer;
DMA_Struct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_Struct.DMA_BufferSize = 1;
DMA_Struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_Struct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_Struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_Struct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_Struct.DMA_Mode = DMA_Mode_Circular;
DMA_Struct.DMA_Priority = DMA_Priority_Medium;
DMA_Struct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_Struct);
DMA_Cmd(DMA1_Channel1, ENABLE);
//-----Настройка аналогового входа-------//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef poten;
poten.GPIO_Mode = GPIO_Mode_AIN;
poten.GPIO_Pin = GPIO_Pin_1;
poten.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &poten);
/*-Настройка АЦП для работы с одним каналом и передачи данных по DMA-*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_InitTypeDef adc_user;
adc_user.ADC_Mode = ADC_Mode_Independent;
adc_user.ADC_ScanConvMode = DISABLE;
adc_user.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
adc_user.ADC_DataAlign = ADC_DataAlign_Right;
adc_user.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &adc_user);
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,1,ADC_SampleTime_55Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
//----Калибровка АЦП----//
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
- Следующим шагом необходимо открыть файл «timerPWM.h» и с помощью директивы «#include<>» подключить к нему файл «main.h».
- Далее нужно открыть файл «timerPWM.c» и подключить к нему заголовочный файл «main.h». В этом файле будут располагаться две функции. Первая функция будет использоваться для инициализации таймера (TIM1) и настройки первого ШИМ-канала. Вторая функция будет принимать в аргументе значение с потенциометра и отправлять его в регистр сравнения первого канала таймера (TIM1). Также здесь находится функция для запуска преобразования входных данных АЦП. Содержание файла «timerPWM.c» представлено в листинге 3.
Листинг 3. Содержание файла «timerPWM.c»
#include "timerPWM.h"
void timerPWM(void)
{
//----Включение тактирования---------//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO
| RCC_APB2Periph_GPIOA, ENABLE);
//---Настройка вывода как альтернативной функции----//
GPIO_InitTypeDef gpio;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_8;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
//---Настройка вывода как альтернативной функции----//
GPIO_InitTypeDef gpio_1;
GPIO_StructInit(&gpio_1);
gpio_1.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_1.GPIO_Pin = GPIO_Pin_13;
gpio_1.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_1);
//--Настройка таймера TIM1-------------//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef timer_TIM1;
TIM_TimeBaseStructInit(&timer_TIM1);
timer_TIM1.TIM_Prescaler = 0;
timer_TIM1.TIM_CounterMode = TIM_CounterMode_Up;
timer_TIM1.TIM_Period = 5000;
timer_TIM1.TIM_ClockDivision =0;
timer_TIM1.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &timer_TIM1);
//----Настройка ШИМ-------------//
TIM_OCInitTypeDef timer_TIM1_OC;
TIM_BDTRInitTypeDef bdtr_struct;
TIM_OCStructInit(&timer_TIM1_OC);
timer_TIM1_OC.TIM_OCMode = TIM_OCMode_PWM1;
timer_TIM1_OC.TIM_OutputState = TIM_OutputState_Enable;
timer_TIM1_OC.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OC1Init(TIM1, &timer_TIM1_OC);
//----Настройка мертвого времени-----//
TIM_BDTRStructInit(&bdtr_struct);
bdtr_struct.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
bdtr_struct.TIM_DeadTime = 36*6;
TIM_BDTRConfig(TIM1, &bdtr_struct);
//----Включение таймера и ШИМ---------//
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
//----Функция записи данных в регистры сравнения----//
void SetPWM(uint16_t PWM)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
TIM1->CCR1 = PWM;
}
- После написания кода необходимо в файле «timerPWM.h» указать прототипы функций (рис. 8).
Рис. 8. Прототипы функций в файле «timerPWM.h»
- Следующим шагом необходимо открыть файл «main.c», подключить все используемые заголовочные файлы и добавить все используемые функции в основную функцию «main()». В бесконечный цикл «while(1)» необходимо написать функцию записи данных в регистры сравнения (рис. 9).
Рис. 9. Подключение заголовочных файлов и используемых функций в «main.c»
- После написания кода программы, его необходимо скомпилировать. Для этого в панели инструментов нужно нажать «Build». В случае успешной компиляции в консоли появится надпись «BUILD SUCCESSFUL», а также будет указан размер программы. Если в коде присутствуют ошибки, то в консоли будет указано, где именно находятся эти ошибки, а также появится надпись «BUILD FAILED».
- После завершения компиляции последним этапом станет загрузка рабочей программы в микроконтроллер. Для этого нужно через специальный кабель (удлинитель USB) подключить программатор, расположенный на лабораторном стенде, к компьютеру. После подключения в панели инструментов нажать «Download Code to Flash» и дождаться окончания загрузки. В случае удачной загрузки в консоли появятся надписи: «Erase: Done»; «Program: Done»; «Verify: Done». Если существуют проблемы с подключением платы к компьютеру, то появится надпись «Error: Connect failed, check config and cable connection». Необходимо проверить кабель, к которому подключено устройство.
Результаты изменения скважности импульсов ШИМ при различных положениях потенциометра даны на рис. 10.
Рис. 10. Осциллограммы изменения скважности сигнала при различных положениях потенциометра с настройкой «мертвого времени»
Литература:
- Анучин А. С. Системы управления электроприводов: учебник для вузов / А. С. Анучин. – М.: Изд. дом МЭИ, 2015. – 373 с.
- Огородников И. Н. Микропроцессорная техника: введение в Cortex-M3: учеб. пособие / И. Н. Огородников. – Екатеринбург: изд-во Урал. Ун-та, 2015. – 116 с.
- Джозеф Ю. Ядро Cortex-M3 компании ARM. Полное руководство / Ю. Джозеф; пер. с англ. А. В. Евстифеева. – М.: Додэка-XXI, 2012. – 552 с.