interrupt

本文介绍了STM32中的中断系统,包括中断的基本概念、中断优先级和嵌套,以及NVIC的角色和功能。EXTI外部中断部分详细讲解了EXTI的结构、功能和配置。接着,文章讨论了定时器的类型,如基本定时器、通用定时器和高级定时器,并给出了定时中断的配置示例。此外,还涵盖了PWM的原理和应用,以及输入捕获用于频率测量的方法。最后,提到了编码器接口的应用。
摘要由CSDN通过智能技术生成

图片均来自江科大STM32教学PPT

中断

中断简介

中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行

中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
在这里插入图片描述

NVIC的作用

  • 中断优先级管理:NVIC允许为每个中断源设置优先级,以确定中断的相对顺序和优先级。较高优先级的中断可以打断正在执行的较低优先级中断。
  • 中断向量表管理:NVIC维护一个中断向量表,其中存储了每个中断向量的地址。当发生中断时,中断控制器将执行相应中断向量表中存储的中断处理程序。
  • 中断使能和禁用:NVIC允许对不同的中断源进行使能和禁用操作。通过使能或禁用特定中断,可以控制中断是否被触发和处理。
  • 中断嵌套管理:NVIC支持嵌套中断,即在处理一个中断时,允许更高优先级的中断打断当前正在执行的中断处理程序。这种机制确保了高优先级任务的及时响应。

使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级。

NVIC结构
在这里插入图片描述
NVIC优先级分组

  • NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级低4-n位的响应优先级
  • 抢占优先级高的可以中断嵌套响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队

响应优先级类似于插队
抢占优先级可以决定是否可以中断嵌套

在这里插入图片描述

EXTI外部中断

简介

  • EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
  • 支持的触发方式:上升沿/下降沿/双边沿/软件触发
    支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断(像PA1,PB1,PC1这种就不行)
  • 通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
  • 触发响应方式:中断响应(执行中断函数)/事件响应(触发别的外设,比如触发ADC转换,触发DMA)

EXTI基本结构

在这里插入图片描述
AFIO

  • AFIO主要用于引脚复用功能的选择和重定义
  • 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择
  • 数据选择器(中断引脚选择),从16个引脚选择其中一个连到EXTI通道上。所以相同的Pin不能同时触发中断

其他外设:就是触发事件响应

EXTI框图

在这里插入图片描述
输入线:由AFIO选择后,连接到这里。
边沿检测电路:因为中断的触发模式可以是上升沿触发下降沿触发,或者双边沿触发
请求挂起寄存器:相当于中断标志,可以判断是哪个通道触发的中断。
中断/事件屏蔽寄存器:类似于开关的作用,置1,就允许中断,置0,就不允许中断。

需要用到外部中断的情况:STM32获取外部驱动的很快的突发信号。 例如旋转编码器的输出信号,不拧就不需要STM32做事情,一拧就要接收信号。信号是突发的,并且是外部。

EXIT代码示例

根据下图配置EXIT, 从GPIO到NVIC 把出现的外设模块都配置好就可以实现。

  1. 配置RCC时钟,把涉及到的外设时钟都打开(这里就开启GPIO和AFIO,EXTI和NVIC都是一直开启的,不需要我们再开启)。
  2. 配置GPIO,选择输入模式
  3. 配置AFIO,选择中断线路
  4. 配置EXTI
  5. 配置NVIC

在这里插入图片描述

void CountSensor_Init(void)
{
    // 使能GPIOB和AFIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    // 配置GPIO引脚
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // 输入上拉模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;     // 使用GPIOB的引脚14
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 配置AFIO中断线路
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);

    // 配置外部中断
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line14;          // 外部中断线14
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;            // 使能外部中断线
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;  // 中断模式
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发
    EXTI_Init(&EXTI_InitStructure);

    // 配置NVIC中断分组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    // 配置NVIC中断
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;   // 外部中断通道
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        // 使能外部中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;          // 子优先级
    NVIC_Init(&NVIC_InitStructure);
}

中断函数都是固定 参考启动文件,都是无参无返回值

