IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F103定时器(未完待续) -> 正文阅读

[嵌入式]STM32F103定时器(未完待续)

一、STM32F103定时器分类及区别

共有8个定时器,它们是:TIM1~TIM8。STM32的定时器分为基本定时器、通用定时器和高等定时器。
TIM6、TIM7(基本定时器):基本定时器是只能向上计数的16位定时器,基本定时器只能有定时的功能,没有外部IO口,所以没有捕获和比较通道。
TIM2、TIM3、TIM4、TIM5(通用定时器):通用定时器是可以向上计数,也可以向下计数的16位定时器。通用定时器可以定时、输出比较、输入捕捉,每个通用定时器具有4个外部IO口。
TIM1、TIM8(高级定时器):高级定时器是是可以向上计数,也可以向下计数的16位定时器。高等定时器可以定时、输出比较、输入捕捉、还可以输出三相电机互补信号,每个高等定时器有8个外部IO口。

二、通用定时器主要功能

通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:
● 16位向上、向下、向上/向下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意
数值
● 4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 使用外部信号控制定时器和定时器互连的同步电路
● 如下事件发生时产生中断/DMA:
─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
● 支持针对定位的增量(正交)编码器和霍尔传感器电路

通用定时器计数模式

向上计数,向下计数,中心对齐

三、通用定时器工作过程

在这里插入图片描述
从时钟源产生框可以看到
定时器时钟有四种来源:
● 内部时钟(CK_INT)
● 外部时钟模式1:外部输入脚(TIx) (输入捕获的引脚)
● 外部时钟模式2:外部触发输入(ETR)
● 内部触发输入(ITRx):(定时器级联)使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
产生CK_PSC时钟,然后在从模式控制器内设置好计数模式(向上向下),再经过预分频器产生CK_CNT,若为CNT计数器向下计数,则当其计数到0时,自动重装载寄存器会重新为CNT计数器装载新值重新递减计数,并产生一个更新事件。

时基单元:
● 计数器寄存器(TIMx_CNT)
● 预分频器寄存器 (TIMx_PSC)
● 自动装载寄存器 (TIMx_ARR)
输入捕获:信号通过捕获通道进入,经滤波,经分频,经,,输入捕获与输出比较的四个通道其实是一个。

四、时钟源配置(选内部时钟)

在这里插入图片描述
在这里插入图片描述
由以上两张图,我们知道CK_CNT时钟来源于APB1,并且如果APB1预分频系数如果不为1则CK_INT=APB1*2(单位是频率),然后设置好预分频系数CK_PSC为N,得CK_CNT=CK_INT / (N+1)。
CK_INT到底是多少呢?
那以STM32F103RBT6为例,打开system_stm32f10x.c文件找到SystemInit函数,其注释如下:
在这里插入图片描述
翻译:设置系统时钟(系统时钟源、PLL倍增器因子、AHB/APBx预分频器和闪存设置)
找到函数,我们为其一一注释:

void SystemInit (void)
{
 /* 使能内部高速时钟 */ 
  RCC->CR |= (uint32_t)0x00000001;
  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL//没有define这个玩意
  RCC->CFGR &= (uint32_t)0xF8FF0000;//这5行是复位个个时钟用的,not define STM32F10X_CL,比如SW设为00即HSI作为系统时钟
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;//把HSE关闭,时钟监测器,PLL关闭。
  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;//HSE没有被旁路
  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;//HSI振荡器时钟经2分频后作为PLL输入时钟 
  									//PREDIV1对输入时钟进行2分频
  									//PLL倍频系数保留
  									//PLL VCO时钟(2xPLLCLK)被除以3(必须配置PLL输出为72MHz); 
/* 禁用时钟中断寄存器 */
#ifdef STM32F10X_CL 
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;
  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;//禁用时钟中断寄存器
  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */

/* 设置外部SRAM,这个不太懂,参考链接2 */
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

/* 配置系统时钟 */
SetSysClock();
  
/*中断向量偏移地址设置,不懂 */
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

[注]: 这里STM32F10X_CL宏定义问题,这玩意没有被定义,参考链接1链接2.

上头函数SystemInit ()的功能主要是复位与时钟相关的寄存器,并执行SetSysClock()。

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz//文件中这个一般高亮
  SetSysClockTo72();
#endif
 
 /* If none of the define above is enabled, the HSI is used as System clock
    source (default after reset) */ 
}

由此部分代码可知(如果宏定义STM3210X_HD),默认状态下,在函数SetSysClock()中将会执行函数SetSysClockTo72()。关于这个函数详细信息参考链接3,主要关注一下

  1. 设置HCLK,HCLK = SYSCLK
  2. 设置PCLK2,PCLK2 = HCLK
  3. 设置PCLK1,PCLK1 = HCLK / 2(即APB1预分频系数为2,不为1的哟!!!)
  4. 设置PLL时钟来源及PLL倍频因数
  5. 选择PLL作为系统时钟源,即PLLCLK = SYSCLK

到现在终于真相大白:CK_CNT=CK_INT /(N+1)=APB1*2 /(N+1)=72M / (N+1)(这里的N指PSC预分频器的预分频系数)。

五、通用定时器配置步骤

void MSTimerInit(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//定时器时钟
	TIM_TimeBaseStructure.TIM_Prescaler = 35999;//设置预分频系数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//上升沿计数
	TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //定时器重装载值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;      
	/*先甭管这个
	  定义在定时器时钟(CK_INT)频率与数字滤波器(ETR,TIx)
	  使用的采样频率之间的分频比例,数字滤波器(ETR,TIx)
	  是为了将ETR进来的分频后的信号滤波,保证通过信号
	  频率不超过某个限定
	*/
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //这个高级定时器才用
	TIM_DeInit(TIM3);//可有可无,网友说有了可以增加程序健壮性,有待考究
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);//定时器初始化
	TIM_ITConfig(  //使能或者失能指定的TIM中断,没中断没必要写
		TIM3, //TIM3
		TIM_IT_Update ,
		ENABLE  //使能
		);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能定时器TIM3

对于上面这段代码,定时器的溢出时间为=(重装载值+1)x(分频系数+1)/72M=(65535+1) x (35999+1) / 72M=65536 x 0.5ms

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-14 23:07:51  更:2021-07-14 23:08:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:42:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码