基于STM32F407的LED灯和蜂鸣器的实现(固件库版本)

固件库  


    (1)固件库 
        STM32固件库就是函数的集合,固件库向下负责与寄存器打交道,向上提供用户函数调用的API
        这种方法当然可以,但是这种方法的劣势就是你不需要掌握寄存器的使用,也可以正确的使用STM32。优势就是开发很方便。
        固件将这些寄存器底层操作全部封装起来了,提供了一套API供用户使用,大部分情况下,你不需要去了解寄存器,只需要知道函数的使用
    (2)Source insight 4.0管理,编辑工程 
    
    (3)STM32F4xx固件库GPIO的操作 
        3.1 使能GPIO分组的时钟(GPIO都属于AHB1) --rcc.h
            void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);
                @RCC_AHB1Periph:指定AHB1上外设的名称  可以位或
                    RCC_AHB1Periph_GPIOA
                    RCC_AHB1Periph_GPIOB 
                    ......
                @NewState:指定该外设的时钟状态
                     ENABLE  使能 
                     DISABLE 禁止  
            比如:想使能GPIOF组和GPIOE组的时钟
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOE,ENABLE);
        
        3.2 初始化GPIO引脚(完成基本的4个寄存器的配置) --gpio.h
            a.定义结构体变量
                GPIO_InitTypeDef GPIO_InitStruct;
            b.给结构体成员赋值
                typedef struct
                {
                  uint32_t GPIO_Pin;//指定要配置的GPIO引脚
                        GPIO_Pin_0
                        GPIO_Pin_1
                        .....
                        GPIO_Pin_All

                  GPIOMode_TypeDef GPIO_Mode;//指定要配置的GPIO引脚的功能模式 
                         GPIO_Mode_IN   输入模式
                         GPIO_Mode_OUT  输出模式
                         GPIO_Mode_AF   复用模式
                         GPIO_Mode_AN   模拟模式                         

                  GPIOSpeed_TypeDef GPIO_Speed;//指定引脚速率 
                        GPIO_Speed_2MHz
                        GPIO_Speed_25MHz
                        GPIO_Speed_50MHz
                        GPIO_Speed_100MHz

                  GPIOOType_TypeDef GPIO_OType;//输出类型 
                        GPIO_OType_PP  推挽模式
                        GPIO_OType_OD  开漏模式

                  GPIOPuPd_TypeDef GPIO_PuPd;//上下拉配置 
                      GPIO_PuPd_NOPULL 无上下拉
                      GPIO_PuPd_UP     上拉
                      GPIO_PuPd_DOWN   下拉
                }GPIO_InitTypeDef;
            GPIO_InitStruct.GPIO_Pin =GPIO_Pin_0;
            .....
            c.把刚才写好的结构体写进寄存器
                GPIO_Init(GPIOF,&GPIO_InitStruct);
        3.3 输入/输出 
            1.输入:从配置好GPIO引脚,获取外部电平 
                a.获取输入寄存器的指定的GPIO引脚的值
                    uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
                    @GPIOx:指定的GPIO分组 
                        GPIOA 
                        GPIOB 
                        .....
                    @GPIO_Pin:指定的引脚编号
                        GPIO_Pin_0
                        GPIO_Pin_1
                        .....
                返回值: 
                    Bit_SET   高电平 
                    Bit_RESET  低电平
                    
                b.获取指定分组的输入寄存器整组的值(16位)
                    uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
                    @GPIOx:指定的GPIO分组 
                        GPIOA 
                        GPIOB 
                        .....
                返回值:是一个无符号的16位的整数,这个整数就是这个分组的16个引脚的电平值
                
                c.获取输出数据寄存器的指定的GPIO引脚的值
                    uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
                d.获取指定分组的输出寄存器整组的值(16位)
                    uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
            2.输出:CPU通过引脚向外部电路输出一个电平值
                a.向指定的引脚输出指定的电平值
                    void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
                    @GPIOx:指定的GPIO分组 
                        GPIOA 
                        GPIOB 
                        .....
                    @GPIO_Pin:指定的引脚编号
                        GPIO_Pin_0
                        GPIO_Pin_1
                        .....
                    @BitVal:想输出的电平 
                        Bit_RESET  低电平 
                        Bit_SET    高电平 
                b.往指定的GPIO分组整组输出(16个引脚一块输出)
                    void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
                    @GPIOx:指定的GPIO分组 
                        GPIOA 
                        GPIOB 
                        .....
                    @PortVal:uint16_t类型(16位的整数) 
                        bit0 ---> 引脚0 
                        ......
                比如: 
                    GPIO_Write(GPIOF,0xF0F0);
                    将PF15~PF12和PF7~PF4输出高电平,其它的输出低电平
                c.向指定的引脚输出一个高电平
                    void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
                d.向指定的引脚输出一个低电平
                    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
                e. 将指定的引脚的输出啊状态进行翻转(1-->0,0-->1)
                    void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
        4. 当GPIO引脚被配置为复用模式的时候才需要使用
            void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF);
                @GPIOx:指定的GPIO分组 
                        GPIOA 
                        GPIOB 
                        .....
                @GPIO_PinSource:指定的GPIO引脚(不可以位或)
                    GPIO_PinSource0
                    GPIO_PinSource1
                    .....
                @GPIO_AF:指定复用成什么功能 
                    GPIO_AF_TIM1
                    ......


    练习1

        使用固件库的方式实现流水灯 
        led_lib.c   led_lib.h       #include "stm32f4xx.h"

