目录
TIM
定时器定时中断
定时器外部时钟
PWM驱动LED呼吸灯(OC)
PWM控制舵机
PWMA驱动直流电机
输入捕获模式测频率(IC)
输入捕获模式测占空比
编码器接口测速(编码器接口)
通用定时器
高级定时器
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即1Hz
TIM_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
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组
//选择分组2
NVIC_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);//初始化NVIC
TIM_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配置(选择配置时钟,预分频器,选择上升/下降有效,滤波器工作模式)
//在此之前还需要配置GPIO
TIM_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即1Hz
TIM_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
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组
//选择分组2
NVIC_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);//初始化NVIC
TIM_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.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 = 1s
TIM_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.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()初始化GPIO
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 = 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 = 1s
TIM_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);
}
}
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()初始化GPIO
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 = 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 = 1s
TIM_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);
}
}
注意:这里尽量不要满速,跑一下,香味就出来了
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 = 1s
TIM_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^6
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//第二步:使用GPIO_Init()初始化GPIO
RCC_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 ;//配置通道1
IC_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);//配置TRGI
TIM_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^6
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//第二步:使用GPIO_Init()初始化GPIO
RCC_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 ;//配置通道1
IC_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);//配置TRGI
TIM_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;//ARR
TIM_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即1Hz
TIM_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
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组
//选择分组2
NVIC_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);//初始化NVIC
TIM_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);//清除中断标志位
}
}