STM32 定时器的简单应用 1ms中断代码

2023-11-12

引言:利用定时器TIM8产生1ms中断,每中断一次,全局变量+1,计数到10即10ms,使得输出引脚翻转一次。芯片采用STM32F103VCT6,系统输入时钟12MHz,完成代码并用示波器输出。

根据要求,本项目涉及系统时钟配置、中断源配置、GPIO输出配置、定时器配置四个部分。

1、准备工作

(1)系统时钟配置

    TIM8时钟为PLCK2,由APB2进行提供,时钟配置流程如下图(具体配置方法见STM32 RCC配置时钟 MCO输出实验_Artemis_yuer的博客-CSDN博客),本项目TIM8选择内部时钟CK_INT作为时钟源。

       配置步骤:

      ①12MHz外部时钟HSE输入;

      ②HSE分频器作为PLL输入,此处选择不分频;

      ③HSE时钟作为PLL输入时钟;

      ④PLL倍频系数,设置为6倍,产生72MHzPLLCLK时钟;

      ⑤选择PLLCLK作为系统时钟;

      ⑥设置AHB时钟,得到HCLK时钟;

      ⑦设置高速AHB时钟,通过APB2得到PLCK2时钟;

      ⑧PLCK2分频得到TIMx CLK;

      ⑨TIMx CLK作为TIM8内部时钟。

(2)中断源配置

         配置TIM8中断向量,这里直接用库函数进行配置。配置相应的主优先级和从优先级。

(3)GPIO输出配置

         TIM8位单片机的PC7引脚,因此需要使能GPIOC,即APB2 外设时钟使能寄存器(RCC_APB2ENR)第四位置1。

        PC7使用端口配置低寄存器(GPIOx_CRL)进行配置,设置为推挽输出模式,如图所示,寄存器复位值并不为0,首先要将寄存器第七位(即31:28)清零,然后赋值0011。

         本项目需要定时器每中断一次,全局变量+1,计数到10即10ms,使得输出引脚翻转一次,设置局部变量和中断输出函数,当进入十次中断后,局部变量+1,输出高电平,再进入十次中断后,局部变量再+1,输出低电平,以此来实现10ms的电平翻转。

       配置步骤:

       ①IOPC使能;②PC7引脚清零;③PC7设置为推挽输出模式;④判断是否溢出中断;⑤清除中断标志位;⑥电平翻转输出。

(4)定时器配置

        实验需设定定时器中断为1ms,输出方波为1kHz,定时中断周期计算公式:

        Tout = ((ARR+1)*(PSC+1))/Tclk ;

        其中:Tclk:定时器的输入时钟频率(单位MHZ)

        Tout:定时器溢出时间(单位为us)

        PSC:定时器预分频值,将Tclk分频了PSC+1,定时器的最终频率就是Tclk/(PSC+1) MHz

        ARR:自动重装载寄存器,定时器计数的值被重装载一次被就是一个更新,若为向上计数,则从0开始重新计数。

        这里为满足要求,设置PSC=72-1;即Tclk分频72次,得到1MHz定时器频率,为1us,项目需要中断为1ms,是1us的1000倍,则ARR值为1000-1,得到1ms中断值;f=1/T=1/1ms=1000Hz,也就是1kHZ的方波。而本项目需要产生20ms周期的方波,f=1/T=1/20ms=50Hz,则输出频率为50Hz的方波(若不需要20ms周期输出,则输出频率为1000Hz)。

       配置步骤:

     ①TIM8时钟使能;

     ②设置TIM8的PSC(预分频值)和ARR(自动重装溢出值);

     ③输出使能(配置高级定时器的刹车和死区寄存器打开);

     ④允许接收中断;

     ⑤使能TIM8。

2、程序代码


(1)基于寄存器代码

#include "sys.h"
#include "main.h"
#include "stm32f10x.h"
#include "misc.h"

