打印
[牛人杂谈]

M0/M4 的 GPIO 初始化

[复制链接]
楼主: 稳稳の幸福
手机看帖
扫描二维码
随时随地手机跟帖
21
什么是“线与”?:
在一个结点(线)上, 连接一个上拉电阻到电源 VCC,或连接到 NPN 或 NMOS 晶体管的集电极 C 或漏极 D 上, 这些晶体管的
发射极 E 或源极 S 都接到地线上, 只要有一个晶体管饱和, 这个结点(线)就被拉到地线电平上. 因为这些晶体管的基极注入电流
(NPN)或栅极加上高电平(NMOS),晶体管就会饱和, 所以这些基极或栅极对这个结点(线)的关系是“或非逻辑”. 如果这个结点后面
加一个反相器, 就是“或逻辑” 。其实可以简单的理解为:在所有引脚连在一起时,外接一上拉电阻,如果有一个引脚输出为逻辑 0,
相当于接地,与之并联的回路“相当于被一根导线短路” ,所以外电路逻辑电平便为 0,只有都为高电平时,与的结果才为逻辑 1。
开漏输出模式需要设置 Px_MODE[2n+1:2n]为 2

使用特权

评论回复
22
734774645| | 2016-7-30 18:59 | 只看该作者
准双向模式
准双向模式最常见的是 8051 单片机,而新唐公司的 M451 系列的 MCU 同样拥有准双向模式的 I/O,准双向模式需要设置
Px_MODE[2n+1:2n]为 3。当引脚被设置为双向输出模式时,但源电流只有数百 uA。当引脚的状态为高电平时,其内部电路不会发
生任何动作,但当引脚的状态切换为低电平时需要 2 个时钟周期才能禁用强输出驱动功能

使用特权

评论回复
23
734774645| | 2016-7-30 19:00 | 只看该作者

M451 支持输入模式、推挽输出模式、开漏输出模式、准双向模式,由于驱动 LED 灯只需要对 PB8 引脚输出高低电平就行了,通
过之前各种 I/O 模式的分析,这里设置 PB8 引脚为推挽输出模式就行了,需要调用库函数 GPIO_SetMode(需要包含 gpio.c)如果点亮 LED 灯需要 I/O 引脚输出低电平,反之熄灭 LED 灯需要 I/O 引脚输出高电平。也代表说当
前控制 LED 灯使用了灌电流的设计方案。在集成电路当中,拉电流和灌电流是一个很重要的概念。由于数字电路的输出只有高、低(0,
1)两种电平值,高电平输出时,一般是输出端对负载提供电流,其提供电流的数值叫“拉电流”;低电平输出时,一般是输出端要吸
收负载的电流,其吸收电流的数值叫“灌(入)电流”。而拉电流和灌电流是衡量电路输出的驱动能力,对每个芯片而言,拉电流和
灌电流的大小都有各自的最大值。默认情况下,灌电流比拉电流具有更强的驱动能力,意味着芯片可以带动更多的负载。
由于现在很多芯片都具有推挽输出模式,拉电流单个 I/O 达到 20mA,但是整体 I/O 输出总电流不能超过 55mA,也代表说如果
驱动多盏 LED 灯再驱动更多的器件,芯片的就显得力不从心。所以,设计电路图是必须要按照实际情况进行设计,因此,驱动 LED
灯默认情况下使用灌电流的形式。

使用特权

评论回复
24
734774645| | 2016-7-30 19:01 | 只看该作者
GPIO_SetMode(PB,BIT8,GPIO_MODE_OUTPUT);
[2]当设置好 PB8 引脚为推挽输出模式后,如何编程引脚为高低电平的输出呢,代码如下:
程序清单 6.2.2 PB8 引脚输出高电平
/* PB8 赋值为‘1’时,也代表着当前的 PB8 引脚状态被编程为高电平输出 */
PB8=1;
程序清单 6.2.3 PB8 引脚输出低电平
/* PB8 赋值为‘0’时,也代表着当前的 PB8 引脚状态被编程为低电平输出 */
PB8=0;
[3]按照实验要求 LED 实现闪烁功能,意味着还得编写一个延时函数,代码如下:
程序清单 6.2.4 软件延时函数编写
VOID Delay(VOID)
{
UINT32 i=0x10000;
while(i--);
}

使用特权

