《STM32单片机应用与全案例实践》沈红卫_2017版读书笔记

介绍

这篇文章是我入门嵌入式的文章,有些理解可能不足。

是看江协和正点原子的视频,板子是STM32F103C8T6最小系统板。 正点为主:第3讲 STM32学习方法_视频说明_哔哩哔哩_bilibili

江协为辅:STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili

这些是我在学习STM32F103C8T6的过程中自己的学习过程,以及练习和总结的个人笔记。

个人(视频)笔记在这里:STM32-江协科技学习笔记-CSDN博客

正在更新,

大家可以在我的gitee仓库 中下载笔记源文件、梁山派资料等

笔记源文件可以在Notion中导入

第一章

1.学习STM32需要什么?

  1. 要清楚基本的电路原理。比如电流、电源、电阻、三极管等等,能看懂原理图
  2. 可以先学51单片机,了解微控制器的基本原理(这里读者是直接入手的Stm32)
  3. C语言必须学好!(一般讲C语言都会连带着了解一些计算机组成的基本知识)
  4. 可以使用万用表、电烙铁等、要是有示波器等高级测量仪器就更好了。

1.STM和51的区别

STM32和51单片机都属于单片机的范畴 不过51是8位的、用的是冯诺依曼结构 STM32是32位的、用的是哈佛结构

他们的性能也不同。巴拉巴拉的。反正32厉害!

2.ARM的含义

ARM是什么

他是ARM公司设计的一个低功耗的CPU及其架构。包括了ARM1~ARM11 以及Cortex 用的比较多的是ARM7 9 11 以及 Cortex系列

ARM公司不生产芯片,他们只是去做内核然后卖给别的公司。特点就是所有的指令格式是一致的。

别的公司买走之后会根据自身的技术以及想法来生产和销售

Cortex是什么

cortex是ARM的全新一代的处理器,本质上是ARM V7 的架构。

有三个分类

  • Cortex-A
  • Cortex-R
  • Cortex-M

STM32就属于Cortex-M类。Cortex-M是一种高性能低成本的微处理器平台

3.STM32的内部结构

STM32不同51的冯诺依曼结构,他是哈佛结构。也就是程序储存器和数据储存器不分开、统一编址

STM32现在(2024年)比较常用的有3个大系列 F1 F4 F7

他们都有升级。

STM32 F1、F4、F7 系列的升级主要体现在内核、性能、功耗和外设等方面,具体区别如下:

  • 内核:F1 系列为 Cortex-M3 内核;F4 系列为 Cortex-M4 内核,具有 Cortex-M3 内核的特性、DSP(数字信号处理)指令并支持浮点运算;F7 系列为 Cortex-M7 内核,具有 Cortex-M4 内核的特性、双精度浮点运算、cache(缓存)和 TCM(紧密耦合内存)。
  • 性能:性能上 F7 远强于 F4,F4 则略好于 F1。这体现在主频上也是 F7 高于 F4 高于 F1。
  • 功耗:功耗方面 F7 大于 F4 大于 F1,一般性能越好,功耗相对越大。
  • 外设:F7 的外设资源比 F4 和 F1 更丰富。

STM32是微处理器,他集成了该有的所有基本组件。通过总线连接在一起。

**主要的功能组件有:**Cortex-M内核、总线、系统时钟发生器、复位电路、程序存储器、数据存储器、中断控制、调试接口以及各个功能部件(外设)。

不同的系列芯片,他的外设数量以及性能不同、但是基本的组成一定是一样的。

**常用的外设一般有:**输入输出接口(GPIO)、定时器/计数器(TIMER/COUNTER)、串行通信接口(USART)、串行总线I2C和SPI或者I2S、SD卡接口SDIO、USB等

32位的地址线有4GB的地址空间,所有的部件、外设都会被统一编址、

外设分为高速和低速外设,他们被挂载的不同的总线上。如APB1、APB2。。外设属于高速还是低速是ST公司已经确定好的。

APB1和APB2是通过AHB系统总线桥接后得到的。

4.STM32的时钟树

1 内部RC振荡器和外部晶振的选择

STM32可以使用内部晶振,也可以用外部晶振,(一般都要用外部晶振的,这个后续也可以在函数的配置文件来修改)

2 STM32时钟源

