STM32
STM32概况
STM32简介
STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器
ST指ST公司,M指微控制器(microcontroller),32指该单片机为32位
在计算机中,32位通常指的是数据总线或处理器的寄存器大小,即32位二进制数的长度。它表示每个数据传输或处理的最大位数为32位,也就是4个字节(byte)。
在32位计算机系统中,每个内存地址都可以用32位二进制数表示,因此可以寻址的内存空间大小为2的32次方,即4GB。这也意味着32位计算机可以处理32位大小的整数和浮点数,以及使用32位指针来访问内存。
对于32位和64位机器,一部分数据类型所占据的大小不同
数据类型 32位系统 64位系统 char1字节 1字节 char*(指 所有指针变量)4字节 8字节 short int2字节 2字节 int4字节 4字节 unsigned int4字节 4字节 float4字节 4字节 double8字节 8字节 long4字节 8字节 long long8字节 8字节 unsigned long4字节 8字节 
在本笔记中,使用的stm32型号为STM32F103C8T6
STM32F103C8T6:
•系列:主流系列STM32F1
•内核:ARM Cortex-M3
•主频:72MHz
•RAM:20K(SRAM)
•ROM:64K(Flash)
•供电:2.0~3.6V(标准3.3V)
•封装:LQFP48
RAM是英文Random Access Memory的缩写,中文称为随机存取存储器,也叫主存或内存。它是计算机中用于临时存储数据和程序的重要部件。
ROM是英文Read-Only Memory的缩写,中文称为只读存储器。与RAM不同,ROM是一种只能读取而不能写入的存储器,它通常用于储存计算机系统的固件、BIOS、引导程序和操作系统等程序和数据。
RAM和ROM是计算机中两种不同类型的存储器,它们在以下几方面有所不同:
- 功能:RAM用于临时存储数据和程序,是计算机的主存储器,数据可以被读取和写入。ROM用于存储程序和数据,是只读存储器,数据只能被读取而不能被写入。
 - 可擦写性:RAM是可写的存储器,数据可以随时被写入和修改,但容易丢失;而ROM是只读存储器,一般情况下不可被修改,但有一些可擦写的ROM也可以被擦除和重新编程。
 - 数据保持性:RAM需要持续的电源供应来维持数据的存储状态,一旦电源中断,其中存储的数据就会丢失。而ROM不需要持续的电源供应来维持数据的存储状态,数据可以长期保持。
 - 容量和速度:RAM的容量通常较大,可以达到几个GB或更大,但读取和写入速度相对较慢。ROM通常容量较小,但读取速度较快,可以用于存储固件、BIOS、引导程序和操作系统等程序和数据。
 - 价格:RAM的价格相对较高,但价格随着容量的提高而逐渐下降。ROM的价格相对较低,但价格随着可擦写性和容量的提高而逐渐上升。
 
STM32外设
| 英文缩写 | 名称 | 英文缩写 | 名称 | 
|---|---|---|---|
| NVIC | 嵌套向量中断控制器 | CAN | CAN通信 | 
| SysTick | 系统滴答定时器 | USB | USB通信 | 
| RCC | 复位和时钟控制 | RTC | 实时时钟 | 
| GPIO | 通用IO口 | CRC | CRC校验 | 
| AFIO | 复用IO口 | PWR | 电源控制 | 
| EXTI | 外部中断 | BKP | 备份寄存器 | 
| TIM | 定时器 | IWDG | 独立看门狗 | 
| ADC | 模数转换器 | WWDG | 窗口看门狗 | 
| DMA | 直接内存访问 | DAC | 数模转换器 | 
| USART | 同步/异步串口通信 | SDIO | SD卡接口 | 
| I2C | I2C通信 | FSMC | 可变静态存储控制器 | 
| SPI | SPI通信 | USB OTG | USB主机接口 | 
STM32命名规则
STM32 F 103 C 8 T 6
产品系列:STM32—基于ARM核心的32位微处理器
产品类型:F —通用系列
产品子系列: 101—基本型(102——USB基本型,103——增强型···)
引脚数目:C —48脚
闪存储存器容量:8—64K字节的闪存储存器
封装: T —LQFT
温度范围:6—工业级温度范围:-40——85
STM32结构
以下主要引自参考手册:
在小容量、中容量和 大容量产品中,主系统由以下部分构成:
● 四个驱动单元: ─ Cortex™-M3内核DCode总线(D-bus),和系统总线(S-bus)
 ─ 通用DMA1和通用DMA2
