STM32 定时器

目录

TIM

定时器定时中断

定时器外部时钟

PWM驱动LED呼吸灯(OC)

PWM控制舵机

PWMA驱动直流电机

输入捕获模式测频率(IC)

输入捕获模式测占空比

编码器接口测速(编码器接口)


TIM

通用定时器

高级定时器

定时器定时中断

Timer.c

#include "stm32f10x.h"                  // Device header//extern uint16_t Num;  //使用extern声明外部变量(如果要在文件中使用其他文件中的变量)/*** @brief  定时器中断初始化* @param  无* @retval 无*/
void Timer_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启RCC时钟//TIM2是APB1总线的外设TIM_InternalClockConfig(TIM2);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//设置周期,即ARR重装值,(0-65535)//72000000/10000/7200 = 1s即1HzTIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元//在TIM_TimeBaseInit函数中,由缓冲寄存器,只有在更新事件时,//才会真正起作用,为了让值立刻起作用,手动生成了一个更新事件,//此时更新事件以及更新中断是同时发生的,更新中断会将置位标志位,故会进入中断进行中断中的操作TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除中断标志位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断输出信号//更新中断到NVIC//配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组//选择分组2NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//配置中断通道//TIM2在NVIC的通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级NVIC_Init(&NVIC_InitStructure);//初始化NVICTIM_Cmd(TIM2,ENABLE);//启动定时器
}/*TIM2中断函数模板
void TIM2_IRQHandler(void)
{if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位{Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断待处理 位}
}
*/

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"uint16_t Num;int main(void)
{OLED_Init();Timer_Init();OLED_ShowString(1,1,"Num:");while(1){OLED_ShowNum(1,5,Num,5);}}/*** @brief  TIM2的中断函数* @param  无* @retval 无*/
void TIM2_IRQHandler()
{if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位{Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位}
}
定时器外部时钟

Timer.c

#include "stm32f10x.h"                  // Device header//extern uint16_t Num;  //使用extern声明外部变量(如果要在文件中使用其他文件中的变量)/*** @brief  定时器外部时钟中断初始化* @param  无* @retval 无*/
void Timer_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启TIM2时钟//TIM2是APB1总线的外设RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//这里使用上拉输入//手册推荐浮空输入当外部输入信号功率很小,内部上拉电阻可能会影响输入信号,防止影响外部输入的电平可以使用GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x05);//通过ETR引脚的外部时钟模式2配置(选择配置时钟,预分频器,选择上升/下降有效,滤波器工作模式)//在此之前还需要配置GPIOTIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//设置周期,即ARR重装值,(0-65535)//72000000/10000/7200 = 1s即1HzTIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元//在TIM_TimeBaseInit函数中,由缓冲寄存器,只有在更新事件时,//才会真正起作用,为了让值立刻起作用,手动生成了一个更新事件,//此时更新事件以及更新中断是同时发生的,更新中断会将置位标志位,故会进入中断进行中断中的操作TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除中断标志位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断输出信号//更新中断到NVIC//配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组//选择分组2NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//配置中断通道//TIM2在NVIC的通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级NVIC_Init(&NVIC_InitStructure);//初始化NVICTIM_Cmd(TIM2,ENABLE);//启动定时器
}uint16_t Timer_GetCounter(void)
{return TIM_GetCounter(TIM2);
}/*TIM2中断函数模板
void TIM2_IRQHandler(void)
{if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位{Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断待处理 位}
}
*/

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"uint16_t Num;int main(void)
{OLED_Init();Timer_Init();OLED_ShowString(1,1,"Num:");OLED_ShowString(2,1,"CNT:");while(1){OLED_ShowNum(1,5,Num,5);OLED_ShowNum(2,5,Timer_GetCounter(),5);}}/*** @brief  TIM2的中断函数* @param  无* @retval 无*/
void TIM2_IRQHandler()
{if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位{Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位}
}

PWM驱动LED呼吸灯(OC)

PWM.c

