定时器同步+触发三ADC采样+输出6路PWM波

时间:2023-03-09 16:49:22
定时器同步+触发三ADC采样+输出6路PWM波

为了熟悉定时器定时器和ADC

用STM32F407DIS做了一个简单的工程:

通过高级定时器TIM1溢出更新时间作为触发输出信号(TRGO),触发TIM8开始计数;

同时TIM1的通道1、2、3以及分别的互补通道输出6路PWM波用于控制三相电机;

TIM1的通道4用于触发ADC1的注入通道;

TIM8的通道1用于触发三个ADC的的规则通道;

TIM8的通道2用于触发ADC2的注入通道;

最后采样结果通过DMA传输到数组内保存起来;

为此,绘制了程序框图:

定时器同步+触发三ADC采样+输出6路PWM波

由框图来看工程更加清晰,更便于理解;

接下来配置工程,实现该任务:

首先配置定时器:

1     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
2 TIM_OCInitTypeDef TIM_OCInitStructure;3 TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
4 GPIO_InitTypeDef GPIO_InitStructure;

开启时钟以及基础设置

定时器同步+触发三ADC采样+输出6路PWM波
 1     // TIM1 clock enable
2 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
3 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE, ENABLE);
4
5 // Time Base configuration
6 TIM_TimeBaseStructure.TIM_Prescaler = 0; //时钟频率除数的预分频值
7 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
8 TIM_TimeBaseStructure.TIM_Period = 4200; //ARR
9 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割
10 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
11 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
定时器同步+触发三ADC采样+输出6路PWM波

通道设置

定时器同步+触发三ADC采样+输出6路PWM波
 1     // Channel 1, 2 and 3 Configuration in PWM mode
2 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
3 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
4 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
5 TIM_OCInitStructure.TIM_Pulse = TIM1->ARR / 2; //待装入捕获比较寄存器的值 5000
6 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出比较极性 高
7 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //互补输出极性 高
8 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; //空闲状态期间输出比较引脚状态
9 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
10
11 TIM_OC1Init(TIM1, &TIM_OCInitStructure);
12 TIM_OC2Init(TIM1, &TIM_OCInitStructure);
13 TIM_OC3Init(TIM1, &TIM_OCInitStructure);
14 TIM_OC4Init(TIM1, &TIM_OCInitStructure);
15
16 TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
17 TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
18 TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
19 TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
定时器同步+触发三ADC采样+输出6路PWM波

死区设置

定时器同步+触发三ADC采样+输出6路PWM波
1     TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
2 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
3 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
4 TIM_BDTRInitStructure.TIM_DeadTime = 60; // 60个周期时间
5 TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
6 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
7 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
8
9 TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
定时器同步+触发三ADC采样+输出6路PWM波

输出六路PWM波通道映射

定时器同步+触发三ADC采样+输出6路PWM波
 1    /* GPIOA Configuration: TIM1 CH1 (PA8) 、 TIM1 CH1N (PA7) 、TIM1 CH3 (PA10) */
2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_7 | GPIO_Pin_10 ;
3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
4 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
5 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
6 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
7 GPIO_Init(GPIOA, &GPIO_InitStructure);
8
9 /* GPIOB Configuration: TIM1 CH2N (PB14) and TIM1 CH3N (PB15) */
10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
11 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
12 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
13 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
14 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
15 GPIO_Init(GPIOB, &GPIO_InitStructure);
16
17 /* GPIOB Configuration: TIM1 CH2 (PE11) and TIM1 CH3 (PE13) */
18 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_11 | GPIO_Pin_14;
19 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
20 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
21 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
22 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
23 GPIO_Init(GPIOE, &GPIO_InitStructure);
24
25 /* Connect TIM1 pins to AF */
26 GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);
27 GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_TIM1);
28 GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_TIM1);
29 GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);
30 GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_TIM1);
31 GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM1);
32 GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_TIM1);
定时器同步+触发三ADC采样+输出6路PWM波

选择主从模式,TIM1为主选择更新时间作为触发输出

1 TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);             //选择更新事件作为触发输出(TRGO)
2 TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);

对相关配置进行使能

定时器同步+触发三ADC采样+输出6路PWM波
 1     TIM_CCPreloadControl(TIM1, ENABLE);