● 四个被动单元: ─ 内部SRAM
 ─ 内部闪存存储器
 ─ FSMC
 ─ AHB到APB的桥(AHB2APBx),它连接所有的APB设备
这些都是通过一个多级的AHB总线构架相互连接的,如上图所示
可以把驱动单元理解成是内核部分,被动单元都理解成外设,而驱动单元和外设都是通过各条总线连接的
对于各总线:
ICode总线
该总线将Cortex™-M3内核的指令总线与闪存指令接口相连接。指令预取在此总线上完成。
ICode总线是专门用来取指令的,其中的I表示Instruction(指令),指令的意思。写好的程序编译之后都是一条条指令,存放在 FLASH中,内核通过ICode总线读取这些指令来执行程序。
**DCode总线 **
该总线将Cortex™-M3内核的DCode总线与闪存存储器的数据接口相连接(常量加载和调试访 问)。
DCode这条总线是用来取数的,其中的D表示Data(数据)。在写程序的时候,数据有常量和变量两种。常量就是固定不变的,用C语言中的const关键字修饰,放到内部FLASH当中。变量是可变的,不管是全局变量还是局部变量都放在内部的SRAM。
**系统总线 **
此总线连接Cortex™-M3内核的系统总线(外设总线)到总线矩阵,总线矩阵协调着内核和DMA间 的访问。
我们通常说的寄存器编程,即读写寄存器都是通过系统总线来完成的,系统总线主要是用来访问外设的寄存器。
**DMA总线 **
此总线将DMA的AHB主控接口与总线矩阵相联,总线矩阵协调着CPU的DCode和DMA到 SRAM、闪存和外设的访问
DMA总线也主要是用来传输数据,这个数据可以是在某个外设的数据寄存器,可以在SRAM,可以在内部FLASH.
因为数据可以被Dcode总线,也可以被DMA总线访问,为了避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。
**总线矩阵 **
总线矩阵协调内核系统总线和DMA主控总线之间的访问仲裁,仲裁利用轮换算法。在其它产品中总线 矩阵包含4个驱动部件(CPU的DCode、系统总线、DMA1总线和DMA2总线)和4个被动部件(闪存 存储器接口(FLITF)、SRAM、FSMC和AHB2APB桥)。 AHB外设通过总线矩阵与系统总线相连,允许DMA访问
AHB/APB桥(APB)
两个AHB/APB桥在AHB和2个APB总线间提供同步连接。APB1操作速度限于36MHz,APB2操 作于全速(最高72MHz)
桥接是将两个或多个网络连接起来,使它们可以互相通信的技术。
内部的闪存存储器Flash
内部的闪存存储器即FLASH,编写好的程序就放在这个地方。内核通过ICode总线来取里面的指令。
内部的SRAM
内部的SRAM,是通常所说的内存,程序中的变量、堆栈等的开销都是基于内部SRAM,内核通过DCode总线来访问它。
FSMC
FSMC的英文全称是Flexible static memory controller(灵活的静态的存储器控制器)。通过FSMC可以扩展内存,如外部的SRAM、NAND-FLASH和NORFLASH.但FSMC只能扩展静态的内存,不能是动态的内存,比如就不能用来扩展SDRAM。
AHB
从AHB总线延伸出来的两条APB2和APB1总线是最常见的总线,GPIO、串口、I2C、SPI 这些外设就挂载在这两条总线上。这个是学习STM32的重点,要学会对这些外设编程,去驱动外部的各种设备。
引脚定义
引脚是电子元器件、集成电路或其他电子设备上的金属接头或插针,用于与其他电子设备连接或传输信号、控制电路等。引脚通常是设备的物理接口,通过引脚可以将设备连接到其他电子设备或电路中。

