要实现课上讲的第一个项目,大体可以分为两大部分,第一部分是配置输出,第二部分是配置输入捕获。
首先是配置输出,输出分为5步:
1.开启总线时钟,包括定时器(APB2)和GPIO(APB1)。
2.配置GPIO,选择为推挽输出,并将定时器配置为内部时钟。
3.配置时基单元,设置不分频,上拉输出,同时配置PSC(分频器)和ARR(时钟周期)。
4.配置输出比较模块,设置初始CCR,以及输出比较模式。
5. 最后是使能时钟。
然后是输入捕获模式,总体可以分为7步
前两步和输出比较一样,其中注意GPIO接口的选择,配置上拉输入模式,以及定时器的选择(TIM3)。
3.时基单元大体一致,但注意Period要设置的大一些,应为这里使用的计算频率的方法是根据输入频率跳动一次的情况下,输入定时器CCR跳到的个数,应当防止数据的溢出(一般为65535),然后是PSC分频的设置,这个的设置尽量的小一点,(因为其中会有+-1的误差在里面,要尽量使这里+-1的误差对整体的影响小,所以要让输入定时器频率快一点,也就是分频小一点),同时为了方便计算频率,所以一般使用PSC设置为72,(这样子72M的频率就可以转化为1M来计算了)。
4.然后是配置输入捕获模块,按照正常配置即可(如上拉,不分频,通道1,滤波0xF)
5.然后是配置从模式,选择输入触发源
6.设置复位模式,让计数归零 //此处作者电路图没太看懂,无法给出更详细的解释,回去好好 //学数电哈哈哈
7.定时器使能
最后按照需要,可以将设置输出比较值和设置PSC1以及获取输入捕获获取频率封装成函数。再在主函数中实现即可,最后奉上代码
//PWM
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启时钟APB1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_IniStruct;
GPIO_IniStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_IniStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_IniStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_IniStruct);
TIM_InternalClockConfig(TIM2);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 100 - 1; //确定周期(ARR)
TIM_TimeBaseInitStruct.TIM_Prescaler = 720 - 1; //确定PSC分频(PSC)
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //通用计时器没有重复计数器功能
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM2, &TIM_OCInitStruct);
TIM_Cmd(TIM2, ENABLE); //定时器使能
}
void PWM_SetCompare1(uint16_t compel)
{
TIM_SetCompare1(TIM2, compel);
}
void PWM_SetPrescaler(uint32_t Prescaler)
{
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}
//IC
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启时钟APB1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_IniStruct;
GPIO_IniStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_IniStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_IniStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_IniStruct);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 65535 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3, &TIM_ICInitStruct);
// 5. 选择从模式的触发源
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
// 6. 选择从模式触发后执行的操作
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_Cmd(TIM3, ENABLE);
}
uint32_t IC_GetFreq(void)
{
return 1000000 / TIM_GetCapture1(TIM3);
}
//main
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
uint8_t i;
int main()
{
OLED_Init();
PWM_Init();
IC_Init();
OLED_ShowString(1, 1, "Freq:00000Hz");
PWM_SetPrescaler(720 - 1); //PWM频率Freq = 72M / (PSC + 1) / 100
PWM_SetCompare1(50); //PWM占空比Duty = CCR / 100
while (1)
{
OLED_ShowNum(1, 6, IC_GetFreq(), 5); //不断刷新显示输入捕获测得的频率
}
}