2 TIM_ARRPreloadConfig(TIM1, ENABLE);
3
4 TIM_ClearFlag(TIM1,TIM_FLAG_Update);
5
6 TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
7 TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE);
8
9 TIM_CCxCmd(TIM1, TIM_Channel_4, TIM_CCx_Enable);
10
11 TIM_Cmd(TIM1, ENABLE);
12
13 // Main Output Enable
14 TIM_CtrlPWMOutputs(TIM1, ENABLE); //设置TIM1 的PWM输出使能
定时器同步+触发三ADC采样+输出6路PWM波

定时器8同样的配置过程

定时器同步+触发三ADC采样+输出6路PWM波
 1     RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
2 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
3
4 TIM_TimeBaseStructure.TIM_Prescaler = 0;
5 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
6 TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //65535
7 TIM_TimeBaseStructure.TIM_ClockDivision = 0;
8 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
9 TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
10
11 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
12 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
13 TIM_OCInitStructure.TIM_Pulse = 500;
14 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
15 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
16 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
17 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
18 TIM_OC1Init(TIM8, &TIM_OCInitStructure);
19 TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);
20 TIM_OC2Init(TIM8, &TIM_OCInitStructure);
21 TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);
22
23 TIM_ARRPreloadConfig(TIM8, ENABLE);
24 TIM_CCPreloadControl(TIM8, ENABLE);
25
26 // PWM outputs have to be enabled in order to trigger ADC on CCx
27 TIM_CtrlPWMOutputs(TIM8, ENABLE);
28
29 TIM_SelectInputTrigger(TIM8, TIM_TS_ITR0); //选择输入触发源 ITR0
30 TIM_SelectSlaveMode(TIM8, TIM_SlaveMode_Reset); //计数器从模式选择 所选的触发信号上升沿重新初始化
31
32 // TIM_ITRxExternalClockConfig(TIM8, TIM_TS_ITR0); //选择ITR0为触发源提供时钟
33
34 TIM_CCxCmd(TIM8, TIM_Channel_1, TIM_CCx_Enable);
35 TIM_CCxCmd(TIM8, TIM_Channel_2, TIM_CCx_Enable);
36
37 TIM_ITConfig(TIM8, TIM_IT_CC1, ENABLE);
38 TIM_ITConfig(TIM8, TIM_IT_CC2, ENABLE);
39
40 TIM_ClearFlag(TIM8,TIM_FLAG_Update);
41 TIM_GenerateEvent(TIM8, TIM_EventSource_Trigger);
42
43 TIM_Cmd(TIM8, ENABLE);
44 }
定时器同步+触发三ADC采样+输出6路PWM波

如此计算可知:

定时器同步+触发三ADC采样+输出6路PWM波        定时器同步+触发三ADC采样+输出6路PWM波

查阅手册可知:

定时器同步+触发三ADC采样+输出6路PWM波

TIM1为主,TIM8为从,内部是通过ITR0连接的,所以在上面的配置过程中,TIM8的触发源要配置为ITR0;

接下来配置ADC

ADC要配置为三重模式

不开启连续转换

ADC1选择外部触发,但ADC2/3必须配置为软件触发

定时器同步+触发三ADC采样+输出6路PWM波
 1     ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;                 //adc三重模式