图中橙色为电源相关引脚
蓝色为最小系统板相关引脚
绿色为I/O口,功能引脚等
在类型这一项中,s代表电源,I代表输入,o代表输出。
而在I/O口容忍电平这一项中,FT代表最高可容忍5v电压
STM32启动配置

启动配置是为了确定程序开始的位置
一般情况下,程序在主闪存存储器启动
但也可以通过启动配置,使其在其他位置启动,以完成特殊功能
STM32最小系统电路

GPIO
GPIO概况
- GPIO(General Purpose Input Output)通用输入输出口
 - 可配置八种输入输出格式
 - 引脚电平0v-3.3v,部分容忍5伏(容忍5v即可以输出5v的电压但输出最大为3.3伏)(在引脚定义中有FT的即能容忍5v电压)
 - 输出模式下可控制端口输出高低电平来进行控制
 - 输入模式下可以读取端口的高低电压或电平,常用于读取按键输入等
 
1.在嵌入式系统中,端口通常指的是设备或芯片与外部世界进行通信的物理接口或连接点。在嵌入式系统中,这些端口可以是电气端口,如引脚或插座,也可以是逻辑端口,如软件接口或通讯协议。
GPIO基本结构

- GPIO都是挂设在APB2外设总线上的
 
系统总线:系统总线是一种嵌入式系统中用于连接不同硬件模块和设备的通信系统。它是一组共享物理通信线路和协议,用于在多个设备之间传输数据和控制信息。系统总线可以大大简化硬件设计和软件开发,提高系统的灵活性和可扩展性。
AHB系统总线:AHB(Advanced High-performance Bus)系统总线是ARM公司推出的一种高性能、高可靠性的总线标准,主要用于连接ARM处理器核心和外围设备,是ARM处理器的一部分。AHB总线支持高性能数据传输和多个主设备并行访问,具有灵活性、可扩展性和可靠性等优点。
APB系统总线:APB(Advanced Peripheral Bus)系统总线是ARM公司推出的一种低功耗、低成本的总线标准,用于连接嵌入式系统中的外围设备和处理器核心。APB总线支持低功耗模式和多个从设备共享总线,是ARM处理器的一部分。
APB总线通常用于连接嵌入式系统中的外围设备,如定时器、串口、GPIO等。与AHB总线相比,APB总线的传输速度较慢,但功耗更低,适合于低功耗、低成本的嵌入式系统。ARM公司还推出了其他系统总线标准,如AHB总线和AXI(Advanced eXtensible Interface)总线,用于连接不同类型的硬件设备和处理器核心。
在计算机领域,Peripheral(外围设备)指的是连接到计算机系统中的各种硬件设 备,如键盘、鼠标、显示器、打印机、扫描仪、存储设备等。这些设备通常与计算机主体不直接相连,而是通过各种接口和总线连接到计算机系统中。
外围设备的作用是扩展计算机系统的功能和性能,为用户提供更加丰富、方便的应用环境。例如,键盘和鼠标是常见的输入设备,用于向计算机输入数据和指令;显示器是常见的输出设备,用于显示计算机处理结果和用户交互界面;存储设备则用于存储和读取数据和程序。
在计算机科学中,Bus通常指的是一组物理线路或信号传输介质,用于连接多个计算机硬件设备或子系统,实现数据、地址和控制信息的传输和交换。Bus可以理解为一种通信通道或数据传输路径,用于连接不同的硬件设备和组件,以实现数据交换和控制。
Bus通常由多个线路组成,包括数据线、地址线、控制线等,用于传输不同类型的信息。例如,数据线用于传输实际的数据;地址线用于指定数据的存储位置;控制线用于传输控制信号,如时钟信号、读写信号、中断信号等。
计算机中的Bus可以分为多种类型,如系统总线、内存总线、I/O总线等。其中,系统总线用于连接计算机的主要硬件组件,如处理器、内存、输入输出设备等;内存总线用于连接处理器和内存;I/O总线用于连接处理器和外部设备。
- GPIO名称是按GPIOA,GPIOB,GPIOC来命名的
 - 每个GPIO有16个引脚(Pin)编号从0到15编号,命名规则为P+GPIO的编号+引脚编号。如GPIOA的引脚编号为PA0,PA1······
 