#include "stm32f10x.h"                  // Device header/*** @brief  初始化PWM波形* @param  无* @retval 无*/
void PWM_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//第一步:使用RCC开启GPIO时钟GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//重映射到PA^15引脚GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//第二步:使用GPIO_Init()初始化GPIO//端口重映射//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟//GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//设置重映射//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//解除JTAG复用,保留SWD复用RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启RCC时钟//TIM2是APB1总线的外设TIM_InternalClockConfig(TIM2);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;//设置周期,即ARR重装值,(0-65535)TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元TIM_OCInitTypeDef TIM_OCInitstructure;//含有高级定时器参数TIM_OCStructInit(&TIM_OCInitstructure);//为结构体赋初始值TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式TIM_OCInitstructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性TIM_OCInitstructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能TIM_OCInitstructure.TIM_Pulse = 0;//设置CCR//PWM频率 = 72MHz/PSC+1/ARR+1//PWM占空比 = CCR/ARR+1//PWM分辨率 = 1/(ARR+1)//1Hz = 1sTIM_OC1Init(TIM2,&TIM_OCInitstructure);//初始化输出比较单元(PA^0对应TIM_OC1Init)TIM_Cmd(TIM2,ENABLE);//启动定时器
}/*** @brief  设置通道1中CCR的值* @param  被设定的CCR的值 * @retval 无*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2,Compare);}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"uint8_t KeyNum;int main(void)
{OLED_Init();PWM_Init();uint8_t tmp;while(1){for(tmp = 0;tmp <= 100;tmp++){PWM_SetCompare1(tmp);Delay_ms(10);}for(tmp = 0;tmp <= 100;tmp++){PWM_SetCompare1(100 - tmp);Delay_ms(10);}}}
PWM控制舵机

PWM.c

#include "stm32f10x.h"                  // Device header/*** @brief  初始化PWM波形* @param  无* @retval 无*/
void PWM_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//第一步:使用RCC开启GPIO时钟GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//第二步:使用GPIO_Init()初始化GPIORCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启RCC时钟//TIM2是APB1总线的外设TIM_InternalClockConfig(TIM2);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;//设置周期,即ARR重装值,(0-65535)TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;//这里可以得出频率为50Hz,//周期为0.02s,已知需要高电平0.5ms~2.5ms,周期X占空比=0.5ms,占空比为0.025//那么CCR = 500 ~ 2500//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元TIM_OCInitTypeDef TIM_OCInitstructure;//含有高级定时器参数TIM_OCStructInit(&TIM_OCInitstructure);//为结构体赋初始值TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式TIM_OCInitstructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性TIM_OCInitstructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能TIM_OCInitstructure.TIM_Pulse = 0;//设置CCR//PWM频率 = 72MHz/PSC+1/ARR+1//PWM占空比 = CCR/ARR+1//PWM分辨率 = 1/(ARR+1)//1Hz = 1sTIM_OC2Init(TIM2,&TIM_OCInitstructure);//初始化输出比较单元(PA^1对应TIM_OC2Init,见引脚定义表)TIM_Cmd(TIM2,ENABLE);//启动定时器
}/*** @brief  设置通道2中CCR的值* @param  被设定的CCR的值 * @retval 无*/
void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM2,Compare);}

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"/*** @brief  初始化PWM* @param  无* @retval 无*/
void Servo_Init(void)
{PWM_Init(); 
}/*** @brief  设置转动角度* @param  Angle 转动角度* @retval 无*/
void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);//0   500;180    2500
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"uint8_t KeyNum;
float Angle;int main(void)
{OLED_Init();Servo_Init();Key_Init();OLED_ShowString(1,1,"Angle:");while(1){KeyNum = Key_GetNum();//此前在Key.c中已初始化PB^1故能读出数据if(KeyNum == 1){Angle += 30;if(Angle > 180){Angle = 0;}}Servo_SetAngle(Angle);OLED_ShowNum(2,1,Angle,3);}}
PWMA驱动直流电机

PWM.c

#include "stm32f10x.h"                  // Device header/*** @brief  初始化PWM波形* @param  无* @retval 无*/
void PWM_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//第一步:使用RCC开启GPIO时钟GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//接在PA^3上GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//第二步:使用GPIO_Init()初始化GPIORCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启RCC时钟//TIM2是APB1总线的外设TIM_InternalClockConfig(TIM2);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;//设置周期,即ARR重装值,(0-65535)TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元TIM_OCInitTypeDef TIM_OCInitstructure;//含有高级定时器参数TIM_OCStructInit(&TIM_OCInitstructure);//为结构体赋初始值TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式TIM_OCInitstructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性TIM_OCInitstructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能TIM_OCInitstructure.TIM_Pulse = 0;//设置CCR//PWM频率 = 72MHz/PSC+1/ARR+1//PWM占空比 = CCR/ARR+1//PWM分辨率 = 1/(ARR+1)//1Hz = 1sTIM_OC3Init(TIM2,&TIM_OCInitstructure);//初始化输出比较单元(PA^2对应TIM_3C1Init)TIM_Cmd(TIM2,ENABLE);//启动定时器
}/*** @brief  设置通道1中CCR的值* @param  被设定的CCR的值 * @retval 无*/
void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2,Compare);}

