STM32自学笔记2-中断和定时器
一、中断1、NVICNVIC 即嵌套向量中断控制器使用步骤1、设置中断分组AIRCR寄存器10:8;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_x); //NVIC_PriorityGroup_1~NVIC_PriorityGroup_42、设置中断优先级IPR寄存器7:4NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel XXX_IRQn; // 中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; // 抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority 2; // 响应子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; // 使能 NVIC_Init(NVIC_InitStructure);3、使能中断ISER寄存器//上面NVIC_Init(NVIC_InitStructure);已完成使能 NVIC_EnableIRQ(XXX_IRQn);中断向量表2、外部中断AFIOEXTI线路说明EXTI 线 0~15对应外部IO 口的输入中断EXTI 线 16连接PVD输出EXTI 线17连接到RTC闹钟事件EXTI 线 18连接到USB唤醒事件EXTI 线19连接到以太网唤醒事件联网型芯片int16_t Encoder_Count; //全局变量用于计数旋转编码器的增量值 /** * 函 数旋转编码器初始化 * 参 数无 * 返 回 值无 */ void Encoder_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟外部中断必须开启AFIO的时钟 /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); //将PB0和PB1引脚初始化为上拉输入 /*AFIO选择中断引脚*/ GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//将外部中断的0号线映射到GPIOB即选择PB0为外部中断引脚 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//将外部中断的1号线映射到GPIOB即选择PB1为外部中断引脚 /*EXTI初始化*/ EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量 EXTI_InitStructure.EXTI_Line EXTI_Line0 | EXTI_Line1; //选择配置外部中断的0号线和1号线 EXTI_InitStructure.EXTI_LineCmd ENABLE; //指定外部中断线使能 EXTI_InitStructure.EXTI_Mode EXTI_Mode_Interrupt; //指定外部中断线为中断模式 EXTI_InitStructure.EXTI_Trigger EXTI_Trigger_Falling; //指定外部中断线为下降沿触发 EXTI_Init(EXTI_InitStructure); //将结构体变量交给EXTI_Init配置EXTI外设 /*NVIC中断分组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2 //即抢占优先级范围0~3响应优先级范围0~3 //此分组配置在整个工程中仅需调用一次 //若有多个中断可以把此代码放在main函数内while循环之前 //若调用多次配置分组的代码则后执行的配置会覆盖先执行的配置 /*NVIC配置*/ NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量 NVIC_InitStructure.NVIC_IRQChannel EXTI0_IRQn; //选择配置NVIC的EXTI0线 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //指定NVIC线路使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; //指定NVIC线路的抢占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; //指定NVIC线路的响应优先级为1 NVIC_Init(NVIC_InitStructure); //将结构体变量交给NVIC_Init配置NVIC外设 NVIC_InitStructure.NVIC_IRQChannel EXTI1_IRQn; //选择配置NVIC的EXTI1线 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //指定NVIC线路使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; //指定NVIC线路的抢占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority 2; //指定NVIC线路的响应优先级为2 NVIC_Init(NVIC_InitStructure); //将结构体变量交给NVIC_Init配置NVIC外设 } /** * 函 数旋转编码器获取增量值 * 参 数无 * 返 回 值自上此调用此函数后旋转编码器的增量值 */ int16_t Encoder_Get(void) { /*使用Temp变量作为中继目的是返回Encoder_Count后将其清零*/ /*在这里也可以直接返回Encoder_Count 但这样就不是获取增量值的操作方法了 也可以实现功能只是思路不一样*/ int16_t Temp; Temp Encoder_Count; Encoder_Count 0; return Temp; } /** * 函 数EXTI0外部中断函数 * 参 数无 * 返 回 值无 * 注意事项此函数为中断函数无需调用中断触发后自动执行 * 函数名为预留的指定名称可以从启动文件复制 * 请确保函数名正确不能有任何差异否则中断函数将不能进入 */ void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) SET) //判断是否是外部中断0号线触发的中断 { /*如果出现数据乱跳的现象可再次判断引脚电平以避免抖动*/ if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) 0) { if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0) //PB0的下降沿触发中断此时检测另一相PB1的电平目的是判断旋转方向 { Encoder_Count --; //此方向定义为反转计数变量自减 } } EXTI_ClearITPendingBit(EXTI_Line0); //清除外部中断0号线的中断标志位 //中断标志位必须清除 //否则中断将连续不断地触发导致主程序卡死 } } /** * 函 数EXTI1外部中断函数 * 参 数无 * 返 回 值无 * 注意事项此函数为中断函数无需调用中断触发后自动执行 * 函数名为预留的指定名称可以从启动文件复制 * 请确保函数名正确不能有任何差异否则中断函数将不能进入 */ void EXTI1_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line1) SET) //判断是否是外部中断1号线触发的中断 { /*如果出现数据乱跳的现象可再次判断引脚电平以避免抖动*/ if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0) { if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) 0) //PB1的下降沿触发中断此时检测另一相PB0的电平目的是判断旋转方向 { Encoder_Count ; //此方向定义为正转计数变量自增 } } EXTI_ClearITPendingBit(EXTI_Line1); //清除外部中断1号线的中断标志位 //中断标志位必须清除 //否则中断将连续不断地触发导致主程序卡死 } }3、定时器对于定时器最基本的是CNT计数到ARR值时触发中断事件由此拓展出两个功能--输入捕获/输出比较。输出比较OC即是在计数过程中设一个“闹钟”。比如他走到500时硬件自动把某个引脚拉高或拉低。重点这是定时器主动控制外部到了设定时刻就改变电平常用于生成特定时序。PWM脉宽调制是输出比较最经典的应用。固定电平翻转时间--控制led亮度让电平翻转时间不断变化--呼吸灯。输入捕获IC角色完全反转是外部控制定时器。相当于在外部电平输入过程中设一个“照相机”。当外部引脚发生跳变比如按键按下相机瞬间拍下快递员当前的位置计数值。重点这是外部事件触发定时器记录用来测量外部信号的周期或脉宽。配置定时器包括设置预分频器Prescaler和自动重装载寄存器Auto-reload Register。预分频器用于降低定时器的时钟频率而自动重装载寄存器决定了计数器的最大值。预分频器 (PSC - Prescaler)作用将高频的系统时钟如 72MHz进行降频。原理如果 PSC 设为 71那么输入时钟会被 72 分频输出给计数器(系统频率为72MHZ)的频率就是 1MHz即每秒跳变 1,000,000 次每 1μs 计一次数。计数器 (CNT - Counter)作用它是真正负责“数数”的寄存器。过程在驱动时钟的每一个脉冲到来时CNT 的值就会1向上计数模式有三种计数模式向上计数向下计数中央对齐计数先向上数到ARR再向下数到0循环往复。自动重装寄存器 (ARR - Auto-Reload Register)作用设定一个“终点值”。原理当 CNT 增加到和 ARR 相等时就会产生一个“更新事件”同时 CNT 会清零重新开始计数。TIM中断#include stm32f10x.h // Device header /** * 函 数定时中断初始化 * 参 数无 * 返 回 值无 * 注意事项此函数配置为外部时钟定时器相当于计数器 */ void Timer_Init(void) { /*开启时钟*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*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); //将PA0引脚初始化为上拉输入 //TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟若不调用此函数TIM默认也为内部时钟 /*外部时钟配置*/ TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F); //选择外部时钟模式2时钟从TIM_ETR引脚输入 //注意TIM2的ETR引脚固定为PA0无法随意更改 //最后一个滤波器参数加到最大0x0F可滤除时钟信号抖动 /*时基单元初始化*/ 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的值 TIM_TimeBaseInitStructure.TIM_Prescaler 1 - 1; //预分频器即PSC的值 TIM_TimeBaseInitStructure.TIM_RepetitionCounter 0; //重复计数器高级定时器才会用到 TIM_TimeBaseInit(TIM2, TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit配置TIM2的时基单元 /*中断输出配置*/ TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定时器更新标志位 //TIM_TimeBaseInit函数末尾手动产生了更新事件 //若不清除此标志位则开启中断后会立刻进入一次中断 //如果不介意此问题则不清除此标志位也可 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断 /*NVIC中断分组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2 //即抢占优先级范围0~3响应优先级范围0~3 //此分组配置在整个工程中仅需调用一次 //若有多个中断可以把此代码放在main函数内while循环之前 //若调用多次配置分组的代码则后执行的配置会覆盖先执行的配置 /*NVIC配置*/ NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量 NVIC_InitStructure.NVIC_IRQChannel TIM2_IRQn; //选择配置NVIC的TIM2线 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //指定NVIC线路使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 2; //指定NVIC线路的抢占优先级为2 NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; //指定NVIC线路的响应优先级为1 NVIC_Init(NVIC_InitStructure); //将结构体变量交给NVIC_Init配置NVIC外设 /*TIM使能*/ TIM_Cmd(TIM2, ENABLE); //使能TIM2定时器开始运行 } /** * 函 数返回定时器CNT的值 * 参 数无 * 返 回 值定时器CNT的值范围0~65535 */ uint16_t Timer_GetCounter(void) { return TIM_GetCounter(TIM2); //返回定时器TIM2的CNT } /* 定时器中断函数可以复制到使用它的地方 void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) SET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } */输出比较模式输出PWMPWM 就是输出比较模式的一种通常是模式1或2。普通输出比较快递员跑到设定值引脚翻转一次就结束了除非你下次手动改。PWM模式快递员自动循环跑向上计数再向下计数或自动清零。硬件会在“比较值”处自动翻转引脚你只需改比较值CCR占空比就变了无需软件干预。ARR寄存器决定PWM周期CCR寄存器决定占空比#include stm32f10x.h // Device header /** * 函 数PWM初始化 * 参 数无 * 返 回 值无 */ void PWM_Init(void) { /*开启时钟*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*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); //将PA1引脚初始化为复用推挽输出 //受外设控制的引脚均需要配置为复用模式 /*配置时钟源*/ TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟若不调用此函数TIM默认也为内部时钟 /*时基单元初始化*/ 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的值 TIM_TimeBaseInitStructure.TIM_Prescaler 72 - 1; //预分频器即PSC的值 TIM_TimeBaseInitStructure.TIM_RepetitionCounter 0; //重复计数器高级定时器才会用到 TIM_TimeBaseInit(TIM2, TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit配置TIM2的时基单元 /*输出比较初始化*/ TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量 TIM_OCStructInit(TIM_OCInitStructure); //结构体初始化若结构体没有完整赋值 //则最好执行此函数给结构体所有成员都赋一个默认值 //避免结构体初值不确定的问题 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //输出比较模式选择PWM模式1 TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //输出极性选择为高若选择极性为低则输出高低电平取反 TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //输出使能 TIM_OCInitStructure.TIM_Pulse 0; //初始的CCR值 TIM_OC2Init(TIM2, TIM_OCInitStructure); //将结构体变量交给TIM_OC2Init配置TIM2的输出比较通道2 /*TIM使能*/ TIM_Cmd(TIM2, ENABLE); //使能TIM2定时器开始运行 } /** * 函 数PWM设置CCR * 参 数Compare 要写入的CCR的值范围0~100 * 返 回 值无 * 注意事项CCR和ARR共同决定占空比此函数仅设置CCR的值并不直接是占空比 * 占空比Duty CCR / (ARR 1) */ void PWM_SetCompare2(uint16_t Compare) { TIM_SetCompare2(TIM2, Compare); //设置CCR2的值 }输入捕获假设你要测一个高电平的持续时间配置把捕获通道设为“上升沿触发”。动作上升沿到来时硬件立刻把当前计数值锁存到捕获寄存器CCR并触发中断。你在中断里读取这个值记作t1。再配置改为“下降沿触发”。动作下降沿到来时硬件再次锁存计数值记作t2。结果高电平时间 (t2 - t1) * 时钟周期。整个过程不需要你用GPIO去读电平全是硬件自动完成。测频率#include stm32f10x.h // Device header /** * 函 数输入捕获初始化 * 参 数无 * 返 回 值无 */ void IC_Init(void) { /*开启时钟*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); //将PA6引脚初始化为上拉输入 /*配置时钟源*/ TIM_InternalClockConfig(TIM3); //选择TIM3为内部时钟若不调用此函数TIM默认也为内部时钟 /*时基单元初始化*/ 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 72 - 1; //预分频器即PSC的值 TIM_TimeBaseInitStructure.TIM_RepetitionCounter 0; //重复计数器高级定时器才会用到 TIM_TimeBaseInit(TIM3, TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit配置TIM3的时基单元 /*输入捕获初始化*/ TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量 TIM_ICInitStructure.TIM_Channel TIM_Channel_1; //选择配置定时器通道1 TIM_ICInitStructure.TIM_ICFilter 0xF; //输入滤波器参数可以过滤信号抖动 TIM_ICInitStructure.TIM_ICPolarity TIM_ICPolarity_Rising; //极性选择为上升沿触发捕获 TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1; //捕获预分频选择不分频每次信号都触发捕获 TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI; //输入信号交叉选择直通不交叉 TIM_ICInit(TIM3, TIM_ICInitStructure); //将结构体变量交给TIM_ICInit配置TIM3的输入捕获通道 /*选择触发源及从模式*/ TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1 TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位 //即TI1产生上升沿时会触发CNT归零 /*TIM使能*/ TIM_Cmd(TIM3, ENABLE); //使能TIM3定时器开始运行 } /** * 函 数获取输入捕获的频率 * 参 数无 * 返 回 值捕获得到的频率 */ uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) 1); //测周法得到频率fx fc / N这里不执行1的操作也可 }PWMI模式测频率占空比通道1TI1FP1保持你的配置 →上升沿捕获→ 存入CCR1通道2TI1FP2自动配置为 →下降沿捕获→ 存入CCR2#include stm32f10x.h // Device header /** * 函 数输入捕获初始化 * 参 数无 * 返 回 值无 */ void IC_Init(void) { /*开启时钟*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); //将PA6引脚初始化为上拉输入 /*配置时钟源*/ TIM_InternalClockConfig(TIM3); //选择TIM3为内部时钟若不调用此函数TIM默认也为内部时钟 /*时基单元初始化*/ 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 72 - 1; //预分频器即PSC的值 TIM_TimeBaseInitStructure.TIM_RepetitionCounter 0; //重复计数器高级定时器才会用到 TIM_TimeBaseInit(TIM3, TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit配置TIM3的时基单元 /*PWMI模式初始化*/ TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量 TIM_ICInitStructure.TIM_Channel TIM_Channel_1; //选择配置定时器通道1 TIM_ICInitStructure.TIM_ICFilter 0xF; //输入滤波器参数可以过滤信号抖动 TIM_ICInitStructure.TIM_ICPolarity TIM_ICPolarity_Rising; //极性选择为上升沿触发捕获 TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1; //捕获预分频选择不分频每次信号都触发捕获 TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI; //输入信号交叉选择直通不交叉 TIM_PWMIConfig(TIM3, TIM_ICInitStructure); //将结构体变量交给TIM_PWMIConfig配置TIM3的输入捕获通道 //此函数同时会把另一个通道配置为相反的配置实现PWMI模式 /*选择触发源及从模式*/ TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1 TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位 //即TI1产生上升沿时会触发CNT归零 /*TIM使能*/ TIM_Cmd(TIM3, ENABLE); //使能TIM3定时器开始运行 } /** * 函 数获取输入捕获的频率 * 参 数无 * 返 回 值捕获得到的频率 */ uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) 1); //测周法得到频率fx fc / N这里不执行1的操作也可 } /** * 函 数获取输入捕获的占空比 * 参 数无 * 返 回 值捕获得到的占空比 */ uint32_t IC_GetDuty(void) { return (TIM_GetCapture2(TIM3) 1) * 100 / (TIM_GetCapture1(TIM3) 1); //占空比Duty CCR2 / CCR1 * 100这里不执行1的操作也可 }编码器计数#include stm32f10x.h // Device header /** * 函 数编码器初始化 * 参 数无 * 返 回 值无 */ void Encoder_Init(void) { /*开启时钟*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); //将PA6和PA7引脚初始化为上拉输入 /*时基单元初始化*/ 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_TimeBaseInit配置TIM3的时基单元 /*输入捕获初始化*/ TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量 TIM_ICStructInit(TIM_ICInitStructure); //结构体初始化若结构体没有完整赋值 //则最好执行此函数给结构体所有成员都赋一个默认值 //避免结构体初值不确定的问题 TIM_ICInitStructure.TIM_Channel TIM_Channel_1; //选择配置定时器通道1 TIM_ICInitStructure.TIM_ICFilter 0xF; //输入滤波器参数可以过滤信号抖动 TIM_ICInit(TIM3, TIM_ICInitStructure); //将结构体变量交给TIM_ICInit配置TIM3的输入捕获通道 TIM_ICInitStructure.TIM_Channel TIM_Channel_2; //选择配置定时器通道2 TIM_ICInitStructure.TIM_ICFilter 0xF; //输入滤波器参数可以过滤信号抖动 TIM_ICInit(TIM3, TIM_ICInitStructure); //将结构体变量交给TIM_ICInit配置TIM3的输入捕获通道 /*编码器接口配置*/ TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //配置编码器模式以及两个输入通道是否反相 //注意此时参数的Rising和Falling已经不代表上升沿和下降沿了而是代表是否反相 //此函数必须在输入捕获初始化之后进行否则输入捕获的配置会覆盖此函数的部分配置 /*TIM使能*/ TIM_Cmd(TIM3, ENABLE); //使能TIM3定时器开始运行 } /** * 函 数获取编码器的增量值 * 参 数无 * 返 回 值自上此调用此函数后编码器的增量值 */ int16_t Encoder_Get(void) { /*使用Temp变量作为中继目的是返回CNT后将其清零*/ int16_t Temp; Temp TIM_GetCounter(TIM3); TIM_SetCounter(TIM3, 0); return Temp; }