以前在本科时写的教程文章,主要是把自己当时参赛的方法拿出来做了个总结。
想当年天天水论坛好为人师,现在已经全面转向计算机视觉方向了,颇为感慨。不过,自己的理性选择,个中得失早就意料之中。塞翁失马,焉知非福?
原文链接:http://www.openedv.com/forum.php?mod=viewthread&tid=82594&extra=
【教程】使用STM32测量频率和占空比的几种方法(申请置酷!)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93void Tim2_PWMIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; /* TIM4 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); /* GPIOB clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /* TIM4 chennel2 configuration : PB.07 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Connect TIM pin to AF2 */ GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4); /* Enable the TIM4 global Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0; TIM_PWMIConfig(TIM4, &TIM_ICInitStructure); /* Select the TIM4 Input Trigger: TI2FP2 */ TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2); /* Select the slave Mode: Reset Mode */ TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset); TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable); /* TIM enable counter */ TIM_Cmd(TIM4, ENABLE); /* Enable the CC2 Interrupt Request */ TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE); } //中断程序: void TIM4_IRQHandler(void) { /* Clear TIM4 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM4, TIM_IT_CC1|TIM_IT_CC2); /* Get the Input Capture value */ IC2Value = TIM_GetCapture2(TIM4);//周期 if (IC2Value != 0) { highval[filter_cnt]=TIM_GetCapture1(TIM4);//高电平周期 waveval[filter_cnt]=IC2Value; filter_cnt++; if(filter_cnt>=FILTER_NUM) filter_cnt=0; } else { DutyCycle = 0; Frequency = 0; } } //主循环: while (1) { uint32_t highsum=0,wavesum=0,dutysum=0,freqsum=0; LCD_Clear(0); for(i=0;i<FILTER_NUM;i++) { highsum+=highval[i]; wavesum+=waveval; } [/i] delay_ms(1); DutyCycle=highsum*1000/wavesum; Frequency=(SystemCoreClock/2*1000/wavesum); freq=Frequency*2.2118-47.05;//线性补偿 sprintf(str,"DUTY:%3dnFREQ:%.3f KHZn",DutyCycle,freq/1000); LCD_ShowString(0,200,str); delay_ms(100); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89//定时器5通道1输入捕获配置 //arr:自动重装值(TIM2,TIM5是32位的!!) //psc:时钟预分频数 void TIM5_CH1_Cap_Init(u32 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0 GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0复用位定时器5 TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure); //初始化TIM5输入捕获参数 TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上 TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波 TIM_ICInit(TIM5, &TIM5_ICInitStructure); TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断 TIM_Cmd(TIM5,ENABLE ); //使能定时器5 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 } //捕获状态(对于32位定时器来说,1us计数器加1,溢出时间:4294秒) //定时器5中断服务程序 void TIM5_IRQHandler(void) { if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件 { if(edge==RESET)//上升沿 { rising=TIM5->CCR1-rising_last; rising_last=TIM5->CCR1; TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=0 设置为上升沿捕获 edge=SET; } else { falling=TIM5->CCR1-rising_last; TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获 edge=RESET; } } TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位 } 主程序: while (1) { uint32_t highsum=0,wavesum=0,dutysum=0,freqsum=0; LCD_Clear(0); delay_ms(1); sprintf(str,"rise:%3dnfall:%dnfall-rise:%d",rising,falling,falling-rising); LCD_ShowString(0,100,str); sprintf(str,"Freq:%.2f HznDuty:%.3fn",90000000.0/rising,(float)falling/(float)rising);//频率、占空比 LCD_ShowString(0,200,str); delay_ms(100); }
注意的是,中断程序当中的变量rising,last因为多次修改的缘故,与名称本身含义有所区别,示意如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72/TIM2_CH1->PA5 //TIM2_CH2->PB3 void TIM2_CH1_Cap_Init(u32 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; TIM_DeInit(TIM2); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM2时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTA时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //GPIOA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; //速度100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA0 GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PA0 GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2); //PA0复用位定时器5 GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_TIM2); //PA0复用位定时器5 TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //初始化TIM2输入捕获参数 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波 TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01 选择输入端 IC1映射到TI1上 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //上升沿捕获 TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2,ENABLE);//允许更新中断 ,允许CC1IE捕获中断 // TIM2_CH1_Cap_DMAInit(); TIM_Cmd(TIM2,ENABLE ); //使能定时器5 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 } //定时器2中断服务程序(对于32位定时器来说,1us计数器加1,溢出时间:4294秒) void TIM2_IRQHandler(void) { if(TIM2->SR&TIM_FLAG_CC1)//TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件 { rising=TIM2->CCR1-rising_last; rising_last=TIM2->CCR1; return; } if(TIM2->SR&TIM_FLAG_CC2)//TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET) { falling=TIM2->CCR2-rising_last; return; } TIM2->SR=0; }
这样,最高频率能够达到约1.1MHz,是一个不小的进步。但是,其根本问题——中断太频繁——仍然存在。
解决思路也是存在的。本质上,我们实际上只需要读取CCR1和CCR2寄存器。而在内存复制过程中,面对大数据量的转移时,我们会想到什么?显然,我们很容易想到——利用DMA。所以,我们使用输入捕获事件触发DMA来搬运寄存器而非触发中断即可,然后将这些数据存放在一个数组当中并循环刷新。这样,我们可以随时来查看数据并计算出频率。
这一方法我曾经尝试过,没有调出来,因为,有一个更好的方法存在。但是理论上这是没有问题的,以供参考我列出如下。
【注意:这段程序无法工作,仅供参考!!!】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47//TIM2_CH1->DMA1_CHANNEL3_STREAM5 u32 val[FILTER_NUM]={0}; void TIM2_CH1_Cap_DMAInit(void) { NVIC_InitTypeDef NVIC_InitStructure; DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 DMA_DeInit(DMA1_Stream5); while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){}//等待DMA可配置 /* 配置 DMA Stream */ DMA_InitStructure.DMA_Channel = DMA_Channel_3; //通道选择 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM5->CCR1);//DMA外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)val;//DMA 存储器0地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//存储器到外设模式 DMA_InitStructure.DMA_BufferSize = FILTER_NUM;//数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:8位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//存储器数据长度:8位 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//中等优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输 DMA_Init(DMA1_Stream5, &DMA_InitStructure);//初始化DMA Stream TIM_DMAConfig(TIM5,TIM_DMABase_CCR1,TIM_DMABurstLength_16Bytes); TIM_DMACmd(TIM5,TIM_DMA_CC1,ENABLE); //如果需要DMA中断则如下面所示 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn; //使能TIM中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); DMA_ITConfig(DMA1_Stream5,DMA_IT_TC,ENABLE); //开启DMA传输 DMA_Cmd(DMA1_Stream5, ENABLE); } void DMA1_Stream5_IRQHandler(void) { DMA_ClearITPendingBit(DMA1_Stream5,DMA_IT_TCIF5); }

