当前位置: 首页 > news >正文

软件网站建设基本流程图高级网站开发工信部

软件网站建设基本流程图,高级网站开发工信部,电子商务平台内的自然人经营者,数据网站建设成本目录 一、TIM简介 二、基本定时器(TIM6和TIM7) 1. TIM6和TIM7简介 2. TIM6和TIM7的主要特性 3. TIM6和TIM7的功能 3.1 时基单元 3.2 计数模式 3.3 时钟源 三、通用定时器 1. TIMx(2、3、4、5)简介 2. TIMx主要功能 3. 时钟选择 4. 影子寄存…

目录

一、TIM简介   

二、基本定时器(TIM6和TIM7)

1. TIM6和TIM7简介

2. TIM6和TIM7的主要特性

3. TIM6和TIM7的功能

3.1 时基单元

 3.2 计数模式

 3.3 时钟源

三、通用定时器

1. TIMx(2、3、4、5)简介

2. TIMx主要功能

3. 时钟选择

 4. 影子寄存器

 5. 定时中断程序实现

5.1 函数TIM_TimeBaseInit

 源码:

 5.2 函数NVIC_Init

 5.3 定时中断初始化

5.4 TIM2中断函数

6. TIMx输出比较功能

 6.1 输出比较模式的配置步骤

6.2 PWM模式

    PWM基本结构:

6.3 呼吸灯代码实现 

初始化:

 STM32103C8T6的引脚定义图:

pwm配置:

main函数:

7.  输入捕获

7.1 频率测量方法

 7.2 输入捕获通道

        TIM_ICInit函数:(输入捕获初始化)

         STM32通用或高级定时器的从模式有如下几种:

 8. PWMI模式

 注意:

         PWMI模块初始化:

        TIM_PWMIConfig()函数:

四、高级定时器

1. TIM1和TIM8简介

2. 重复计数器

 3. 互补输出和死区插入

位操作

        左移与右移    


一、TIM简介   

        定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断;

        16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时【1/(72MHZ/65536*65536)(预分频器和计数器都是16位的)

        根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型  

类型

编号

总线

功能

高级定时器

TIM1TIM8

APB2

拥有通用定时器全部功能,

并额外具有重复计数器、死区生成、互补输出、刹车输入等功能

通用定时器

TIM2TIM3

TIM4TIM5

APB1

拥有基本定时器全部功能,

并额外具有内外时钟源选择、输入捕获、输出比较、

编码器接口、主从触发模式等功能

基本定时器

TIM6TIM7

APB1

拥有定时中断、主模式触发DAC的功能

二、基本定时器(TIM6和TIM7)

1. TIM6和TIM7简介

         基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。 它们可以作为通用定时器提供时间基准,特别地可以为数模转换器(DAC)提供时钟。实际上,它们在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。 这2个定时器是互相独立的,不共享任何资源。

2. TIM6和TIM7的主要特性

        TIM6和TIM7定时器的主要功能包括: 16位自动重装载累加计数器 ,16位可编程(可实时修改)预分频器,用于对输入的时钟按系数为1~65536之间的任意数值分频 ,触发DAC的同步电路 , 在更新事件(计数器溢出)时产生中断/DMA请求。

         上图可以简单的由下图理解:(基准时钟预分频,计数器累加到重装载值产生中断或者事件)

        

3. TIM6和TIM7的功能

3.1 时基单元

         时基单元包含: ● 计数器寄存器(TIMx_CNT) ● 预分频寄存器(TIMx_PSC) ● 自动重装载寄存器(TIMx_ARR) 

        预分频器:预分频可以以系数介于1至65536之间的任意数值对计数器时钟分频。它是通过一个16位寄存器(TIMx_PSC)的计数实现分频。

        因为TIMx_PSC控制寄存器具有缓冲,可以在运行过程中改变它的数值,新的预分频数值将在下一个更新事件时起作用。

        CK_PSC预分频器的输入时钟、CNT_EN计数器使能,前半段,从计数器使能开始,定时器时钟等于计数器时钟,后半段,预分频系数从1变成2,定时器时钟变成预分频器输入时钟的一半。当计数周期没有结束时,改变预分频寄存器的值,不会立即生效,而是等到计数结束产生中断,才会传递改变的数值到缓冲寄存器里。

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

 3.2 计数模式

        计数器从0累加计数到自动重装载数值(TIMx_ARR寄存器),然后重新从0开始计数并产生一个计数器溢出事件。

        当发生一次更新事件时,所有寄存器会被更新并(根据URS位)设置更新标志(TIMx_SR寄存器的UIF位): ● 传送预装载值(TIMx_PSC寄存器的内容)至预分频器的缓冲区。 ● 自动重装载影子寄存器被更新为预装载值(TIMx_ARR)。

 

         当计数值到了0x36后,计数器溢出,触发中断,并更新中断标志位计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)

 3.3 时钟源

        计数器的时钟由内部时钟(CK_INT)提供。