Motor.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"/*** @brief  初始化电机方向控制脚以及PMW* @param  无* @retval 无*/
void Motor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//第一步:使用RCC开启GPIO时钟GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//第二步:初始化电机方向控制脚PWM_Init();
}/**
* @brief  设置电机运行速度,为负时为反转* @param  Speed   电机运行速度* @retval 无*/
void Motor_SetSpeed(int8_t Speed)
{if(Speed >= 0)//正转 {GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(Speed);}else{//反转GPIO_SetBits(GPIOA,GPIO_Pin_5);GPIO_ResetBits(GPIOA,GPIO_Pin_4);PWM_SetCompare3(-Speed);}
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"uint8_t KeyNum;
int8_t Speed;int main(void)
{OLED_Init();Motor_Init();Key_Init();OLED_ShowString(1,1,"Speed:");while(1){KeyNum = Key_GetNum();if(KeyNum == 1){Speed += 20;if(Speed > 60){Speed = -60;}}Motor_SetSpeed(Speed);OLED_ShowSignedNum(2,1,Speed,3);}}

注意:这里尽量不要满速,跑一下,香味就出来了

输入捕获模式测频率(IC)

PWM.c

#include "stm32f10x.h"                  // Device header/*** @brief  初始化PWM波形* @param  无* @retval 无*/
void PWM_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//第一步:使用RCC开启GPIO时钟GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//重映射到PA^15引脚GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//第二步:使用GPIO_Init()初始化GPIO//端口重映射//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟//GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//设置重映射//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//解除JTAG复用,保留SWD复用RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启RCC时钟//TIM2是APB1总线的外设TIM_InternalClockConfig(TIM2);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;//设置周期,即ARR重装值,(0-65535)TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元TIM_OCInitTypeDef TIM_OCInitstructure;//含有高级定时器参数TIM_OCStructInit(&TIM_OCInitstructure);//为结构体赋初始值TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式TIM_OCInitstructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性TIM_OCInitstructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能TIM_OCInitstructure.TIM_Pulse = 0;//设置CCR//PWM频率 = 72MHz/PSC+1/ARR+1//PWM占空比 = CCR/ARR+1//PWM分辨率 = 1/(ARR+1)//1Hz = 1sTIM_OC1Init(TIM2,&TIM_OCInitstructure);//初始化输出比较单元(PA^0对应TIM_OC1Init)TIM_Cmd(TIM2,ENABLE);//启动定时器
}/*** @brief  设置通道1中CCR的值(占空比)* @param  被设定的CCR的值 * @retval 无*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2,Compare);
}/*** @brief  写入PSC数值(修改频率)* @param  被设定的PSC数值* @retval 无*/
void PWM_SetPrescaler(uint16_t Prescaler)
{TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);//所使用定时器,设定数值,立刻重装载模式
}

IC.c