//时钟配置
void Stm32_Clock_Init()
{
        uint8_t temp=0;
	    RCC_DeInit();                   /* 时钟复位 */
	    RCC->CR|=1<<16;                 /* 使能HSE时钟 */
	    while(!(RCC->CR|=1>>17))        /* 判断HSE就绪 */
	    {
		}
		RCC->CFGR=0x00000400;           /* APB1=DIV2;APB2=DIV1;AHB=DIV1 */
		RCC->CFGR|=1<<16;               /* 配置HSE时钟作为PLL时钟输入 */
		FLASH->ACR|=0x32;               /* FLASH延时两个周期 */
		RCC->CFGR|=0x00100000;          /* PLL 6倍频输出 */
	    RCC->CR|=1<<24;                 /* PLL使能 */
		while(!(RCC->CR|=1>>25))        /* 判断PLL时钟就绪 */
		{
		}
		RCC->CFGR|=0x02;                /* 选择PLL为SYSCLK */
	
		
		while(temp!=0x02)               /* 判断SYSCLK是否设置成功 */
		{   
		temp=RCC->CFGR>>2;
		temp&=0x03;
		}    
		
}		 

//GPIO配置  PC7
void TIM8GPIOConfig()

{
      RCC->APB2ENR|=1<<4;             /* IOPC使能 */
	  GPIOC->CRL&=0X0FFFFFFF;         /* PC7引脚清零 */
	  GPIOC->CRL|=0X30000000;         /* PC7设置为推挽输出模式 */
    
}



//Timer配置  1kHz
void TIM8_Init()

{
   
      RCC->APB2ENR|=1<<13;           /* TIM8时钟使能 */
	  TIM8->ARR=999;                 /* 计数器自动重装值为1000,刚好1ms,1KHz */
	  TIM8->PSC=71;                  /* 预分频器72,得到1MHz的计数频率 */

	  TIM8->BDTR = 0x8000;           /* 输出使能 */
	  TIM8->CR1|=0x0080;             /* 寄存器装入缓冲器 */ 
	
	  TIM8->DIER|=1<<0;              /* 允许更新中断 */
	  TIM8->DIER|=1<<6;              /* 允许触发中断 */
      TIM8->CR1 |=0X01;              /* 使能定时器8 */
}



//TIM8中断优先级配置
void TIM8_IT_Init()	    
{    
      NVIC_InitTypeDef  NVIC_InitStructure;    
	  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);              
	  NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_IRQn;  
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
      NVIC_Init(&NVIC_InitStructure);  
    
}	




//中断输出配置
uint16_t cnt=0;

void TIM8_UP_IRQHandler(void)
{
   static uint16_t flag=0;
   if(TIM8->SR&0x0001)                     /* 判断是否溢出中断 */
		{
		   TIM8->SR&=~(1<<0);              /* 清除中断标志位 */
		   cnt++;                          /* 每进一次中断,CNT+1 */
	       if(cnt>=10)                     /* 如果CNT=10,输出*/
		    {	
					cnt=0;
					flag++;                    /* 每十个中断flag+1*/
					if(flag%2==0)              /* 若为奇数*/
					{
						GPIOC->ODR|=1<<7;      /* 输出高电平*/
					}
					else
					{  
                        GPIOC->ODR&=0<<7;      /* 否则输出低电平*/
                    }
		
		    }
	
	     }

}



	
	
int main()
{
  	  Stm32_Clock_Init();
	  TIM8GPIOConfig();
	  TIM8_Init();
	  TIM8_IT_Init();	 
	
	 
	  while(1)
		{
			
			
		}
}

(2)基于库函数代码

#include "sys.h"
#include "main.h"
#include "stm32f10x.h"
#include "misc.h"