由上图可看出,LED灯低电平状态下才能在电器元件两端形成电势差,产生电压,有电流产生并流过LED灯,使LED灯处于工作状态;高电平状态下LED灯不工作。

led_lib.c

#include "stm32f4xx.h"
#include "led_lib.h"

void led_lib_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
	GPIO_Init(GPIOF,&GPIO_InitStruct);

	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
	GPIO_Init(GPIOE,&GPIO_InitStruct);

	GPIO_SetBits(GPIOF, GPIO_Pin_9 | GPIO_Pin_10);
	GPIO_SetBits(GPIOE, GPIO_Pin_13 | GPIO_Pin_14);
}


void led_Ctrl(int led_num,int status )
{
	if(led_num == D1)
	{
		status ? D1_OFF : D1_ON;
	}
	if(led_num == D2)
	{
		status ? D2_OFF : D2_ON;
	}
	if(led_num == D3)
	{
		status ? D3_OFF : D3_ON;
	}
	if(led_num == D4)
	{
		status ? D4_OFF : D4_ON;
	}
}

void delay_ms(uint32_t ms)
{
    uint32_t i;
    for(i = 0; i < ms * 7000; i++);
}


led_lib.h

#ifndef __LED_LIB_H__
#define __LED_LIB_H__

#include "stm32f4xx.h"

/*灯的编号*/
enum LED_NUM
{
	D1,
	D2,
	D3,
	D4
};
/*灯的状态*/
enum LED_STATUS
{
	ON,
	OFF
};
//灯的控制
#define D1_ON GPIO_ResetBits(GPIOF, GPIO_Pin_9) 
#define D1_OFF GPIO_SetBits(GPIOF, GPIO_Pin_9)
#define D2_ON GPIO_ResetBits(GPIOF, GPIO_Pin_10)  
#define D2_OFF GPIO_SetBits(GPIOF, GPIO_Pin_10) 
#define D3_ON GPIO_ResetBits(GPIOE, GPIO_Pin_13)  
#define D3_OFF GPIO_SetBits(GPIOE, GPIO_Pin_13) 
#define D4_ON GPIO_ResetBits(GPIOE, GPIO_Pin_14)  
#define D4_OFF GPIO_SetBits(GPIOE, GPIO_Pin_14)



void led_lib_init(void);
void led_Ctrl(int led_num,int status);
void delay_ms(uint32_t ms);
#endif

main.c

#include "main.h"
#include "stm32f4xx.h"
#include "led_lib.h"
#include "beep_lib.h"
#include "key_lib.h"
#include "exti.h"