三、通用定时器

1. TIMx(2、3、4、5)简介

        通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。 它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)。 使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。

2. TIMx主要功能

        通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:

        ● 16位向上、向下、向上/向下自动装载计数器 (与基本定时器的区别之一)● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值 ● 4个独立通道: ─ 输入捕获 ─ 输出比较 ─ PWM生成(边缘或中间对齐模式) ─ 单脉冲模式输出 ● 使用外部信号控制定时器和定时器互连的同步电路

        ● 如下事件发生时产生中断/DMA: ─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) ─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) ─ 输入捕获 ─ 输出比较

        ● 支持针对定位的增量(正交)编码器和霍尔传感器电路 ● 触发输入作为外部时钟或者按周期的电流管理      

3. 时钟选择

        计数器时钟可由下列时钟源提供:

        ● 内部时钟(CK_INT)

        ● 外部时钟模式1:外部输入脚(TIx)

        ● 外部时钟模式2:外部触发输入(ETR)

        ● 内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。

        对于基本定时器,只能选择72MHz的内部时钟,而通用定时器可以选择如下时钟:(外部时钟+内部时钟)[ITR接别的定时器]
  

 4. 影子寄存器

        当发生一个更新事件时,所有的寄存器都被更新,硬件同时(依据URS位)设置更新标志位(TIMx_SR寄存器中的UIF位)。 ● 预分频器的缓冲区被置入预装载寄存器的值(TIMx_PSC寄存器的内容)。 ● 自动装载影子寄存器被重新置入预装载寄存器的值(TIMx_ARR)。

        下图给出一些例子,当TIMx_ARR=0x36时计数器在ARPE=0/1时的动作。

        当没有预装入时,写入新数值至TIMx_ARR寄存器,,计数器会直接开始自增到36,再发生溢出触发中断。

        而当ARPE=1,真正起作用的变成了自动加载影子寄存器,计数器会先计数到F5,等到计数周期结束才开始重新计数到36,如果没有影子寄存器,就会出现,计数器先从F1自增到0xFFFF,再从0计数到36的现象,计数时间增加。

 5. 定时中断程序实现

5.1 函数TIM_TimeBaseInit

TIM_TimeBaseInitTypeDef structure
TIM_TimeBaseInitTypeDef定义于文件“stm32f10x_tim.h”:
typedef struct
{
u16 TIM_Period;
u16 TIM_Prescaler;
u8 TIM_ClockDivision;
u16 TIM_CounterMode;
} TIM_TimeBaseInitTypeDef;

TIM_Period
        TIM_Period设置了在下一个更新事件装入活动的自动重装载寄存器周期的值。它的取值必须在0x0000和0xFFFF之间。
TIM_Prescaler
        TIM_Prescaler设置了用来作为TIMx时钟频率除数的预分频值。它的取值必须在0x0000和0xFFFF之间。
TIM_ClockDivision
        TIM_ClockDivision设置了时钟分割。该参数取值见下表。

TIM_ClockDivision描述
TIM_CKD_DIV1TDTS = Tck_tim
TIM_CKD_DIV2TDTS = 2Tck_tim
TIM_CKD_DIV4TDTS = 4Tck_tim

TIM_CounterMode
        TIM_CounterMode选择了计数器模式。该参数取值见下表。

