普中-精靈1開發板,主芯片為STM32F103C8T6,4個獨立按鍵K1~K4依次接PA15~PA12,按下為低電平,8個LED燈D1~D8,依次接PA0~PA7。查詢手冊得知:PA15主功能為JTDI,PA14為JTCK/SWCLK,PA13為JTMS/SWDIO。采用串口進行程序下載(普中ISP)。用4個按鍵,控制4個LED,主程序如下:
/*按鍵程序,普中-精靈1開發板*/
#include "stm32f10x.h"
#include "delay.h"
#include "key.h"
int main(void)
{ KEY_Init();// 初始化 LED 亮滅標志為 0 0:熄滅 1:亮起unsigned int led_flag1 = 0;unsigned int led_flag2 = 0;unsigned int led_flag3 = 0;unsigned int led_flag4 = 0;// 初始化 按鍵按下標志為 0 0:彈起 1:按下unsigned int key_is_press1 = 0;unsigned int key_is_press2 = 0;unsigned int key_is_press3 = 0;unsigned int key_is_press4 = 0;while (1){ if( key_is_press1 == 0) //無按鍵{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) ==0){ // 如果按鍵按下Delay(20); // 按鍵消抖if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15)==0 ){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press1 = 1;// 設置 LED 亮滅標志翻轉一次led_flag1 = ~led_flag1;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press1 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15)==0 ){ // 按鍵仍然處于按下狀態,不進行任何操作}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press1 = 0;}} if( key_is_press2 == 0){if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14) ==0){ // 如果按鍵按下Delay(20); // 按鍵消抖if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14)==0 ){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press2 = 1;// 設置 LED 亮滅標志翻轉一次led_flag2 = ~led_flag2;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press2 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14)==0 ){ // 按鍵仍然處于按下狀態,不進行任何操作}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press2 = 0;} } if( key_is_press3 == 0){if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13) ==0){ // 如果按鍵按下Delay(20); // 按鍵消抖if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13)==0 ){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press3 = 1;// 設置 LED 亮滅標志翻轉一次led_flag3 = ~led_flag3;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press3 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13)==0 ){ // 按鍵仍然處于按下狀態,不進行任何操作}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press3 = 0;} }if( key_is_press4 == 0){if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) ==0){ // 如果按鍵按下Delay(20); // 按鍵消抖if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12)==0 ){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press4 = 1;// 設置 LED 亮滅標志翻轉一次led_flag4 = ~led_flag4;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press4 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12)==0 ){ // 按鍵仍然處于按下狀態,不進行任何操作}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press4 = 0;} }// 根據按鍵按下的標志狀態操作功能// 如果按鍵被按下了,執行功能if( key_is_press1 == 1){ // 根據 LED 的亮滅標志控制 LED 亮起和熄滅if(led_flag1){// 點亮 LEDGPIO_ResetBits(GPIOA, GPIO_Pin_0 ); }else{// 熄滅 LEDGPIO_SetBits(GPIOA, GPIO_Pin_0 ); } }if( key_is_press2 == 1){ // 根據 LED 的亮滅標志控制 LED 亮起和熄滅if(led_flag2){// 點亮 LEDGPIO_ResetBits(GPIOA, GPIO_Pin_1 ); }else{// 熄滅 LEDGPIO_SetBits(GPIOA, GPIO_Pin_1 ); } } if( key_is_press3 == 1){ // 根據 LED 的亮滅標志控制 LED 亮起和熄滅if(led_flag3){// 點亮 LEDGPIO_ResetBits(GPIOA, GPIO_Pin_2 ); }else{// 熄滅 LEDGPIO_SetBits(GPIOA, GPIO_Pin_2 ); } } if( key_is_press4 == 1){ // 根據 LED 的亮滅標志控制 LED 亮起和熄滅if(led_flag4){// 點亮 LEDGPIO_ResetBits(GPIOA, GPIO_Pin_3 ); }else{// 熄滅 LEDGPIO_SetBits(GPIOA, GPIO_Pin_3 ); } } }}
按鍵初始化程序key.c如下:
/*key.c按鍵初始化
*/
#include "key.h"
#include "delay.h"
void KEY_Init(void)
{ GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); // 開啟時鐘//GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //配置GPIO頻率為50MHzGPIO_InitStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15 ; //GPIO_SetBits(GPIOA, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
}
執行以上,會發現K1、K3、K4功能正常,而K2(PA14)無效,此時D2(PA1)常亮,按照手冊,若此時禁掉SWD,即去掉GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);前面的注釋,此時并無效果,反而有可能出現K1(PA15)、K3(PA13)也失效的情形。此時,需要執行非常關鍵的一個操作,即對PA12、PA13、PA14、PA15置1,且要在設置MODE之前進行,去掉GPIO_SetBits(GPIOA, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);前面的注釋,會發現K2功能也正常了。實際上,如果用CMSIS-DAP(實際為WCH CMSIS-DAP,SW模式,BOOT0=1)下載程序,不需要增加GPIO_SetBits(GPIOA, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);這條指令,K2功能也是正常的。但神奇的是,利用JTAG(實際為J-Link ARM-OB STM32,SW模式,BOOT0=1),則和ISP方式效果一致。
在普中的這款開發板做進一步開發,例如把按鍵和數碼管結合起來,按K1數碼管顯示加1,按K2減1,按K3數碼管左移1位,按K4數碼管右移1位。,主程序如下:
/*按鍵驅動數碼管,普中-精靈1開發板*/
#include "stm32f10x.h"
#include "delay.h"
#include "key.h"
uint16_t table[] = {0xFF3F,0xFF06,0xFF5b,0xFF4f,0xFF66,0xFF6d,0xFF7d,0xFF07,0xFF7f,0xFF6f}; //段碼
uint16_t wei[]={0xff00,0xff20,0xff10,0xff30,0xff08,0xff28,0xff18,0xff38}; //位碼
static uint8_t k=0; //聲明變量 k,j
static uint8_t j=0;
int main(void)
{ KEY_Init();unsigned int key_is_press1 = 0;unsigned int key_is_press2 = 0;unsigned int key_is_press3 = 0;unsigned int key_is_press4 = 0;while (1){ if( !key_is_press1) //無按鍵{if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15)){ // 如果按鍵按下Delay(20); // 按鍵消抖if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) ){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press1 = 1;j=j+1;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press1 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) ) //按鍵彈起,設置按鍵按下標志為 0key_is_press1 = 0;} if( !key_is_press2){if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14)){ // 如果按鍵按下Delay(20); // 按鍵消抖if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14)){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press2 = 1;j=j-1;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press2 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14) ) // 按鍵彈起,設置按鍵按下標志為 0key_is_press2 = 0;} if( !key_is_press3 ){if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13)){ // 如果按鍵按下Delay(20); // 按鍵消抖if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13)){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press3 = 1;k++;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press3 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13) ) // 按鍵彈起,設置按鍵按下標志為 0key_is_press3 = 0;}if(!key_is_press4 ){if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12)){ // 如果按鍵按下Delay(20); // 按鍵消抖if( !GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) ){ // 如果按鍵被按下,設置按鍵按下標志為 1key_is_press4 = 1;k--;}}else{ // 如果按鍵彈起,設置按鍵按下標志為 0key_is_press4 = 0;}}else // 如果按鍵已經按下了,判斷按鍵是否彈起{if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) ) // 按鍵彈起,設置按鍵按下標志為 0key_is_press4 = 0;}GPIO_Write(GPIOA,table[j%8] );GPIO_Write(GPIOB, wei[k%8] );}
}
段碼數組要32位數賦值,因為GPIO_Write(GPIOA,...)默認情況下是對整個PA進行操作,如果只給出16位數,那么高16位數將被賦值為0,顯然這樣就有可能導致讀數據失敗。參考按鍵初始化程序:
/*key.c
按鍵初始化
*/
#include "key.h"
#include "delay.h"
void KEY_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); // 開啟時鐘GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //配置GPIO頻率為50MHzGPIO_InitStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15 ; GPIO_SetBits(GPIOA, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; GPIO_SetBits(GPIOA, GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_Init(GPIOB, &GPIO_InitStructure);
}
?
?