本次设计中需要的外围电路的输入以及输出,这里就以正点原子的库函数为例,进行IO口的初始化配置。
首先,以继电器驱动为例,代表了IO口开漏输出,通过输出高电平,控制外围电路。
void Relay_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //ʹÄÜGPIOB¶Ë¿ÚʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //ËÙ¶ÈΪ50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //¸ù¾Ý²ÎÊý³õʼ»¯GPIOB.8
// GPIO_ResetBits(GPIOB,GPIO_Pin_14);//Êä³ö0£¬
GPIO_SetBits(GPIOB,GPIO_Pin_14);
}
继电器的IO口我选择的是PB14,下面对此IO口进行配置,首先,目的是要输出,驱动,需要较大的电流以及电压,因此,使用普通开漏输出模式。
普通开漏输出(GPIO_Mode_Our_OD):若要输出5V,则需外加上拉电阻,电源为5V,输出为高阻态时,由上拉电阻和电源向外输出5V的高电平。
开漏输出:
输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。开漏形式的电路有以下几个特点:
1、利用外部电路的驱动能力,减少IC内部的驱动。当IC内部MOSFET导通时,驱动电流是从外部的VCC流经上拉电阻、MOSFET到GND。IC内部仅需很小的栅极驱动电流。
2、一般来说,开漏是用来连接不同电平的器件,匹配电平用的,因为开漏引脚不连接外部的上拉电阻时,只能输出低电平,如果需要同时具备输出高电平的功能,则需要接上拉电阻,很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。比如加上上拉电阻就可以提供TTL/CMOS电平输出等。(上拉电阻的阻值决定了逻辑电平转换的速度。阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)
3、开漏输出提供了灵活的输出方式,但是也有其弱点,就是带来上升沿的延时。因为上升沿是通过外接上拉无源电阻对负载充电,所以当电阻选择小时延时就小,但功耗大;反之延时大功耗小。所以如果对延时有要求,则建议用下降沿输出。
4、可以将多个开漏输出连接到一条线上。通过一只上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系,即“线与”。可以简单的理解为:在所有引脚连在一起时,外接一上拉电阻,如果有一个引脚输出为逻辑0,相当于接地,与之并联的回路“相当于被一根导线短路”,所以外电路逻辑电平便为0,只有都为高电平时,与的结果才为逻辑1。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
初始化配置中,这里的频率设置,虽然不太懂,但应该是输出速度吧,我就按照大部分的默认50MHz了。
GPIO_SetBits(GPIOB,GPIO_Pin_14);
//GPIO_ResetBits(GPIOB,GPIO_Pin_14);
初始化配置后,还有一个对于端口状态的初始化,这里的话还是能比较清晰的看到两个函数的功能,一个初始化为低,一个是初始化为高。
这是这个函数就相当于把本来应该一个个配置的寄存器,变得比较具象,但同时呢,也模糊掉了底层的工作原理。
#define Relay PBout(14)
初始化完毕后,主程序中需要对IO口进行操作,这里使用自定义,PB14的输出映射为Relay。
这里的PBout以及PBin,按照我的理解,PBout(14)指PB14端口向外输出一个高电平或者低电平,PBin(14)指PB14内部上拉一个高电平或者低电平。
准备就绪后,需要继电器开时,输出Relay = 0(因为继电器驱动电路的设计,低电平开继电器)。反之,Relay = 1,继电器关闭。
接下来是按键输入检测的IO口配置,这里的按键需要外接,通过下面这个电路。
按键的IO口使用的是A11,根据原理图,可以看到PA11口被上拉,因此默认高电平。
这里先说一下为什么要上拉电阻,以及上拉的作用。上拉就是将不确定的信号通过一个电阻钳位在高电平,电阻同时起限流作用。下拉同理,也是将不确定的信号通过一个电阻钳位在低电平。提高总线的抗电磁干扰能力,管脚悬空就比较容易接受外界的电磁干扰。芯片的管脚加上拉电阻来提高输出电平,从而提高芯片输入信号的噪声容限,增强抗干扰能力。为增强输出引脚的驱动能力,有的单片机管脚上也常使用上拉电阻。长线传输中电阻不匹配容易引起反射波干扰,加上、下拉电阻是电阻匹配,有效的抑制反射波干扰。
所以IO口上拉后,按键按下,即闭合时候相当于PA11短路接地,因此使用时只需要判断PA11 == 0,即可判断按键是否按下。
因为上拉输入,所以端口初始化如下:
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
在这里,选择的模式就是相应的上拉输入GPIO_Mode_IPU,这里引入一个问题,就是上拉输入和下拉输入到底有啥区别?
上拉输入模式:区别在于没有输入信号的时候默认输入高电平(因为有弱上拉)。
下拉输入模式:区别在于没有输入信号的时候默认输入低电平(因为有弱下拉)。
对于浮空输入模式顾名思义也就是输入什么信号才是什么信号,对于浮空输入要保证有明确的输入信号
这也就是为什么这里选择上拉输入,因为没有信号输入时是高电平。
主程序中只需要在消除抖动后,在代码中判断KEY_Fan,也就是读PA11端口的状态即可。
需要检测外来信号0V或5V然后MCU做出相应的动作。
void Fan_Init(void) //IO³õʼ»¯ PB15
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//ʹÄÜPORTA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PB15ÉèÖóÉÊäÈ룬ĬÈÏÏÂÀ
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯GPIOB.15
// GPIO_SetBits(GPIOB,GPIO_Pin_15);
GPIO_ResetBits(GPIOB,GPIO_Pin_15);
}
熟悉的初始化,跟按键初始化很相似,本质上都是检测输入。只不过成了下拉输入,默认低电平,模式改为GPIO_Mode_IPD。