int main(void)
{ 
	led_lib_init();
	while(1)
	{
		led_Ctrl(D1, ON);
		delay_ms(500);
		led_Ctrl(D1, OFF);
		
		led_Ctrl(D2, ON);
		delay_ms(500);
		led_Ctrl(D2, OFF);

		led_Ctrl(D3, ON);
		delay_ms(500);
		led_Ctrl(D3, OFF);

		led_Ctrl(D4, ON);
		delay_ms(500);
		led_Ctrl(D4, OFF);
	}
	//定义四个标志位来表示四个按键是被按下还是松开
	//默认按键被松开标志位为1
//	int S1 = 1;
//	int S2 = 1;
//	int S3 = 1;
//	int S4 = 1;
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//	led_lib_init();
//	beep_lib_init();
//	EXTIX_Init();
//	while(1);
//	beep_lib_init();
//	key_lib_init();
//	while(1)
//	{	//S1按键
//		if(KEY0 == 0)//判断按键KEY0是否被按下
//		{
//			delay_ms(50);	//延时消抖
//			if(KEY0 == 0)	//判断按键KEY0是否被按下
//			{
//				if(S1)
//				{
//					S1 = 0;//标志位S1置0
//					GPIO_ToggleBits(GPIOF,GPIO_Pin_9);//翻转D1灯的状态					
//					GPIO_ToggleBits(GPIOF,GPIO_Pin_10);//翻转D2灯的状态					
//				}
//			}
//		}
//		if(KEY0 == 1)//判断按键KEY0是否被松开
//		{
//			S1 = 1;//标志位S1置1
//		}
//		//S2按键
//		if(KEY1 == 0)//判断按键KEY1是否被按下
//		{
//			delay_ms(50);//延时消抖
//			if(KEY1 == 0)//判断按键KEY1是否被按下
//			{
//				if(S2)
//				{
//					S2 = 0;//标志位S2置0
//					GPIO_ToggleBits(GPIOE,GPIO_Pin_13);//翻转D3灯的状态						
//					GPIO_ToggleBits(GPIOE,GPIO_Pin_14);//翻转D4灯的状态
//				}
//			}
//		}	
//		if(KEY1 == 1)//判断按键KEY1是否被松开
//		{
//			S2 = 1;//标志位S2置1		
//		}		
//		//S3按键
//		if(KEY2 == 0)//判断按键KEY2是否被按下
//		{
//			delay_ms(50);//延时消抖
//			if(KEY2 == 0)//判断按键KEY2是否被按下
//			{
//				if(S3)
//				{
//					S3 = 0;//标志位S3置0
//					GPIO_ToggleBits(GPIOF,GPIO_Pin_8);//翻转蜂鸣器的状态							
//				}
//			}
//		}	
//		if(KEY2 == 1)//判断按键KEY2是否被松开
//		{
//			S3 = 1;//标志位S3置1		
//		}
//		//S4按键
//		if(KEY3 == 0)//判断按键KEY3是否被按下
//		{
//			delay_ms(50);//延时消抖
//			if(KEY3 == 0)//判断按键KEY3是否被按下
//			{
//				if(S4)
//				{
//					S4 = 0;//标志位S4置0
//					GPIO_ToggleBits(GPIOF,GPIO_Pin_9);//翻转D1灯的状态					
//					GPIO_ToggleBits(GPIOF,GPIO_Pin_10);//翻转D2灯的状态		
//					GPIO_ToggleBits(GPIOE,GPIO_Pin_13);//翻转D3灯的状态						
//					GPIO_ToggleBits(GPIOE,GPIO_Pin_14);//翻转D4灯的状态							
//				}
//			}
//		}	
//		if(KEY3 == 1)//判断按键KEY3是否被松开
//		{
//			S4 = 1;//标志位S4置1		
//		}
//	}
}


    
----------------------------------------------------------------------------
    按键的使用:
    1.看原理图: 
            S1 -- PA0 
            S2 -- PE2 
            S3 -- PE3
            S4 -- PE4 
        这四个引脚配置为上拉输入 
        经过分析: 
            以S1按键为例,按下S1按键,CPU读取PA0是低电平,松开S1按键,CPU读取PA0是高电平
            
    代码为例: 
        int main()
        {
            //初始化函数.... 
            while(1)
            {
                if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0)
                {
                    //点灯
                }
            }
        }
    以上的代码在实际上行不通。还要进行"按键消抖"
    抖动的原因: 
        单片机上的按键大部分都是机械弹性按键,这种按键在按下或者弹起的时候发生抖动,对实验造成影响
    市面上消抖的方法有两种: 
        1.硬件消抖 
            在按键的电路上并联一个电容,利用电容的充放电特性对毛刺进行平滑出来,有效果,但是现在基本不会用这种方法
            增加了成本 
        2.软件消抖 
        利用一个小延时跳过抖动的时间,大部分的按键延时个10ms左右可以跳过抖动 
        延时可以改成for(i=0;i<0x2000;i++)   mydelay(100)近似10ms 
    把上述的代码进行改动
        int main()
        {
            //初始化函数.... 
            while(1)
            {
                if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0)//S1
                {
                    mydelay(100);
                    if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0)//确定是人为按下
                    {
                        //点灯
                    }        
                }
                if()
                {
                    ......
                }
            }
        }


    练习2


        利用按键去控制灯,蜂鸣器....
        第一次按下S1按键的时候,D1和D2亮,第二次按下S1按键的时候,D1和D2灭
        S2-->D3和D4
        S3-->BEEP     

由原理图可知,蜂鸣器在低电平下不工作,高电平下工作

beep_lib.c

#include "stm32f4xx.h"
#include "beep_lib.h"

void beep_lib_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
	GPIO_Init(GPIOF,&GPIO_InitStruct);

	GPIO_ResetBits(GPIOF, GPIO_Pin_8);
}

void beep_Ctrl(int status)
{
	status ? BEEP_OFF : BEEP_ON;
}


beep_lib.h

#ifndef __BEEP_LIB_H__
#define __BEEP_LIB_H__

#include "stm32f4xx.h"

/*蜂鸣器的状态*/
enum BEEP_STATUS
{
	beep_ON,
	beep_OFF
};
//蜂鸣器的控制
#define BEEP_OFF GPIO_ResetBits(GPIOF, GPIO_Pin_8)  
#define BEEP_ON GPIO_SetBits(GPIOF, GPIO_Pin_8)

