为了验证GD32F130C8与ST的兼容性,版主本次做了按键扫描的实验。
本次实验使用GD32130C-START的开发板,其按键连接PA0引脚,并通过上拉电阻与电容来做硬件消抖与EMI去除。
在软件上面,仍然使用STM32F0xx的固件库。版主以STM32F030为基准型号生成固件库,并放入IAR软件里调用。
软件架构实现方式:
首先,使用库函数的方式初始化了芯片的晶振系统,使用其外置的8MHz晶振。
然后初始化了板载外设,两个LED灯与1个按键;
在板载bsp支持包内添加按键扫描功能函数,其函数具体实现请看版主的源代码;
在应用层上面设计了按键扫描的检测函数,通过状态机的方式来实现按键的各个状态之间的流轮。状态图版主这里因为时间关系没有画,也请大家直接看源代码,毕竟代码量较少,还是相当容易就能看出来的。
实验现象:当有按键按下时,LED0灯将会亮起,按键释放后,LED1灯将会熄灭;
实验结果:实验结果与设计方案完全相符,STM32F0xx的固件库目前完美支持GD32F130C8芯片。
版主源代码如下:
void SysClockInit(void) { ErrorStatus HSEStartUpStatus; /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------------------------*/ /* RCC system reset(for debug purpose) */ RCC_DeInit(); /* Enable HSE */ RCC_HSEConfig(RCC_HSE_ON); /* Wait till HSE is ready */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if (HSEStartUpStatus == SUCCESS) { /* Enable Prefetch Buffer */ FLASH_PrefetchBufferCmd(ENABLE); /* Flash 2 wait state */ FLASH_SetLatency(FLASH_Latency_0); /* HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* PCLK2 = HCLK */ RCC_PCLKConfig(RCC_HCLK_Div1); /* PLLCLK = 8MHz * 6 = 48 MHz */ // RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* 此处需要根据外部晶振的改变而改变 */ RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_12); /* Max Freq = 48MHz */ /* Enable PLL */ RCC_PLLCmd(ENABLE); /* Wait till PLL is ready */ while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /* Select PLL as system clock source */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* Wait till PLL is used as system clock source */ while(RCC_GetSYSCLKSource() != 0x08) { } } else { /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */ /* Go to infinite loop */ while (1) { } } } /** * @brief 初始化按键 PA0 * @param * @retval * @date 2015-03-26 * @note 外部连接上拉电阻,空闲状态为高电压,按下时为低电压 */ void KeyInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); /* Configure PA0 in input pushpull mode */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; // GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); } /** * @brief scan key * @param the key number * @retval true = press down; false = idle; * @date 2015-03-28 * @note PA0 =>外部连接上拉电阻,空闲状态为高电压,按下时为低电压 */ bool KeyScan(uint8_t num) { bool keyStatus = false; uint16_t t; t = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0); switch(num) { case 0: { if(GPIO_Pin_0 == (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))) { keyStatus = false; } else { keyStatus = true; } break; } default: keyStatus = false; } return keyStatus; } /** * @brief led initial * @param * @retval * @date 2015-03-26 * @note LED0 =>PF6 LED1 =>PF7 */ void LedInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOF, &GPIO_InitStructure); } /** * @brief LED on * @param * @retval * @date 2015-03-27 * @note */ void LedOn(uint8_t num) { switch(num) { case 0: { GPIO_SetBits(GPIOF, GPIO_Pin_6); break; } case 1: { GPIO_SetBits(GPIOF, GPIO_Pin_7); break; } } } /** * @brief LED off * @param * @retval * @date 2015-03-27 * @note */ void LedOff(uint8_t num) { switch(num) { case 0: { GPIO_ResetBits(GPIOF, GPIO_Pin_6); break; } case 1: { GPIO_ResetBits(GPIOF, GPIO_Pin_7); break; } } } /** * @brief led toggle * @param * @retval * @date 2015-03-28 * @note */ void LedToggle(uint8_t num) { switch(num) { case 0: { GPIOF->ODR ^= GPIO_Pin_6; break; } case 1: { GPIOF->ODR ^= GPIO_Pin_7; break; } } } /** * @brief bsp initial * @param * @retval * @date 2015-03-26 * @note 1 *key; 1 *LED */ void bspInit(void) { SysClockInit(); LedInit(); KeyInit(); }
/** * @brief key check * @param * @retval * @date 2015-03-28 * @note */ void KeyCheck(void) { bool KeyStatus; KeyStatus = KeyScan(0); switch(gKeyStatus) { case 0: /*!< 空闲状态 */ { if(KeyStatus == true) { gKeyStatus = 1; } else { gKeyStatus = 0; LedOff(0); } break; } case 1: /*!< 消抖状态 */ { if(KeyStatus == true) { gKeyCnt = 5; gKeyStatus = 2; } else { gKeyCnt = 0; gKeyStatus = 0; } break; } case 2: /*!< 按下状态 */ { if(KeyStatus == true) { if(gKeyCnt == 0) { LedOn(0); } else { gKeyStatus = 2; } } else { gKeyCnt = 0; gKeyStatus = 0; } break; } case 3: /*!< 确认按下 */ { LedOn(0); break; } default: gKeyStatus = 0; } } void main(void) { bool LedStatus[2]; gKeyStatus = 0; bspInit(); gCntLed[0] = 500; gCntLed[1] = 500; LedStatus[0] = false; LedStatus[1] = false; if (SysTick_Config(48000)) //参数为系统时钟的向上溢出值,此配置为48000,即1ms中断一次 { /* Capture error */ while (1); } while(1) { if(gCntLed[0] == 0) { LedToggle(1); gCntLed[0] = 500; } KeyCheck(); } } /** * @brief SysTick_Handler的中断入口函数 * @param * @retval * @date 2014-11-23 * @note */ void SysTick_Handler(void) { if(gCntLed[0] > 0) { gCntLed[0]--; } else { gCntLed[0] = 0; } if(gCntLed[1] > 0) { gCntLed[1]--; } else { gCntLed[1] = 0; } if(gKeyCnt > 0) { gKeyCnt--; } else { gKeyCnt = 0; } }
IAR工程源代码:exp02_key.zip