OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4741|回复: 6

使用DMA精确控制PWM脉冲个数

[复制链接]

7

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1327
金钱
1327
注册时间
2019-7-11
在线时间
165 小时
发表于 2019-9-21 10:50:48 | 显示全部楼层 |阅读模式
世界和平
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

7

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1327
金钱
1327
注册时间
2019-7-11
在线时间
165 小时
 楼主| 发表于 2019-9-21 10:55:39 | 显示全部楼层
  1. #include "tim_dma_pwm_pulse_output.h"
  2. #include "delay.h"

  3. u16 ZhanKongBi=0;

  4. void TIM3_Dma_Pwm_Pulse_Output_Test(void)
  5. {
  6.     TIM3_Dma_Pwm_Pulse_Output_Init();
  7.     TIM3_Dma_Pwm_Pulse_Output(1000-1,71,10,11); //周期=1000*72/72000000=1ms 占空比10%  10个脉冲 10ms
  8.     delay_ms(11);                               // 保证输出完毕 并和下一个脉冲再间隔 1ms
  9.     TIM3_Dma_Pwm_Pulse_Output(1000-1,71,20,6);
  10.     delay_ms(6);
  11.     TIM3_Dma_Pwm_Pulse_Output(1000-1,71,50,3);
  12. }
  13. void TIM3_Dma_Pwm_Pulse_Output_Init(void)
  14. {
  15.     GPIO_InitTypeDef         GPIO_InitStructure;
  16.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  17.     TIM_OCInitTypeDef        TIM_OCInitStructure;
  18.     DMA_InitTypeDef          DMA_InitStructure;
  19.     NVIC_InitTypeDef         NVIC_InitStructure;

  20.     TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);  //设置缺省值,这一步最好加上防止放到串口初始化后出问题
  21.     TIM_OCStructInit(&TIM_OCInitStructure);          //设置缺省值,这一步最好加上防止放到串口初始化后出问题
  22.     //TIM_ICStructInit(&TIM_ICInitStructure);        //设置缺省值,这一步最好加上防止放到串口初始化后出问题

  23.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);                              //使能定时器3时钟
  24.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
  25.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  26.    
  27.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  
  28.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         
  29.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  30.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  31.     //初始化TIM3
  32.     TIM_TimeBaseStructure.TIM_Period = 1000 - 1;                 //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
  33.     TIM_TimeBaseStructure.TIM_Prescaler = 0;                     //设置用来作为TIMx时钟频率除数的预分频值
  34.     TIM_TimeBaseStructure.TIM_ClockDivision = 0;                 //设置时钟分割:TDTS = Tck_tim
  35.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
  36.     TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);         
  37.                
  38.                          
  39.     //初始化TIM3 Channe1 PWM模式         
  40.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;            //选择定时器模式:TIM脉冲宽度调制模式1
  41.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
  42.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;    //输出极性:TIM输出比较极性高,为了默认情况下输出低电平
  43.     TIM_OC1Init(TIM3, &TIM_OCInitStructure);                     //初始化通道1
  44.     TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);            //使能TIM3在通道1上的预装载寄存器

  45.     DMA_DeInit(DMA1_Channel3);                                                 //将DMA的通道1寄存器重设为缺省值
  46.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&TIM3->CCR1;               //DMA外设基地址
  47.     DMA_InitStructure.DMA_MemoryBaseAddr     = (u32)&ZhanKongBi;               //DMA内存基地址
  48.     DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;          //DMA_DIR_PeripheralSRC:从外设读  DMA_DIR_PeripheralDST:从内存读
  49.     DMA_InitStructure.DMA_BufferSize         = 0;                              //不加一就少一个,那么就直接设置pulseNumber多一就好
  50.     DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;      //外设地址寄存器不变
  51.     DMA_InitStructure.DMA_MemoryInc          = DMA_PeripheralInc_Disable;      //内存地址寄存器递增
  52.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度为8位
  53.     DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;    //数据宽度为8位
  54.     DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;                //工作在正常模式
  55.     DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;            //DMA通道 x拥有中优先级
  56.     DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;                //是否开启内存到内存传输(关闭表示只有事件产生才传输一次数据,开启表示一直传输)
复制代码


世界和平
回复 支持 反对

使用道具 举报

