CMS32L051定时器时钟选择

文章目录

概要

  1. CMS32L051的定时器搭载两个通用定时器单元,每个单元含有4个通道。每个通用定时器单元有4个16位定时器。各16位定时器称为“通道”,既能分别用作独立的定时器,也能组合多个通道用作高级的定时器功能。
  2. 定时器时钟选择寄存器m(TPSm)是16位寄存器,选择提供给各通道的2种或者4种公共运行时钟(CKm0、CKm1、CKm2、CKm3)。通过TPSm寄存器的bit3~0选择CKm0,通过TPSm寄存器的bit7~4选择CKm1。另外,只有通道1和通道3才能选择CKm2和CKm3,通过TPSm寄存器的bit9~8选择CKm2,通过TPSm寄存器的bit13和bit12选择CKm3。
  3. 官方提供的标准库函数全是使用CKm0作为运行时钟,这将导致使用同一个定时器单元下的通道时,时钟分频必须保持一直,否则将会使用最后一个分频系数,导致时钟错乱。
  4. 修改标准库函数中的定时器初始化,根据分频系数确定选择的运行时钟。
  5. 各通道的寄存器使用或的关系赋值,不能相互影响。

代码

  1. int TIM_Init(TIM_InitTypeDef *TIM_InitStruct)
/**
  * @brief  Initializes the TIEMR peripheral according to the specified
  *         parameters in the TIM_InitStruct .
  * @param  TIM_InitStruct: pointer to a TIM_InitTypeDef structure that contains
  *         the configuration information for the specified TIEMR peripheral.
  * @retval initial result
  */
int TIM_Init(TIM_InitTypeDef *TIM_InitStruct)
{
	int ret = TIM_SUCC;
	uint8_t i=0,j=0;
	uint8_t chanPos =0,chanNum=0,pos=0,currentChan[8]={0};
	uint8_t masterPos =0,masterNum=0,posm=0,currentMChan[4]={0};
	uint16_t Ckm_Type = 0;
	
	assert_param(IS_TIM(TIM_InitStruct->TIM));	
	assert_param(IS_TIM_CHANNEL(TIM_InitStruct->TIM_Channel));
	
	Ckm_Type = TIM_InitStruct->TIM_ClkDivision;
	
	if (Ckm_Type & 0x000f) {
		Ckm_Type = _0000_TM_CLOCK_SELECT_CKM0;
	} else if (Ckm_Type & 0x00f0) {
		Ckm_Type = _8000_TM_CLOCK_SELECT_CKM1;
	} else if (Ckm_Type & 0x0f00) {
		Ckm_Type = _4000_TM_CLOCK_SELECT_CKM2;
	} else if (Ckm_Type & 0xf000) {
		Ckm_Type = _C000_TM_CLOCK_SELECT_CKM3;
	} else if (Ckm_Type == 0){
		Ckm_Type = _0000_TM_CLOCK_SELECT_CKM0;
	}
	
	if(TIM_InitStruct->TIM == TIM40)
	{
		CGC_PER0PeriphClockCmd(CGC_PER0Periph_TIM40,ENABLE);
	}
	else if(TIM_InitStruct->TIM == TIM41)
	{
		CGC_PER0PeriphClockCmd(CGC_PER0Periph_TIM41,ENABLE);		
	}

	Tim_RegSetting(TIM_InitStruct->TIM);
	
#if 0
	*TIM_reg.TPS = TIM_InitStruct->TIM_ClkDivision;	
#else
	*TIM_reg.TPS |= TIM_InitStruct->TIM_ClkDivision;	
#endif
	if(1==IS_TTM_Master_Chan(TIM_InitStruct->TIM_Selection_Master))//multi-tim combination
	{
		for(masterPos = 0; masterPos < 8; masterPos++)
		{
			posm = ((char)0x01) << masterPos;
			masterNum = TIM_InitStruct->TIM_Selection_Master & posm;
			if(masterNum == posm)
			{
				currentMChan[j]=masterPos;
	
				if(masterPos == 0)
				{
					*TIM_reg.TMR[currentMChan[j]] = Ckm_Type | TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_InitStruct->TIM_Mode | TIM_InitStruct->TIM_StartInt;//								
				}
				else
				{
					*TIM_reg.TMR[masterPos] = Ckm_Type |0x0800|TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_InitStruct->TIM_Mode | TIM_InitStruct->TIM_StartInt;								
				}
				*TIM_reg.TDR[currentMChan[j]] = TIM_InitStruct->TIM_Period[currentMChan[j]] -1;				 
				*TIM_reg.TO &= ~(1 << masterPos);
				*TIM_reg.TOE &= ~(1 << masterPos);	
				MISC->NFEN1 |=  (1<<currentMChan[j]);	 //后加			
				j++;
			}			
		}
		for(chanPos = 0; chanPos < 8; chanPos++)   //从属通道配置
		{
			pos = ((uint8_t)0x01) << chanPos;
			chanNum = TIM_InitStruct->TIM_Channel & pos;
			if(chanNum == pos)
			{
			  //currentChan[i]=chanPos;
			  //i++;
			    *TIM_reg.TMR[chanPos] = Ckm_Type |TIM_Trigger_UseMaster_Int |TIM_Mode_PWM_Slave| TIM_InitStruct->TIM_Mode |TIM_InitStruct->TIM_StartInt;// | TIM_InitStruct->TIM_Mode 
				*TIM_reg.TDR[chanPos] = TIM_InitStruct->TIM_Period[chanPos];
				*TIM_reg.TO &= ~(1 << chanPos);
				*TIM_reg.TOE |= (1 << chanPos);
				*TIM_reg.TOM |= (1 << chanPos);
				*TIM_reg.TOL &= ~(1 << chanPos);
			}
		}
		*TIM_reg.TS |= TIM_InitStruct->TIM_Channel |TIM_InitStruct->TIM_Selection_Master;   //TIM Start

	}
	else
	{
		for(chanPos = 0; chanPos < 8; chanPos++)
		{
			pos = ((uint8_t)0x01) << chanPos;
			chanNum = TIM_InitStruct->TIM_Channel & pos;
			if(chanNum == pos)
			{
			  currentChan[i]=chanPos;
			  i++;
			}
		}
		if(i == 1)
		{
			*TIM_reg.TDR[currentChan[0]] = TIM_InitStruct->TIM_Period[currentChan[0]] -1;
			*TIM_reg.TT |=  TIM_InitStruct->TIM_Channel;   //TIM stop

			*TIM_reg.TMR[currentChan[0]] = Ckm_Type | TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_InitStruct->TIM_Mode | TIM_InitStruct->TIM_StartInt;

			*TIM_reg.TO &= ~ TIM_InitStruct->TIM_Channel;
			if(TIM_InitStruct->TIM_Mode == 0x0000)    //tim output
			{
				*TIM_reg.TOE |= TIM_InitStruct->TIM_Channel;
			}
			else   //input event for tim 
			{
				*TIM_reg.TOE &= ~ TIM_InitStruct->TIM_Channel;
				if(TIM_InitStruct->TIM_Mode == TIM_Mode_EventCount)
				{
					*TIM_reg.TMR[currentChan[0]] |= 0x1000;		
				}
				if(TIM_InitStruct->TIM == TIM40)
				{
					 MISC->NFEN1 |=  TIM_InitStruct->TIM_Channel;
				}
				if(TIM_InitStruct->TIM == TIM41)
				{
					 MISC->NFEN2 |=  TIM_InitStruct->TIM_Channel;
				}						
				if((TIM_InitStruct->TIM_Channel == 0x01 || TIM_InitStruct->TIM_Channel == 0x02) && (TIM_InitStruct->TIM == TIM40))
				{
					MISC->TIOS0 |=  TIM_InitStruct->TIM4_Input;
					if(TIM_InitStruct->TIM4_Input)
					{
						MISC->NFEN1 &=  ~(TIM_InitStruct->TIM_Channel);					
					}	
				}		
			}				
			*TIM_reg.TS |=  TIM_InitStruct->TIM_Channel;   //TIM Start
		}
		else
		{
			return TIM_ERR;
		}
	}
	
	return ret;
}

