完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
对于控制步进电机来说,最重要的控制参数是脉冲的数量和频率,两者结合可以实现满足要求的电机加减速曲线。在一些电机应用数量不多的场合,通常使用定时器中断发送脉冲来控制步进电机,优点是原理简单代码易于实现。但是一旦控制的电机多起来,就会占用大量的MCU资源,这在大多数情况下是不可接受的,更不用说多轴联动了。那么如何做到占用很少的MCU资源,又能实现脉冲发送的精确控制?
于是就想到了使用DMA功能更新PWM的输出, DMA全称Direct Memory Access,即直接存储器访问。DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。它允许不同速度的硬件装置来沟通,而不需要依赖于MPU的大量中断负载。 通过设置DMA传输数据的数量,可以控制发送的脉冲数。通过设置不同的装载值和顺序,可以使用不同频率和脉宽。当需要发送较多数量的脉冲时,则可以使用DMA传输完成中断中切换DMA传输的数据起始地址及发送数量,继续发送。这个方法即方便,又减轻MPU的负担,可以同时驱动多个电机工作,还可以根据电机的启动、运行、停止使用不同的频率。 定时器DMA模式 MM32F0270的定时器tiM1、TIM2、TIM3、TIM15、TIM16/17有DMA模式,能够在发生单个事件时生成多个DMA 请求。主要目的是在没有软件开销的情况下,多次重新编程定时器的一部分,也可以用于按周期读取数个寄存器。下面以TIM1为例介绍: TIM1_DCR 和 TIM1_DMAR 寄存器跟 DMA 模式相关。DMA 控制器的目标是唯一的,必须指向TIM1_DMAR 寄存器。开启 DMA 使能后,在给定的 TIM1 事件发生时, TIM1 会给 DMA 发送请求。 对 TIM1_DMAR 寄存器的每次写操作都被重定向到一个 TIM1 寄存器。TIM1_DCR寄存器的DBL位定义了DMA连续传送的长度,即传输寄存器数量;当对TIM1_DMAR进行读写操作时,定时器识别 DBL,确定传输的寄存器数量。TIM1_DCR 寄存器的 DBA 位定义了DMA 传输的基地址, 定义从 TIM1_CR1 寄存器地址开始的偏移量(00000 为 TIM1_CR1;00001 为TIM1_CR2;……; 00110 为 TIM1_CCMR1 等)。 通过定时器的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) { } } 演示 下载程序到目标板。连接逻辑分析仪测试PA8、PA9、PA10的输出,打开对应上位机软件启动采样,运行程序,各通道的PWM输出情况如下: 截取其中1个周期观察: TIM1_CH1输出PWM占空比为20%和80%, TIM1_CH1输出PWM占空比为30%和70%, TIM1_CH1输出PWM占空比为40%和60%,运行结果和预期一致。 实验简单演示了MM32F0270的定时器TIM1的DMA方式更新PWM,通过该方案可以实现多路、不同频率、不同脉宽、数量精确可控的PWM波。 参考Demo程序可登录MindMotion的官网下载MM32F0270库函数和例程 : https://www.mindmotion.com.cn/pr ... instream/mm32f0270/ 工程路径如下: ~ MM32FMM32F0270_Lib_SamplesMM32F0270_SamplesLibSamplesTIMTIM1_DMA_UPData。 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2246个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11575 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5907 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10879 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4559 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4284 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
948浏览 1评论
773浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 11:06 , Processed in 0.450901 second(s), Total 37, Slave 32 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号