#include "stm32f10x.h"                  // Device header/*** @brief  输入捕获初始化* @param  无* @retval 无*/
void IC_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//第一步:使用RCC开启GPIO时钟GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//使用TIM3通道1查表为PA^6GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//第二步:使用GPIO_Init()初始化GPIORCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启RCC时钟//TIM3是APB1总线的外设(因为TIM2要放出被测的PWM)TIM_InternalClockConfig(TIM3);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//设置周期,即ARR重装值,(0-65535)TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//配置时基单元TIM_ICInitTypeDef IC_InitStructure;IC_InitStructure.TIM_Channel = TIM_Channel_1 ;//配置通道1IC_InitStructure.TIM_ICFilter = 0xF ;//配置输入捕获滤波器IC_InitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising ;//配置极性(上升沿触发)IC_InitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1 ;//配置触发信号分频器(不分频)IC_InitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI ;//配置数据选择器(直连)TIM_ICInit(TIM3,&IC_InitStructure);TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//配置TRGITIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//配置从模式TIM_Cmd(TIM3,ENABLE);//启动定时器
}uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1); //1M是当前TIM3频率//待测PWM的频率为1000Hz,
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1,1,"Freq:00000Hz");PWM_SetPrescaler(720 - 1);//设置PSC   Freq = 72MHz / (PSC + 1) / (ARR + 1)PWM_SetCompare1(50);//设置CCR  Duty(占空比) =  CCR / (ARR + 1)while(1){OLED_ShowNum(1,6,IC_GetFreq(),5);}}

输入捕获模式测占空比

IC.c

#include "stm32f10x.h"                  // Device header/*** @brief  输入捕获初始化* @param  无* @retval 无*/
void IC_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//第一步:使用RCC开启GPIO时钟GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//使用TIM3通道1查表为PA^6GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//第二步:使用GPIO_Init()初始化GPIORCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启RCC时钟//TIM3是APB1总线的外设(因为TIM2要放出被测的PWM)TIM_InternalClockConfig(TIM3);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//初始化时基单元TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//设置周期,即ARR重装值,(0-65535)TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//配置时基单元TIM_ICInitTypeDef IC_InitStructure;IC_InitStructure.TIM_Channel = TIM_Channel_1 ;//配置通道1IC_InitStructure.TIM_ICFilter = 0xF ;//配置输入捕获滤波器IC_InitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising ;//配置极性(上升沿触发)IC_InitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1 ;//配置触发信号分频器(不分频)IC_InitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI ;//配置数据选择器(直连)//TIM_ICInit(TIM3,&IC_InitStructure);TIM_PWMIConfig(TIM3,&IC_InitStructure);//会自动把剩下的一个通道(1或2)初始化成相反的配置TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//配置TRGITIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//配置从模式TIM_Cmd(TIM3,ENABLE);//启动定时器
}/*** @brief  获取频率* @param  无* @retval 返回被测端口频率*/
uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1); //1M是当前TIM3频率//待测PWM的频率为1000Hz,
}/*** @brief  获取占空比* @param  无* @retval 返回被测端口占空比*/
uint32_t IC_GetDuty(void)
{return (TIM_GetCapture2(TIM3)+1) * 100 / (TIM_GetCapture1(TIM3) + 1);//通道二存储有效电平计次,通道一存储整个周期计次
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1,1,"Freq:00000Hz");OLED_ShowString(2,1,"Duty:000%");PWM_SetPrescaler(7200 - 1);//设置PSC   Freq = 72MHz / (PSC + 1) / (ARR + 1)PWM_SetCompare1(80);//设置CCR  Duty(占空比) =  CCR / (ARR + 1)while(1){OLED_ShowNum(1,6,IC_GetFreq(),5);OLED_ShowNum(2,6,IC_GetDuty(),3);}}

编码器接口测速(编码器接口)

Ecoder.c

