赞
踩
主要是自己最近在学习stm32固件库的使用(对于一定要求不使用固件库的,实际上没有特别必要,因为这是统一官方版的库,就和stdio.h之类的差不多,不过最好也学会自己写,过一段时间,我也会写不使用固件库的)
(后面写了一个中断实现的https://blog.csdn.net/qq_44885018/article/details/103070394)
1.按键点灯,键按下灯发亮,按键松开,灯熄灭
2.当两个键同时按下的时候,蜂鸣器鸣叫
作为学习单片机或者arm,首先第一件事情是就电路图进行分析
先让我们看看LED的电路图
先分析一下二极管,二极管负极结的芯片,正极接3.3v的电压,想要二极管发光,就需要芯片输出一个低电平,而且可以从图中看出灯D1-D3对应引脚是PH10-PH12(也就是GPIO口H组的第10-12号引脚)
然后分析一下按键电路
首先可以从图中看出如果按键没有按下,芯片引脚电平是高电平,而且外部电路提供上拉电阻,内部引脚设置可以是悬空,当按键按下,芯片引脚与地相连,为低电平。实现就是通过读取芯片引脚电平的状态来判断是否按键的(这里的stm32单片机与c51不一样,他的引脚需要设置模式才可以输入读取,而c52只需要直接读或者写就可以)
也可以看到K2用的是GPIO口的A组,0号引脚
K3用的是GPIO口的C组,13号引脚
下面分析一下蜂鸣器的电路图
在不是硬件设计过程中,我们基本上可以将二级管的状态看成只有两个状态(忽略放大)一个反向截止,一个饱和导通,导通的条件的话就是发射结和集电结均正偏,截止就是均反偏,以后看见这种电路,直接看发射结就可以判断需要什么电平。实现这个三极管很明显是NPN型,所有需要基极高电平,才可以蜂鸣器鸣叫。
而且可以看出基极接的GPIO口为B组5号引脚。
个人建议直接复制,然后用source_insight软件(一款适合写项目代码的软件,不过好像不可以写makefile,shell脚本)
下面代码基本上按照工程规范去书写的,所有可能用了很多宏定义
(注意工程中能用宏,就尽量少用常量)
1.LED的代码和头文件
#ifndef __LED_H__ #define __LED_H__ #define GEC_LED_ON 0 #define GEC_LED_OFF 1 #define GEC_F429_D3 3 #define GEC_F429_D4 4 #define GEC_F429_D5 5 //GEC_led_init:初始化led所使用的端口,默认初始化为高电平 void GEC_led_init(void); /*GEC_led_ctl:对灯进行控制 @led_n:表示灯的编号 例如:GEC_F429_D3:表示LED灯3 GEC_F429_D4:表示LED灯4 GEC_F429_D5:表示LED灯5 @on_off:表示灯的状态 例如: GEC_LED_OFF:表示灯灭 GEC_LED_ON: 表示灯亮 */ void GEC_led_ctl(int led_n,int on_off); #endif
LEDcode
#include<stdio.h> #include"led.h" #include"stm32f4xx.h" #include"stm32f4xx_gpio.h" //GEC_led_init:初始化led所使用的端口,默认初始化为高电平 void GEC_led_init(void) { //使能GPIOH端口时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//设置模式为输出模式 GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//输出类型为推挽 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//输出速率为50MHz GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;//初始化的引脚为10、11、12 GPIO_Init(GPIOH,&GPIO_InitStruct);//进行初始化 //对端口设置默认电平----高电平 GPIO_WriteBit(GPIOH, GPIO_Pin_10,Bit_SET); GPIO_WriteBit(GPIOH, GPIO_Pin_11,Bit_SET); GPIO_WriteBit(GPIOH, GPIO_Pin_12,Bit_SET); } /*GEC_led_ctl:对灯进行控制 @led_n:表示灯的编号 例如:GEC_F429_D3:表示LED灯3 GEC_F429_D4:表示LED灯4 GEC_F429_D5:表示LED灯5 @on_off:表示灯的状态 例如: GEC_LED_OFF:表示灯灭 GEC_LED_ON: 表示灯亮 */ void GEC_led_ctl(int led_n,int on_off) { switch (led_n) { case GEC_F429_D3: { if(GEC_LED_OFF==on_off) { GPIO_WriteBit(GPIOH, GPIO_Pin_10,Bit_SET); } else if(GEC_LED_ON==on_off) { GPIO_WriteBit(GPIOH, GPIO_Pin_10,Bit_RESET); } }break; case GEC_F429_D4: { if(GEC_LED_OFF==on_off) { GPIO_WriteBit(GPIOH, GPIO_Pin_11,Bit_SET); } else if(GEC_LED_ON==on_off) { GPIO_WriteBit(GPIOH, GPIO_Pin_11,Bit_RESET); } }break; case GEC_F429_D5: { if(GEC_LED_OFF==on_off) { GPIO_WriteBit(GPIOH, GPIO_Pin_12,Bit_SET); } else if(GEC_LED_ON==on_off) { GPIO_WriteBit(GPIOH, GPIO_Pin_12,Bit_RESET); } }break; default:; } }
2.KEY的代码和头文件
#ifndef __KEY_H__ #define __KEY_H__ #define GEC_F429_K2 2 #define GEC_F429_K3 3 #define GEC_F429_K2_K3 4 #define GEC_KEY_UP 1 #define GEC_KEY_DOWN 0 #define KEY_ALL_DOWN 0 #define KEY_K2_DOWN 1 #define KEY_K3_DOWN 2 #define KEY_ALL_UP 3 //GEC_key_init:初始化key所使用的端口 void GEC_key_init(void); /* GEC_key_ctl:实现对按键的状态的监控 @key_n:用于保存键返回状态的主源 例如: GEC_F429_K2_K3:表示主源为两个键 GEC_F429_K2:表示主源是键K2 GEC_F429_K3:表示主源是键k3 返回值:返回主源键的状态 例如: GEC_KEY_DOWN:表示主源键按下 GEC_KEY_UP:表示主源键松开 (注意当主源键为GEC_F429_K2_K3表示两个键按下或者松开,当主源键为一个时表示另一个为松开状态) */ int GEC_key_ctl(int *key_n); void time_sleep(int x); #endif
KEY的头文件
#include"key.h" #include<stdio.h> #include"stm32f4xx.h" #include"stm32f4xx_gpio.h" //GEC_key_init:初始化key所使用的端口 void GEC_key_init(void) { //使能GPIOA、GPIOC端口时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); //设置模式 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;//设置为输入模式 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;//设置相应端口 GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;//输入模式为悬空 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//速率为50MHz GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化端口 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;//切换引脚 GPIO_Init(GPIOC,&GPIO_InitStruct);//切换组号,并且初始化 } /* GEC_key_ctl:实现对按键的状态的监控 @key_n:用于保存键返回状态的主源 例如: GEC_F429_K2_K3:表示主源为两个键 GEC_F429_K2:表示主源是键K2 GEC_F429_K3:表示主源是键k3 返回值:返回主源键的状态 例如: GEC_KEY_DOWN:表示主源键按下 GEC_KEY_UP:表示主源键松开 (注意当主源键为GEC_F429_K2_K3表示两个键按下或者松开,当主源键为一个时表示另一个为松开状态) */ int GEC_key_ctl(int *key_n) { //读取键的电平状态 uint8_t status_a=GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);//获取键k2的电平 uint8_t status_c=GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13);//获取键k3的电平 //将键k2的电平左移1位和键k3的电平组合去满足宏的范围 /* KEY_ALL_DOWN:表示键k2、k3按下 KEY_K2_DOWN:表示键k2按下,k3松开 KEY_K3_DOWN:表示键k3按下,k2松开 KEY_ALL_UP:表示键k2、k3松开 */ status_c+=status_a<<1; switch (status_c) { case KEY_ALL_DOWN: { *key_n=GEC_F429_K2_K3; return GEC_KEY_DOWN; } case KEY_K2_DOWN: { *key_n=GEC_F429_K2; return GEC_KEY_DOWN; } case KEY_K3_DOWN: { *key_n=GEC_F429_K3; return GEC_KEY_DOWN; } case KEY_ALL_UP: { *key_n=GEC_F429_K2_K3; return GEC_KEY_UP; } default:; } return GEC_KEY_UP; }
status_c+=status_a<<1;
语句解释:利用status_c低两个bit为记录按键的所有情况,
例如:status_a表示KEY2的情况,实际上是只有一个bit有用,我们通过左移移位将其加到status_c的第二个bit(1-8bit算),就用两个bit实现所有情况,当然你也可以改,将status_c或者status_a省掉用一个status_c变量就可以实现。
3.蜂鸣器的代码和头文件
#ifndef __BEEP_H__ #define __BEEP_H__ #define GEC_BEEP_ON 1 #define GEC_BEEP_OFF 0 //初始化蜂鸣器端口 void GEC_beep_init(void); /* GEC_beep_ctl:实现对蜂鸣器的控制 @on_off:表示蜂鸣器的鸣叫或者不鸣 例如: GEC_BEEP_ON:表示蜂鸣器鸣叫 GEC_BEEP_OFF:表示蜂鸣器不鸣 */ void GEC_beep_ctl(int on_off); #endif
蜂鸣器的code
#include<stdio.h> #include"stm32f4xx.h" #include"stm32f4xx_gpio.h" #include"beep.h" //初始化蜂鸣器端口 void GEC_beep_init(void) { //使能蜂鸣器端口时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//设置蜂鸣器端口为输出模式 GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//将输出模式设置为推挽 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//设置蜂鸣器的端口为pin_5 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//设置输出速率为50MHz GPIO_Init(GPIOB,&GPIO_InitStruct);//初始化蜂鸣器端口模式 GPIO_WriteBit(GPIOB, GPIO_Pin_5,Bit_RESET);//设置默认为蜂鸣器不鸣 } /* GEC_beep_ctl:实现对蜂鸣器的控制 @on_off:表示蜂鸣器的鸣叫或者不鸣 例如: GEC_BEEP_ON:表示蜂鸣器鸣叫 GEC_BEEP_OFF:表示蜂鸣器不鸣 */ void GEC_beep_ctl(int on_off) { if(GEC_BEEP_ON==on_off) { GPIO_WriteBit(GPIOB, GPIO_Pin_5, Bit_SET); } else { GPIO_WriteBit(GPIOB, GPIO_Pin_5,Bit_RESET); } }
4.主函数的代码
#include<stdio.h> #include"led.h" #include"key.h" #include"stm32f4xx.h" #include"stm32f4xx_gpio.h" #include"beep.h" int main() { GEC_led_init();//初始化LED灯 GEC_key_init();//初始化按键灯 GEC_beep_init();//初始化蜂鸣器 int i,key_n; while(1) { i=GEC_key_ctl(&key_n);//判断键的状态 if(GEC_KEY_DOWN==i) { switch (key_n) { case GEC_F429_K2: { GEC_led_ctl(GEC_F429_D3,GEC_LED_ON); GEC_led_ctl(GEC_F429_D4,GEC_LED_OFF); GEC_beep_ctl(GEC_BEEP_OFF); }break; case GEC_F429_K3: { GEC_led_ctl(GEC_F429_D4,GEC_LED_ON); GEC_led_ctl(GEC_F429_D3,GEC_LED_OFF); GEC_beep_ctl(GEC_BEEP_OFF); }break; case GEC_F429_K2_K3: { GEC_led_ctl(GEC_F429_D4,GEC_LED_ON); GEC_led_ctl(GEC_F429_D3,GEC_LED_ON); GEC_beep_ctl(GEC_BEEP_ON); }break; default:; } } else { GEC_led_ctl(GEC_F429_D4,GEC_LED_OFF); GEC_led_ctl(GEC_F429_D3,GEC_LED_OFF); GEC_beep_ctl(GEC_BEEP_OFF); } } }
也许你会感觉有点疑惑为什么要写的这样麻烦,主要是为了每个代码函数的高内聚低耦合,例如按键,不管怎么样,这个函数只返回按键的情况,至于做什么操作,这是交给主函数去操作。
如果有什么疑问可以留言,看到了,我会尽量解答,如果有什么需要讨论的,也可以留言,欢迎一起讨论
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。