单片机学习小组
直播中

h1654155275.5669

7年用户 1028经验值
私信 关注

如何配置IO的输出模式?

如何配置IO的输出模式?

回帖(1)

张梅

2022-2-7 16:01:28
在上一章,我们把IO系统的时钟源进行了一个梳理和详细分析,在正确的配置了相关的系统时钟源和IO模块的时钟源后,接下来还要做一件重要的事情,就是配置IO的输出模式。
既然是IO,就有输出也有输入,所以需要配置来选择正确的方向。

上图是STM32F103的IO基本结构图。
我们把这张图分两部分来解读:

  第一部分: 输入input,如图中红色部分所示

当I/O端口配置为输入时,如上图简化后的图,注意红色圆圈的几个地方:
1.输出缓冲器被禁止,如图A点,被断开,所以你的输出数据无法反应到IO端口上,此路不通。
2. 施密特触发输入被激活,如图B点
这两步动作是把端口模式配置为输入后自动进行的,无需额外配置
3. 根据输入配置(上拉,下拉或浮动)的不同,弱上拉和下拉电阻被连接
4. 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器,这就是IO能捕捉到数据的最大的频率,如果你的输入数的频率高于这个频率,将不会正确的捕捉到。
5. 对输入数据寄存器的读访问可得到I/O状态。

  输入的三条路径如下
第一条路径是模拟信号输入路径,它是直达系统的模拟输入器件端口的,比如ADC,比较器等模拟威廉希尔官方网站 ,所以它要绕过输入部分的数字威廉希尔官方网站 (施密特触发器)。如下图ADC的输入路径所示,它从IO口进来后会进入一个MUX(多路复用器,算是一个模拟开关),然后到达ADC转换单元完成模拟到数字的转换后,才送到后端进行进一步的处理。

特别留意一下模拟输入的时候示意图如下:

如上图所示,当I/O端口被配置为模拟输入时:


  • 输出缓冲器被禁止;
  • 禁止施密特触发输入,实现了每个模拟I/O引脚上的零消耗。施密特触发输出值被强置
    为’0’;所以,此时输入阻抗很高,容易吸收干扰信号。
  • 弱上拉和下拉电阻被禁止;
  • 读取输入数据寄存器时数值为’0’

第二条路径是特殊功能输入,但是它输入的是数字信号,典型的应用比如UART的接收,PWM的捕获等数字信号。这个数字信号还会送到后面的数字威廉希尔官方网站 进行进一步的处理,比如UART。下图中红色代表UART的接收数据RX,它会经过一个移位寄存器,按照我们设定的参数(数据位数,奇偶校验位,停止位数等)把数据组合成一个字节后,才送入RDR寄存器。

对于特殊功能的路径,简化后如下:

当I/O端口被配置为复用功能时:


  • 在开漏或推挽式配置中,输出缓冲器被打开
  • 内置外设的信号驱动输出缓冲器(复用功能输出),路径是图中A点,此时IO输出数据的路径被断开,所以你无法写数据到IO引脚
  • 施密特触发输入被激活。
  • 弱上拉和下拉电阻被禁止,如图C,上下拉电阻被disable掉了。
    5.在每个APB2时钟周期,出现在I/O脚上的数据被采样到输入数据寄存器,此采样频率决定了外设的工作速度
  • 开漏模式时,读输入数据寄存器时可得到I/O口状态
  • 在推挽模式时,读输出数据寄存器时可得到最后一次写的值

第三条路径是最简单的一条路径。它把IO引脚的电平经过可选的施密特触发器整型后(所以你的输入电平要达到一定的电压才能被认识为高电平),就直接把结果放入到输入寄存器了,你读到的IO电平就是这个寄存器的数值。

  第二部分 输出output,如第一张图的蓝色部分所示

当I/O端口被配置为输出时,IO的结构如上图所示:
1.输出缓冲器被激活
─ 开漏模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将端口置于高阻状态(PMOS从不被激活,相当于已经被从系统断开)。
─ 推挽模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将激活P-MOS。
2. 施密特触发输入被激活,如图C点
3. 弱上拉和下拉电阻被禁止
4.出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器,这样才可以读到输出的数据
5.在开漏模式时,对输入数据寄存器的读访问可得到I/O状态
6. 在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。

  对应的输出也会有三条路径
从图上可以看出来,三路输出的路径最后都要经过一个输出控制单元的控制,所以输出路径的特殊之处在于没有模拟信号输出。
第一条路径是特殊功能输出,比如UART的TX,DAC的输出等。
第二条路径,就是直接写端口的寄存器来输出数据,如下图所示,STM32F103的输出数据一般都是16bit(32bit的MCU最高是可以到32bit的)。
GPIOA->ODR = 0x0012;         //将0x0012送到A端口,输出完毕后,端口的bit1,bit5变1
第三条路径就是arm的一个特殊操作,bit操作。这个操作的目的就是加速单个IO的数据输出速度。
IO的数据输入输出寄存器是32bit,我们读的时候就是一次性读入的,写也是一次性输出的,比如向GPIOA输出数据:
GPIOA->ODR = PortVal; //这样输出是一次性输出16bit,同时改变16位的数据。如果我们只需要输出bit0的数据,就需要这样来操作才可以:PortVal  = GPIOx->ODR;//先读入整个端口的输出寄存器值。PortVal &= 0xFFFFFFFE;//mask掉bit0If(要输出bit0==1)        PortVal |= 0x00000001;GPIOA->ODR = PortVal; //输出数据 以上操作相当的繁琐,效率低下,如果用ARM的位操作来做,非常简单:
GPIOA->BSRR = GPIO_Pin1;// GPIO_Pin1 == 1 只需要向这个特殊的寄存器的对应位写1就一步完成了操作,效率提高若干倍。
要注意的是复位对应的位也是写1而不是0,只是所用的寄存器不一样,
GPIOA->BRR = GPIO_Pin1;// GPIO_Pin1 ==0

最后通过两个特殊的寄存器,来选择我们需要的输出和输入路径:


根据你的输入输出功能,选择正确的输出路径后,基本通道就打通了。
别高兴太早了,还要一步需要我们去完成,看到图一中的ABCD几个地方的设置了吗?
举报

更多回帖

发帖
×
20
完善资料,
赚取积分