void EXTI15_10_IRQHandler(void)
{
    //  判断是否为14号中断线触发的中断标志位
    if(EXTI_GetITStatus(EXTI_Line14)==SET)
    {
        CountSensor_Count++;
        //  清除中断标志位,防止程序一直申请中断,导致程序卡死
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
}

TIM定时中断

简介

  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器预分频器自动重装寄存器时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择输入捕获输出比较编码器接口主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器通用定时器基本定时器三种类型

定时器类型

在这里插入图片描述

STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4

基本定时器

在这里插入图片描述

  • 基本定时器只能选择内部时钟
  • PSC预分频器连着内部时钟(72MHz),可以对72MHz进行预分频,这个寄存器写0,就是不分频,或者说1分频;如果写1,就是2分频,即 输出频率=输入频率/2=72MHz/2=36MHz 实际分频系数=预分频器的值+1。
  • CNT计数器可以对分频后的计数时钟进行计数。计数时钟每来一个上升沿,计数器加1。仅支持向上计数
  • ARR自动重装载寄存器存储目标值,当CNT的值等于ARR的值,就会产生中断,并且清零CNT。
  • 向上折线箭头表示产生中断信号(更新中断),更新中断后通往NVIC,当我们配置好NVIC定时器通道后,就可以得到CPU的响应;
  • 向下箭头表示会产生一个事件(更新事件),更新事件不会触发中断,但可以触发其他内部电路工作,这里可以把更新事件映射到触发输出(TRGO),TRGO直接接到DAC触发转换引脚,这样就可以通过硬件自动触发,就不需要频繁中断手动触发DAC转换。

TRGO:代表"Trigger Output"(触发输出)。TRGO是一种特殊的输出信号,用于触发或同步外部设备或其他STM32微控制器的操作。TRGO通常与定时器(Timer)相关,特别是与定时器的触发功能(Trigger)有关。定时器可以设置为根据某些事件触发并生成TRGO信号,以便在特定的时间点上发送触发脉冲.TRGO信号可以由定时器的各种事件触发,例如计数器溢出、捕获/比较匹配、外部触发事件等。通过将TRGO信号连接到其他外部设备或其他STM32微控制器的输入引脚,可以实现各种应用,例如同步多个设备的操作或触发复杂的时间序列。

通用定时器

  • CNT可以支持向上计数向下计数中央对齐三种模式。
  • 时钟源不仅可以选择内部时钟,还可以选择外部时钟
    在这里插入图片描述
  • 右下方的是输出比较电路,总共有四个通道,CH1~CH4,可以用于输出PWM波形,驱动电机
  • 左下方的是输入捕获电路,也是四个通道,可以用于测量输入方波的频率等
  • 中间是捕获/比较寄存器,是输入捕获电路和输出比较电路共用寄存器。

高级定时器

  • 重复次数计数器:可以实现每隔几个周期触发一次
  • DTG是死区生成电路
  • 右边引脚由一个变成了两个互补输出,可以输出一对互补的PWM波形(用于驱动三相无刷电机)
  • BRK刹车功能,用于在发生故障的时候切断输出,防止意外发生。
    在这里插入图片描述

定时中断基本结构

在这里插入图片描述

预分频器时序

在这里插入图片描述

  • 计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)

计数器时序

在这里插入图片描述

计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)

RCC时钟树

在这里插入图片描述

定时器中断代码实例

  1. 开启RCC时钟
  2. 选择时基单元的时钟源
  3. 配置时基单元
  4. 使能更新中断
  5. 配置NVIC
  6. 运行控制

在这里插入图片描述
选择内部时钟