评论回复
25
734774645| | 2016-7-30 19:02 | 只看该作者
int32_t main(void)
{
PROTECT_REG
(
/* 系统时钟初始化 */
SYS_Init(PLL_CLOCK);
)
/* PB8 引脚初始化为推挽输出模式 */
GPIO_SetMode(PB,BIT8,GPIO_MODE_OUTPUT);
while(1)
{
/* PB8 引脚输出高电平*/
PB8=1;
/* 延时一会儿 */
Delay();
/* PB8 引脚输出低电平*/
PB8=0;
/* 延时一会儿 */
Delay();


使用特权

评论回复
26
734774645| | 2016-7-30 19:04 | 只看该作者

按键硬件电路可以知道,KEY1 与 KEY2 都外接 10K 欧姆的上拉电阻。 这里我们必须要了解为什么要加上拉电阻。
当设置好 KEY1 和 KEY2 引脚为输入模式的时候,I/O 状态表现为高阻状态用于检测外部的电平的变化,如果是高电平的话,必须
要检测到 3.3V 的电压,如果是低电平的话,必须检测到 0V 的电压。倘若如果当前 KEY1 和 KEY2 只是悬空引脚的话,高电平就不
复存在,同时,当按键没有按下的时候,KEY1 与 KEY2 引脚表现为悬空状态,引脚状态是不确定的,容易接受外界的电磁干扰。在
制作工艺为 CMOS 的芯片上,为了防止静电造成损坏,不用的管脚不能悬空,一般接上拉电阻令输入阻抗降低,提供泄荷通路。通
过以上分析,就知道为什么按键硬件电路的设计必须接上上拉电阻的原因了。

为了检测引脚的电平,可以将 I/O 引脚设置为输入模式或准双向模式,当前实验,这里选择为输入模式,需要调用库函数
GPIO_SetMode(需要包含 gpio.c) ,代码如下:
程序清单 6.2.6 设置 PB0、PE8 引脚为输入模式
/* PB0 引脚初始化为输入模式 */
GPIO_SetMode(PB,BIT0,GPIO_MODE_INPUT);
/* PE8 引脚初始化为输入模式 */
GPIO_SetMode(PE,BIT8,GPIO_MODE_INPUT);
[2] 在单片机的应用中,利用按键实现与用户的交互功能是相当常见的,同时按键的检测也是很讲究的,众所周知,在有键按下后,
数据线上的信号出现一段时间的抖动,然后为低,当按键释放时,信号抖动一段时间后变高,然而这段抖动时间要维持 10ms~50ms,
这个与按键本身的材质有一定的关系,在这个范围内基本上都可以确定的。当前实验,只是验证输入模式,那么按键扫描采用简单的
按键延时消抖去实现。

使用特权

评论回复
27
734774645| | 2016-7-30 19:08 | 只看该作者
int32_t main(void)
{
PROTECT_REG
(
/* 系统时钟初始化 */
SYS_Init(PLL_CLOCK);
/* 串口 0 初始化,波特率 115200bps */
UART0_Init(115200);
)
/* PB0 引脚初始化为输入模式 */
GPIO_SetMode(PB,BIT0,GPIO_MODE_INPUT);
/* PE8 引脚初始化为输入模式 */
GPIO_SetMode(PE,BIT8,GPIO_MODE_INPUT);
while(1)
{
/* 检查 KEY1 是否按下 */
if(PB0 ==0)
{
/* 延时 20ms */
Delayms(20);
/* 等待 KEY1 释放 */
while(PB0 == 0);
/* 打印 KEY1 输出信息 */
printf("KEY1 is pressed\r\n");
}
/* 检查 KEY2 是否按下 */
if(PE8 ==0)
{
/* 延时 20ms */
Delayms(20);
/* 等待 KEY2 释放 */
while(PE8 == 0);
/* 打印 KEY2 输出信息 */
printf("KEY2 is pressed\r\n");
}
}
}


使用特权

评论回复
28
zhuotuzi| | 2016-7-31 21:33 | 只看该作者
/*  将 PE2 配置为输入模式,打开内部上拉,并使能下降沿中断 */
  
GPIO_SetMode(PE, BIT2, GPIO_PMD_INPUT);
  
GPIO_ENABLE_PULL_UP(PE, BIT2);
  
GPIO_EnableInt(PE, 2, GPIO_INT_FALLING);
  
NVIC_EnableIRQ(GPDEF_IRQn);
这个内部有上拉电阻。

使用特权

评论回复
29
zhuomuniao110| | 2016-7-31 21:41 | 只看该作者
NUC472和 NUC442Vbat 负责 PG.14、PG.15、PA.0 和 PA.1,这些脚由 Vbat 负责供电,所以Vbat一定要有电,即使不接电池也要和 VDD接到一起。

使用特权

评论回复
30
稳稳の幸福|  楼主 | 2016-8-6 23:20 | 只看该作者
为了检测引脚的电平,可以将 I/O 引脚设置为输入模式或准双向模式,当前实验,这里选择为输入模式,需要调用库函数
GPIO_SetMode(需要包含 gpio.c)

使用特权

评论回复
31
稳稳の幸福|  楼主 | 2016-8-6 23:52 | 只看该作者
新唐所有的M0/M4芯片基本上所有的IO都可以发生中断,为了符合大家的习惯还是有所谓的外部中断EINT0和EINT1。

使用特权

评论回复
32
稳稳の幸福|  楼主 | 2016-8-6 23:53 | 只看该作者
有2根GPIO脚可以配置为EINT0功能和EINT1功能,分别将发生EINT0中断和EINT1中断。其它的IO脚也会导致发生中断,但是为很多IO共用一个向量的方式

使用特权

评论回复
33
天灵灵地灵灵| | 2016-8-7 09:04 | 只看该作者
每个IO都有边沿中断消抖功能,一般用作按键的时候或者外部输入信号会抖动的情况下需要打开。

使用特权

评论回复
34
捉虫天师| | 2016-8-7 11:52 | 只看该作者
/**************************************************************************//**
* @file     main.c
* @version  V3.00
* $Revision: 3 $
* $Date: 14/04/03 9:17a $
* @brief    M051 Series GPIO Driver Sample Code
*
* @note
* Copyright (C) 2013 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/
#include <stdio.h>
#include "M051Series.h"


#define PLLCON_SETTING      CLK_PLLCON_50MHz_HXT
#define PLL_CLOCK           50000000


/**
* @brief       External INT0 IRQ
*
* @param       None
*
* @return      None
*
* @Details     The External INT0(P3.2) default IRQ, declared in startup_M051Series.s.
*/
void EINT0_IRQHandler(void)
{
    /* For P3.2, clear the INT flag */
    P3->ISRC = BIT2;

    printf("P3.2 EINT0 occurred.\n");
}

/**
* @brief       External INT1 IRQ
*
* @param       None
*
* @return      None
*
* @details     The External INT1(P3.3) default IRQ, declared in startup_M051Series.s.
*/
void EINT1_IRQHandler(void)
{
    /* For P3.3, clear the INT flag */
    P3->ISRC = BIT3;

    printf("P3.3 EINT1 occurred.\n");
}

void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Enable Internal RC 22.1184MHz clock */
    CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;

    /* Waiting for Internal RC clock ready */
    while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk));

    /* Switch HCLK clock source to Internal RC and and HCLK source divide 1 */
    CLK->CLKSEL0 &= ~CLK_CLKSEL0_HCLK_S_Msk;
    CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_HIRC;
    CLK->CLKDIV &= ~CLK_CLKDIV_HCLK_N_Msk;
    CLK->CLKDIV |= CLK_CLKDIV_HCLK(1);

    /* Enable external XTAL 12MHz clock */
    CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;

    /* Waiting for external XTAL clock ready */
    while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk));

    /* Set core clock as PLL_CLOCK from PLL */
    CLK->PLLCON = PLLCON_SETTING;
    while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk));
    CLK->CLKSEL0 &= (~CLK_CLKSEL0_HCLK_S_Msk);
    CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_PLL;

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
    //SystemCoreClockUpdate();
    PllClock        = PLL_CLOCK;            // PLL
    SystemCoreClock = PLL_CLOCK / 1;        // HCLK
    CyclesPerUs     = PLL_CLOCK / 1000000;  // For SYS_SysTickDelay()

    /* Enable UART module clock */
    CLK->APBCLK |= CLK_APBCLK_UART0_EN_Msk;

    /* Select UART module clock source */
    CLK->CLKSEL1 &= ~CLK_CLKSEL1_UART_S_Msk;
    CLK->CLKSEL1 |= CLK_CLKSEL1_UART_S_PLL;

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/

    /* Set P3 multi-function pins for UART0 RXD, TXD, EINT0 and EINT1 */
    SYS->P3_MFP &= ~(SYS_MFP_P30_Msk | SYS_MFP_P31_Msk | SYS_MFP_P32_Msk | SYS_MFP_P33_Msk);
    SYS->P3_MFP |= (SYS_MFP_P30_RXD0 | SYS_MFP_P31_TXD0 | SYS_MFP_P32_INT0 | SYS_MFP_P33_INT1);

}