uint16_t cnt=0;
void RCC_Init()                                      /* 系统时钟配置 */
{    
	    ErrorStatus HSEStartUpStatus;                    /* 枚举型变量 */
		RCC_DeInit();                                    /* 重置RCC  */
		RCC_HSEConfig(RCC_HSE_ON);                       /* HSE使能 */
		HSEStartUpStatus=RCC_WaitForHSEStartUp();        /* 等待HSE起振 */
		if(HSEStartUpStatus==SUCCESS)                    /* 判断HSE起振成功 */
		{
				
		    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        
            FLASH_SetLatency(FLASH_Latency_2);           /* 2个延时周期*/
		    RCC_HCLKConfig(RCC_SYSCLK_Div1);               
		    RCC_PCLK1Config(RCC_HCLK_Div2);              /* 设置低速APB1时钟PLCK1*/
			RCC_PCLK2Config(RCC_HCLK_Div1);              /* 设置高速APB2时钟PLCK2*/
			RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_6);       /* 6倍频 */
		}	
		else
	   {
			    /*do nothing*/
       }
			
			
		RCC_PLLCmd(ENABLE);                                   /* PLL使能 */
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)     /* 检查使能标志位 */
		{
		}
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);            /* PLLCLK作为SYSCLK */
		while (RCC_GetSYSCLKSource()!=0x08)     
        /* 判断SYSCLK是否设置成功  0x08PLL作为系统时钟 */
		{
		}
}


void TIM8_GPIO_Config(void)                                            /* GPIO配置 */
{		
    GPIO_InitTypeDef GPIO_InitStruct;                                  /* 结构体定义 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);              /* GPIOC使能 */
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;                               /* PC7引脚 */
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;                        /* 推挽输出 */
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;                       /* 50MHz*/
    GPIO_Init(GPIOC,&GPIO_InitStruct);                                 /*初始化GPIOC */
	}


	
	

void TIM8_Init()
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);           /* TIM8时钟使能 */
	TIM_DeInit(TIM8);
	TIM_InternalClockConfig(TIM8);
    TIM_TimeBaseStructure.TIM_Period = 71;            /* 预分频器72,得到1MHz的计数频率 */
    TIM_TimeBaseStructure.TIM_Prescaler =999;         /* 计数器自动重装值为1000 */
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     /* 向上计数 */ 
    TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); 
    TIM_ITConfig(TIM8,TIM_IT_Update,ENABLE);
	TIM_Cmd(TIM8, ENABLE); 
	 
}
  


void TIM8_IT_Init()
{
	NVIC_InitTypeDef  NVIC_InitStructure;    
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure);  
          
	  
}

void TIM8_UP_IRQHandler(void)
{
	  static uint16_t flag=0;
	  if (TIM_GetITStatus(TIM8, TIM_IT_Update)!= RESET) 
      {
        TIM_ClearITPendingBit(TIM8, TIM_IT_Update);  
        cnt++;
		  
		 
		 if(cnt>=100)
		 {
              cnt=0;
			  flag++;
			  if(flag%2==0)
				{
			      GPIO_SetBits(GPIOC,GPIO_Pin_7);
				}
				else					  
                {			
	              GPIO_ResetBits(GPIOC,GPIO_Pin_7);
                }
          }
       }
}



int main()
{
      RCC_Init();
	  TIM8_GPIO_Config();
	  TIM8_Init();
	  TIM8_IT_Init();
	  
	  while(1)
		{
			
		}
}

3、信号输出