void Timer_Init(void)
{

    //	1.使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    //	2.选择内部时钟
    TIM_InternalClockConfig(TIM2);

    //	3.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;  // 定义一个TIM_TimeBaseInitStruct结构体变量,用于配置定时器的基本参数
    // 定时1s就是 72MHz/10000/7200=1s
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;  // 设置时钟分频系数为1,即不分频
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;  // 设置计数器模式为向上计数
    TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;  // [ARR]设置计数器的周期为10000-1,即计数器从0到9999循环计数
    TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;  // [psc]设置预分频系数为7200-1,将时钟频率分频为1 MHz
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;  // 设置重复计数器的值为0,表示不使用重复计数器
    
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);  // 使用TIM2定时器和上述配置参数进行定时器的初始化设置


    //	手动清除更新中断标志位,避免刚初始化玩就进入中断
    TIM_ClearFlag(TIM2,TIM_IT_Update);

    //	4.使能更新中断
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

    //	5.设置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
    NVIC_Init(&NVIC_InitStruct);

    //	启动定时器
    TIM_Cmd(TIM2,ENABLE);

}

选择外部时钟

void Timer_Init(void)
{

    //	1.使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    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);

    //	2.配置ETR外部时钟2
    TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_Inverted,0x00);

    //	3.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_Period=10-1;
    TIM_TimeBaseInitStruct.TIM_Prescaler=1-1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);

    //	手动清除更新中断标志位,避免刚初始化玩就进入中断
    TIM_ClearFlag(TIM2,TIM_IT_Update);

    //	4.使能更新中断
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

    //	5.设置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
    NVIC_Init(&NVIC_InitStruct);

    //	启动定时器
    TIM_Cmd(TIM2,ENABLE);

}

输出比较

  • OC(Output Compare)输出比较
  • 输出比较可以通过比较CNT与CCR(捕获/比较)寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
  • 每个高级定时器和通用定时器都拥有4个输出比较通道
  • 高级定时器的前3个通道额外拥有死区生成和互补输出的功能

PWM简介

  • PWM(Pulse Width Modulation)脉冲宽度调制
  • 在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
  • PWM参数:频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
    在这里插入图片描述

输出比较通道(通用定时器):
在这里插入图片描述
输出比较模式:
在这里插入图片描述

PWM基本结构

  • 黄色线:ARR
  • 蓝色线:CNT
  • 红色线:CCR

PWM频率:Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比:Duty = CCR / (ARR + 1)
PWM分辨率:Reso = 1 / (ARR + 1)

在这里插入图片描述

PWM示例代码

void PWM_Init(void)
{
//	1.使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;	//	复用推挽输出,片上外设来输出
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //	2.选择内部时钟
    TIM_InternalClockConfig(TIM2);

    //	3.配置时基单元
    //	输出频率为1KHz,占空比:50%,
    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
    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;
    //	设置CCR
    TIM_OCInitStruct.TIM_Pulse=0;	//	CCR	这里利用下面的函数来单独修改CCR的值
    TIM_OC1Init(TIM2,&TIM_OCInitStruct);

    //	启动定时器
    TIM_Cmd(TIM2,ENABLE);
}

输入捕获

  • IC(Input Capture)输入捕获
  • 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
  • 每个高级定时器和通用定时器都拥有4个输入捕获通道
  • 可配置为PWMI模式,同时测量频率和占空比
  • 可配合主从触发模式,实现硬件全自动测量

频率测量

在这里插入图片描述
在这里插入图片描述
注意:只有第一条路就只能测频率。

从GPIO输入波形信号后,会经过边缘检测,上升沿触发走TI1FP1通道,选择不分频后,CNT的值会存储到CCR寄存器里,然后选择TI1FP1为触发源信号,从模式选择复位操作,自动清零CNT的值,这里CNT的值就是测周法里的N,fc就是PSC/(预分频系数+1)

在这里插入图片描述
注意:可以同时测量周期和占空比
当检测到下降沿就会触发TI1FP2,将此时的CNT的值存储到CCR2里,这就是高电平持续时间的计数值,CCR1是整个周期的值,CCR2/CCR1就是占空比

输入捕获代码示例

这里采用STM32产生PWM波形,然后输入到STM32的输入捕获

产生PWM波形