在电子电路中,引脚(Pin)是连接电子元件和电路板之间的接口,通常是一个金属片或针脚。引脚通常用于连接电子元件和电路板之间的信号、电源和地等信号,以实现信号的输入、输出和功耗的传递。
- GPIO中主要是寄存器和驱动器
 
寄存器(Register)是计算机系统中用于存储和处理数据的一种高速、低容量的存储器件。寄存器通常位于CPU(中央处理器)内部,并与CPU的指令集密切相关,负责执行指令和处理数据。
GPIO中寄存器的每一位对应一个引脚
输出时寄存器写1,对应引脚输出高电平;写0,对应引脚输出低电平
输入时寄存器读1,对应引脚为高电平 ;读0,对应引脚为低电平
驱动器:增强信号的驱动能力

对于GPIO的每个引脚,其结构如图所示:
对于上图,可分为上下两部分,上方为输入部分,下方为输出部分
对于上方输入部分,
I/O引脚的保护二极管起保护作用,防止过高或过低电压损害电路
之后上拉电阻与下拉电阻,可配置输入模式(上拉输入,下拉输入,浮空输入)
肖特基触发器可进行整流
对于下方输出部分
寄存器可以进行数据的输出
在输出驱动器中,我们可以通过控制P_MOS和N_MOS的开关来进行配置输出的推挽开漏或者关闭模式
关于mos管详细内容,请看以下链接:
[一文讲明白MOS管工作原理](一文讲明白MOS管工作原理 - 知乎 (zhihu.com))
GPIO模式
| 模式名称 | 性质 | 特征 | 
|---|---|---|
| 浮空输入 | 数字输入 | 可读取引脚电平,若引脚悬空,则电平不确定 | 
| 上拉输入 | 数字输入 | 可读取引脚电平,内部连接上拉电阻,悬空时默认高电平 | 
| 下拉输入 | 数字输入 | 可读取引脚电平,内部连接下拉电阻,悬空时默认低电平 | 
| 模拟输入 | 模拟输入 | GPIO无效,引脚直接接入内部ADC | 
| 开漏输出 | 数字输出 | 可输出引脚电平,高电平为高阻态,低电平接VSS | 
| 推挽输出 | 数字输出 | 可输出引脚电平,高电平接VDD,低电平接VSS | 
| 复用开漏输出 | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS | 
| 复用推挽输出 | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS | 
 
   
上拉输入:上拉输入模式中,上拉电阻开,这样在I/O引脚未输入电压时默认为高电平
下拉输入:在下拉输入模式中,下拉电阻开,这样在I/O引脚未输入电压时默认为低电平
浮空输入:两电阻均关

模拟输入:信号直接自引脚输入到外设,不过GPIO

开漏输出:P_MOS无效,
推挽输出:P_MOS,N_MOS均有效
在输出模式下,输入模式是有效的,但在输入模式下输出是无效的
在推挽输出时,P_MOS,N_MOS均有效,当输出1时P_MOS导通,N_MOS断开,输出高电平,反之,输出低电平(存疑)
在推挽输出时,STM32对I/O口有绝对控制权,输出高低电平由STM32决定
开漏输出时,P_MOS无效,N_MOS有效