STM32有5个时钟源:

  • HSI 高速内部时钟,RC振荡器,频率为8MHZ
  • HSE 高速外部时钟,可以接石英、陶瓷振荡器或者别的外部的时钟源。范围是4MHZ -16Mhz(72M是通过倍频得来的)
  • LSI 低速内部时钟,RC真昂起,频率为40KHZ
  • LSE 低速外部时钟,同上,频率范围是32.768KHZ(因为这个频率可以被2分频为1)
  • PLL 锁相环倍频输出, 其时钟输入源可以选择HSI/2、HSE 或者 HSE/2,倍频可以是2~16倍。(但是最大输出一般不会超过72Mhz)

3 时钟树的输入与输出

时钟树可以大概理解为,不同外设可以有不同的频率来运行。就像大树一样,不同的枝干(外设)有不同的粗细(频率)。

51单片机的所有外设都是在一条枝干上的,除非更换外部晶振的频率。 但STM32的时钟树不同于51不可更改。

STM32微控制器的时钟树是可以配置的,时钟在输入后可以由多个分频器、锁相环(可以倍频)、以及AHB、APB2等的与分频。

举例来说可以看下面的图

路径 1 2 3 4 5 6 7

也可以看路径②:1 5 6 7

4 STM32中与时钟相关的几个概念

  • SYSCLK :系统时钟,STM32大部分器件的时钟来源。他有AHB总线分配到各个部件
  • HCLK :由AHB预分频器直接输出得到,是高速总线AHB的时钟信号。他提供信号给储存器、DMA、以及Cortex内核。是Cortex内核运行的时钟。CPU的主频就是这个信号。他的大小与STM32的运算速度。数据存取速度密切相关
  • FCLK :由AHB预分频器直接输出得到,是内核的“自有运行时钟”。 “自由”表现在FCLK独立于HCLK,即使HCLK不运行了(休眠了)。也能够去采集和跟踪休眠时的事件。它与HCLK互相同步。
  • PCLK1 :外设时钟1,由APB1 与分频器输出得到,最大频率为36MHZ,提供给挂载在APB1总线上的外设(低速外设)
  • PCLK2 :外设时钟2,由APB1 与分频器输出得到,最大频率为72MHZ,提供给挂载在APB1总线上的外设(高速外设)

5.时钟输出的使能及其流程

当使用某个外设的时候,必须先使能其对应的时钟。

6.STM23的开发模式

  1. 基于寄存器的开发模式 这里就大概了解。 寄存器的开发需要熟悉各个部件的功能 要熟悉主要寄存器的定义以及作用 巴拉巴拉
  2. 基于库函数的开发模式 这种的话上手难度偏低,但对寄存器底层了解会变少,建议适当接触底层吧。 维护和调试也容易。
  3. 基于操作系统的开发模式 常用的实时系统有FreeRTOS、Linux、等等等 在嵌入式以上使用操作系统有大好处
    1. 当任务量少的时候,程序员可以看得过来。但是如果任务量多,你要去手动编制CPU的管理程序,就比较困难了。很难发挥32位CPU的处理能力。 但是当用操作系统后,就可以更多的把精力放在程序本身,因为此时的操作系统与目标板的硬件和结构无关,而不必去注重系统资源的管理。
    2. 让系统开发变的简单,缩短开发周期。并且使用系统可以更加高效可靠。

学习STM32.建议使用寄存器和固件库混合的方式,这样两者都可以比较明白。而且也能缩短开发周期等等。

第二章

STM32的固件库

STM32的固件库也称为固件包,他包含了这个板子的所有外设的驱动函数。

由程序、数据结构和各种的宏组成。

相当于为用户提供了一个可以操控底层寄存器的API接口。我们只需要调用API填写相应的参数就可以实现对外设 的操控。

下载固件库可以在ST官网上下载。

STM32的固件库组成