void beep_lib_init(void);
void beep_Ctrl(int status);
#endif


main.c

#include "main.h"
#include "stm32f4xx.h"
#include "led_lib.h"
#include "beep_lib.h"
#include "key_lib.h"
#include "exti.h"

int main(void)
{ 
//	led_lib_init();
//	while(1)
//	{
//		led_Ctrl(D1, ON);
//		delay_ms(500);
//		led_Ctrl(D1, OFF);
//		
//		led_Ctrl(D2, ON);
//		delay_ms(500);
//		led_Ctrl(D2, OFF);

//		led_Ctrl(D3, ON);
//		delay_ms(500);
//		led_Ctrl(D3, OFF);

//		led_Ctrl(D4, ON);
//		delay_ms(500);
//		led_Ctrl(D4, OFF);
//	}
	//定义四个标志位来表示四个按键是被按下还是松开
	//默认按键被松开标志位为1
	int S1 = 1;
	int S2 = 1;
	int S3 = 1;
	int S4 = 1;
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	led_lib_init();
//	beep_lib_init();
//	EXTIX_Init();
//	while(1);
	beep_lib_init();
	key_lib_init();
	while(1)
	{	//S1按键
		if(KEY0 == 0)//判断按键KEY0是否被按下
		{
			delay_ms(50);	//延时消抖
			if(KEY0 == 0)	//判断按键KEY0是否被按下
			{
				if(S1)
				{
					S1 = 0;//标志位S1置0
					GPIO_ToggleBits(GPIOF,GPIO_Pin_9);//翻转D1灯的状态					
					GPIO_ToggleBits(GPIOF,GPIO_Pin_10);//翻转D2灯的状态					
				}
			}
		}
		if(KEY0 == 1)//判断按键KEY0是否被松开
		{
			S1 = 1;//标志位S1置1
		}
		//S2按键
		if(KEY1 == 0)//判断按键KEY1是否被按下
		{
			delay_ms(50);//延时消抖
			if(KEY1 == 0)//判断按键KEY1是否被按下
			{
				if(S2)
				{
					S2 = 0;//标志位S2置0
					GPIO_ToggleBits(GPIOE,GPIO_Pin_13);//翻转D3灯的状态						
					GPIO_ToggleBits(GPIOE,GPIO_Pin_14);//翻转D4灯的状态
				}
			}
		}	
		if(KEY1 == 1)//判断按键KEY1是否被松开
		{
			S2 = 1;//标志位S2置1		
		}		
		//S3按键
		if(KEY2 == 0)//判断按键KEY2是否被按下
		{
			delay_ms(50);//延时消抖
			if(KEY2 == 0)//判断按键KEY2是否被按下
			{
				if(S3)
				{
					S3 = 0;//标志位S3置0
					GPIO_ToggleBits(GPIOF,GPIO_Pin_8);//翻转蜂鸣器的状态							
				}
			}
		}	
		if(KEY2 == 1)//判断按键KEY2是否被松开
		{
			S3 = 1;//标志位S3置1		
		}
		//S4按键
		if(KEY3 == 0)//判断按键KEY3是否被按下
		{
			delay_ms(50);//延时消抖
			if(KEY3 == 0)//判断按键KEY3是否被按下
			{
				if(S4)
				{
					S4 = 0;//标志位S4置0
					GPIO_ToggleBits(GPIOF,GPIO_Pin_9);//翻转D1灯的状态					
					GPIO_ToggleBits(GPIOF,GPIO_Pin_10);//翻转D2灯的状态		
					GPIO_ToggleBits(GPIOE,GPIO_Pin_13);//翻转D3灯的状态						
					GPIO_ToggleBits(GPIOE,GPIO_Pin_14);//翻转D4灯的状态							
				}
			}
		}	
		if(KEY3 == 1)//判断按键KEY3是否被松开
		{
			S4 = 1;//标志位S4置1		
		}
	}
}

由原理图的按键电路可知,S1,S2,S3,S4未被按下时,端口的电平值连接的是VDD3.3V,即高电平1,按下以后电路连通到了GND,测到的是低电平。总而言之,KEY0 == 0时,S1被按下。同时四个按键默认高电平,外部分别接入了一个上拉电阻,因此上拉/下拉寄存器应配置为上拉。

key_lib.c

#include "stm32f4xx.h"
#include "key_lib.h"

void key_lib_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOE,&GPIO_InitStruct);//KEY1,KEY2,KEY3

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);//KEY0
}


key_lib.h

#ifndef __KEY_LIB_H__
#define __KEY_LIB_H__

#include "stm32f4xx.h"

//按键S1,S2,S3,S4的状态
#define KEY0 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)  
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) 
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) 
#define KEY3 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) 


void key_lib_init(void);

#endif



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值