STM32基础(4)使用SysTick滴答定时器实验精准延时

2023-05-16

原理

SysTick 定时器也叫 SysTick 滴答定时器,它是 Cortex-M3 内核的一个外设, 被嵌入在 NVIC 中。它是一个 24 位向下递减的定时器,每计数一次所需时间为 1/SYSTICK,SYSTICK 是系统定时器时钟,它可以直接取自系统时钟,还可以通过系统时钟 8 分频后获取。

当定时器计数到 0 时,将从 LOAD 寄存器中自动重装定时器初值,重新向下递减计数,如此循环往复。如果开启SysTick 中断的话,当定时器计数到 0,将产生一个中断信号。因此只要知道计数的次数就可以准确得到它的延时时间。

在 STM32F1 库函数中,并没有提供相应的 SysTick 定时器配置函数,我们要操作 SysTick 定时器就需要了解它的寄存器功能。CTRL 是 SysTick 定时器的控制及状态寄存器。LOAD 是 SysTick 定时器的重装载数值寄存器。VAL 是 SysTick 定时器的当前数值寄存器。

步骤

  1. 编写SysTick驱动程序(STM32F1系列通用)
    1. 将固件库文件misc.c添加至工程,misc.c中包含SysTick寄存器的操作函数
    2. 编写头文件:函数声明
    3. 编写驱动文件:初始化函数、延时us函数、延时ms函数
  2. 对GPIO的IDR和ODR寄存器位操作进行封装(STM32F1系列通用)
  3. 编写LED驱动程序
    1. 编写头文件:宏定义连接LED的端口、端口引脚、端口时钟、引脚位带,函数声明
    2. 编写驱动文件:
      1. LED初始化函数:开启端口时钟,定义GPIO_InitTypeDef结构体变量并初始化,拉高引脚电平
  4. 主函数调用延时初始化函数、延时函数

代码

//SysTick.h
#ifndef _SYSTICK_H
#define _SYSTICK_H

#include "system.h"

void SysTick_Init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);

#endif

//SysTick.c
#include "SysTick.h"

static u8 fac_us = 0;		//保存倍乘数
static u16 fac_ms = 0;

void SysTick_Init(u8 SYSCLK)
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);	//将CTRL寄存器的第二位置0,即用外部时钟源
	fac_us = SYSCLK/8;	//72/8
	fac_ms = (u16)fac_us*1000;
}

void delay_us(u32 nus)
{
	u32 temp;
	SysTick->LOAD = nus*fac_us;//重装载值
	SysTick->VAL = 0x00;//当前数值清0
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//使能SysTick
	do
	{
		temp = SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));//定时器开启且未倒数到0
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//失能SysTick
	SysTick->VAL = 0x00;//当前数值清0
}

/*
注意:nms的值,SysTick->LOAD为24位寄存器,不要大于0xffffff*8*1000/SYSCLK,对72M条件下,nms<=1864ms 
*/
void delay_ms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;				//时间加载(SysTick->LOAD为24bit)
	SysTick->VAL =0x00;							//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;       					//清空计数器	  	    
} 
//system.c
#include "system.h"		//头文件中把GPIO的IDR和ODR寄存器位操作进行了封装

//system.h
#ifndef _system_H
#define _system_H

#include "stm32f10x.h"

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#endif
//led.h
#ifndef _led_H
#define _led_H

#include "stm32f10x.h"	//定义了各种地址
#include "system.h"

#define LED1_PORT GPIOB
#define LED1_PIN GPIO_Pin_5
#define LED1_PORT_RCC RCC_APB2Periph_GPIOB

#define LED2_PORT GPIOE
#define LED2_PIN GPIO_Pin_5
#define LED2_PORT_RCC RCC_APB2Periph_GPIOE

#define LED1 PBout(5)  	
#define LED2 PEout(5) 

void LED_Init(void);

#endif

//led.c
#include "led.h"