因此,高频时仍然推荐以下方法。
思路四:使用外部时钟计数器
这种方法是我这几天回答问题时推荐的方法。思路是配置两个定时器,定时器a设置为外部时钟计数器模式,定时器b设置为定时器(比如50ms溢出一次,也可以用软件定时器),然后定时器b中断函数中统计定时器a在这段时间内的增量,简单计算即可。
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57//TIM7->100ms //TIM2_CH2->PB3 void TIM_Cnt_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_DeInit(TIM2); TIM_DeInit(TIM7); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM7,ENABLE); //TIM2时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTA时钟 //IO GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; //速度100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //下拉 GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PA0 GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_TIM2); //PA0复用位定时器5 //TIM2配置 TIM_TimeBaseStructure.TIM_Prescaler=0; //定时器分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=0xFFFFFFFF; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); TIM_TIxExternalClockConfig(TIM2,TIM_TIxExternalCLK1Source_TI2,TIM_ICPolarity_Rising,0);//外部时钟源 //TIM7 100ms TIM_TimeBaseStructure.TIM_Prescaler=18000-1; //定时器分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=1000-1; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM7,&TIM_TimeBaseStructure); //中断 NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);//允许更新中断 ,允许CC1IE捕获中断 TIM_Cmd(TIM7,ENABLE ); //使能定时器5 TIM_Cmd(TIM2,ENABLE ); //使能定时器5 } u32 TIM7_LastCnt; //频率为TIM_ExtCntFreq void TIM7_IRQHandler(void) { char str[32]; TIM_ExtCntFreq=(TIM2->CNT-TIM7_LastCnt)*(1/SAMPLE_PERIOD);// SAMPLE_PERIOD为采样周期0.1s sprintf(str,"%3.3f",TIM_ExtCntFreq/1000.0);//必须加这一句,莫明其妙 TIM7_LastCnt=TIM2->CNT; TIM_ClearITPendingBit(TIM7,TIM_IT_Update); }

当采样数n趋于无穷时,事件A的概率即趋近于统计的频率。所以,当采样数越大,则采样到的高电平占样本总数的频率即趋近于概率——占空比!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85//ADC1-CH13-PC3 //DMA2-CH0-STREAM0 #define ADCx ADC1 #define ADC_CHANNEL ADC_Channel_13 #define ADCx_CLK RCC_APB2Periph_ADC1 #define ADCx_CHANNEL_GPIO_CLK RCC_AHB1Periph_GPIOC #define GPIO_PIN GPIO_Pin_3 #define GPIO_PORT GPIOC #define DMA_CHANNELx DMA_Channel_0 #define DMA_STREAMx DMA2_Stream0 #define ADCx_DR_ADDRESS ((uint32_t)&(ADCx->DR))//((uint32_t)0x4001224C) void ADC_DMAInit(void) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable ADCx, DMA and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RCC_AHB1PeriphClockCmd(ADCx_CHANNEL_GPIO_CLK, ENABLE); RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE); /* DMA2 Stream0 channel2 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_CHANNELx; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&(ADC_DATAPOOL[0]); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = ADC_POOLSIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA_STREAMx, &DMA_InitStructure); DMA_Cmd(DMA_STREAMx, ENABLE); /* Configure ADC3 Channel7 pin as analog input ******************************/ GPIO_InitStructure.GPIO_Pin = GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIO_PORT, &GPIO_InitStructure); /* ADC Common Init **********************************************************/ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; ADC_CommonInit(&ADC_CommonInitStructure); /* ADC3 Init ****************************************************************/ ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADCx, &ADC_InitStructure); /* ADC3 regular channel7 configuration **************************************/ ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_480Cycles); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE); /* Enable ADC3 DMA */ ADC_DMACmd(ADCx, ENABLE); /* Enable ADC3 */ ADC_Cmd(ADCx, ENABLE); } 主程序: for(j=0;j<ADC_POOLSIZE;j++) { if(ADC_DATAPOOL[j]>0x01) posicnt++; } duty=100*posicnt/(float)(ADC_POOLSIZE)+0.1f;//线性补偿
最后
以上就是缥缈蜗牛最近收集整理的关于使用 STM32 测量频率和占空比的几种方法的全部内容,更多相关使用内容请搜索靠谱客的其他文章。
发表评论 取消回复