Author's Blog Home Page
Author: Eterlove
, one stroke at a time, recording my study life! Standing on Shoulders of Giants!
This article is original, please indicate the source and author for reprinting
Disclaimer: This time is busy, and I will take time to make up for the analysis and explanation of relevant knowledge points.
1. Learning records
Use the timer TIM3 to generate a PWM waveform [adjustable frequency, adjustable duty cycle -> relatively adjustable], and then use the input capture function of TIM2 to measure the frequency of the waveform .
PA1---->TIM2_CH2
PA2---->TIM2_CH3
PA6---->TIM3_CH1
PA7---->TIM3_CH2
2. Generate PWM waveform TIM3_CH1_PA6
/* PA6----TIM3_CH1
PA7----TIM3_CH2 */
#include "stm32f10x.h"
#include "TIM3.h"
// The TIM3 is running at 1 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1)
// 1 KHz = 1MHZ /1000
//ARR = (TIM3 counter clock /Frequency)-1
//PWM 信号频率可调,占空比可调 PA6
void TIM3_PWM_Output(float Duty , uint32_t Frequency)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* GPIOA clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO ,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = (1000000/Frequency)-1; //ARR = (TIM3 counter clock /Frequency)-1
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = ((1000000/Frequency)-1)*Duty;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
}
Why is the frequency and duty cycle relatively adjustable?
TIM_TimeBaseStructure.TIM_Prescaler = 71;
here I fixed the count clock frequency 72MHZ/72 =1MHZ
TIM_TimeBaseStructure.TIM_Period = (1000000/Frequency)-1; //ARR = (TIM3 counter clock /Frequency)-1
Frequency if the variable value is very high "Wonderful", then TIM_Period can only be divided by the whole, which will cause a little error. The same goes for the duty cycle. So I wrote this just to facilitate the direct input parameter call in the main function, the specific problem is analyzed in detail, please reconfigure some values that are not easy to handle, and "round up"
TIM_OCInitStructure.TIM_Pulse = ((1000000/Frequency)-1 )*Duty;
3. The input capture measurement frequency of TIM2 TIM2_CH2_PA1
//Input_Capture.C文件
#include "Input_Capture.h"
//PA1---->TIM2_CH2
//PA2---->TIM2_CH3
__IO uint16_t IC2ReadValue1 = 0, IC2ReadValue2 = 0;
__IO uint16_t CaptureNumber = 0;
__IO uint32_t Capture = 0;
__IO uint32_t TIM2Freq = 0;
void Input_Capture_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//留下一个问题,这里为什么不使能AFIO??
/* 参考手册P121 对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作前,应当首先打开AFIO
的时钟。参考第6.3.7节APB2外设时钟使能寄存器(RCC_APB2ENR)。 */
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA and GPIOB clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* TIM2 channel 2,3 pin (PA.01,PA.02) configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535 ;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
//输入捕获配置 TIM2_CH2
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_ICInit(TIM2, &TIM_ICInitStructure);
//输入捕获配置 TIM2_CH3
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/* TIM enable counter */
TIM_Cmd(TIM2, ENABLE);
/* Enable the CC2 Interrupt Request */
TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_CC3, ENABLE);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET)
{
/* Clear TIM2 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
if(CaptureNumber == 0)
{
/* Get the Input Capture value */
IC2ReadValue1 = TIM_GetCapture2(TIM2);
CaptureNumber = 1;
}
else if(CaptureNumber == 1)
{
/* Get the Input Capture value */
IC2ReadValue2 = TIM_GetCapture2(TIM2);
/* Capture computation */
if (IC2ReadValue2 > IC2ReadValue1)
{
Capture = (IC2ReadValue2 - IC2ReadValue1);
}
else
{
Capture = ((0xFFFF - IC2ReadValue1) + IC2ReadValue2);
}
/* Frequency computation */
//TIM2Freq = (uint32_t) SystemCoreClock/72/ Capture;
TIM2Freq = (uint32_t)1000000 / Capture;
CaptureNumber = 0;
}
}
}
Input_Capture.C file, why do you want to divide TIM2 /72 to get a count frequency of 1MHZ?
Because our CCRx register is a 16-bit register, the count range is 0 to 0xFFFF, that is, 0~65535, but when the measured rectangular wave period is too long, the pulse width is too wide, and our counting is too fast, CCRx overflow is prone to occur. Therefore, when we measure low-frequency signals, we must divide the clock of the TIM , so that our counting will not be so fast and overflow will not occur.
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535 ;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
4. Experimental phenomenon
#include "stm32f10x.h"
#include "lcd.h"
#include "stdio.h"
#include "Key.h"
#include "TIM3.h"
#include "LED.h"
#include "string.h"
#include "Input_Capture.h"
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);
u8 TIM2FreqBuffer[20] = {
0};
extern __IO uint32_t TIM2Freq;
//Main Body
int main(void)
{
SysTick_Config(SystemCoreClock/1000);
Delay_Ms(200);
STM3210B_LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
Led_Init(); //LED初始化
Led_Control(LED_ALL , OFF); //LED全关
Key_Init(); //按键初始化
TIM3_PWM_Output(0.40 , 1000); //PWM 信号频率可调 ,占空比可调 PA6
Input_Capture_Init(); //定时器TIM2 捕获初始化
while(1)
{
//测得频率显示在LCD
sprintf(TIM2FreqBuffer , "TIM2Freq:%d HZ" ,TIM2Freq);
LCD_DisplayStringLine(Line5 , TIM2FreqBuffer );
}
}
//毫秒延时函数
void Delay_Ms(u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
(1) For example, the output is duty: 40%, 1KHZ PWM waveform
TIM3_PWM_Output(0.40 , 1000); //PWM 信号频率可调 ,占空比可调 PA6
Verify with an oscilloscope and measure the frequency of the PWM output from the PA6 pin to prevent accidents
Input_Capture_Init(); //定时器TIM2 捕获初始化
Connect PA6 and PA1
Increase the PWM waveform frequency to 55KHZ
TIM3_PWM_Output(0.40 , 55000); //PWM 信号频率可调 ,占空比可调 PA6
Input_Capture_Init(); //定时器TIM2 捕获初始化
Thanks everyone for reading!