生成代码编译后烧写至芯片内,通过示波器显示如下图:

              

       由示波器可以观察到输出周期为20ms,也就是说配置定时器中断为1ms,,示波器频率显示为50HZ,实验成功。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 定时器的简单应用 1ms中断代码 的相关文章

  • wxWidgets with quick-x

    前言 OSX下 Qt5 所生成应用包的大小有七八十兆大小 单独一个 debug 版本的可执行程序都有 15 7MB 再加上 QtCore QtGui QtOpenGL 等 framework 包大小分分钟上来 曾经发布过的 Qt5 2 qu
  • 微信公众号实现“一键关注”功能

    背景 之前用的一键关注要么通过图文 要么通过二维码 这样甚是麻烦 而且引导不到位 而看到朋友圈打广告的一些公众号可以直接关注 于是一直研究这个功能 今天终于实现了 分享给所有朋友 希望能帮助到所有朋友 这个引导关注的页面包含了公众号的log
  • 密码学之哈希算法

    1 哈希算法 哈希算法是将任意长度的二进制值映射为较短的固定长度的二进制值 这个小的二进制值称为哈希值 哈希值是一段数据唯一且极其紧凑的数值表示形式 如果散列一段明文而且哪怕只更改该段落的一个字母 随后的哈希都将产生不同的值 要找到散列为同
  • 滑动关机BAT脚本

    滑动关机脚本 1 脚本功能 增加一个一键关机的功能 点击这个按钮 即可滑动关闭电脑 非常酷炫好用 2 脚本内容 slidetoshutdown 3 使用方式 新建slideDown bat文件 编辑 把上面的脚本内容粘贴进去 然后双击执行s
  • MySQL(十三):分区表( Partitioning Table)

    文章目录 1 MySQL 分区简介 1 1 什么是分区表 1 2 分区表优点 1 3 分区表缺点 2 MySQL 分区类型 2 1 范围分区 RANGE 2 1 1 基于时间间隔的分区方案 2 1 1 1 按 RANGE 对表进行分区 2

