何为高低电平?
- 高电平电压(high level voltage),输出的电压值相对较高
- 低电平电压(low level voltage),输出的电压值相对较低
高低电平的电压具体值是多少需要参考数据手册,举个例子,如下表所示,VDD的典型值是3.3V,根据数据手册可以知道低电平下GPIO输出的最大电压是0.4V;高电平下GPIO输出的最小电压是3.3-0.4=2.9V。
VCC、VEE、VDD和VSS的含义和区别
Back in the pleistoscene (1960s or earlier), logic was implemented with bipolar transistors. Even more specifically, they were NPN because for some reasons I'm not going to get into, NPN were faster. Back then it made sense to someone that the positive supply voltage would be called Vcc where the "c" stands for collector. Sometimes (but less commonly) the negative supply was called Vee where "e" stands for emitter.
When FET logic came about, the same kind of naming was used, but now the positive supply was Vdd (drain) and the negative Vss (source). With CMOS this makes no sense, but it persists anyway. Note that the "C" in CMOS stands for "complementary". That means both N and P channel devices are used in about equal numbers. A CMOS inverter is just a P channel and a N channel MOSFET in its simplest form. With roughly equal numbers of N and P channel devices, drains aren't more likely to be positive than sources, and vice versa. However, the Vdd and Vss names have stuck for historical reasons. Technically Vcc/Vee is for bipolar and Vdd/Vss for FETs, but in practise today Vcc and Vdd mean the same, and Vee and Vss mean the same.[1]
☑️VCC[2]
- VCC用作使BJT(双极性晶体管,俗称三极管)的电路的正电源电压(positive supply voltage)。
- VCC中的"C"表示Collecter(集电极)
- 普遍认为,"VCC"中的出现两个"C"的原因是为了将其与集电极电压VC区分开来。
☑️VEE
- VEE用作使用双极晶体管(BJT)的电路的负电源电压(negative supply voltage)。
- VEE中的"E"表示Emitter(发射极)
- 普遍认为,"VEE"中的出现两个"E"的原因是为了将其与发射极电压VE区分开来。
☑️VDD
- VDD用作使用场效应晶体管(FET)的电路的正电源电压。
- VDD中的"D"表示Drain(漏极)。
- 普遍认为,"VDD"中的出现两个"D"的原因是为了将其与漏极电压VD区分开来。
☑️VSS
- VSS用作使用场效应晶体管(FET)的电路的负电源电压。
- VSS中的"S"表示Source(源极)。
- 普遍认为,"VSS"中的出现两个"S"的原因是为了将其与漏极电压VS区分开来。
总结一下,由于历史原因,VDD和VSS的名称一直存在。从技术上讲,VCC/VEE用于双极性晶体管(BJT),VDD/Vss用于场效应晶体管(FET),但在今天的实际情况下VSS和VEE是相同的意思,表示电源负极;VDD和VCC是相同的意思,表示电源正极。
GPIO
STM32芯片中,通用输入输出(General Purpose IO: GPIO) 可以被配置成以下模式:
- 浮空输入(Input floating)
- 上拉输入(Input pull-up)
- 下拉输入(Input pull-down)
- 模拟(Analog)
- 开漏输出(Output open-drain)
- 推挽输出(Output push-pull)
- 复用推挽输出(Alternate function push-pull)
- 复用开漏输出(Alternate function open-drain)
推挽输出
推挽输出模式下,MCU向输出数据寄存器中写入逻辑"1",输出控制器将P-MOS管开启,N-MOS管关闭,I/O与VDD接通,因此I/O引脚输出高电平,电流从VDD流向I/O引脚,电流往外流,就像是把电流往外推(push)一样。如图所示灯泡被点亮。
MCU向输出数据寄存器中写入逻辑"0",P-MOS管关闭,N-MOS管开启,I/O与VSS(0V)接通,因此I/O引脚输出低电平,灯泡两端都是接地,没有电压差,因此没有电流路过,灯泡也不会亮。如果,此时外接一个电源,存在电压差,电流向单片机内部VSS流动,就像是把电流往回挽(pull)留一样
开漏输出
开漏输出模式下,MCU向输出数据寄存器中写入逻辑"0",P-MOS管关闭,N-MOS管开启,相当于I/O引脚与Vss接通,所以输出低电平。要点亮灯泡,就必须外接电源,此时电流从I/O引脚流向VSS,即从N-MOS的漏极(drain)流向源极(source),这也是开漏输出中的"漏"的来源。
开漏输出模式下,MCU向输出数据寄存器中写入逻辑"1",P-MOS管关闭,N-MOS管关闭,即电路处于开路状态。I/O引脚输出为高阻态(输出状态不确定),通常要使高电平下MCU也对I/O口有驱动能力,此时外接一个上拉电阻将I/O引脚拉到高电平
开漏与推挽输出的总结
- 推挽输出下,MCU可以直接驱动I/O口输出高低电平;推挽输出模式一般应用在输出电平为0和3.3伏而且需要高速切换开关状态的场合。
- 开漏模式输出下,MCU高电平没有驱动能力,低电平才有驱动能力,适合在连接的外设电压比单片机电压低的场合
在STM32的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。
GPIO实现流水灯
正如上面所说,选择GPIO的推挽输出模式,LED灯正极外接3.3V电源,因此单片机向输出数据寄存器(Output data register, ODR)写入0即可点亮LED灯。输出数据寄存器共有16位,假设要PA0输出低电平,可以向ODR中写入1111 1111 1111 1110b
对应的16进制数:0xfffe
,在while循环中遍历数组即可实现流水灯
#include "stm32f10x.h"
#include "delay.h"
const uint16_t val[4] = { 0xfffe, 0xfffd, 0xfffb, 0xfff7}; //用于点亮LED灯
int main()
{
/* 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* 配置GPIOA口 */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
while (1)
{
for(int i = 0 ; i < 4; i++)
{
GPIO_Write(GPIOA, val[i]);
delay_ms(500); //delay 500ms
}
}
}