TIM_CounterMode描述
TIM_CounterMode_UpTIM向上计数模式
TIM_CounterMode_DownTIM向下计数模式
TIM_CounterMode_CenterAligned1TIM中央对齐模式1计数模式
TIM_CounterMode_CenterAligned2TIM中央对齐模式2计数模式
TIM_CounterMode_CenterAligned3TIM中央对齐模式3计数模式
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0xF;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure);
 源码:

        注意:TIM_TimeBaseInit函数末尾,手动产生了更新事件,若不清除此标志位,则开启中断后,会立刻进入一次中断,如果不介意此问题,则不清除此标志位也可。

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{uint16_t tmpcr1 = 0;/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx)); assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));tmpcr1 = TIMx->CR1;  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||(TIMx == TIM4) || (TIMx == TIM5)) {/* Select the Counter Mode */tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;}if((TIMx != TIM6) && (TIMx != TIM7)){/* Set the clock division */tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;}TIMx->CR1 = tmpcr1;/* Set the Autoreload value */TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;/* Set the Prescaler value */TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  {/* Set the Repetition Counter value */TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;}/* Generate an update event to reload the Prescaler and the Repetition countervalues immediately */TIMx->EGR = TIM_PSCReloadMode_Immediate;           
}

 5.2 函数NVIC_Init

 5.3 定时中断初始化

        1. 开启时钟 2. 配置时钟源 3. 配置时基单元初始化 4. 触发中断(开启中断、中断优先级、调用NVIC)

/*** 函    数:定时中断初始化* 参    数:无* 返 回 值:无*/
void Timer_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟/*配置时钟源*/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 = 10000 - 1;				//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 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线路的抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}
5.4 TIM2中断函数
  * 函    数:TIM2中断函数* 参    数:无* 返 回 值:无* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行*           函数名为预留的指定名称,可以从启动文件复制*           请确保函数名正确,不能有任何差异,否则中断函数将不能进入*/
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断{Num ++;												//Num变量自增,用于测试定时中断TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位//中断标志位必须清除//否则中断将连续不断地触发,导致主程序卡死}
}

6. TIMx输出比较功能

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

        即通过比较CNT计数器和捕获/比较寄存器,输出电平。

        上图,CCIP极性选择,此外,输出模式控制器模式如下:

模式

描述

冻结

CNT=CCR时,REF保持为原状态

匹配时置有效电平

CNT=CCR时,REF置有效电平

匹配时置无效电平

CNT=CCR时,REF置无效电平

匹配时电平翻转

CNT=CCR时,REF电平翻转

强制为无效电平

CNTCCR无效,REF强制为无效电平

强制为有效电平

CNTCCR无效,REF强制为有效电平

PWM模式1

向上计数:CNT<CCR时,REF置有效电平,CNTCCR时,REF置无效电平

向下计数:CNT>CCR时,REF置无效电平,CNTCCR时,REF置有效电平

PWM模式2

向上计数:CNT<CCR时,REF置无效电平,CNTCCR时,REF置有效电平

向下计数:CNT>CCR时,REF置有效电平,CNTCCR时,REF置无效电平

 6.1 输出比较模式的配置步骤

        1. 选择计数器时钟(内部,外部,预分频器)

        2. 将相应的数据写入TIMx_ARR和TIMx_CCRx寄存器中

        3. 如果要产生一个中断请求和/或一个DMA请求,设置CCxIE位和/或CCxDE位。

        4. 选择输出模式(往往设置为PWM1模式)

        例如当计数器CNT与CCRx匹配时翻转OCx的输出引脚,CCRx预装载未用,开启OCx输出且高电平有效,则必须设置OCxM=’011’、OCxPE=’0’、CCxP=’0’和CCxE=’1’。(怎么理解?)

        CCxP = 0///CCxE = 1(捕获/比较使能寄存器(TIMx_CCER))开启OCx输出且高电平有效

         OCxM=’011’、OCxPE=’0翻转OCx的输出引脚,CCRx预装载未用

捕获/比较模式寄存器1(TIMx_CCMR1):

      

       5. 设置TIMx_CR1寄存器的CEN位启动计数器

        TIMx_CCRx寄存器能够在任何时候通过软件进行更新以控制输出波形,条件是未使用预装载寄存器(OCxPE=’0’,否则TIMx_CCRx影子寄存器只能在发生下一次更新事件时被更新)。下图给出了一个例子。

        计数器的值和输出比较寄存器的值一直在比较,待,计数器的值达到CCR的003A,因为设置的模式时翻转电平,所以通过输出模式控制器后到达的OC1电平从低电平变成高电平,但是由于CNT的值还没有到重装载寄存器的值,计数器接着自增。而此时,在CC1R寄存器写入B201h,那么由于没有使用预装载,那么待到B201,再次马上翻转电平。 