void LED_Init(void){
	
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(LED1_PORT_RCC|LED2_PORT_RCC, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = LED1_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(LED1_PORT, &GPIO_InitStructure);
	GPIO_SetBits(LED1_PORT, LED1_PIN);
	
	GPIO_InitStructure.GPIO_Pin = LED2_PIN;
	GPIO_Init(LED2_PORT, &GPIO_InitStructure);
	GPIO_SetBits(LED2_PORT, LED2_PIN);
}
//main.c

#include "system.h"
#include "SysTick.h"
#include "led.h"

int main()
{
	
	LED_Init();
	SysTick_Init(72);
	
	while(1)
	{
		LED1 = 0;
		LED2 = 0;
		delay_ms(500);
		LED1 = 1;
		LED2 = 1;
		delay_ms(500);
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32基础(4)使用SysTick滴答定时器实验精准延时 的相关文章

  • 如何在 Cortex-M3 (STM32) 上从 RAM 执行函数?

    我正在尝试从 Cortex M3 处理器 STM32 上的 RAM 执行函数 该函数会擦除并重写内部闪存 所以我肯定需要在 RAM 中 但我该怎么做呢 我尝试过的是 使用 memcpy 将函数复制到 RAM 中的字节数组 检查它是否正确对齐
  • 在地址“0xXXXXXX”处中断,没有可用的调试信息,或在程序代码之外

    配置 使用 Nucleo L476RG 使用 GNU ARM Eclipse 我从 STM32CubeMX 生成了一个极简代码 我已经在我的板载 ST Link 中刷新了 J link 驱动程序 一直在尝试为我的代码运行调试器 但我的程序计
  • GCC - 如何停止链接 malloc?

    我正在努力将我的代码缩减到最小的骨架大小 我使用的是只有 32k 闪存的 STM32F0 需要很大一部分闪存用于数据存储 我的代码已经有大约 20k 闪存大小 其中一些是由于使用了 STM32 HAL 函数 我可以在以后需要时对其进行解释和
  • STM32 F072上的软件如何跳转到bootloader(DFU模式)?

    STM32应用笔记2606对此进行了讨论 但没有简单的代码示例 该答案已使用 IAR EWARM 在 STM32F072 Nucleo 板上进行了测试 这个答案使用 STM32标准外设库 仅此而已 请注意 验证您是否成功进入引导加载程序模式
  • rt-thread studio中新建5.02版本报错

    先吐槽一下 rt thread studio出现BUG真多 好多时间都是在找BUG 但里面用好多控件还是挺好用的 真是又爱又恨 所以一般使用功能不多的话还是用keil多一点 创建5 02版本工程之后直接进行编译 直接会报下面这个错误 资源
  • 匹配 STM32F0 和 zlib 中的 CRC32

    我正在研究运行 Linux 的计算机和 STM32F0 之间的通信链路 我想对我的数据包使用某种错误检测 并且由于 STM32F0 有 CRC32 硬件 并且我在 Linux 上有带有 CRC32 的 zlib 所以我认为在我的项目中使用
  • STM32用一个定时器执行多任务写法

    文章目录 main c include stm32f4xx h uint32 t Power check times 电量检测周期 uint32 t RFID Init Check times RFID检测周期 int main Timer
  • 毕业设计 江科大STM32的智能温室控制蓝牙声光报警APP系统设计

    基于STM32的智能温室控制蓝牙声光报警APP系统设计 1 项目简介 1 1 系统构成 1 2 系统功能 2 部分电路设计 2 1 stm32f103c8t6单片机最小系统电路设计 2 2 LCD1602液晶显示电路设计 2 2 风
  • SHT10温湿度传感器——STM32驱动

    实验效果 硬件外观 接线 3 3V供电 IIC通讯 代码获取 查看下方 END
  • 硬件基础-电容

    电容 本质 电容两端电压不能激变 所以可以起到稳定电压作用 充放电 电容量的大小 想使电容容量大 使用介电常数高的介质 增大极板间的面积 减小极板间的距离 品牌 国外 村田 muRata 松下 PANASONIC 三星 SAMSUNG 太诱
  • VS Code 有没有办法导入 Makefile 项目?

    正如标题所说 我可以从现有的 Makefile 自动填充 c cpp properties json 吗 Edit 对于其他尝试导入 makefile 的人 我找到了一组脚本 它们完全可以实现我想要实现的目标 即通过 VS Code 管理
  • 最终启动顺序错误 - STM32L476 的 Eclipse System Workbench 调试

    我正在尝试调试和运行 STM32L476 的简单汇编代码 我已经设置了 Eclipse Oxygen 在 Eclipse 中安装了最新版本的 System Workbench 插件并安装了 ST Link 驱动程序 IDE 成功构建了程序
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • Freertos低功耗管理

    空闲任务中的低功耗Tickless处理 在整个系统运行得过程中 其中大部分时间都是在执行空闲任务的 空闲任务之所以执行 因为在系统中的其他任务处于阻塞或者被挂起时才会执行 因此可以将空闲任务的执行时间转换成低功耗模式 在其他任务解除阻塞而准
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • 特殊寄存器

    特殊寄存器 文章目录 前言 一 背景 二 2 1 2 2 总结 前言 前期疑问 STM32特殊寄存器到底是什么 特殊寄存器怎么查看和调试代码 本文目标 记录和理解特殊寄存器 一 背景 最近在看ucosIII文章是 里面提到特殊寄存器 这就进
  • 嵌入式 C++11 代码 — 我需要 volatile 吗?

    采用 Cortex M3 MCU STM32F1 的嵌入式设备 它具有嵌入式闪存 64K MCU固件可以在运行时重新编程闪存扇区 这是由闪存控制器 FMC 寄存器完成的 所以它不像a b那么简单 FMC 获取缓冲区指针并将数据刻录到某个闪存
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d

随机推荐

  • Kettle-excel数据同步

    Kettle excel数据同步 Excel输入组件编辑文件选择选择工作表内容字段预览记录 Excel输入组件 编辑 文件选择 选择工作表 内容 字段 若String类型不设置长度 xff08 或设置为 1 xff09 xff0c 则默认长
  • oracle中数据类型number(9,2)的意思

    9表示这个数据的有效位数 xff08 精度 xff09 xff0c 2表示两个小数位 xff08 刻度 xff09 例如 xff1a 1234567 89
  • mybatis-忽略实体对象的某个属性

    方法一 xff1a 在需要忽略的属性上增加 64 transient注解 javax persistence Transient transient是类型修饰符 xff0c 只能用来修饰字段 在对象序列化过程中 xff0c 被transie
  • Elasticsearch -删除索引(index)

    删除单个 DELETE index curl XDELETE 39 http 192 169 1 666 9200 index 你也可以这样删除多个索引 xff1a DELETE index one index two curl XDELE
  • STM32F103ZET6程序移植为C8T6+C8T6下载程序flash timeout的解决方案

    文章目录 一 程序移植 xff1a 程序移植还是蛮简单的二 程序下载 会出现问题 xff08 一 xff09 BOOT0和BOOT1 xff08 二 xff09 程序下载1 代码通用2 状况不断3 解决办法 xff08 三 xff09 ST
  • Android-Studio-Chipmunk版本解决gradle报错connection-refuse的问题

    Android Studio Chipmunk版本解决gradle报错connection refuse的问题 文章目录 Android Studio Chipmunk版本解决gradle报错connection refuse的问题一 问题
  • MapReduce编程-join算法实现

    假设有订单表t order和t product两张数据库表 xff0c 现在需要进行关联查询 这样的sql语句很容易写 select a span class hljs preprocessor id span a span class h
  • 《将博客搬至CSDN》

    将博客搬至CSDN
  • 3D打印Gcode文件命令详解

    目录 3D打印Gcode文件命令详解Gcode文件作用 常用命令 命令 注释G28命令 复位G90和G91命令 设置定位模式M82和M83命令 设定挤丝模式G1命令 运动命令G92命令 设置当前位置M104和M109命令 加热喷嘴M140和
  • 机器学习系统安全

    Abstract 机器学习 已经成为当前计算机领域研究和应用最广泛的技术之一 xff0c 在图像处理 自然语言处理 网络安全等领域被广泛应用 然而 xff0c 一些机器学习算法和训练数据本身还面临着诸多安全威胁 xff0c 进而影响到基于机
  • 汇编语言测试

    汇编测试
  • 汇编语言-DosBox环境搭建

    汇编语言 王爽 问题 xff1a debug 不是内部或外部命令 原因 xff1a 现在windows下不集成了 xff0c 我们可以利用DosBox工具帮助我们学习汇编 汇编语言环境搭建 参考帖子 xff1a https www cnbl
  • 矩阵快速幂详解

    矩阵快速幂 在讲矩阵快速幂之前 xff0c 先引入整数快速幂的概念 整数快速幂 为了引出矩阵快速幂 xff0c 以及说明快速幂算法的好处 xff0c 我们可以先求整数的幂 如果现在要算X 8 则X X X X X X X X X 按照寻常思
  • ubuntu 20.04安装ROS noetic添加秘钥失败 gpg: no valid OpenPGP data found.

    在安装ROS noetic时 xff0c 可能会遇到以下错误 当运行以下命令时 curl s https raw githubusercontent com ros rosdistro master ros asc sudo apt key
  • 【CentOS7 Samba服务器配置】

    第四章 Samba服务器配置 文章目录 第四章 Samba服务器配置前言一 Samba是什么 xff1f 二 使用步骤1 安装软件包2 配置Samba服务器3 创建文件夹4 添加 Samba 用户5 开启服务6 测试 总结 前言 本章学习S
  • ArgumentError: Could not parse rfc1738 URL from string

    使用flask sqlacodegen遇到如上问题时 xff0c 引号要用双引号 xff0c 并且要mysql xff08 如果你使用的是其他的数据库这里应该填你使用的数据库 xff09 注意 注意 注意要加上数据库驱动 xff0c 向下面
  • 多任务学习为什么有效?

    前言 多任务学习 xff08 Multi task Learning MTL xff09 在机器学习领域应用广泛 xff0c 比如自然语言处理和计算机视觉等领域 xff0c 这也侧面反映了 MTL 的有效性 本文将从 MTL 的概念 使用动
  • 简单绕过chrome(谷歌游览器) 查看已保存的密码

    利用场景 xff1a 同事或朋友外出有事 xff0c 电脑未锁屏离开座位 可以利用这一间隙 xff0c 查看Ta在Chrome浏览器上保存的账号密码 查看逻辑 xff1a 当我们要查看Chrome浏览器上保存的密码时 xff0c 点击显示
  • 根据数据库表生成 model 类

    根据数据库表生成 model 类 创建一个Django项目 code django admin startproject xxxx code 修改setting文件 xff0c 在setting里面设置你要连接的数据库类型和连接名称 xff
  • STM32基础(4)使用SysTick滴答定时器实验精准延时

    原理 SysTick 定时器也叫 SysTick 滴答定时器 xff0c 它是 Cortex M3 内核的一个外设 xff0c 被嵌入在 NVIC 中 它是一个 24 位向下递减的定时器 xff0c 每计数一次所需时间为 1 SYSTICK