复用开漏输出 /复用推挽输出 :与开漏输出,推挽输出类似 ,不过是由片上外设进行输出
- 上拉输入 : GPIO 上拉输入是指将 GPIO 引脚连接到一个高电平(通常是 3.3V 或 5V),这样当 GPIO 引脚没有被连接到任何外部设备时,它就会处于高电平状态。GPIO 上拉输入可以防止 GPIO 引脚在没有被连接到任何外部设备时产生不确定的状态。
 - 下拉输入:下拉输入是指将 GPIO 引脚连接到一个低电平(通常是 0V),这样当 GPIO 引脚没有被连接到任何外部设备时,它就会处于低电平状态。下拉输入可以防止 GPIO 引脚在没有被连接到任何外部设备时产生不确定的状态。
 - 浮空输入:浮空输入是指 GPIO 引脚没有连接到任何外部设备,也不连接到任何内部电阻。当 GPIO 引脚处于浮空状态时,它的状态是未定义的。
 - 模拟输入:模拟输入是指可以输入连续的模拟信号的 GPIO 引脚。模拟输入通常用于读取外部设备的模拟信号,例如温度传感器或光敏电阻。
 - 开漏输出:
 - 推挽输出
 - 复用开漏输出
 - 复用推挽输出
 
GPIO输出
外设—LED灯
LED灯结构
发光二极管,正向通电点亮,反向通电不亮
长脚为正极,短脚为负极
LED常用接线方法:

低电平接法:STM32输出低电平点亮,高电平关闭
LED灯闪烁
接线图:

对于最小系统板,3.3可提供正极,GND(G)提供负极LED灯正极连在正极,负极连在STM32的一接口上,在这里我们选择PA0接口
使用GPIO接口步骤: 1.RCC开启GPIO时钟
 2.GPIO_Init初始化GPIO
 3.使用输入输出函数控制GPIO口
RCC常用函数:
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);//AHB外设时钟控制
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);//APB2外设时钟控制
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);//APB1外设时钟控制
功能:
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);//AHB外设时钟控制
/**
  * @brief  Enables or disables the AHB peripheral clock.
            使能或失能AHB外设时钟
  * @param  RCC_AHBPeriph: specifies the AHB peripheral to gates its clock.
     参数:  RCC_AHBPeriph: 指定要使能或关闭的时钟
  *
  *   For @b STM32_Connectivity_line_devices, this parameter can be any combination
  *   of the following values:        
  *     @arg RCC_AHBPeriph_DMA1
        显然RCC_AHBPeriph_DMA1为宏定义标志符,代表对应的数字
  *     @arg RCC_AHBPeriph_DMA2
  *     @arg RCC_AHBPeriph_SRAM
  *     @arg RCC_AHBPeriph_FLITF
  *     @arg RCC_AHBPeriph_CRC
  *     @arg RCC_AHBPeriph_OTG_FS    
  *     @arg RCC_AHBPeriph_ETH_MAC   
  *     @arg RCC_AHBPeriph_ETH_MAC_Tx
  *     @arg RCC_AHBPeriph_ETH_MAC_Rx
  * 
  *   For @b other_STM32_devices, this parameter can be any combination of the 
  *   following values:        
  *     @arg RCC_AHBPeriph_DMA1
  *     @arg RCC_AHBPeriph_DMA2
  *     @arg RCC_AHBPeriph_SRAM
  *     @arg RCC_AHBPeriph_FLITF
  *     @arg RCC_AHBPeriph_CRC
  *     @arg RCC_AHBPeriph_FSMC
  *     @arg RCC_AHBPeriph_SDIO
  *   
  * @note SRAM and FLITF clock can be disabled only during sleep mode.
  * @param  NewState: new state of the specified peripheral clock.
     参数    NewState: 指定要使能或关闭的时钟状态
  *   This parameter can be: ENABLE or DISABLE.
                        值为: ENABLE 或 DISABLE.
  * @retval None
  */
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);//APB2外设时钟控制
/**
  * @brief  Enables or disables the High Speed APB (APB2) peripheral clock.
  * @param  RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
  *   This parameter can be any combination of the following values:
  *     @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
  *          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
  *          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
  *          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
  *          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
  *          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
  *          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11     
  * @param  NewState: new state of the specified peripheral clock.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);//APB1外设时钟控制
/**
  * @brief  Enables or disables the Low Speed APB (APB1) peripheral clock.
  * @param  RCC_APB1Periph: specifies the APB1 peripheral to gates its clock.
  *   This parameter can be any combination of the following values:
  *     @arg RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4,
  *          RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7,
  *          RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3,
  *          RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_USART4, 
  *          RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2,
  *          RCC_APB1Periph_USB, RCC_APB1Periph_CAN1, RCC_APB1Periph_BKP,
  *          RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC,
  *          RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14
  * @param  NewState: new state of the specified peripheral clock.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
GPIO库函数:
void GPIO_DeInit(GPIO_TypeDef* GPIOx);//函数用于复位GPIO外设
void GPIO_AFIODeInit(void);//函数用于复位AFIO外设
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);//初始化GPIO口
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
/*GPIO读取函数*/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
/*GPIO写入函数*/
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//将指定端口设为高电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//将指定端口设为低电平
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
具体代码:
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void){
    /*开启时钟*/
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA,ENABLE);
    /*初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
    
	GPIO_SetBits(GPIOA,GPIO_Pin_0);//将某个引脚的值设为1,使LED初始状态为管=关
	
	while(1){
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
		Delay_ms(1000);
		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
		Delay_ms(1000);
	}
	
}
流水灯代码:
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    /*引脚的初始化也可用位或运算GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2······*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	while (1)
	{
		/*
		GPIO_Write函数:GPIO_Write 函数将 PortVal 值写入 GPIOx 的输出数据寄存器
		其中PortVal 值是 16 位值(16位的二进制数),它指定了要写入 GPIOx 输出数据寄存器的值。该值的每一位
		可以是 0 或 1,其中 0 表 示输出低电平,1 表示输出高电平。又由于c语言无法表示二进制数,用16位代替
		
		
		*/
        GPIO_Write(GPIOA,~0x0001);
        /*0x0001即0000 0000 0000 0001,~代表取反,使只有0号引脚低电平点亮 */
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0002);
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0004);
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0008);
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0010);
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0020);
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0040);
		Delay_ms(500);
		GPIO_Write(GPIOA,~0x0080);
		Delay_ms(500);
	}
}
GPIO输入
按键输入
按键执行逻辑:按下后电路联通,松手后断开
按键电路