7

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1327
金钱
1327
注册时间
2019-7-11
在线时间
165 小时
 楼主| 发表于 2019-9-21 10:58:31 | 显示全部楼层
  1.     DMA_Init(DMA1_Channel3, &DMA_InitStructure);                               //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器                 

  2.     DMA_Cmd(DMA1_Channel3, ENABLE);               //DMA1_3使能
  3.     TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE);     //定时器3TIM_DMA_Update使能
  4.    
  5.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;   
  6.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     // 优先级设置
  7.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
  8.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  9.     NVIC_Init(&NVIC_InitStructure);               
  10.     DMA_ClearFlag(DMA1_Channel3_IRQn);                                         //清除DMA所有标志
  11.     DMA_ITConfig(DMA1_Channel3,DMA_IT_TC,ENABLE);                              //开传输完成中断
  12.        
  13.     TIM_SetCounter(TIM3, 0);
  14.     TIM_SetCompare1(TIM3,0);      //默认情况下占空比为0,配合比较输出极性设为high,也就是低电平输出
  15.     TIM_Cmd(TIM3, ENABLE);        //使能TIM3

  16. }
  17. void TIM3_Dma_Pwm_Pulse_Output(u16 arr,u16 psc,u8 zhankongbi_temp,u16 geshu)
  18. {
  19.     TIM3_Dma_Pwm_Pulse_Output_Set(arr,psc,zhankongbi_temp,geshu);
  20. }
  21. void TIM3_Dma_Pwm_Pulse_Output_Set(u16 arr,u16 psc,u8 zhankongbi_temp,u16 geshu)
  22. {
  23.     TIM_SetAutoreload(TIM3,arr);                               //设置重装载寄存器
  24.     TIM_PrescalerConfig(TIM3,psc,TIM_PSCReloadMode_Immediate); //设置定时器时钟分频,立即生效
  25.        
  26.     ZhanKongBi=(arr+1) * zhankongbi_temp / 100;                //计算占空比
  27.     TIM_SetCompare1(TIM3,ZhanKongBi);                          //占空比填入比较寄存器

  28.     DMA_Cmd(DMA1_Channel3, DISABLE);                           //DMA失能才能设置
  29.     DMA_SetCurrDataCounter(DMA1_Channel3,geshu);               //设置DMA长度,即脉冲数量
  30.     DMA_Cmd(DMA1_Channel3, ENABLE);                            //开启

  31.     TIM_SetCounter(TIM3, 0);                                   //确保定时器计数归零
  32.     TIM_Cmd(TIM3, ENABLE);                                     //开启
  33. }

  34.     void TIM3_ReInit(void){
  35.     TIM_SetCounter(TIM3, 0);
  36.     TIM_SetCompare1(TIM3, 0);     
  37. }
  38. void DMA1_Channel3_IRQHandler(void)//脉冲输出完毕,不关闭定时器,而是继续输出低电平
  39. {
  40.     if(DMA_GetITStatus(DMA1_FLAG_TC3))
  41.     {
  42.         TIM3_ReInit();
复制代码


世界和平
回复 支持 反对

使用道具 举报

7

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1327
金钱
1327
注册时间
2019-7-11
在线时间
165 小时
 楼主| 发表于 2019-9-21 10:59:58 | 显示全部楼层
  1.         DMA_ClearFlag(DMA1_Channel3_IRQn);                       
  2.         DMA_ClearFlag(DMA1_FLAG_GL3);        
  3.     }
  4. }
复制代码


世界和平
回复 支持 反对

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-9-21 12:09:42 | 显示全部楼层
默认就是不输出脉冲为低电平吧。当时有几个群友做固定脉冲输出,就简单写了个。有两个小bug都备注了,也懒得改了,你这个解决了下次输出的第一个脉冲是上次的问题哈,应该在我那个帖子下回复个这个问题的解决思路
回复 支持 反对

使用道具 举报

7

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1327
金钱
1327
注册时间
2019-7-11
在线时间
165 小时
 楼主| 发表于 2019-9-21 13:03:55 | 显示全部楼层
nashui_sx 发表于 2019-9-21 12:09
默认就是不输出脉冲为低电平吧。当时有几个群友做固定脉冲输出,就简单写了个。有两个小bug都备注了,也懒 ...

在那里面发这么多影响观感,东西都在注释里边了
世界和平
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2019-7-8
在线时间
8 小时
发表于 2019-10-15 10:20:38 | 显示全部楼层
好,不错
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-22 01:52

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表