随机推荐

  • Maven项目版本定义

    Maven使用占位符实现一处定义项目版本 使用 revision 定义整个项目的版本 方便修改 父pom
  • Java实现杨辉三角

    代码实现 package day01 public class yanghui public static void main String args 声明二维数组并初始化 int yanghui new int 10 给二维数组赋值 fo
  • jsp 新能源汽车论坛网Myeclipse开发mysql数据库web结构java编程计算机网页项目

    一 源码特点 JSP 新能源汽车论坛网是一套完善的java web信息管理系统 对理解JSP java编程开发语言有帮助 系统具有完整的源代码和数据库 系统主要采用B S模式开发 开发环境为 TOMCAT7 0 Myeclipse8 5开发
  • 《如何为Android Studio安装HAXM》

    注意 当你在Android studio直接下载sdk和HAXM一些安卓环境依赖的文件时 会出现haxm文件已经下载 但未安装 导致启动avd模拟器不成功 如下图 emulator64 x86 avd 32 QVGA ADP2 API 25
  • Python爬虫实战——搭建自己的IP代理池

    如今爬虫越来越多 一些网站网站加强反爬措施 其中最为常见的就是限制IP 对于爬虫爱好者来说 能有一个属于自己的IP代理池 在爬虫的道路上会减少很多麻烦 环境参数 工具 详情 服务器 Ubuntu 编辑器 Pycharm 第三方库 reque
  • sql增删改查_Zhuo笔记:使用C#链接SQL数据库并进行增删改查操作

    一 首先使用SQL语句在建立数据库及表 二 在C 中做一个简单窗口以便对SQL数据库进行操作 三 编写代码进行SQL链接 1 C 访问SQL SERVER首先需要引用using System Data 和usingSystem Data S
  • 芯片IO口Driving能力(Sourcing Current)测试方法

    PMOS管测试步骤 Drive High Ability 1 将IO PAD配置成output模式 DUT供电电压为可正常工作的最低电压 如依datasheet允许 下降10 3 3V gt 2 97V 等 2 将IO PAD配置成最大Dr
  • 图文详解GPT-4最强对手Claude2的使用方法

    大家好 我是herosunly 985院校硕士毕业 现担任算法研究员一职 热衷于机器学习算法研究与应用 曾获得阿里云天池比赛第一名 CCF比赛第二名 科大讯飞比赛第三名 拥有多项发明专利 对机器学习和深度学习拥有自己独到的见解 曾经辅导过若
  • 基于粒子群算法优化LSTM的多输入单输出台风风电功率预测

    基于粒子群算法优化LSTM的多输入单输出台风风电功率预测 随着风电产业的快速发展 风电场的管理和运行越来越依赖于准确的风速信息和风力预测 因此 台风风电功率预测的研究变得越来越重要 在本文中 我们将使用粒子群算法 PSO 来优化长短期记忆网
  • spring-boot项目使用ulisesbocchio对配置文件敏感信息加密

    参考文献github官网地址 https github com ulisesbocchio jasypt spring boot 1 添加依赖 maven
  • kiel5编译报错error: L6235E: More than one section matches selector - cannot all be FIRST/LAST.

    原因是startup xxx s文件只能保留其中一种 启动文件分别带有hd md ld和cl vl xl几种种字样 需要查看mcu的flash内存大小来选择 cl 互联型产品 stm32f105 107系列 vl 超值型产品 stm32f1
  • 世界各国英文简写一览表

    整理了一份世界各国英文简写表 供大家参考 country cName country code country eName 中国 CN China 中国台湾 W aiwan 中国澳门 MO Macao 中非共和国 CF he Central
  • 基于STM32c8t6的5路pwm占空比测量实验总结

    测量方式 1 正点原子例程里使用的方式 定时器通道的相关引脚输入捕获上升沿触发中断 在中断函数里 检测到上升沿之后TIM SetCounter TIMX 0 将计数器的值置零重新开始计数 同时将定时器中断触发方式切换为下降沿触发 待到下降沿
  • 嵌入式(TCP编程)

    TCP编程API 1 socket 函数 参数 2 bind 函数 如果是IPV6的编程 要使用 struct sockddr in6结构体 man 7 ipv6 通常更通用的方法可以通过struct sockaddr storage来编程
  • VulnHub渗透实战Billu_b0x

    简介 VulnHub是一个面向所有人开放的安全靶场 里面有很多安全环境 只要下载相关镜像 在相关虚拟机上面运行就可以练习相关靶场了 里面设计了好多关 如果有耐心一定可以到达峰顶 许多考oscp人员 也会利用vulnhub靶场进行刷题 我们下
  • pycharm缩进快捷键

    1 pycharm使多行代码同时右移缩进 鼠标选中多行代码后 按下Tab键 一次缩进四个字符 2 pycharm使多行代码同时左移 鼠标选中多行代码后 同时按住shift Tab键 一次左移四个字符
  • python函数和模块有什么特性_python-函数包和模块

    python函数的作用 在Python代码段中如果有一段几十行的代码 需要多次重复使用这几十行代码时 为了提高代码的可用性 将代码段放进函数体内 以后在使用中直接调用该函数模块即可 函数是一个独立的函数体或是一段独立的功能体 最主要的作用是
  • 头脑风暴会议的注意事项

    在组织内会经常召开头脑风暴的讨论会 如何举办一个成功的讨论会议呢 请看如下的30个要点 头脑风暴会议的注意事项 序号 分类 要点 1 会前 明确会议目的 议程 时间 地点 交通方式等 并确保通知到与会人员 以便参与者有充分准备 2 准备必要
  • 智能系统设计开发 java_一种基于java语言的智能系统设计与开发.doc

    一种基于java语言的智能系统设计与开发 doc 还剩 36页未读 继续阅读 下载文档到电脑 马上远离加班熬夜 亲 很抱歉 此页已超出免费预览范围啦 如果喜欢就下载吧 价低环保 内容要点 兰州交通大学毕业设计 论文 32参考文献 1 郭今吕
  • STM32 定时器的简单应用 1ms中断代码

    引言 利用定时器TIM8产生1ms中断 每中断一次 全局变量 1 计数到10即10ms 使得输出引脚翻转一次 芯片采用STM32F103VCT6 系统输入时钟12MHz 完成代码并用示波器输出 根据要求 本项目涉及系统时钟配置 中断源配置