K1按下,PA0输入为低电平,K1松手,按键断开,PA0不确定,所以采用上拉输入模式
所以大体思路为通过读取按键的输入来控制输出,进而控制LED
首先进行初始化
然后读取按键值,如果按下,则改变输出
光敏传感器

对于光敏传感器,DO灯亮表示有光,输出低电平,反之,输出高电平
中断系统
中断系统介绍
•中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理 完成后又返回原来被暂停的位置继续运行
•中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
•中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程 序,处理完成后依次进行返回
STM32中断
•68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设
•使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级
NVIC基本结构
NVIC(Nested Vectored Interrupt Controller)是用于中断管理的关键组件之一。它负责管理和分配中断请求,并控制中断的优先级。

NVIC优先级分组
•NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级
•抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
| 分组方式 | 抢占优先级 | 响应优先级 | 
|---|---|---|
| 分组0 | 0位,取值为0 | 4位,取值为0~15 | 
| 分组1 | 1位,取值为0~1 | 3位,取值为0~7 | 
| 分组2 | 2位,取值为0~3 | 2位,取值为0~3 | 
| 分组3 | 3位,取值为0~7 | 1位,取值为0~1 | 
| 分组4 | 4位,取值为0~15 | 0位,取值为0 | 
EXIT外部中断
基本概念
•EXTI(Extern Interrupt)外部中断
•EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
•支持的触发方式:上升沿/下降沿/双边沿/软件触发
上升沿: 低电平到高电平触发中断
下降沿:高电平到低电平触发中断
双边沿:上升沿和下降沿都可以触发中断
软件触发:相应程序的代码可以触发中断
•支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
相同的Pin不能同时触发中断:比如,PA0,PB0不能同时触发中断
•通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
16各GPIO_Pin接口对应了从GPIO_Pin_1到GPIO_Pin_15,我认为,其解释了所有GPIO口,但相同的Pin不能同时触发中断的原因
(存疑)
外部中断功能可以从低功耗模式的停止模式下唤醒STM32
•触发响应方式:中断响应/事件响应
中断响应:CPU中断,执行中断函数
事件响应:STM32对外部中断增加的一种额外的功能,当外部中断被触发时,除了可以触发中断外,也可以触发一个事件,此时,中断信号并不推向CPU而是推向其他外设,由其他外设响应
基本结构