6.2 PWM模式

        脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。

PWM模式1

向上计数:CNT<CCR时,REF置有效电平,CNTCCR时,REF置无效电平

向下计数:CNT>CCR时,REF置无效电平,CNTCCR时,REF置有效电平

PWM模式2

向上计数:CNT<CCR时,REF置无效电平,CNTCCR时,REF置有效电平

向下计数:CNT>CCR时,REF置有效电平,CNTCCR时,REF置无效电平

        仅当发生一个更新事件的时候,预装载寄存器才能被传送到影子寄存器,因此在计数器开始计数之前,必须通过设置TIMx_EGR寄存器中的UG位来初始化所有的寄存器。


          下面是一个PWM模式1的例子。当TIMx_CNT<TIMx_CCRx时PWM信号参考OCxREF为高,否则为低。如果TIMx_CCRx中的比较值大于自动重装载值(TIMx_ARR),则OCxREF保持为’1’。如果比较值为0,则OCxREF保持为’0’。 下图为TIMx_ARR=8时边沿对齐的PWM波形实例。

            注意:CCxIF中断标志,当TIMx_CNT与TIMx_CCR1匹配时置1

    PWM基本结构:

   30相当于CCR的值(捕获比较寄存器),99相当于自动重装载值

        PWM频率:  Freq = CK_PSC / (PSC + 1) / (ARR + 1)
        PWM占空比:  Duty = CCR / (ARR + 1)
        PWM分辨率:  Reso = 1 / (ARR + 1)
6.3 呼吸灯代码实现 
初始化:

        需要注意的是GPIO的配置,要配置成复用推挽输出。

        将PA0引脚初始化为复用推挽输出,受外设控制的引脚,均需要配置为复用模式 。      

/*开启时钟*/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_0;		//GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);				//将PA0引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式		/*配置时钟源*/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 = 100 - 1;					//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 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模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure);						//将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}

 注意其中对于GPIO的初始化还可以使用I/O口重映射:

/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);				//将PA0引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式		
 STM32103C8T6的引脚定义图:

         查手册可以直到复用的引脚为PA15,如下表:

         使用下图函数进行配置,改变指定引脚的映射。

 

         但是PA15正好是主功能是JTDI的特殊引脚,故在配置io口时需要注意让该io口变成普通的io再配置复用。

         具体配置代码如下:

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
pwm配置:
/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}
main函数:
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"uint8_t i;			//定义for循环的变量int main(void)
{/*模块初始化*/OLED_Init();		//OLED初始化PWM_Init();			//PWM初始化while (1){for (i = 0; i <= 100; i++){PWM_SetCompare1(i);			//依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮Delay_ms(10);				//延时10ms}for (i = 0; i <= 100; i++){PWM_SetCompare1(100 - i);	//依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗Delay_ms(10);				//延时10ms}}
}

7.  输入捕获

        输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数;每个高级定时器和通用定时器都拥有4个输入捕获通道;可配置为PWMI模式,同时测量频率和占空比。

7.1 频率测量方法

        测频法:在闸门时间T内,对上升沿计次,得到N,则频率f = N/T;

        测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率f = fc/N。

        频率的定义是:1s内出现多少个重复的周期。那么测频法如果T=1s,那么在闸门时间内,计数次数刚好等于频率。但是如果待测信号的频率非常低,1s内出现的上升沿将非常少甚至没有,但是频率肯定不是0,故当计数次数少时,即上升沿出现次数少时,对于频率测量的误差会很大,故往往测频法适用于测量高频信号,有助于减少误差。(计数次数都希望越大越好,以减少误差,但是注意计数均存在±1的误差,因为当周期只出现了一半的时候,若闸门时间就到了,那么就会只取次数,出现误差)

        而测周法恰恰相反,对于低频信号而言,周期更长,计数次数会增加,误差减小。假如有一待测信号为500KHz,而fc = 1MHz,那么一个周期内仅仅能计数一两次,那么当待测信号频率更高时,计次次数将更小甚至为0,那么对于待测信号频率的判断误差会很大。

        那什么是高频信号什么是低频信号?中界频率:测频法与测周法误差相等的频率点。

 7.2 输入捕获通道
        TIM_ICInit函数:(输入捕获初始化)

        具体代码如下:

/*输入捕获初始化*/TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1TIM_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的输入捕获通道

         需要注意下图部分,每次捕获后计数器清零。

         STM32通用或高级定时器的从模式有如下几种:

        1、复位模式 【Reset mode】

        2、触发模式 【Trigger mode】

        3、门控模式 【Gate mode】

        4、外部时钟模式1 【External clock mode 1】

        5、编码器模式 【encode mode】

        计数器开始依据内部时钟计数,然后正常运转直到TI1出现一个上升沿;此时,计数器被清零然后从0重新开始计数。同时,触发标志(TIMx_SR寄存器中的TIF位)被设置,根据TIMx_DIER寄存器中TIE(中断使能)位和TDE(DMA使能)位的设置,产生一个中断请求或一个DMA请求。下图显示当自动重装载寄存器TIMx_ARR=0x36时的动作。在TI1上升沿和计数器的实际复位之间的延时,取决于TI1输入端的重同步电路。

        当有效触发输入信号出现时,计数器将会被复位,同时还会产生更新事件和触发事件。如果计数器向上计数或中央对齐模式的话,复位后计数器从0开始计数,如果向下计数模式,复位后计数器从ARR值开始计数。不妨以计数器向上计数为例,将它配置在复位从模式。比方说当计数器计数到某个数据的时候,来了个触发信号,计数器不再继续往上计数,而是重新归0后开始计数。当然,计数器的实际复位操作与触发沿之间往往会有个小的延时,这是由于触发信号作为有效触发脉冲的话,还需要经过定时器内的同步电路确认。

        下面列出了相关寄存器:

         清零逻辑如下图,触发源选择器选择TI1FP1,TRGI触发从模式reset。(但是自动清除只能选择通道1和通道2)

        即当检测到上升沿后,该触发信号将CNT计数器的值转运到捕获寄存器中,即CCR1 = CNT,之后CNT置零,CNT计数继续++,只要没有达到自动重装载值,当边沿检测到下一次上升沿,再次发生转运,CCR1 = CNT,这样刚好得到了一个周期的计数值,故其实输入捕获使用的是测周法获取频率值。

 这里再简单介绍一下从模式控制寄存器(TIMx_SMCR)

        滤波的配置:

         从模式清零:

         TIM_SelectInputTrigger():

         即TI1产生上升沿时,会触发CNT归零。实现代码:

/*选择触发源及从模式*/TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);					//触发源选择TI1FP1TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);					//从模式选择复位//即TI1产生上升沿时,会触发CNT归零

 8. PWMI模式

        两个通道,一个上升沿触发一个下降沿触发,当上升沿触发时,CCR1 = CNT,之后从模式控制寄存器使得CNT = 0,待下次下降沿到来,CCR2 = CNT(该计数值刚好一个高电平的计数值。),之后依次循环。

 注意:

        GPIO的配置,需要配置成浮空输入,我这里配置成了上拉输入:可以参考这篇文章:

        输入捕获时,GPIO引脚的输入方式如何设置?-CSDN博客

        引申:什么时候可以用浮空输入?
        当捕获方波信号的时候,应该用浮空输入,不能用下拉输入。因为方波信号本身既有高电平也有低电平,强制下拉为低电平会影响方波信号。捕获发生在上升沿或者下降沿,如果没有上升沿和下降沿,就无法发生捕获。被捕捉的信号本身没有上升沿或下降沿,要通过IO口输入设置造出上升沿或下降沿,被捕捉信号本身有上升沿或下降沿的,IO口设置为浮空输入即可。

/*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引脚初始化为上拉输入

        为什么初始化PA6?

         PWMI模块初始化:
/*PWMI模式初始化*/TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1TIM_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的输入捕获通道//此函数同时会把
        TIM_PWMIConfig()函数:
/*** @brief  Configures the TIM peripheral according to the specified*         parameters in the TIM_ICInitStruct to measure an external PWM signal.* @param  TIMx: where x can be  1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.* @param  TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure*         that contains the configuration information for the specified TIM peripheral.* @retval None*/
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)
{uint16_t icoppositepolarity = TIM_ICPolarity_Rising;uint16_t icoppositeselection = TIM_ICSelection_DirectTI;/* Check the parameters */assert_param(IS_TIM_LIST6_PERIPH(TIMx));/* Select the Opposite Input Polarity */if (TIM_ICInitStruct->TIM_ICPolarity == TIM_ICPolarity_Rising){icoppositepolarity = TIM_ICPolarity_Falling;}else{icoppositepolarity = TIM_ICPolarity_Rising;}/* Select the Opposite Input */if (TIM_ICInitStruct->TIM_ICSelection == TIM_ICSelection_DirectTI){icoppositeselection = TIM_ICSelection_IndirectTI;}else{icoppositeselection = TIM_ICSelection_DirectTI;}if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_1){/* TI1 Configuration */TI1_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,TIM_ICInitStruct->TIM_ICFilter);/* Set the Input Capture Prescaler value */TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);/* TI2 Configuration */TI2_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);/* Set the Input Capture Prescaler value */TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);}else{ /* TI2 Configuration */TI2_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,TIM_ICInitStruct->TIM_ICFilter);/* Set the Input Capture Prescaler value */TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);/* TI1 Configuration */TI1_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);/* Set the Input Capture Prescaler value */TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);}
}

四、高级定时器

1. TIM1和TIM8简介

        高级控制定时器(TIM1和TIM8)由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。 它支持针对定位的增量(正交)编码器和霍尔传感器电路,它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、PWM、嵌入死区时间的互补PWM(死区时间可编程的互补输出)等)。 使用定时器预分频器和RCC时钟控制预分频器,可以实现脉冲宽度和波形周期从几个微秒到几个毫秒的调节。

        和高级定时器最大的两处区别:

2. 重复计数器

         关于高级定时器 重复计数值寄存器的使用介绍 - ZaiLi - 博客园 (cnblogs.com)

 3. 互补输出和死区插入

          驱动电机的时候常用,防止mos管短暂的直接导通。

        高级控制定时器(TIM1和TIM8)能够输出两路互补信号,并且能够管理输出的瞬时关断和接通。 这段时间通常被称为死区,用户应该根据连接的输出器件和它们的特性(电平转换的延时、电源开关的延时等)来调整死区时间。

        如果OCx和OCxN为高有效:

        ● OCx输出信号与参考信号相同,只是它的上升沿相对于参考信号的上升沿有一个延迟。

        ● OCxN输出信号与参考信号相反,只是它的上升沿相对于参考信号的下降沿有一个延迟。         如果延迟大于当前有效的输出宽度(OCx或者OCxN),则不会产生相应的脉冲。 下列几张图显示了死区发生器的输出信号和当前参考信号OCxREF之间的关系。

           逻辑门图解—与门、或门、非门、与非门、或非门、异或门、同或门_小小本科生debug的博客-CSDN博客

         当写入0时,与门有0则0,全1为1

位操作

【精选】【STM32】位操作、按位与、按位或、按位异或、取反、左移、右移等基础 C 语言知识补充_按位与操作是什么意思-CSDN博客

运算符含义
&按位与
按位或
^按位异或
~取反
<<左移
>>右移

        总结:对于原二进制数来说,&0是屏蔽,&1是不变。0&x = 0,1&x = x;0与任何数等于0,1与任何数等于本身,不改变。进行清0操作

        总结:对于原二进制数来说,|0是不变,|1是置1。0|x = x,1|x = 1;0或任何数等于本身,1或任何数等于1。

