通过定时器的DMA模式来更新PWM,本文参官网例程“TIM1_DMA_UPData”进行说明具体实现方法。
实验
本实验使用TIM1的DMA模式,当更新事件发生时,更新 TIM1_CCR1、TIM1_CCR2 和 TIM1_CCR3 寄存器的内容。程序中配置TIM1的通道1、通道2、通道3输出PWM,再通过DMA搬运数据来改变PWM的占空比。定时器每产生一个溢出事件(即计数完成),就发送DMA请求,根据数据在数组中的排列顺序以生成所需要的时序。
程序部分
GPIO初始化
配置TIM1_CH1、TIM1_CH2 和 TIM1_CH3对应的GPIO。void TIM1_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphclockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_2);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}TIM1 DMA初始化TIM1_CH3对应DMA1通道5,将data[]中的数据传送到TIM1_DMAR寄存器,传输方向从存储器到外设,数据宽度为半字,使能DMA传输完成中断。void TIM_DMA_Init(void)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel5);
DMA_StructInit(&DMA_InitStruct);
//Transfer register address
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32) & (TIM1->DMAR);
//Transfer memory address
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)data;
//Transfer direction, from memory to register
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_BufferSize = 6;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//Transfer completed memory address increment
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStruct);
DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
}
TIM1 PWM初始化
TIM1输出PWM,配置时钟分频系数和预装载值,递增计数,使用PWM模式1,输出高电平有效,分别对TIM1_CH1、TIM1_CH2、TIM1_CH3指定要加载到捕获比较寄存器中的脉冲值为arr/2、arr/4、arr/6,使能TIM1的DMA模式,起始地址为TIM1_CCR1,传输长度为3。void TIM1_PWM_Init(u16 arr, u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_TIM1, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_Period = arr;
TIM_TimeBaseStruct.TIM_Prescaler = psc;
//Setting Clock Segmentation
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
///TIM Upward Counting Mode
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);
TIM_OCStructInit(&TIM_OCInitStruct);
//Select Timer Mode: TIM Pulse Width Modulation Mode 2
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
//Setting the Pulse Value of the Capture Comparison Register to be Loaded
TIM_OCInitStruct.TIM_Pulse = arr / 2;
TIM_OC1Init(TIM1, &TIM_OCInitStruct);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OCInitStruct.TIM_Pulse = arr / 4;
TIM_OC2Init(TIM1, &TIM_OCInitStruct);
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OCInitStruct.TIM_Pulse = arr / 6;
TIM_OC3Init(TIM1, &TIM_OCInitStruct);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMAburstLength_3Bytes);
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);
}
使能DMA1通道5
DMA_Cmd(DMA1_Channel5, ENABLE);配置NVIC NVIC_Configure(DMA1_Channel4_5_6_7_IRQn, 1, 1);DMA1中断服务子程序void DMA1_Channel4_5_6_7_IRQHandler(){
IF (DMA_GetITStatus(DMA1_IT_TC5)) {
//clear IRQ flag
DMA_ClearITPendingBit(DMA1_IT_TC5);
}
}定义数组data[]static u16 data[] = {2000, 3000, 4000, 8000, 7000, 6000};Main()函数s32 main(void)
{
TIM1_GPIO_Init();
TIM1_PWM_Init(10000, 0);
TIM_DMA_Init();
NVIC_Configure(DMA1_Channel4_5_6_7_IRQn, 1, 1);
DMA_Cmd(DMA1_Channel5, ENABLE);
while (1) {
}
}
|