#include "stm32f10x.h"                  // Device header/*** @brief  对GPIO,时基单元,TIM捕获配置以及定时器编码器接口进行初始化* @param  无* @retval 无*/
void Encoder_Init(void)
{//打开各自RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//GPIO配置GPIO_InitTypeDef GPIO_InitStructrue;GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_IPU ;//设置上拉输入//如果外部空闲模块默认输出高电平,就选择上拉输入,默认输入高电平//如果外部空闲模块默认输出低电平,就选择下拉输入,默认输入低电平//和外部模块保持状态一致,防止默认电平打架。//如果不确定外部模块输出的默认状态或外部信号输出功率非常小,这时候选择浮空输入//浮空输入:没有上拉电阻和下拉电阻去影响外部信号,但缺点是当引脚悬空时,//没有默认的电平了,输入就会收噪声干扰,来回不断的跳变GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 ;GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz ;GPIO_Init(GPIOA,&GPIO_InitStructrue);//时基单元配置TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1 ;//PSC(不进行分频)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//输入捕获配置TIM_ICInitTypeDef  TIM_ICInitStructure;TIM_ICStructInit(&TIM_ICInitStructure);//为结构体赋初始值TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 ;TIM_ICInitStructure.TIM_ICFilter = 0xf;//TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//这里的极性选择不代表上升沿有效,这里代表的是高低电平极性不翻转(也就是TI1与TI2是否反向)//上升沿不反向,下降沿反向TIM_ICInit(TIM3,&TIM_ICInitStructure);TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;TIM_ICInitStructure.TIM_ICFilter = 0xf;//TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//这里的极性选择不代表上升沿有效,这里代表的是高低电平极性不翻转(也就是TI1与TI2是否反向)//上升沿不反向,下降沿反向(后面编码器接口会进行重复配置)TIM_ICInit(TIM3,&TIM_ICInitStructure);//配置编码器接口TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);TIM_Cmd(TIM3,ENABLE);//启动定时器
}/*** @brief  返回TIM3在1s的时间下CNT的值* @param  无* @retval 无*/
int16_t Encoder_Get(void)
{int16_t tmp;tmp = TIM_GetCounter(TIM3);TIM_SetCounter(TIM3,0);//读取cnt并将其置零,用于测频法测频率以及测速return tmp;
}

Timer.c