总结:对于原二进制数来说,^0是不变,^1是反转。即:0 ^ 0 = 0 ,0 ^ 1 = 1,1 ^ 0 = 1 ,1 ^ 1 = 0 ,
按位异或的3个特点:1.) 0 ^ 0 = 0 , 0 ^ 1 = 1, 0异或任何数=任何数。2.)1 ^ 0 = 1 , 1 ^ 1 = 0 , 1异或任何数=任何数取反。

       而对于取反需要注意:对一个二进制数进行取反。1变0,0变1。

        唯一需要注意的一点是,~的优先级是逻辑运算符中最高的,必须优先计算。

        不改变其他位时,对某几个位设定值。比如要改变 GPIOA 的状态,可以先对寄存器的值进行 & 清零操作GPIOA -> CRL &= 0XFFFFFF0F;  将第 4-7 位清 0,然后再与需要设置的值进行 | 或运算GPIOA -> CRL |= 0X00000040;设置相应位的值,且不改变其他位的值。


        左移与右移    

        对于无符号数,左移时右侧补0(相当于逻辑移位)
        对于无符号数,右移时左侧补0(相当于逻辑移位)

        左移规则:左移运算是将一个二进制位的操作数按指定移动的位数向左移动,移出位被丢弃,右边移出的空位一律补0。

        简单说就是:左边丢弃,右边补0

        ​​​​​​​https://blog.csdn.net/m0_64280701/article/details/123064976

        右移运算是将一个二进制位的操作数按指定移动的位数向右移动,移出位被丢弃,左边移出的空位一律补0,或者补符号位,这由不同的机器而定。在使用补码作为机器数的机器中,正数的符号位为 0 ,负数的符号位为 1 。简单说就是:(分为 2 种)1. 逻辑右移,左边用0填充,右边丢弃。2. 算术右移左边用原该值的符号位填充,右边丢弃。到底是逻辑右移还是算术右移取决于编译器,我当前使用的编译器,它采用的是算术右移。

   单片机的位操作知识_单片机位操作-CSDN博客   

        位运算实战演练1
        回顾:要置1用|,用清零用&,要取反用^,~和<< >>用来构建特定二进制数。
        1.给定一个整型数a,设置a的bit3,保证其他位不变。
                a = a | (1<<3)或者 a |= (1<<3)

        2.给定一个整形数a,设置a的bit3~bit7,保持其他位不变。
                a = a | (0b11111<<3)或者 a |= (0x1f<<3);

        3.给定一个整型数a,清除a的bit15,保证其他位不变。
                a = a & (~(1<<15));或者 a &= (~(1<<15));

        4.给定一个整形数a,清除a的bit15~bit23,保持其他位不变。
                a = a & (~(0x1ff<<15));或者 a &= (~(0x1ff<<15));

        5.给定一个整形数a,取出a的bit3~bit8。
        思路:
                第一步:先将这个数bit3~bit8不变,其余位全部清零。
                第二步,再将其右移3位得到结果。
                第三步,想明白了上面的2步算法,再将其转为C语言实现即可。
                a &= (0x3f<<3);
                a >>= 3;

        6.用C语言给一个寄存器的bit7~bit17赋值937(其余位不受影响)。
        关键点:第一,不能影响其他位;第二,你并不知道原来bit7~bit17中装的值。
思路:

        第一步,先将bit7~bit17全部清零,当然不能影响其他位。

        第二步,再将937写入bit7~bit17即可,当然不能影响其他位。

        a &= ~(0x7ff<<7);

        a |= (937<<7);

http://www.yayakq.cn/news/94833/

相关文章:

  • 视频模板网站推荐科技助手和平精英
  • 如何把电脑改成服务器 做网站织梦网站模板如何安装教程视频教程
  • 广告设计网站排行榜前十名用dedecms做的网站
  • 网站建设团队定制怎样添加字体到wordpress
  • 公司网站seo怎么做google搜索下载
  • php 网站缓存制作网站代码大全
  • 目前有做电子合同的网站吗企业建设网站的作用
  • 网站制作推广SSL自定义wordpress登录界面
  • 服装网站建设项目实施报告网站开发招标网
  • 安徽省住房和城乡建设厅网站域名网站建设工作室图片
  • 网站制作模板代码小程序怎么移除
  • 卖农产品最好的平台wordpress的seo作用
  • phpcms 手机网站模板只做健康产品的网站
  • 厦门专业网站建设团队php网站数据库修改
  • xml网站地图格式北大青鸟的网站建设课程多少钱
  • 北京网站制作公司兴田德润实惠网站开发交付清单
  • 网站开发什么语言好酒店预定类网站建设
  • 免费可用的网站源码二级域名做网址导航大全网站
  • wordpress无法访问站点推广方式和推广渠道的区别
  • 阿里云主机建网站网站流量 龙优化软件
  • 网站右下角广告代码企业站手机网站
  • 营口电商网站建设西安互联网网站建设
  • 求免费的那种网站有哪些怀宁县住房与城乡建设局网站
  • 会计公司网站模板下载南沙免费网站建设
  • 什么东西可以做网站市场营销研究生好考吗
  • 用宝塔做网站步骤网站开发制作全包
  • 平湖手机网站设计网页怎么制作成二维码
  • 全flash网站制作教程磁力吧
  • 为代理网站做网站商丘网站推广的方法
  • 芙蓉网站制作有没有介绍做私家导游的网站