固件库主要文件有

  • Library 存放驱动库的源代码启动文件

    • STM32F10x_StdPeriph_Driver 文件夹存放的是制造商在Cortex-M3内核上外加的外设的驱动程序,包好inc(include)和src(source)两个文件,inc是头文件,src里是对应的C语言程序源码
    • CMSIS 存放的是Cortex - M3内核自带的驱动代码和启动代码,其中的M3文件夹是主要的,其他的可以忽略
      • M3 包含两文件夹:CoreSupport和DeviceSupport
        • CoreSupport 只有两个文件,是Cortex-M3内核自带的外设驱动程序,非常重要
        • DeviceSupport 只包含ST,ST文件下只包含STM32F10x
          • ST
            • STM32F10x 文件夹中有Starup文件夹,和一些别的文件
              • Starup 中又会根据不同的开发环境分为好几个文件夹,里面存放的是芯片的启动代码。这里我们用到的是ARM,也就是对应了KEIL的开发环境。他们的后缀不同,这些是根据芯片的容量不同。LD为小容量。MD为中容量。HD为大容量这些根据Flash的大小来选择。(启动代码是芯片上电后最先执行的一段汇编程序)
              • stm32f10x.h :这个头文件包含了 STM32F1 系列微控制器的所有寄存器定义、位定义以及相关的结构体和枚举类型等。通过包含这个头文件,开发者可以方便地访问和操作芯片的各种寄存器,实现对硬件的控制和配置。例如,通过其中的定义可以设置时钟、GPIO 引脚的状态等。
              • system_stm32f10x.c :这个文件通常包含了系统初始化相关的代码,例如设置系统时钟、配置闪存的等待周期等。它确保了系统在启动时能够以正确的方式进行初始化,为后续的程序运行提供稳定的基础。
              • system_stm32f10x.h :与 system_stm32f10x.c 配套使用,包含了相关的宏定义、函数声明等,为系统初始化的代码提供了必要的声明和配置信息。
  • Project 存放用驱动库写的子和一个工程模板。 在官方给的工程模板STM32F10x_StdPeriph_Template中,有4个文件是十分重要的.是必须使用的。

    • system_stm32f10x.c:是用来修改程序的时钟配置
    • stm32f10x_conf.h:这是STM32F10x芯片配置头文件,用于定义外设接口地址和其他特定于硬件的设置。
    • stm32f10x_it.c 和 stm32f10x_it.h:这些文件可能包含中断服务函数(ISRs)及其相关声明,用于处理来自STM32F10x芯片的各种中断事件。
    • system_stm32f10x.c:这个文件可能实现了一个系统时钟初始化函数或其他与系统相关的功能,以确保STM32F10x芯片正确运行

    上面俩是比较重要的。其余的供参考

  • stm32f10x_stdperiph_lib_um.chm 是已经编译的帮助系统。是讲如何用固件库来编写代码,以及举例说明。

  • Utilities 存放ST对评估板的相关例程代码(没用)

这里还可以结合正点原子对于固件库的讲解来再次吸收一下

存储器映射

存储器指可以存储数据的设备,本身没有地址信息,对存储器分配地址的过程称为存储器映射。

ST将32位共4GB的内存分为八个块。

(F1为例,不同的系列架构不同,总线之类的也不一样)

他们都有自己的地址,可以在寄存器找到

  • Block 0: Code(FLASH)
  • Block 1:SRAM
  • Block 2:片上外设
    • APB1总线外设
    • APB2总线外设
    • AHB总线外设
  • Block 3:FSMC Bank1&2
  • Block 4: FSMC Bank3&4
  • Block 5:FSMC寄存器
  • Block 6:没用到
  • Block 7:Cortex M3内部外设

寄存器基础知识

单片机内部一种特殊的内存,可以实现对单片机各个功能的控制,是单片机内部的控制开关

  1. STM32的寄存器分类:
    • 内核寄存器
      • 内核相关寄存器
      • 中断控制寄存器
      • SysTick寄存器
      • 内存保护寄存器
      • 调试系统寄存器
    • 外设寄存器
  2. 寄存器映射:

寄存器是特殊的存储器,给寄存器地址命名的过程,就叫寄存器映射。

  1. 寄存器的计算

为了方便编写代码及使用,我们将寄存器地址分为三个部分

1、总线基地址(BUS_BASE_ADDR)

2,外设基于总线基地址的偏移量(PERIPH_OFFSET)

3、寄存器相对外设基地址的偏移量(REG_OFFSET) 寄存器地址 = BUS_BASE_ADDR + PERIPH_OFFSET + REG_OFFSET寄存器地址

这里的寄存器每次都要去手册查找就很麻烦,所以有库帮我们用结构体全部重定义过了。我们可以用结构体很方便的去映射。 所以不同的芯片就要使用不同的库。他们的手册也不太一样。但总体思路是一样的

下载对应芯片的固件包方法

在使用一款芯片的时候,第一步要下载他的固件包。去相应的官网去找就ok