void UART0_Init()
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init UART                                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Reset UART IP */
    SYS->IPRSTC2 |=  SYS_IPRSTC2_UART0_RST_Msk;
    SYS->IPRSTC2 &= ~SYS_IPRSTC2_UART0_RST_Msk;

    /* Configure UART0 and set UART0 Baudrate */
    UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(PLL_CLOCK, 115200);
    UART0->LCR = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
}

/*---------------------------------------------------------------------------------------------------------*/
/* MAIN function                                                                                           */
/*---------------------------------------------------------------------------------------------------------*/
int main(void)
{
    /* Unlock protected registers */
    SYS->REGWRPROT = 0x59;
    SYS->REGWRPROT = 0x16;
    SYS->REGWRPROT = 0x88;

    /* Init System, peripheral clock and multi-function I/O */
    SYS_Init();

    /* Lock protected registers */
    SYS->REGWRPROT = 0x0;

    /* Init UART0 for printf */
    UART0_Init();

    printf("\n\nCPU @ %d Hz\n", SystemCoreClock);
    printf("+------------------------------------------------------------+\n");
    printf("|    GPIO EINT0/EINT1 Interrupt and De-bounce Sample Code    |\n");
    printf("+------------------------------------------------------------+\n\n");

    /*-----------------------------------------------------------------------------------------------------*/
    /* GPIO External Interrupt Function Test                                                               */
    /*-----------------------------------------------------------------------------------------------------*/
    printf("EINT0(P3.2) and EINT1(P3.3) are used to test interrupt \n");

    /* Configure P3.2 as EINT0 pin and enable interrupt by falling edge trigger */
    P3->PMD = P3->PMD & (~GPIO_PMD_PMD2_Msk) | (GPIO_PMD_INPUT << GPIO_PMD_PMD2_Pos);
    P3->IMD |= (GPIO_IMD_EDGE << 2);
    P3->IEN |= (BIT2 << GPIO_IEN_IF_EN_Pos);
    NVIC_EnableIRQ(EINT0_IRQn);

    /* Configure P3.3 as EINT1 pin and enable interrupt by rising and falling edge trigger */
    P3->PMD = P3->PMD & (~GPIO_PMD_PMD3_Msk) | (GPIO_PMD_INPUT << GPIO_PMD_PMD3_Pos);
    P3->IMD |= (GPIO_IMD_EDGE << 3);
    P3->IEN |= ((BIT3 << GPIO_IEN_IR_EN_Pos) | (BIT3 << GPIO_IEN_IF_EN_Pos));
    NVIC_EnableIRQ(EINT1_IRQn);

    /* Enable interrupt de-bounce function and select de-bounce sampling cycle time is 1024 * 10 KHz clock */
    GPIO->DBNCECON = (GPIO_DBNCECON_ICLK_ON_Msk | GPIO_DBCLKSRC_LIRC | GPIO_DBCLKSEL_1024);
    P3->DBEN |= (BIT2 | BIT3);

    /* Waiting for interrupts */
    while(1);
}

