Skip to content

重要外设

重要外设:

GPIO

GPIO(General-purpose input/output)是控制或者采集外部器件的信息的外设 (其实就是几组从芯片引出的引脚),你可以把它理解为芯片的嘴巴和耳朵(芯片靠读取引脚上的电平信号与外界交流)是芯片用于和外部交流的窗口。

f103有四组GPIO口(GPIOA~GPIOD)共51个IO口 (查表带有TF标志的兼容5V)

GPIO 有八种工作模式,分别是:

  1. 输入浮空(电平由外界决定,默认状态)
  2. 输入上拉(默认高电平)
  3. 输入下拉(默认低电平)
  4. 模拟输入(不使用施密特触发器滤波保持输入波形)
  5. 开漏输出(交替输出低电平和高阻态)
  6. 推挽输出(交替输出高低电平)
  7. 开漏式复用功能
  8. 推挽式复用功能

其实大致上来讲就分为输入模式,输出模式,复用模式(复用就是同一个引脚可以选择不同的功能,一个 IO 口可以是通用的 IO 口功能,还可以是其它外设的特殊功能引脚,当选择复用功能时,引脚的状态是由对应的外设控制,而不是输出数据寄存器。 )每组GPIO有16个IO口(GPIOX1~16),三个寄存器(配置,数据,位置寄存器)。

STM32的 io 有3类功能 :一个是默认的, 一个是复用, 一个是重映射功能。

NVIC/EXTI

在讲外设之前,先解释中断这个概念,我们应该知道在MCU处理同一时间只能处理一个任务,因此如果我们的单片机正在执行任务A时突然需要处理任务B,这就需要把任务A打断,去执行完任务B,然后再回来执行任务A,这个过程就是中断。

NVIC

NVIC(Nested vectored interrupt controller)是嵌套向量中断控制器,人话就是管理中断请求的东西,它是属于内核内部。M3内核支持256种中断(16个系统中断,240个外部中断),然而F103RCT6只用了10种系统中断和60个外部中断,这些中断记录在中断向量表中,在stm32f103xe.h 文件中被定义。

NVIC的寄存器有:

  1. 中断使能寄存器 *8(每个32位对应256个中断,写1有效使能,写零无效)
  2. 中断除能寄存器 *8 (同上,设计两个寄存器的原理是防止在位操作时干扰到其它位)
  3. 中断使能挂起控制寄存器*8(置一将正在执行的中断挂起去执行其它中断)
  4. 中断解挂控制寄存器 *8
  5. 中断激活标志位寄存器 *8(只读寄存器,用来判断哪个中断被执行,硬件自动清零)
  6. 中断优先级控制的寄存器 *240(这是240个8位寄存器,用于编写240个外部中断的优先级)

ps.f1中只用到了寄存器的一小部分,同时优先级寄存器每个也只用到了高四位,高四位也被分为两部分用于编写抢断优先级和响应优先级,这两个部分各占多少位由SCB->AIRCR 寄存器的 bit10~8 来定义,中断优先级相同那么中断向量表中的排序越小优先级越高。

EXTI

EXTI(External interrupt/event controller)是外部中断和事件控制器,前面讲过NVIC是属于内核的,而外设想要申请中断都需要通过IO口向NVIC发起请求,这些外部中断的申请都要先经过EXTI的管理才能输入到内核去触发中断。

EXTI 有两大功能分别产生中断与产生事件(随着程序进行产生的变化都可以称为事件,需要MCU紧急处理的事件称为中断,这里的事件指的是需要其它外设进行处理的事件)

EXTI一共有20个输入线支持20个外部中断/事件请求:

  1. EXTI 线 0~15:对应外部 IO 口的输入中断
  2. EXTI 线 16:连接到 PVD 输出
  3. EXTI 线 17:连接到 RTC 闹钟事件
  4. EXTI 线 18:连接到 USB 唤醒事件
  5. EXTI 线 19:连接到以太网唤醒事件

EXTI线1负责管控GPIOX1其它的以此类推,至于X到底是A还是B或者其他的由AFIO_EXTICR寄存器配置。

每开启一个中断就要编写相应的中断服务函数,然后把想要实现的功能编写在中断回调函数之中,中断触发时内核会自己找到中断服务函数,中断服务函数会调用回调函数从而实现功能。F1的IO口的外部中断服务只有7个却对应了16个中断线:

void EXTI0_IRQHandler();
void EXTI1_IRQHandler();
void EXTI2_IRQHandler();
void EXTI3_IRQHandler();
void EXTI4_IRQHandler();
void EXTI9_5_IRQHandler();
void EXTI15_10_IRQHandler();

DMA

DMA(Direct Memory Access)翻译过来就是直接存储器访问,作用就是在不同外设,存储器之间传递数据。不使用DMA,外设想要访问内存空间就需要经过CPU的调度,这就会占用CPU宝贵的时间,因此DMA存在的意义就是将CPU从传递数据的这种“体力活”中解放出来,使外设可以通过DMA直接访问内存空间。

f1的有两个DMA控制器,DMA1有7个通道,DMA2有5个通道,每一个通道管理着不同外设,不同通道的请求根据优先级来执行,并且每一个通道同一时间只能处理一个外设的传输请求

STM32F103 的 DMA 有以下一些特性:

● 每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发。这些功能通过软件来配置。

● 在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如在相等优先权时由硬件决定(请求 0 优先于请求 1,依此类推) 。

● 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。

● 支持循环的缓冲器管理

● 每个通道都有 3 个事件标志(DMA 半传输, DMA 传输完成和 DMA 传输出错),这 3 个事件标志逻辑或成为一个单独的中断请求。

● 存储器和存储器间的传输

● 外设和存储器,存储器和外设的传输

● 闪存、 SRAM、外设的 SRAM、 APB1、 APB2 和 AHB 外设均可作为访问的源和目标。

● 可编程的数据传输数目:最大为 65536

当DMA同时接到多个通道的请求时,它会根据优先级依次进行传输,确保优先级高的任务先进行,优先级分为软件优先级硬件优先级 ,以软件优先级为主(自行设置),硬件优先级为辅(通道号越低硬件优先级越高),每个通道都有一套对应的寄存器用于配置(有专门的地址用于写入数据的源地址和目标地址),详情请看手册。

Timer

定时器就是用来计时的外设(其实我觉得叫计数器更恰当),可以用来测量脉冲的时长,为中断触发定时,甚至是输出特定频率的电信号。stm32F1一共有八个定时器:

定时器类型 定时器 计数器位数 计数模式 预分频系数 ( 整数) 产生DMA 请求
基本定时器 TIM6TIM7 16 递增 1~65536 可以
通用定时器 TIM2TIM3TIM4TIM5 16 递 增 、 递减、中央对齐 1~65536 可以
高级定时器 TIM1TIM8 16 递 增 、 递减、中央对齐 1~65536 可以

基本定时器的时钟源来自内部的APB1总线,经过控制器之后,再到时基单元。时基但愿有三个寄存器:

  1. 预分频器寄存器(TIMx_PSC)
  2. 计数器寄存器(TIMx_CNT)
  3. 自动重载寄存器(TIMx_ARR)

时钟信号首先需要经过预分频寄存器进行分频(就是频率除以分频数让频率降低),然后计数寄存器内的数据每次接到分频后的信号就加1直到和自动重载寄存器内的数据一样大时就会产生更新事件(事件的概念在中断部分已经讲过)

ps.PSC和ARR寄存器都有影子寄存器,影子寄存器是一个实际起作用的寄存器, 不可直接访问。举个例子:我们可以把预分频系数写入预分频器寄存器(TIMx_PSC),但是预分频器寄存器只是起到缓存数据的作用,只有等到更新事件发生时,预分频器寄存器的值才会被自动写入其影子寄存器中,这时才真正起作用。

通用定时器和基本计时器的基本原理相同,不过添加了更多的选择和功能,比如增加了输入捕获的部分(可以用来测量外部电信号的周期,记录外来信号跳变的次数),输出捕获(可以用来输出PWM波)。

同时信号源也有了四种选择:

  1. 内部时钟(CK_INT)
  2. 外部时钟模式 1:外部输入引脚(TIx), x=1, 2(即只能来自于通道 1 或者通道 2)
  3. 外部时钟模式 2:外部触发输入(ETR)
  4. 内部触发输入(ITRx):使用一个定时器作为另一定时器的预分频器(定时器串联)

DAC/ADC