2 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
3 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
4 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
5 ADC_CommonInit(&ADC_CommonInitStructure);
6
7 // Channel-specific settings
8 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //ADC分辨率双模式 12位精度
9 ADC_InitStructure.ADC_ScanConvMode = ENABLE; //扫描模式
10 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
11 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling; //选择外部触发方式 下降沿触发
12 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_CC1; //选择TIM8_CC1触发规则组开始转换的外部事件
13 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐
14 ADC_InitStructure.ADC_NbrOfConversion = 4; //指定使用规则通道组完成转换的次数 采样通道数
15
16 ADC_Init(ADC1, &ADC_InitStructure);
17 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //不使用外部触发 (多ADC模式中,外部事件触发必须仅触发主ADC,从ADC设置为软件触发)
18 ADC_InitStructure.ADC_ExternalTrigConv = 0;
19 ADC_Init(ADC2, &ADC_InitStructure);
20 ADC_Init(ADC3, &ADC_InitStructure);
21
22 // Enable DMA request after last transfer (Multi-ADC mode) 多ADC模式下 使能 源数据变化时开启DMA传输
23 ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
24
25 // Injected channels for current measurement at end of cycle
26 ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_CC4);
27 ADC_ExternalTrigInjectedConvConfig(ADC2, ADC_ExternalTrigInjecConv_T8_CC2);
28 ADC_ExternalTrigInjectedConvEdgeConfig(ADC1, ADC_ExternalTrigInjecConvEdge_Falling);
29 ADC_ExternalTrigInjectedConvEdgeConfig(ADC2, ADC_ExternalTrigInjecConvEdge_Falling);
30 ADC_InjectedSequencerLengthConfig(ADC1, 2); //设置注入通道长度 1-4
31 ADC_InjectedSequencerLengthConfig(ADC2, 2);
32
33 ADC_Channels();
34
35 // Interrupt
36 ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE); //使能ADC的JEOC中断源 注入转换中断屏蔽结束
37
38 // ADC_AutoInjectedConvCmd(ADC1, ENABLE);
39 // ADC_AutoInjectedConvCmd(ADC2, ENABLE);
40
41 ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_CC4);
42 ADC_ExternalTrigInjectedConvConfig(ADC2, ADC_ExternalTrigInjecConv_T8_CC2);
43
44 //Enable ADC_DMA
45 ADC_DMACmd(ADC1, ENABLE);
46 ADC_DMACmd(ADC2, ENABLE);
47 ADC_DMACmd(ADC3, ENABLE);
48
49 // Enable ADC1
50 ADC_Cmd(ADC1, ENABLE);
51
52 // Enable ADC2
53 ADC_Cmd(ADC2, ENABLE);
54
55 // Enable ADC3
56 ADC_Cmd(ADC3, ENABLE);
定时器同步+触发三ADC采样+输出6路PWM波

再配置一下ADC的通道

定时器同步+触发三ADC采样+输出6路PWM波
 1     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_15Cycles);         //(15+12)/42 = 0.6429 us  总转换时间
2 ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_15Cycles);
3 ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 3, ADC_SampleTime_15Cycles);
4 ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_15Cycles);
5
6 // ADC2 regular channels
7 ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_15Cycles);
8 ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 2, ADC_SampleTime_15Cycles);
9 ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 3, ADC_SampleTime_15Cycles);
10 ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 4, ADC_SampleTime_15Cycles);
11
12 // ADC3 regular channels
13 ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_15Cycles);
14 ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 2, ADC_SampleTime_15Cycles);
15 ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_15Cycles);
16 ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 4, ADC_SampleTime_15Cycles);
17
18 // Injected channels
19 ADC_InjectedChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_15Cycles);
20 ADC_InjectedChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_15Cycles);
21 ADC_InjectedChannelConfig(ADC2, ADC_Channel_8, 1, ADC_SampleTime_15Cycles);
22 ADC_InjectedChannelConfig(ADC2, ADC_Channel_9, 2, ADC_SampleTime_15Cycles);
定时器同步+触发三ADC采样+输出6路PWM波

最后配置DMA

定时器同步+触发三ADC采样+输出6路PWM波
 1 DMA_InitStructure.DMA_Channel = DMA_Channel_0;                   //通道0
2 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_Value;
3 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC->CDR;
4 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
5 DMA_InitStructure.DMA_BufferSize = 12; //指定DMA通道的DMA缓存的大小
6 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
7 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
8 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度
9 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
10 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环缓存模式
11 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
12 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //关闭FIFO模式
13 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; //FIFO阈值级别
14 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
15 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
16 DMA_Init(DMA2_Stream4, &DMA_InitStructure);
17
18 // DMA2_Stream0 enable
19 DMA_Cmd(DMA2_Stream4, ENABLE);
20
21 // Enable transfer complete interrupt
22 DMA_ITConfig(DMA2_Stream4, DMA_IT_TC, ENABLE);
定时器同步+触发三ADC采样+输出6路PWM波

如此,工程便配置完成了

通过示波器验证:

定时器1的通道1、2、3和他们的互补通道(6路PWM波):

定时器同步+触发三ADC采样+输出6路PWM波

定时器同步+触发三ADC采样+输出6路PWM波

TIM1通道4的波形(ADC1注入通道)  和  TIM8输出的波形(ADC规则通道、ADC2注入通道):

定时器同步+触发三ADC采样+输出6路PWM波

定时器同步+触发三ADC采样+输出6路PWM波

程序验证正常。