/*** (C) COPYRIGHT 2013 Nuvoton Technology Corp. ***/

使用特权

评论回复
35
yiyigirl2014| | 2016-8-7 13:56 | 只看该作者
NUC472/NUC442和M451的IO比较特别,它们有多个Power Domain,就是所有的IO的供电电压可以不同,在使用时一定要注意。

使用特权

评论回复
36
玛尼玛尼哄| | 2016-8-7 15:03 | 只看该作者
Vbat一定要有电,即使不接电池也要和 VDD接到一起。

使用特权

评论回复
37
heisexingqisi| | 2016-8-7 23:11 | 只看该作者
以前不知道还有配置软件,都是参考例程配置的

使用特权

评论回复
38
wahahaheihei| | 2016-8-8 21:48 | 只看该作者
NUC472/NUC442和M451的IO比较特别,它们有多个Power Domain,就是所有的IO的供电电压可以不同,在使用时一定要注意。

使用特权

评论回复
39
gejigeji521| | 2016-8-9 00:13 | 只看该作者
当 IC 内部 MOSFET 导通时,驱动电流是从外部的 VCC 流经上拉电阻,MOSFET到 GND。IC 内部仅需很小的栅极驱动电流。

使用特权

评论回复
40
598330983| | 2016-8-9 11:27 | 只看该作者
Vbat一定要有电,即使不接电池也要和 VDD接到一起。另外 PG.14和 PG.15默认为晶振功能用于外接 32K晶振,如果想改为 GPIO需要修改 Configarea

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则