taozhi11 发表于 2021-7-6 14:16

KF32F341的IO输入功能

关于IO口输入(按键)失灵的分析
采用的是KF32F350的官方例程,移植到KF34F341的板子上出现了问题
预期实现:供电后LED亮,按下按键后LED状态翻转

硬件:
1.按下按键后并无反应
2.万用表测量按键一端电压,有0->3.3V电压状态改变
3.直接将3.3V电压接触实现按键的芯片引脚,LED也无现象
4.改代码,用其他IO口做输入,仍无响应
5.换了另一块341的板子也不可以
软件:
1.将该程序烧入至F350开发板,板子能正确工作,LED正常反转
2.换用按键中断程序,代码不能正常工作,将IO输入的函数注释掉后可以正常工作
3.经实测IO口的输出以及模拟输入功能正常,如LED闪烁,ADC采样功能无恙

希望各位老哥能提供下帮助呀

yangxiaor520 发表于 2021-7-6 17:36

上代码看看

taozhi11 发表于 2021-7-6 21:14

yangxiaor520 发表于 2021-7-6 17:36
上代码看看

#include "system_init.h"

#define    KEY2    GPIO_Read_Input_Data_Bit(GPIOA_SFR,GPIO_PIN_MASK_3)
//延时函数 局部变量用volatile声明,否则可能会被优化
//主频时120M 1ms延时函数
void delay_ms(volatile uint32_t nms)
{
        volatile uint32_t i,j;
        for(i=0;i<nms;i++)
        {
                j=700;
                while(j--);
        }

}


/**
* 描述GPIOx 输出初始化配置。
* 输入 : GPIOx: 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。
*       GpioPin: 端口引脚掩码,取值为GPIO_PIN_MASK_0~GPIO_PIN_MASK_15中的一个或多个组合。
* 返回无。
*/
void GPIOInit_Output_Config(GPIO_SFRmap* GPIOx,uint16_t GpioPin)
{
        /*初始化复位GPIOx外设,使能GPIOx外设时钟*/
                GPIO_Reset(GPIOx);

        /* 配置 Pxy作为输出模式参数 */
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_Struct_Init(&GPIO_InitStructure);
        GPIO_InitStructure.m_Pin = GpioPin;
        GPIO_InitStructure.m_Speed = GPIO_LOW_SPEED;          //初始化 GPIO输出速度
        GPIO_InitStructure.m_Mode = GPIO_MODE_OUT;            //初始化 GPIO方向为输出
        GPIO_InitStructure.m_PullUp = GPIO_NOPULL;            //初始化 GPIO是否上拉
        GPIO_InitStructure.m_PullDown = GPIO_NOPULL;          //初始化 GPIO是否下拉
        GPIO_Configuration(GPIOx,&GPIO_InitStructure);

        GPIO_Set_Output_Data_Bits(GPIOx,GpioPin,Bit_SET);                                        //先设置为高电平

}

/**
* 描述GPIOx 输入初始化配置。
* 输入 : GPIOx: 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。
*       GpioPin: 端口引脚掩码,取值为GPIO_PIN_MASK_0~GPIO_PIN_MASK_15中的一个或多个组合。
* 返回无。
*/
void GPIOInit_Input_Config(GPIO_SFRmap* GPIOx,uint16_t GpioPin)
{
        /*初始化复位GPIOx外设,使能GPIOx外设时钟*/
                GPIO_Reset(GPIOx);

        /* 配置 Pxy作为输入模式 */
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_Struct_Init(&GPIO_InitStructure);
        GPIO_InitStructure.m_Pin = GpioPin;
        GPIO_InitStructure.m_Speed = GPIO_LOW_SPEED;                   //初始化 GPIO输出速度
        GPIO_InitStructure.m_Mode = GPIO_MODE_IN;                      //初始化 GPIO方向为输入
        GPIO_InitStructure.m_PullUp = GPIO_NOPULL;                     //初始化 GPIO是否上拉 不上拉
        GPIO_InitStructure.m_PullDown = GPIO_NOPULL;                   //初始化 GPIO是否下拉 不下拉
        GPIO_Configuration(GPIOx,&GPIO_InitStructure);
}


/**
* 描述GPIOx 输入与输出初始化配置。
* 输入 : 无
* 返回无。
*/
void GPIO_Init(void)
{
        GPIOInit_Input_Config(GPIOA_SFR,GPIO_PIN_MASK_3);
        GPIOInit_Output_Config(GPIOA_SFR,GPIO_PIN_MASK_8|GPIO_PIN_MASK_7);//PB8 PB9 PB10初始化输出高电平
}

//主函数
void main()
{
        /*用户可参考该例程在KF32F350_demo板上实现GPIO输入配置功能。
       * 例程中使用GPIO PD6作为按键的输入IO PB8 PB9 PB10作为输出
       * 按键KEY2按下,LED0 LED1灯熄灭,再次按下LED0 LED1灯点亮。
       */

        //系统时钟120M,外设高频时钟16M
        SystemInit();//系统时钟初始化

        //GPIO初始化
        GPIO_Init();   //把PD6设为输入模式 PB8 PB9 PB10初始化输出高电平

        while(1)
        {
      if(KEY2)
      {
              delay_ms(50);   //延时50ms抖动
              if(KEY2)         //有按键按下
              {
                      GPIO_Toggle_Output_Data_Config (GPIOA_SFR,GPIO_PIN_MASK_8);
                      GPIO_Toggle_Output_Data_Config (GPIOA_SFR,GPIO_PIN_MASK_7);
              }

      }

        }               
}