#include "stm32f10x.h"                  // Device header//extern uint16_t Num;  //使用extern声明外部变量(如果要在文件中使用其他文件中的变量)/*** @brief  定时器中断初始化* @param  无* @retval 无*/
void Timer_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启RCC时钟//TIM2是APB1总线的外设TIM_InternalClockConfig(TIM2);//选择时基单元时钟//TIM2的时基单元就由内部时钟来驱动(定时器上电默认使用内部时钟)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision =  TIM_CKD_DIV1;//设置时钟分频,选择一分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//设置周期,即ARR重装值,(0-65535)//72000000/10000/7200 = 1s即1HzTIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//设置预分频器值(psc),(0-65535)TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//配置重复计数器值(高级定时器会用到)TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元//在TIM_TimeBaseInit函数中,由缓冲寄存器,只有在更新事件时,//才会真正起作用,为了让值立刻起作用,手动生成了一个更新事件,//此时更新事件以及更新中断是同时发生的,更新中断会将置位标志位,//故会进入中断进行中断中的操作TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除中断标志位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断输出信号//更新中断到NVIC//配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组//选择分组2NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//配置中断通道//TIM2在NVIC的通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级NVIC_Init(&NVIC_InitStructure);//初始化NVICTIM_Cmd(TIM2,ENABLE);//启动定时器
}/*TIM2中断函数模板
void TIM2_IRQHandler(void)
{if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位{Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断待处理 位}
}
*/

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"int16_t Speed;int main(void)
{OLED_Init();Timer_Init();Encoder_Init();OLED_ShowString(1,1,"Speed:");while(1){OLED_ShowSignedNum(1,7,Speed,5);//Delay_ms(1000);//防止阻塞将其移动至定时器中断进行配置}}/*** @brief  TIM2的中断函数(1s)* @param  无* @retval 无*/
void TIM2_IRQHandler()
{if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位{Speed = Encoder_Get();TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/676669.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot项目热部署实现(Spring Boot DevTools方式)

文章目录 Spring Boot DevTools简介Spring Boot DevTools原理spring Boot Devtools优缺点Spring Boot DevTools集成步骤第一步&#xff1a;添加maven依赖第二步&#xff1a;IDEA热部署配置 Spring Boot DevTools简介 Spring Boot DevTools是Spring Boot提供的一个开发工具&…

Vue事件中如何使用 event 对象

在Vue中&#xff0c;事件处理函数常常需要获取事件触发时的相关信息&#xff0c;比如鼠标位置、按键信息等。而要获取这些信息&#xff0c;就需要使用event对象。那么在Vue的事件中如何正确使用event对象呢&#xff1f;接下来就来详细介绍一下。 首先&#xff0c;在Vue的事件中…

JSP编程

JSP编程 您需要理解在JSP API的类和接口中定义的用于创建JSP应用程序的各种方法的用法。此外,还要了解各种JSP组件,如在前一部分中学习的JSP动作、JSP指令及JSP脚本。JSP API中定义的类提供了可借助隐式对象通过JSP页面访问的方法。 1. JSP API的类 JSP API是一个可用于创建…

专业145+总分400+合肥工业大学833信号分析与处理综合考研经验电子信息通信,真题,大纲,参考书

今年专业课145总分400&#xff0c;我总结一下自己的专业课合肥工业大学833信号分析与处理和其他几门的复习经验。希望对大家复习有帮助。 我所用的教材是郑君里的《信号与系统》&#xff08;第三版&#xff09;和高西全、丁玉美的《数字信号处理》&#xff08;第四版&#xff…

堆排序----C语言数据结构

目录 引言 堆排序的实现**堆的向下调整算法** 对排序的时间复杂度建堆的时间复杂度&#xff1a;排序过程的时间复杂度&#xff1a;总体时间复杂度&#xff1a; 引言 堆排序&#xff08;Heap Sort&#xff09;是一种基于比较的排序算法&#xff0c;利用堆的数据结构来实现。它的…

备战蓝桥杯---动态规划之背包问题引入

先看一个背包问题的简单版&#xff1a; 如果我们暴力枚举可能会超时。 但我们想一想&#xff0c;我们其实不关心怎么放&#xff0c;我们关心的是放后剩下的体积。 用可行性描述即可。 于是我们令f[i][j]表示前i个物品能否放满体积为j的背包。 f[i][j]f[i-1][j]||f[i-1][j-v…

C++ 内存管理(newdelete)

目录 本节目标 1. C/C内存分布 2. C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free 3. C内存管理方式 3.1 new/delete操作内置类型 3.2 new和delete操作自定义类型 4. operator new与operator delete函数 5. new和delete的实现原理 6. 定位new表达式(placem…

【5G NR】【一文读懂系列】移动通讯中使用的信道编解码技术-卷积码原理

目录 一、引言 二、卷积编码的发展历史 2.1 卷积码的起源 2.2 主要发展阶段 2.3 重要里程碑 三、卷积编码的基本概念 3.1 基本定义 3.2 编码器框图 3.3 编码多项式 3.4 网格图(Trellis)描述 四、MATLAB示例 一、引言 卷积编码&#xff0c;作为数字通信领域中的一项…

文心一言 VS 讯飞星火 VS chatgpt (197)-- 算法导论14.3 5题

五、用go语言&#xff0c;对区间树 T 和一个区间 i &#xff0c;请修改有关区间树的过程来支持新的操作 INTERVALSEARCH-EXACTLY(T&#xff0c;i) &#xff0c;它返回一个指向 T 中结点 x 的指针&#xff0c;使得 x.int. lowi.low 且 x.int.high i.high ;或者&#xff0c;如果…

爱奇艺图片格式演进

01 背景 图片是爱奇艺APP页面的主要视觉元素&#xff0c;对整体用户体验有着至关重要的影响。同时&#xff0c;由大量启动带来的图片CDN峰值带宽成本也有待降低。因此&#xff0c;在努力提升用户体验的同时&#xff0c;优化图片CDN峰值带宽成本已成为一项关键任务。而决定图片显…

研究多态恶意软件,探讨网络安全与AI

前言 近期ChatGPT火遍全球&#xff0c;AI技术被应用到了全球各行各业当中&#xff0c;国内外各大厂商也开始推出自己的ChatGPT&#xff0c;笔者所在公司在前段时间也推出了自研的安全GPT&#xff0c;AI技术在网络安全行业得到了很多的应用&#xff0c;不管是网络安全研究人员、…

ElasticSearch之倒排索引

写在前面 本文看下es的倒排索引相关内容。 1&#xff1a;正排索引和倒排索引 正排索引就是通过文档id找文档内容&#xff0c;而倒排索引就是通过文档内容找文档id&#xff0c;如下图&#xff1a; 2&#xff1a;倒排索引原理 假定我们有如下的数据&#xff1a; 为了建立倒…

?你咋知道我的电脑密码的?---> Mimikatz!

还记得昨天在内网中提到了mimikatz这个工具&#xff0c;那么今天就来和大家讲一下这一款牛逼的工具 但是在这里先祝自己和各位看官新年快乐&#xff0c;万事顺遂 &#x1f409;&#x1f432;&#x1f432;&#x1f432;&#x1f432; 1.Mimikatz的介绍 传说呢&#xff0c;是…

学习通考试怎么搜题找答案? #学习方法#微信#其他

大学生必备的做题、搜题神器&#xff0c;收录上万本教材辅助书籍&#xff0c;像什么高数、物理、计算机、外语等都有&#xff0c;资源十分丰富。 1.菜鸟教程 菜鸟教程是一个完全免费的编程学习软件。 它免费提供了HTML / CSS 、JavaScript 、服务端、移动端、XML 教程、http…

开发JSP应用程序

开发JSP应用程序 问题陈述 TecknoSoft Pvt Ltd.公司的首席技术官(CTO)John Barrett将创建一个应用程序的任务委托给了开发团队,该应用程序应在客户访问其账户详细信息前验证其客户ID和密码。客户ID应是数字形式。John希望如果所输入的客户ID或密码不正确,应向客户显示错误…

Stable Diffusion 模型下载:Disney Pixar Cartoon Type A(迪士尼皮克斯动画片A类)

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十 下载地址 模型介绍 目前还没有一个好的皮克斯迪士尼风格的卡通模型&#xff0c;所以我决定自己制作一个。这是将皮克斯风格模型与我自己的Loras合并在一起&#xff0c;创建一个通用的…

endnotesX9 如何批量导入 .enw文件

文章是用schoolar搜出来 点击下载引用之后&#xff0c;endnotesX9只能一个一个从.enw文件导入&#xff0c;麻烦 —————————————— 可以在schoolar保存到个人图书馆 类似于上面这种&#xff0c;我用的是保存&#xff0c;保存很多的论文之后点我的个人图书馆&#x…

【GO语言卵细胞级别教程】03.条件与循环语句

注意&#xff1a;以下演示所用的项目&#xff0c;在第一章节已经介绍了&#xff0c;这里不做赘述 目录&#xff1a; 【GO语言卵细胞级别教程】03.条件与循环语句1.条件语句1.1 if语句1.1.1 单层if语句1.1.2 if-else语句1.1.3 if-else-if 语句1.1.4 if 嵌套 1.2 switch 语句1.1…

使用CICFlowMeter 实现对pcap文件的特征提取【教程】

使用CICFlowMeter 实现对pcap文件的特征提取【教程】 针对现有的关于CICFlowMeter 的使用教程不够全面&#xff0c;一些细节没有展示&#xff0c;我将结合网络上的相关资料和实际的经历&#xff0c;提供一些经验和建议。 configuration information --------------- Windows…

C++入门学习(二十六)for循环

for (初始化; 条件; 递增/递减) { // 代码块 } 打印1~10&#xff1a; #include <iostream> using namespace std; int main() { for (int i 1; i < 10; i) { cout <<i<<endl; } return 0; } 打印九九乘法表&#xff1a; #include <iostream…