例如STM32系列的就去STM32Cube官网去下载

GD32则可以去兆易创新官网去下载

CMSIS文件夹简介

CMSIS(微控制器软件接口标准)是幽ARM和与其合作的芯片厂商、软件工具厂商,共同制定的标准 CMSIS全称是:Cortex Microcontroller Software Interface Standard, 用户(用户层)需要通过中间层CMSIS来控制硬件层

ST为了用于方便开发smt32提供了三种库, 0. 直接操作寄存器

  1. 【已停止维护】标准外设库(Standard Peripheral Libraries
  2. HAL库(硬件抽象层):Hardware Abstraction Layer 全系列兼容、主推的库、兼容性和易移植性、但效率比较低
  3. LL库:Low Layer 与上者捆绑发布,集成上者优点,轻量级。效率高,但不匹配复杂的外设。

里面有好多文件,我们需要在新建工程的时候从里边挑我们要用的。

芯片型号。。或者是芯片的容量。或者是通用的

大概的我不想记录了。看视频

用到的文件夹就有Drive 和 include

【【正点原子】手把手教你学STM32 HAL库开发全集【真人出镜】STM32入门教学视频教程 单片机 嵌入式】第23讲 基础篇-初始HAL库_STM32Cube固件包浅析_哔哩哔哩_bilibili

创建工程模板

创建的时候是用必要的文件,这里是全部添加进去了。全添加编译速度会慢一点点。

依据江协创建的工程模板如下:

DebugConfig
    Target_1_STM32F103C8_1.0.0.dbgconf
Library
    misc.c
    misc.h
    stm32f10x_adc.c
    stm32f10x_adc.h
    stm32f10x_bkp.c
    stm32f10x_bkp.h
    stm32f10x_can.c
    stm32f10x_can.h
    stm32f10x_cec.c
    stm32f10x_cec.h
    stm32f10x_crc.c
    stm32f10x_crc.h
    stm32f10x_dac.c
    stm32f10x_dac.h
    stm32f10x_dbgmcu.c
    stm32f10x_dbgmcu.h
    stm32f10x_dma.c
    stm32f10x_dma.h
    stm32f10x_exti.c
    stm32f10x_exti.h
    stm32f10x_flash.c
    stm32f10x_flash.h
    stm32f10x_fsmc.c
    stm32f10x_fsmc.h
    stm32f10x_gpio.c
    stm32f10x_gpio.h
    stm32f10x_i2c.c
    stm32f10x_i2c.h
    stm32f10x_iwdg.c
    stm32f10x_iwdg.h
    stm32f10x_pwr.c
    stm32f10x_pwr.h
    stm32f10x_rcc.c
    stm32f10x_rcc.h
    stm32f10x_rtc.c
    stm32f10x_rtc.h
    stm32f10x_sdio.c
    stm32f10x_sdio.h
    stm32f10x_spi.c
    stm32f10x_spi.h
    stm32f10x_tim.c
    stm32f10x_tim.h
    stm32f10x_usart.c
    stm32f10x_usart.h
    stm32f10x_wwdg.c
    stm32f10x_wwdg.h
Listings
    startup_stm32f10x_md.lst
Objects
    Project.lnp
    Project.sct
Start
    core_cm3.c
    core_cm3.h
    startup_stm32f10x_cl.s
    startup_stm32f10x_hd.s
    startup_stm32f10x_hd_vl.s
    startup_stm32f10x_ld.s
    startup_stm32f10x_ld_vl.s
    startup_stm32f10x_md.s
    startup_stm32f10x_md_vl.s
    startup_stm32f10x_xl.s
    stm32f10x.h
    system_stm32f10x.c
    system_stm32f10x.h
User
    main.c
    stm32f10x_conf.h 
    stm32f10x_it.c  
    stm32f10x_it.h

Project.uvguix.xxx
Project.uvoptx
Project.uvprojx

程序的烧写

每个STM32上都有BOOT0和BOOT1引脚,在芯片复位的时候,这两个引脚的高低电平决定了芯片复位后从那些区域开始执行程序 ,

BOOT0引脚状态BOOT1引脚状态启动模式
0X从Flash启动
10从系统内存启动
11从内嵌SRAM启动

烧写分为这三种。他们所用的IO口不一样

6.[正点]时钟树系统的了解

STM32(ARM)的时钟为什么要设置的那么复杂

为什么ARM的芯片不能像51单片机就一样,全部都弄成一个时钟呢?

  1. 有利于省电 51单片机是很早之前比较广泛应用,当时对芯片的功耗高低的要求不高 而STM32作为新型的芯片,他的内核是Cortex - M3的内核。他对于功耗的要求就比较高。这里的高不是功耗要变高,而是对功耗控制的精度变高。不同的外设用不同的频率。因为频率越高。功耗也就越高
  2. 不同外设的频率不相同 使用不同外设,如果用相同的频率。那么外设的抗干扰能力就会变弱。功耗也会变大。

分析时钟树的方法(这里是对F4系列芯片)

时钟分析方法

要分析之前,首先要知道梯形符号是什么意思. 梯形符号叫做**“选择器”** 他可以选择多个时钟的其中一条来输出

  1. LSI 低速内部时钟 L - low低速 S - speed 速度 I - interior内部

    频率为32KHZ,是内部的LC振荡器,不太稳定。一般是给独立看门狗做时钟的。(看门狗也需要使能看门狗的使能位。)

  2. LSE 低速外部时钟

    E - external 外部 这里是我们外接的(低速)晶振时钟。它的稳定性就很高了。

  3. HSI 高速内部时钟 16Mhz 。 内部的,不稳定

  4. PLLCLK 锁相环时钟输出 有俩,第一个是主用的,第二个是专用的。 其中的xN是倍频器。 /P是分频器。 /Q是USB模块用的。/R主用的没用到。

    为什么要有一个专用的呢?因为对于I2S的时钟对频率要求非常高,所以是专用的。

    可以看到,主PLL锁相环输出的系统时钟。可以经过选择器。 AHB与分频器给很多的外设 AHB的信号,又能经过APBX的与分频器,又能产生很多时钟。 APBX就是给相关外设用的。

  5. HSE 高速外部时钟(可以接4-26M的外部时钟)

  6. MCO1MCO2 这两个是可以经过分频器和选择器来输出到芯片引脚上的

总结:

  1. STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL.

    1. HSI是高速内部时钟,RC振荡器,频率为16MHZ,精度不高。可以直接作为系统时钟或者用作PLL时钟输入。
    2. HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHZ。
    3. LSI是低速内部时钟,RC振荡器,频率为32KH2,提供低功耗时钟。主要供独立看门狗和自动唤醒单元使用。
    4. LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTCPLL为锁相环倍频输出。STM32F4有两个PLL
      1. 主PLL(PLL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟
        1. 第一个输出PLLP用于生成高速的系统时钟(最高168MHz)
        2. 第二个输出PLLQ用于生成USBOTGFS的时钟(48MHZ),随机数发生器的时钟和SDIO时钟。
      2. 专用PLL(PLLI2S)用于生成精确时钟,从而在12S接口实现高品质音频性能
  2. .系统时钟SYSCLK可来源于三个时钟源:

  3. HSI振荡器时钟

  4. HSE振荡器时钟

  5. PLL时钟

常用时钟配置寄存器

  • RCC时钟控制寄存器 RCC_CR

    主要用来配置、使能时钟源。就绪时钟源的

  • RCC PLL配置寄存器 RCC_PLLCFGR

    是用来配置PLL锁相环输出中的P、Q、R等值。

  • RCC 时钟配置寄存器 RCC_CFGR

    用来配置分频系数以及时钟源。(梯形以及方块里的/M的配置)

  • RCC AHBX外设时钟使能寄存器 RCC_ AHBXENR

    使能一些外设的时钟

  • RCC APB1、APB2 外设时钟使能寄存器 RCC_APBXENR

    使能一些外设的时钟

7.[正点]SystemInit.c时钟系统初始化文件了解

在系统初始化之后,是先调用Systemlnit函数,然后才调用main函数的。(这点在.s的启动文件哪里,可大概看到汇编指令是先执行sys再执行main的)

这个文件会打开时钟以及复位一些东西,具体可以去手册的RCC和SystemInit.c文件中对应的去看。把16进制翻译为2进制后,找到寄存器的对应位就OK。这样就知道这些是什么作用了。

这个建议新手不要改

8.[正点]Systick定时器

Systick定时器基础知识了解

  • Systick定时器,是一个简单的定时器,对于CM3.CM4内核芯片,都有Systick定时器
  • Systick定时器常用来做延时,或者实时系统的心跳时钟这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟:
  • Svstick定时器就是系统滴答定器一个24 位的倒计数定时器, 计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SvsTick控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作:
  • SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15) 意思就是它能够产生中断。 Systick中断的优先级也可以设置

Systick定时器的四个寄存器

  • SysTick控制和状态寄存器 - CRTR

    可以配置使能、是否产生中断(异常请求)、配置内外部时钟源 以及在一次循环之后。可以读取的位段16的值。(读取后复位)

    配置的函数:SysTick_CLKSourceConfig();

  • SysTick 自动重装载初值寄存器 - LOAD 放重装时放的值

  • SysTick 当前值寄存器 - VAL 把重装值复制过来,然后每个时钟周期-1 减到零就再次重装

  • SysTick 校准值寄存器

    不太重要。

Systick相关函数

固件库中在 misc.c文件中

SysTick_CLKSourceConfig(); 时钟源选择

SysTick_Config(uint32_t ticks); 初始化Systick,时钟为HCLK。并开启中断

SYstick中断服务函数

void SysTick_Handler(void);

尝试使用Systick写一个延时函数

  1. 把定义好Systick的重装值。

    这里使用到了中断与Systick的 LOAD 寄存器

    // 延时函数初始化
    void Delay_Init(void)
    {
        // 配置 SysTick 为 1us 中断一次
        if (SysTick_Config(SystemCoreClock / 1000000))
        {
            while (1);  // 配置错误,进入死循环
        }
    }
    

    SysTick_Config是SysTick的时钟源选择函数。 起内部的代码是

    static __INLINE uint32_t SysTick_Config(uint32_t ticks)
    { 
      if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                                   
      SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
      NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
      SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
      SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                       SysTick_CTRL_TICKINT_Msk   | 
                       SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
      return (0);                                                  /* Function successful */
    }
    

    在判断是否超过最大值后,这个函数会把你传入的值放到SYStick的LOAD寄存器(重装寄存器)中。 然后设置优先级为最高 并且将VAL寄存器(当前值寄存器)置零。 噔噔蹬蹬….

    SystemCoreClock 是 STM32 标准库中定义的一个全局变量,用于表示系统的核心时钟频率。使用了条件编译的命令。这里默认为F1的72M

    那么SysTick_Config(SystemCoreClock / 1000000) 的意思就是设置系统滴答定时器的重装值为为7200(72 000 000000/1000000)。

    因为晶振的速度为72M,也就是一秒钟有72M个高电平。

    所以晶振震荡7200次花费的时间就是1us。

    所以可以这样去判断

    // 延时函数
    void Delay_us(uint32_t us)
    {
        TimingDelay = us;
        while (TimingDelay!= 0);
    }
    
    // SysTick 中断处理函数
    void SysTick_Handler(void)
    {
        if (TimingDelay!= 0)
        {
            TimingDelay--;
        }
    }
    

    其中的中断函数void SysTick_Handler(void),是库函数固定的,必须要用这个名字。他是SysTick的固定中断服务函数。

    void Delay_us(uint32_t us) 是定义的us函数

    举例子说,想Delay_us 函数中传参:50.

    那么全局变量TimingDelay == 50

    然后就会进入到while (TimingDelay!= 0); 命令中一直等待。此时就在等待中断处理函数把全局变量TimingDelay 减为0.然后跳出函数。此时程序就能继续运行了。

    在中断处理函数中,每当重装值7200 减 到 0 之后。就会触发一次中断,(也就是执行一次 SysTick_Handler()函数。)全局变量TimingDelay就会减一。当他捡到0之后就不会再减了。

    要实现1ms延时。也很简单。只需要把传入的值x1000就OK啦

    // 毫秒级延时函数
    void Delay_ms(uint32_t ms)
    {
        Delay_us(ms * 1000);
    }
    

    这次用这个Delay函数来实现一下闪烁灯试试.完全Ok。

    (如果在编译的时候报错,根据报错信息。大概率要去stm32f103x_it.h找到void SysTick_Handler(void)函数然后注释掉。不然会出现多次定义。头文件。)

    int main()
    {
    
        KEY_Init();//初始化KEY
        LED_Init();//初始化LED
        Delay_Init();//初始化延时函数
        
        while(1)
        {
            LED_ON(1);
            Delay_ms(500);
            LED_OFF(1);
            Delay_ms(500);
        }
    }
    

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值