#include "stm32f10x.h"                  // Device header
void PWM_Init(void)
{
    //	1.使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;	//	复用推挽输出,片上外设来输出
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //	2.选择内部时钟
    TIM_InternalClockConfig(TIM2);

    //	3.配置时基单元
    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
    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;
    //	设置CCR
    TIM_OCInitStruct.TIM_Pulse=0;	//	CCR	这里利用下面的函数来单独修改CCR的值
    TIM_OC1Init(TIM2,&TIM_OCInitStruct);

    //	启动定时器
    TIM_Cmd(TIM2,ENABLE);
}

//	单独更改通道1的CCR的值
void PWM_SetCompare1(uint16_t Compare)
{
    TIM_SetCompare1(TIM2,Compare);
}

//	单独修改PSC
void PWM_SetPrescaler(uint16_t Prescaler)
{
    //	立即生效
    TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);
}

输入捕获

#include "stm32f10x.h"                  // Device header

/*
*	输入捕获模块
*/

void IC_Init(void)
{
    //	1.使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    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);

    //	2.选择内部时钟
    TIM_InternalClockConfig(TIM3);

    //	3.配置时基单元
    //	输出频率为1KHz,占空比:50%,
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_Period=65536-1;			//	周期 ARR
    TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;			//	预分频器 PSC
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);


    //	4.初始化输入捕获单元
    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.配置TRGI的触发源为TI1FP1
    TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);

    //	6.配置从模式为Reset
    TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);

    //	7.启动定时器
    TIM_Cmd(TIM3,ENABLE);
}

//	读取CCR
uint32_t IC_GetFreq(void)
{
    //	Fx=Fc/N		Fc=72M/(PSC+1)	这里Fc=1MHz
    return 1000000/(TIM_GetCapture1(TIM3)+1);

}

编码器

  • Encoder Interface 编码器接口
  • 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
  • 每个高级定时器和通用定时器都拥有1个编码器接口
  • 两个输入引脚借用了输入捕获的通道1和通道2

在这里插入图片描述

输入捕获两个通道通过GPIO口接入编码器A,B相,这里的PSC就不用内部时钟,由编码器接口接管。
在这里插入图片描述
正转向上计数;反转向下计数

在这里插入图片描述

实例(均不反相)
在这里插入图片描述
实例(TI1反相)
在这里插入图片描述

编码器示例代码

利用定时器每隔一秒进一次中断,获得编码器的值,这就相当于旋转编码器的速度。

#include "stm32f10x.h"                  // Device header

void Encoder_Init(void)
{
    //	1.使能时钟,开启GPIO和定时器的时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    //	2.配置GPIO,这里需要把PA6和PA7配置成输入模式

    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);

    //	这里编码器会托管时钟(带方向的外部时钟,就不需要选择内部时钟
	//	TIM_InternalClockConfig(TIM3);

    //	3.配置时基单元 预分频器选择不分频(PSC),自动重装器(ARR)给65535
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;	//	这里没用到,计数模式也是被编码器托管的(默认就是向上向下都计数)
    TIM_TimeBaseInitStruct.TIM_Period=65536-1;			//	ARR
    TIM_TimeBaseInitStruct.TIM_Prescaler=1-1;			//	预分频器 PSC
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);


    //	4.初始化输入捕获单元
    TIM_ICInitTypeDef TIM_ICInitStruct;
    TIM_ICStructInit(&TIM_ICInitStruct);		//	给结构体赋初值,结构体配置不完整
    TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
    TIM_ICInitStruct.TIM_ICFilter=0XF;
    TIM_ICInit(TIM3,&TIM_ICInitStruct);

    TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;
    TIM_ICInitStruct.TIM_ICFilter=0XF;
    TIM_ICInit(TIM3,&TIM_ICInitStruct);

    //	配置编码器接口 TI1 TI2都计数,TIM_ICPolarity_Rising:代表不反向
    TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);

    //	启动定时器
    TIM_Cmd(TIM3,ENABLE);
}

//	获取CNT的值
int16_t Encode_Get(void)
{
    int16_t Temp;
    Temp=TIM_GetCounter(TIM3);

    //	给CNT清零
    TIM_SetCounter(TIM3,0);

    return Temp;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值