编号10086 发表于 2021-7-8 12:46

GPIOInit_Input_Config(GPIOA_SFR,GPIO_PIN_MASK_3);
GPIOInit_Output_Config(GPIOA_SFR,GPIO_PIN_MASK_8|GPIO_PIN_MASK_7);//PB8 PB9 PB10初始化输出高电平

这两句话官方的api中都调用了GPIO_Reset(GPIOx);这个函数

经过我的测试,这个函数会把GPIOA管脚的配置都复位掉。
也就是你这样写GPIOInit_Input_Config(GPIOA_SFR,GPIO_PIN_MASK_3);
GPIOInit_Output_Config(GPIOA_SFR,GPIO_PIN_MASK_8|GPIO_PIN_MASK_7);
实际上只有后面的PA7,PA8配置成了输出模式。而PA3没有配置成输入模式。

编号10086 发表于 2021-7-8 12:49

我参考官方的api,自己写了 一个时钟使能的函数。
/*
*********************************************************************************************************
*函数名:GPIO_CLK_CTL
*功能说明:初始化CLK时钟
*形参:GPIOx:代表某组管脚,NewState:代表是否使能
*返回值:无
*********************************************************************************************************
*/
void GPIO_CLK_CTL(GPIO_SFRmap* GPIOx, FunctionalState NewState)
{
    /* 参数校验 */
    CHECK_RESTRICTION(CHECK_GPIO_ALL_PERIPH(GPIOx));

    if (GPIOx == GPIOA_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOACLKEN, NewState);
    }
    else if (GPIOx == GPIOB_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOBCLKEN, NewState);
    }
    else if (GPIOx == GPIOC_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOCCLKEN, NewState);
    }
    else if (GPIOx == GPIOD_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIODCLKEN, NewState);
    }
    else if (GPIOx == GPIOE_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOECLKEN, NewState);
    }
    else if (GPIOx == GPIOF_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOFCLKEN, NewState);
    }
    else if (GPIOx == GPIOG_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOGCLKEN, NewState);
    }
    else if (GPIOx == GPIOH_SFR)
    {
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOHCLKEN, NewState);
    }
    else
    {
      ;
    }
}

你把 GPIO_Reset(GPIOx);替换成我的这个GPIO_CLK_CTL(GPIOx,ENABLE);应该就可以了。

编号10086 发表于 2021-7-8 12:57

官方例程中用gpio_reset作为时钟使能。你看官方的这个代码
/**
* 描述复位GPIO外设,使能外设时钟。
* 输入GPIOx: 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。
* 返回无。
*/
void
GPIO_Reset (GPIO_SFRmap* GPIOx)
{
    /* 参数校验 */
    CHECK_RESTRICTION(CHECK_GPIO_ALL_PERIPH(GPIOx));

    if (GPIOx == GPIOA_SFR)
    {
      RST_CTL0_Peripheral_Reset_Enable(RST_CTL0_GPIOARST, TRUE);
      RST_CTL0_Peripheral_Reset_Enable(RST_CTL0_GPIOARST, FALSE);
      PCLK_CTL0_Peripheral_Clock_Enable(PCLK_CTL0_GPIOACLKEN, TRUE);
    }

它还配置了GPIOxRST这个寄存器,不知道为什么官方要这么做..
而且它其他的串口,定时器的时钟使能也是用类似的做法实现的。

stm32的话不用配置,也能读取IDR寄存器,但是我测试芯旺微的KF32,你要读取PIR寄存器的话,必须把这个管脚配置成输入模式。


你自己debug模式下,看功能寄存器的值,看看pmod是不是配置成你要的。用官方的api配置的话,我看贴的那个代码,应该pmod寄存器应该不是你要的那种配置的。

taozhi11 发表于 2021-7-8 18:13

编号10086 发表于 2021-7-8 12:57
官方例程中用gpio_reset作为时钟使能。你看官方的这个代码




太感谢老哥这么认真的回复我了{:handshake:}{:handshake:},确实是RESET的问题,我把第二个RESET函数注释掉就可以跑通了。这个例程在老芯片上跑是没问题的,应该是老板子IO没有全部复位?导致我一致认为这个例程是没问题的。{:handshake:}感谢感谢

编号10086 发表于 2021-7-9 13:41

更正一点,那个复位寄存器RST_CTLX,是需要配置的。
我提供的api,GPIO_CLK_CTL里面没有加,但是却能够正常使用。
是因为RST_CTL0复位值就是0,而其他的是1。
所以我在今天改写spi例程的时候,突然发现用不来了。


所以总结得出芯旺微单片机要使能某个时钟的话,需要两步
1.把对应的 RST_CTLX 寄存器 置0.
2.把对应的 PCLK_CTLX寄存器 置1.

之前配置GPIO的时候第一步没有做,不过阴差阳错,正好复位状态它就是0,所以使用起来还没什么影响。。
页: [1]
查看完整版本: KF32F341的IO输入功能