小结

  1. 当配置TIM41_CH1作为PWM输出时,再使用TIM41_CH0作为定时器时,PWM输出会受到影响,因此不能再使用TIM41_CH0,可以使用TIM41_CH2或者TIM41_CH3。
STM32F103ZET6是一款基于ARM Cortex-M3内核的微控制器,它包含了一组功能强大的定时器,用于控制各种周期性的事件、计数和其他时间相关的任务。其中,TIM1到TIM8定时器是STM32常用的时间控制资源。 下面以STM32F103ZET6的 TIM1 定时器为例,说明其基本配置步骤: ### 配置步骤 #### 1. 选择和初始化定时器模式 首先,你需要确定TIM1将作为通用定时器(通用PWM)、比较模式下的定时器还是其他模式使用,并相应地配置TIMx_CR1寄存器的对应位(例如,CTC模式通过设置CR1寄存器的CMS位)。 #### 2. 设置预分频因子 预分频因子决定了实际的频率与系统时钟之间的比例。这需要配置TIMx_PSC寄存器,通常根据所需的工作频率计算出合适的值。 #### 3. 配置自动重装载寄存器 这个寄存器(TIMx_ARR)的值决定了定时器达到最大值后的溢出时间长度,也就是中断发生的时间间隔。 #### 4. 初始化输入捕获通道 如果你计划使用定时器进行输入信号的捕获,那么需要配置TIMx_ICR寄存器以设定每个输入捕获通道的触发条件和操作。 #### 5. 启动定时器 最后一步是在TIMx_SMCR寄存器中启用定时器的启动(开启预分频器和自动增减计数器),并根据需要配置复位模式。 ### 示例代码段 以下是简化版的TIM1初始化示例代码片段: ```c // 初始化TIM1定时器为通用定时器模式,CTC计数模式,工作于72MHz下,生成1kHz的周期中断 void TIM1_Init(void) { // Enable TIM1 clock __HAL_RCC_TIM1_CLK_ENABLE(); HAL_TIM_Base_Init(&htim1); htim1.Instance = TIM1; htim1.Init.Prescaler = 7199; // 分频系数(72MHz / 1000Hz) htim1.Init.CounterMode = TIM_COUNTERMODE_UP; // CTC模式 htim1.Init.Period = 999; // 1kHz周期 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; if (HAL_TIM_Base_Init(&htim1) != HAL_OK) { Error_Handler(); } HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // 启动定时器通道1用于输出PWM波形 } // 使用函数实例化和初始化TIM1定时器 ``` ### 相关问题: 1. 如何在STM32CubeMX中配置TIM1定时器? 2. STM32F1系列如何利用定时器实现精确脉冲宽度调制(PWM)? 3. 如果想从外部引脚捕获事件并更新定时器的值,应该怎样配置定时器输入捕获功能?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值