每个GPIO口有16条线分别将每个引脚和AFIO(中断引脚选择)连接,AFIO从各GPIO的相同引脚(如PA0,PB0,PC0)中选择一个连在EXIT中

上图为AFIO引脚中断选择的结构,每个数据选择器只能从PA0,PB0····等相同引脚中选择一个,接入EXIT
•AFIO主要用于引脚复用功能的选择和重定义
•在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择

上图为EXIT内部框图,信号由输入线进入边沿检测电路,与边沿检测电路相连的上升沿下降沿触发选择寄存器可以用来选择触发方式为上升沿下降沿还是双边沿触发。随后信号进入或门的输入端(与软件触发寄存器一起进入)。由于或门的性质(任意为一,值为一)所以边缘检测电路或者软件有中断事件发生均会使中断信号继续传递。之后中断信号可以触发中断,也可以触发事件。对于正常触发中断,会有一个请求挂起寄存器,通过请求挂起寄存器,我们可以知道中断信号来自于哪个通道。信号通过请求挂起寄存器,与中断屏蔽寄存器,一起进入与门。由于与门的性质(任意为零,输出为零)所以与门与中断屏蔽寄存器共同起到了开关的作用。如果中断屏蔽寄存器为1,那么输出必为一,即允许中断。如果中断屏蔽寄存器为0,那么输出必为0,即禁止中断。随后信号被输入至NVIC中断控制器
对于触发事件,与正常中断同理,信号与事件屏蔽寄存器进入与门,同意中断后信号通过脉冲发射器传至其他外设。
应用
外设介绍
旋转编码器介绍:
•旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向
Tim定时器
TIM定时器介绍
•TIM(Timer)定时器
•定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
•16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
•不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
•根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
定时器分类:
| 类型 | 编号 | 总线 | 功能 | 
|---|---|---|---|
| 高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 | 
| 通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 | 
| 基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 | 
STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4
定时器结构
基本定时器:

时基单元:由预分频器,CNT计数器,自动重装载寄存器构成,构成了最基本的计数计时功能。
来自基准计数时钟的输入,将信号输入至PSC预分频器进行分频,输出分频后的信号到CNT计数器进行计数,计数时钟每来一个上升沿,计数时钟便加1,当与自动重装载寄存器所存的目标值相同时,便触发中断,清零计数器,计数器重新开始计时,这种中断被称为更新中断,中断信号会传至NVIC触发中断响应。当计数器的计数值与自动重装载寄存器所存的目标值相同时,也可以触发更新事件,即不触发中断,而是触发事件
PSC预分频器:起到对输入端预分频的作用,譬如PSC寄存器参数为0,则分频系数为1,即不分频,输入端为72MHz,PSC预分频器输出也为72MHz。PSC寄存器参数为2,则分频系数为3,即分频,输入端为72MHz,PSC预分频器输出为24MHz。PSC寄存器参数为5,则分频系数为6,即分频,输入端为72MHz,PSC预分频器输出为12MHz。
CNT计数器:用于计数
自动重装载寄存器:用于存储目标值
主模式触发DAC:
可让内部的硬件在不受程序的控制下自动运行
通用计时器:

通用定时器是由基本定时器扩展而来的,所以基本定时器的基本结构为通用定时器的核心,在基本定时器的基础上,在输入输出源进行扩展,并添加一部分其他设备便组成了通用定时器。
对于通用定时器,时基单元与基本定时器相同,但计数器增加了向下计数、向上向下计数
在时钟源选择上,不仅可以选择内部时钟,也可以选择外部时钟,而外部时钟包括TiMx_ETR(位于PA0)、ITR信号(来自其他定时器通过TRGO通道的输出,可实现级联),TI1F_ED(来自TiMx_CH1),TI1FP1(来自CH1),TI2FP2(来自CH2)
输出比较电路:可用于输出波形,驱动电机,分别对应CH1到CH4
输入捕获电路:可用于测输入方波的频率等,分别对应CH1到CH4
高级定时器:

高级定时器基本结构与通用定时器相同,在通用定时器的基础上增加了一些结构
首先,在申请中断处增加一重复次数计数器,用于实现经历数个计数周期才实现一次更新中断
定时中断基本结构:

定时器时序:




RCC时钟树:

RCC时钟树是STM32产生和配置时钟,并将配置好的时钟发送到各个外设的系统
该时钟树可分为两部分:时钟的产生电路和时钟的分配电路
SYSCLK(system clock):72MMHz的系统时钟
● HSI振荡器时钟
● HSE振荡器时钟
● PLL时钟
这些设备有以下2种二级时钟源:
● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/ 待机模式下自动唤醒系统。
● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。
TIM输出比较
OC(Output Compare)意为输出比较,他可以通过比较CNT与CCR寄存器值的大小关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。在定时器中,每个高级定时器和通用定时器都拥有4个输出比较通道,而高级定时器的前3个通道额外拥有死区生成和互补输出的功能。
•PWM(Pulse Width Modulation)脉冲宽度调制
•在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
•PWM参数:
频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
PWM在本人看来,是通过平均速度的原理来进行输出的
譬如,在STM32中,I\O口只能输出高低电平,以高电平5v低电平0v为例,那么正常情况下,I\O口只能输出5v和0v两种电压。但是通过PWM的方法,即我们假设一个周期譬如10ms,在这个周期中,我们全输出高电平,那么输出电压就是5v。但是如果5ms输出高电压,5ms输出低电压,那么输出电压就可以看作2.5v。
PWM的频率
是指在1秒钟内,信号从高电平到低电平再回到高电平的次数,也就是说一秒钟PWM有多少个周期,单位Hz。
PWM的周期
T=1/f,T是周期,f是频率。
如果频率为50Hz ,也就是说一个周期是20ms,那么一秒钟就有 50次PWM周期。
占空比
是一个脉冲周期内,高电平的时间与整个周期时间的比例,单位是% (0%-100%)
•CCR:捕获\比较寄存器
输出比较通道的结构就如下图所示:
.png)
对于输出比较功能,当CNT计数器的值大于等于CCR捕获比较寄存器时,便会向输出模式控制器传入信号,在输出模式控制器中,由OC1M寄存器控制输出模式,输出模式控制器根据输出模式来输出相应的oc1ref参考信号,oc1ref参考信号需要通过极性选择,极性选择是由CC1P寄存器进行控制,假如cc1p寄存器写0,那么oc1ref寄存器直接进入输出使能电路,假如cc1p寄存器写1,那么oc1ref寄存器通过非门,进行一次反转进入输出使能电路。在输出使能电路cc1e寄存器进行使能,随后输出信号
对于输出比较功能的模式有下表:
| 模式 | 描述 | 
|---|---|
| 冻结 | CNT=CCR时,REF保持为原状态 | 
| 匹配时置有效电平 | CNT=CCR时,REF置有效电平 | 
| 匹配时置无效电平 | CNT=CCR时,REF置无效电平 | 
| 匹配时电平翻转 | CNT=CCR时,REF电平翻转 | 
| 强制为无效电平 | CNT与CCR无效,REF强制为无效电平 | 
| 强制为有效电平 | CNT与CCR无效,REF强制为有效电平 | 
| PWM模式1 | 向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平 向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平 | 
| PWM模式2 | 向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平 向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平 | 
有效电平为高电平,无效电平为低电平
