【2k行代码优秀课设】基于stm32f4xx粤嵌GEC-M4的按键密码锁、呼吸灯、蜂鸣器音乐、超声波测距及倒车雷达、温湿度检测、光敏电阻自动灯光调节、USART串口控制系统

【2k行代码】基于stm32f4xx粤嵌GEC-M4的按键密码锁、呼吸灯、蜂鸣器音乐、超声波测距及倒车雷达、温湿度检测、光敏电阻自动灯光调节、USART串口控制系统

STM32

前文:

blog.csdn.net/weixin_53403301/article/details/121684671
blog.csdn.net/weixin_53403301/article/details/121671026

在此基础上增加了光敏电阻自动灯光调节 并增加了音频精度和国际标准音名

音乐播放部分参考:

blog.csdn.net/weixin_53403301/article/details/121735779

【极限精度】基于stm32f4xx的蜂鸣器音乐播放及国际绝对音名标准频率定义(32位无符号整型精度、十二等律体系、A4=440.01000Hz)

资源:

download.csdn.net/download/weixin_53403301/85147738

第一个循环是按键密码锁 每次按下按键就会有对应LED灯点亮 同时蜂鸣器响一声 输入正确的密码才能进入第二模式 密码是四位 默认4321 输入错误则LED及蜂鸣器报警两次
第二模式即呼吸灯、蜂鸣器播放音乐系统 按键1播放生日快乐 按住按键2实现呼吸灯明暗循环变化 按键3播放Linkin Park的In The End
音乐播放截止前 长按按键1或按键3即能实现循环播放 按键4终止循环
第三模式是温湿度检测及超声波测距系统 通过USART串口显示数据 这里超声波测距模块的TX接到PB8 RX接到PB9
LED的PF10一直随距离变换而闪烁 按键1开启蜂鸣器报警 按键4关闭蜂鸣器 蜂鸣器报警和PF10的闪烁频率相同 距离越近 频率越快 同样此功能可以通过串口输入“S”“Q”来控制
在串口输入L即开启随湿度变化的呼吸灯 湿度越高 呼吸灯越亮 输入E开启流水灯循环 输入D关闭呼吸灯
长按0.5秒按键2则可以实现打断循环 按键3用于终止程序(return 0)
第四模式是光敏电阻的自动灯光调节系统 LED的PF9、PE13和14可以随着光照度变化而自动调节亮度 光照度越高 LED灯光越暗 反之越亮

在这里插入图片描述
代码如下:

# include "stm32f4xx.h"  //stm32库
# include  "GPIO.h"  //引脚宏定义库
# include  "DELAY.h"  //定时器精准延时函数库
# include  "GPIO_BUS.h"  //引脚总线输出库
# include  "MUSIC_NOTE.h"
# include  "PITCH.h"
# include <stdio.h>  //用于串口打印printf

unsigned int  times=0;  //测距计数值
unsigned int	S=0;  //测距结果
int32_t jugg_temp=0;  //判断温湿度获取的参数
uint8_t temp_buf[5]={0};  //温湿度赋值后的数组
static uint16_t tim13_period=0;  //音乐播放模式下 定时器13及PF8复用PWM的定时器分频值
/* PB8=TX PB9=RX */  //超声波测距模块TX接PB8 RX接PB9

//串口打印预设
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
//串口打印配置函数
int fputc(int ch, FILE *f)  
{
	USART_SendData(USART1,ch);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_ClearFlag(USART1,USART_FLAG_TXE);
	
	return ch;
}
//光敏电阻模式下的PWM输出定时器初始化
void init_TIM14_ADC()
{
	GPIO_InitTypeDef  GPIO_InitStructure;            //GPIO结构体设置
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;  //定时器14结构体设置
	TIM_OCInitTypeDef TIM_OCInitStruct;              //定时器PWM结构体设置

	//使能时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;          //LED9 在PF9引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;       //初始化的复用功能(因为本引脚还要用到PWM输出功能)
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOF, &GPIO_InitStructure);

		//复用映射到定时器14
	GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);

		//定时器14的配置
	TIM_TimeBaseInitStruct.TIM_Prescaler        = 0; //不进行预分频               
	TIM_TimeBaseInitStruct.TIM_CounterMode      = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period           = 100-1;//设置周期为100
	TIM_TimeBaseInitStruct.TIM_ClockDivision    = 0; 
	TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStruct);

		//PWM初始化配置
	TIM_OCInitStruct.TIM_OCMode =  TIM_OCMode_PWM1; //模式选择
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;  //选择低电平有效
	TIM_OCInitStruct.TIM_Pulse = 0;//配置占空比,满占空比是99
	TIM_OC1Init(TIM14,&TIM_OCInitStruct);

		//使能预装载寄存器
	TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); 

		//使能自动重装载寄存器
	TIM_ARRPreloadConfig(TIM14,ENABLE);
		//使能TIM14
	TIM_Cmd(TIM14,ENABLE); 
}
//光敏电阻模式下的PWM输出定时器初始化
void init_TIM1_ADC()
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIOE_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//初始化结构体
	GPIOE_InitStruct.GPIO_Pin  = GPIO_Pin_13; //定义引脚
	GPIOE_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //定义输出模式
	GPIOE_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOE_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推免输出
	GPIOE_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//复用功能 定时器14
	GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);
	//将结构体给GPIOF组
	GPIO_Init(GPIOE,&GPIOE_InitStruct);
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;  //定时器复用功能结构体
	//NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Prescaler        = 0; //不进行预分频               
	TIM_TimeBaseStructure.TIM_CounterMode      = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period           = 100-1;//设置周期为100
	TIM_TimeBaseStructure.TIM_ClockDivision    = 0; 
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
	
	TIM_OCInitStructure.TIM_OCMode =  TIM_OCMode_PWM1; //模式选择
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;  //选择低电平有效
	TIM_OCInitStructure.TIM_Pulse = 0;//配置占空比,满占空比是99
	TIM_OC3Init(TIM1,&TIM_OCInitStructure);
	
	//使能OC
	TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
	

	TIM_ARRPreloadConfig(TIM1,ENABLE);
	TIM_Cmd(TIM1, ENABLE);
	
	//定义GPIO结构体
	//GPIO_InitTypeDef GPIOE_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//初始化结构体
	GPIOE_InitStruct.GPIO_Pin  = GPIO_Pin_14; //定义引脚
	GPIOE_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //定义输出模式
	GPIOE_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOE_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推免输出
	GPIOE_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//复用功能 定时器14
	GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_TIM1);
	//将结构体给GPIOF组
	GPIO_Init(GPIOE,&GPIOE_InitStruct);
	
	//TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	//TIM_OCInitTypeDef  TIM_OCInitStructure;  //定时器复用功能结构体
	//NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Prescaler        = 0; //不进行预分频               
	TIM_TimeBaseStructure.TIM_CounterMode      = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period           = 100-1;//设置周期为100
	TIM_TimeBaseStructure.TIM_ClockDivision    = 0; 
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM1,TIM_IT_Update, ENABLE);
	
	TIM_OCInitStructure.TIM_OCMode =  TIM_OCMode_PWM1; //模式选择
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;  //选择低电平有效
	TIM_OCInitStructure.TIM_Pulse = 0;//配置占空比,满占空比是99
	TIM_OC4Init(TIM1, &TIM_OCInitStructure);	//OC4表示通道4 即CH4
	//使能OC
	TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
	TIM_ARRPreloadConfig(TIM1,ENABLE);
	TIM_Cmd(TIM1, ENABLE);
}
//ADC通道初始化
void init_ADC(void) 
{
	//定义结构体
	GPIO_InitTypeDef  GPIO_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStruct;
	ADC_InitTypeDef ADC_InitStruct;
	//打开ADC3和GPIOF时钟使能
	RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOF, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);  
	/* 初始化ADC3对应的GPIOF引脚 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//输入输出频率
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//配置为不上拉也不下拉
	GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化

	ADC_DeInit();//对ADC进行复位(进行缺省初始化)

	ADC_CommonInitStruct.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;//DMA失能
	ADC_CommonInitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式
	ADC_CommonInitStruct.ADC_Prescaler=ADC_Prescaler_Div4;//APB2四分频 即84/4=21MHz
	ADC_CommonInitStruct.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;//两个采样阶段的延时5个时钟
	ADC_CommonInit(&ADC_CommonInitStruct);//初始化


	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//关闭连续AD转换
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//右对齐
	ADC_InitStruct.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;//禁止使用软件触发检测
	ADC_InitStruct.ADC_NbrOfConversion=5;//设置为通道5
	ADC_InitStruct.ADC_Resolution=ADC_Resolution_8b;//8位精度
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//非扫描模式
	ADC_Init(ADC3, &ADC_InitStruct);//初始化

	ADC_Cmd(ADC3, ENABLE);//开启ADC
}
 //获取ADC数模转换值的函数
uint16_t  get_ADC(uint8_t ch) //获得某个通道值 
{
	
	ADC_RegularChannelConfig(ADC3, ch, 1, ADC_SampleTime_480Cycles );//ADC3 通道ch 一个序列 采样时间		    

	ADC_SoftwareStartConv(ADC3);//启动ADC转换	
	 
	while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC3);//读取转换结果
}

//温湿度模块初始化
void init_TEMP(void)
{
	//端口G硬件时钟使能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);	
	
	GPIO_InitTypeDef GPIO_InitStructure;
	//配置PG9为输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;		//第9根引脚
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT;	//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;	//推挽输出,增加输出电流能力。
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//高速响应
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//没有使能上下拉电阻

	GPIO_Init(GPIOG,&GPIO_InitStructure);		
	
	//PG9初始状态为高电平,看时序图
	PG_O(9)=1;
}
//读取温湿度模块
int32_t read_TEMP(uint8_t *pbuf)
{
	uint32_t t=0;
	int32_t i=0,j=0;
	uint8_t d=0;
	uint8_t *p=pbuf;
	uint32_t check_sum=0;
	
	GPIO_InitTypeDef GPIO_InitStructure;
	//---------------------通信开始的第一部分,主机信号
	//PG9设置为输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;		//第9根引脚
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT;	//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;	//推挽输出,增加输出电流能力。
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//高速响应
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//没有使能上下拉电阻

	GPIO_Init(GPIOG,&GPIO_InitStructure);	
	
	PG_O(9)=0;
	delay_ms(20);
	
	PG_O(9)=1;
	delay_us(30);	
	
	//-----通信开始的第二部分,DHT信号
	//PG9设置为输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;		//第9根引脚
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN;		//输入模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//高速响应
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//没有使能上下拉电阻

	GPIO_Init(GPIOG,&GPIO_InitStructure);	

	//等待低电平出现
	t=0;
	while(PG_I(9))
	{
		t++;
		
		delay_us(1);
		
		if(t>=4000)
			return -1;
	}
	
	//测量低电平合法性
	t=0;
	while(PG_I(9)==0)
	{
		t++;
		
		delay_us(1);
		
		if(t>=1000)
			return -2;
	}

	//测量高电平合法性
	t=0;
	while(PG_I(9))
	{
		t++;
		delay_us(1);
		if(t>=1000)
			return -3;
	}
	
	//数据0和1的读取
	for(j=0; j<5; j++)
	{
		d=0;
		//一个字节的接收,从最高有效位开始接收
		for(i=7; i>=0; i--)
		{
			//等待数据0/数据1的前置低电平持续完毕
			t=0;
			while(PG_I(9)==0)
			{
				t++;
				delay_us(1);				
				if(t>=1000)
					return -4;
			}

			//延时40us
			delay_us(40);
		
			//判断当前PG9是否为高电平还是低电平
			//若是高电平,则为数据1;
			//若是低电平,则为数据0;
			if(PG_I(9))
			{
				d|=1<<i;//将变量d对应的比特位置1,如i=7,d|=1<<7就是将变量d的bit7置1
			
				//等待高电平持续完毕
				t=0;
				while(PG_I(9))
				{
					t++;
					delay_us(1);
					if(t>=1000)
						return -5;
				}		
			}
		}
		p[j]=d;	
	}
	
	//校验和
	check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
	if(p[4] != check_sum)
		return -6;
	
	return 0;
}
//按键初始化
void init_KEEY(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_KEEY_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	//初始化结构体
	GPIO_KEEY_InitStruct.GPIO_Pin  = GPIO_Pin_0; //定义引脚
	GPIO_KEEY_InitStruct.GPIO_Mode = GPIO_Mode_IN;  //定义输出模式
	GPIO_KEEY_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIO_KEEY_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOA,&GPIO_KEEY_InitStruct);
	
	GPIO_KEEY_InitStruct.GPIO_Pin  = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
	GPIO_Init(GPIOE,&GPIO_KEEY_InitStruct);
}
//蜂鸣器初始化
void init_BEEP(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIOF_BEEP_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	//初始化结构体
	GPIOF_BEEP_InitStruct.GPIO_Pin  = GPIO_Pin_8; //定义引脚
	GPIOF_BEEP_InitStruct.GPIO_Mode = GPIO_Mode_OUT;  //定义输出模式
	GPIOF_BEEP_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOF_BEEP_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推挽输出
	GPIOF_BEEP_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOF,&GPIOF_BEEP_InitStruct);
}
//关闭BEEP
void close_BEEP(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIOF_BEEP_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	//初始化结构体
	GPIOF_BEEP_InitStruct.GPIO_Pin  = GPIO_Pin_8; //定义引脚
	GPIOF_BEEP_InitStruct.GPIO_Mode = GPIO_Mode_IN;  //定义输出模式
	GPIOF_BEEP_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOF_BEEP_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推挽输出
	GPIOF_BEEP_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOF,&GPIOF_BEEP_InitStruct);
}
//两个引脚整体初始化函数
void init_GPIO_EF_OUT(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	//初始化结构体
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_9 | GPIO_Pin_10; //定义引脚
	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;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOF,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_13 | GPIO_Pin_14; //定义引脚
	//将结构体给GPIOE组
	GPIO_Init(GPIOE,&GPIO_InitStruct);
}
//串口初始化函数
void init_USART1(unsigned int Baud)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_KEEY_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	//初始化结构体
	GPIO_KEEY_InitStruct.GPIO_Pin  = GPIO_Pin_9 | GPIO_Pin_10; //定义引脚
	GPIO_KEEY_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //定义输出模式
	GPIO_KEEY_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIO_KEEY_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推挽输出
	GPIO_KEEY_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOA,&GPIO_KEEY_InitStruct);
	
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);  //复用功能
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);  //复用功能
	
	USART_InitTypeDef USART_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	//配置串口
	USART_InitStructure.USART_BaudRate = Baud;  //波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;  //8位数据位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;  //1个停止位
  USART_InitStructure.USART_Parity = USART_Parity_No;  //无校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //无硬件流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  //支持收发数据
	USART_Init(USART1, &USART_InitStructure);
	//中断方式
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  //使能RX

	//中断优先级
	NVIC_InitTypeDef NVIC_InitStructure;
 
   /* Enable the USARTx Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	//使能串口
	USART_Cmd(USART1, ENABLE);
}
//GPIOB_8初始化使能
void init_TX(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	//初始化结构体
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_8; //定义引脚
	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;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOB组
	GPIO_Init(GPIOB,&GPIO_InitStruct);
}
//GPIOB_9初始化使能
void init_RX(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	//初始化结构体
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_9; //定义引脚
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;  //定义输出模式
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOB组
	GPIO_Init(GPIOB,&GPIO_InitStruct);
}
//定时器14及PF9复用PWM初始化
void init_TIM14_PF9(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIOF_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	//初始化结构体
	GPIOF_InitStruct.GPIO_Pin  = GPIO_Pin_9; //定义引脚
	GPIOF_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //定义输出模式
	GPIOF_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOF_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推免输出
	GPIOF_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//复用功能 定时器14
	GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);
	//将结构体给GPIOF组
	GPIO_Init(GPIOF,&GPIOF_InitStruct);
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;  //定时器复用功能结构体
	//NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Period = 100-1;  //10ms周期
	TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;  //定时器预分频 168000000/2/8400=10000 其值系统默认+1 每10000次计数为1秒
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //选择计数模式 向上计数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM14,TIM_IT_Update, ENABLE);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  //PWM模式1  有效状态为小于计数的比较值时
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;  //设置比较值 小于x时为有效 总计数值为100 周期为10ms
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //有效状态为高电平
	//输出化OC
	TIM_OC1Init(TIM14, &TIM_OCInitStructure);
	//使能OC
	TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);
	
//	NVIC_InitTypeDef NVIC_InitStruct;
//	NVIC_InitStruct.NVIC_IRQChannel = TIM8_TRG_COM_TIM14_IRQn;
//	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //中断抢占优先级
//	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //响应优先级
//	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;  //这一项关闭的话 定时器也会关闭
//	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM14, ENABLE);
	TIM_CtrlPWMOutputs(TIM14,ENABLE);		//使能PWM输出控制
}
//定时器1及PE13复用PWM初始化
void init_TIM1_PE13(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIOE_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//初始化结构体
	GPIOE_InitStruct.GPIO_Pin  = GPIO_Pin_13; //定义引脚
	GPIOE_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //定义输出模式
	GPIOE_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOE_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推免输出
	GPIOE_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//复用功能 定时器14
	GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);
	//将结构体给GPIOF组
	GPIO_Init(GPIOE,&GPIOE_InitStruct);
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;  //定时器复用功能结构体
	//NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Period = 100-1;  //10ms周期
	TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;  //定时器预分频 168000000/2/8400=10000 其值系统默认+1 每10000次计数为1秒
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //选择计数模式 向上计数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM1,TIM_IT_Update, ENABLE);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  //PWM模式1  有效状态为小于计数的比较值时
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;  //设置比较值 小于x时为有效 总计数值为100 周期为10ms
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //有效状态为高电平
	//输出化OC
	TIM_OC3Init(TIM1, &TIM_OCInitStructure);	//OC3表示通道3 即CH3
	//使能OC
	TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
	
//	NVIC_InitTypeDef NVIC_InitStruct;
//	NVIC_InitStruct.NVIC_IRQChannel = TIM8_TRG_COM_TIM14_IRQn;
//	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //中断抢占优先级
//	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //响应优先级
//	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;  //这一项关闭的话 定时器也会关闭
//	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM1, ENABLE);
	TIM_CtrlPWMOutputs(TIM1,ENABLE);		//使能PWM输出控制
}
//定时器1及PE14复用PWM初始化
void init_TIM1_PE14(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIOE_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//初始化结构体
	GPIOE_InitStruct.GPIO_Pin  = GPIO_Pin_14; //定义引脚
	GPIOE_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //定义输出模式
	GPIOE_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOE_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推免输出
	GPIOE_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//复用功能 定时器14
	GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_TIM1);
	//将结构体给GPIOF组
	GPIO_Init(GPIOE,&GPIOE_InitStruct);
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;  //定时器复用功能结构体
	//NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Period = 100-1;  //10ms周期
	TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;  //定时器预分频 168000000/2/8400=10000 其值系统默认+1 每10000次计数为1秒
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //选择计数模式 向上计数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM1,TIM_IT_Update, ENABLE);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  //PWM模式1  有效状态为小于计数的比较值时
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;  //设置比较值 小于x时为有效 总计数值为100 周期为10ms
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //有效状态为高电平
	//输出化OC
	TIM_OC4Init(TIM1, &TIM_OCInitStructure);	//OC4表示通道4 即CH4
	//使能OC
	TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
	
//	NVIC_InitTypeDef NVIC_InitStruct;
//	NVIC_InitStruct.NVIC_IRQChannel = TIM8_TRG_COM_TIM14_IRQn;
//	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //中断抢占优先级
//	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //响应优先级
//	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;  //这一项关闭的话 定时器也会关闭
//	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM1, ENABLE);
	TIM_CtrlPWMOutputs(TIM1,ENABLE);		//使能PWM输出控制
}
//定时器13及PF8复用PWM初始化
void init_TIM13_PF8_F(uint32_t freq)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIOF_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	//初始化结构体
	GPIOF_InitStruct.GPIO_Pin  = GPIO_Pin_8; //定义引脚
	GPIOF_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //定义输出模式
	GPIOF_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIOF_InitStruct.GPIO_OType = GPIO_OType_PP;		//定义推免输出
	GPIOF_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;		//定义是否有上下拉电阻 普通
	//复用功能 定时器14
	GPIO_PinAFConfig(GPIOF, GPIO_PinSource8, GPIO_AF_TIM13);
	//将结构体给GPIOF组
	GPIO_Init(GPIOF,&GPIOF_InitStruct);
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;  //定时器复用功能结构体
	//NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Period = (8400000000000/freq)-1;  //10ms周期
	tim13_period = TIM_TimeBaseStructure.TIM_Period;
	TIM_TimeBaseStructure.TIM_Prescaler = 1-1;  //定时器预分频 168000000/2/8400=10000 其值系统默认+1 每10000次计数为1秒
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //选择计数模式 向上计数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInit(TIM13, &TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM13,TIM_IT_Update, ENABLE);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  //PWM模式1  有效状态为小于计数的比较值时
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;  //设置比较值 小于x时为有效 总计数值为100 周期为10ms
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //有效状态为高电平
	//输出化OC
	TIM_OC1Init(TIM13, &TIM_OCInitStructure);
	//使能OC
	TIM_OC1PreloadConfig(TIM13, TIM_OCPreload_Enable);

//	NVIC_InitTypeDef NVIC_InitStruct;
//	NVIC_InitStruct.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn;
//	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //中断抢占优先级
//	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; //响应优先级
//	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;  //这一项关闭的话 定时器也会关闭
//	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM13, ENABLE);
}
//设置定时器13的PWM占空比
//0%~100%  0.0 ~ 1
void TIM13_Set_duty(uint16_t duty)
{
	uint32_t cmp=0;
	
	cmp = (tim13_period+1)*duty/100;//比较值
	
	TIM_SetCompare1(TIM13,cmp);
}
//定时器3初始化
void init_TIM3_RX(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	//TIM_OCInitTypeDef  TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Period = 2-1;  
	TIM_TimeBaseStructure.TIM_Prescaler = 84-1;  //定时器预分频 168000000/2/84=1000000 其值系统默认+1 每1000000次计数为1秒
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //选择计数模式 向上计数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);
	
	/* Enable the TIM3 gloabal Interrupt *///使能定时器3的中断通道
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	//使能定时器3
	TIM_Cmd(TIM3, DISABLE);
}
//定时器2初始化
void init_TIM2_TX(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	//TIM_OCInitTypeDef  TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM2 clock enable */ //使能定时器2时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Period = 5000-1;  
	TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;  //定时器预分频 168000000/2/8400=10000 其值系统默认+1 每10000次计数为1秒
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //选择计数模式 向上计数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
	
	/* Enable the TIM2 gloabal Interrupt *///使能定时器2的中断通道
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	//使能定时器2
	TIM_Cmd(TIM2, ENABLE);
}
//定时器4初始化
void init_TIM4_Warning(unsigned int tim)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	//TIM_OCInitTypeDef  TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	/* TIM3 clock enable */ //使能定时器3时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	//重转载寄存器 定义计数值 决定了计数多少次就进行一次中断 不得大于分频以后的计数值 若改为5000为0.5秒
	TIM_TimeBaseStructure.TIM_Period = tim-1;  
	TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;  //定时器预分频 168000000/2/84=10000 其值系统默认+1 每10000次计数为1秒
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //选择计数模式 向上计数
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
	//设置中断触发方式 计数更新
	TIM_ITConfig(TIM4,TIM_IT_Update, ENABLE);
	
	/* Enable the TIM3 gloabal Interrupt *///使能定时器3的中断通道
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	//使能定时器4
	TIM_Cmd(TIM4, ENABLE);
}
//外部中断0初始化 PA0
void init_EXTI0(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_KEEY_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	//初始化结构体
	GPIO_KEEY_InitStruct.GPIO_Pin  = GPIO_Pin_0; //定义引脚
	GPIO_KEEY_InitStruct.GPIO_Mode = GPIO_Mode_IN;  //定义输出模式
	GPIO_KEEY_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIO_KEEY_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOA,&GPIO_KEEY_InitStruct);
	//选择中断线 中断0 PA组
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0); 
	//使能中断时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 
	//配置中断
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = EXTI_Line0;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
	//嵌套向量中断控制器 
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x0; //中断抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x0; //响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}
//外部中断4初始化 PE4
void init_EXTI4(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_KEEY_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//初始化结构体
	GPIO_KEEY_InitStruct.GPIO_Pin  = GPIO_Pin_4; //定义引脚
	GPIO_KEEY_InitStruct.GPIO_Mode = GPIO_Mode_IN;  //定义输出模式
	GPIO_KEEY_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIO_KEEY_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOE,&GPIO_KEEY_InitStruct);
	//选择中断线 中断0 PA组
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4); 
	//使能中断时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 
	//配置中断
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = EXTI_Line4;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
	
	//嵌套向量中断控制器 
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x0; //中断抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x0; //响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}
//关闭外部中断0初始化 PA0
void close_EXTI0(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_KEEY_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	//初始化结构体
	GPIO_KEEY_InitStruct.GPIO_Pin  = GPIO_Pin_0; //定义引脚
	GPIO_KEEY_InitStruct.GPIO_Mode = GPIO_Mode_IN;  //定义输出模式
	GPIO_KEEY_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIO_KEEY_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOA,&GPIO_KEEY_InitStruct);
	//选择中断线 中断0 PA组
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0); 
	//使能中断时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 
	//配置中断
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = EXTI_Line0;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
	EXTI_InitStruct.EXTI_LineCmd = DISABLE;  //关闭外部中断
	EXTI_Init(&EXTI_InitStruct);
}
//关闭中断4初始化 PE4
void close_EXTI4(void)
{
	//定义GPIO结构体
	GPIO_InitTypeDef GPIO_KEEY_InitStruct;
	//使能GPIOF时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//初始化结构体
	GPIO_KEEY_InitStruct.GPIO_Pin  = GPIO_Pin_4; //定义引脚
	GPIO_KEEY_InitStruct.GPIO_Mode = GPIO_Mode_IN;  //定义输出模式
	GPIO_KEEY_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//定义速度
	GPIO_KEEY_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;		//定义是否有上下拉电阻 普通
	//将结构体给GPIOF组
	GPIO_Init(GPIOE,&GPIO_KEEY_InitStruct);
	//选择中断线 中断0 PA组
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4); 
	//使能中断时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 
	//配置中断
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = EXTI_Line4;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
	EXTI_InitStruct.EXTI_LineCmd = DISABLE;  //关闭外部中断
	EXTI_Init(&EXTI_InitStruct);
}
//主循环函数
void mainloop(void)
{
	init_GPIO_EF_OUT();
	init_BEEP();
	init_KEEY();
	MUSIC_BPM=120;
	int y;
	int flag=0;
	delay_ms(500);
	
	while(1)//按键锁循环
	{
		int buf[4];
		uint8_t key0 = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);
		uint8_t key1 = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2);
		uint8_t key2 = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3);
		uint8_t key3 = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4);
		GPIO_SetBits(GPIOF,GPIO_Pin_9);
		GPIO_SetBits(GPIOF,GPIO_Pin_10);
		GPIO_SetBits(GPIOE,GPIO_Pin_13);
		GPIO_SetBits(GPIOE,GPIO_Pin_14);
		PF_O(8)=0;
		
		if( key0 == Bit_RESET)
		{
			y=0;
			flag++;
			while(1){GPIO_ResetBits(GPIOF,GPIO_Pin_9);PF_O(8)=1;
				uint8_t key0 = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);
				if(key0 == Bit_SET)GPIO_SetBits(GPIOF,GPIO_Pin_9);break;}
			delay_ms(200);PF_O(8)=0;PF_O(9)=1;
		}
		if( key1 == Bit_RESET)
		{
			y=1;
			flag++;
			while(1){GPIO_ResetBits(GPIOF,GPIO_Pin_10);PF_O(8)=1;
				uint8_t key1 = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2);
				if(key1 == Bit_SET)GPIO_SetBits(GPIOF,GPIO_Pin_10);break;}
			delay_ms(200);PF_O(8)=0;PF_O(10)=1;
		}
		if( key2 == Bit_RESET)
		{
			y=2;
			flag++;
			while(1){GPIO_ResetBits(GPIOE,GPIO_Pin_13);PF_O(8)=1;
				uint8_t key2 = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3);
				if(key2 == Bit_SET)GPIO_SetBits(GPIOE,GPIO_Pin_13);break;}
			delay_ms(200);PF_O(8)=0;PE_O(13)=1;
		}
		if( key3 == Bit_RESET)
		{
			y=3;
			flag++;
			while(1){GPIO_ResetBits(GPIOE,GPIO_Pin_14);PF_O(8)=1;
				uint8_t key3 = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4);
				if(key3 == Bit_SET)GPIO_SetBits(GPIOE,GPIO_Pin_14);break;}
			delay_ms(200);PF_O(8)=0;PE_O(14)=1;
		}
		if (flag >= 1){buf[flag-1]=y;}
		if (flag == 4){
			buf[flag-1]=y;flag=0;
			if (buf[0]==3 && buf[1]==2 && buf[2]==1 && buf[3]==0)
			{
				PF_O(9)=1;PF_O(10)=1;PE_O(13)=1;PE_O(14)=1;PF_O(8)=0;
				delay_ms(200);	
				PF_O(9)=0;PF_O(10)=0;PE_O(13)=0;PE_O(14)=0;PF_O(8)=1;
				delay_ms(200);
				break;
			}
			else if (buf[0]!=3 | buf[1]!=2 | buf[2]!=1 | buf[3]==0){
				PF_O(9)=1;PF_O(10)=1;PE_O(13)=1;PE_O(14)=1;PF_O(8)=0;
				delay_ms(200);
				PF_O(9)=0;PF_O(10)=0;PE_O(13)=0;PE_O(14)=0;PF_O(8)=1;
				delay_ms(200);
				PF_O(9)=1;PF_O(10)=1;PE_O(13)=1;PE_O(14)=1;PF_O(8)=0;
				delay_ms(200);
				PF_O(9)=0;PF_O(10)=0;PE_O(13)=0;PE_O(14)=0;PF_O(8)=1;
				delay_ms(200);
				PF_O(9)=1;PF_O(10)=1;PE_O(13)=1;PE_O(14)=1;PF_O(8)=0;
				delay_ms(200);
			}
		}	
	}
	PF_O(8)=0;
	init_TIM14_PF9();
	init_TIM1_PE13();
	init_TIM1_PE14();
	PF_O(9)=1;PF_O(10)=1;PE_O(13)=1;PE_O(14)=1;
	TIM_SetCompare1(TIM14,100);  //设置比较值
	TIM_SetCompare3(TIM1,100);
	TIM_SetCompare4(TIM1,100);
	int PWM;
	TIM_Cmd(TIM13, DISABLE);
	while(1)  //呼吸灯及播放音乐
	{	
		if(PE_I(4)==0)
		{
			TIM_Cmd(TIM13, DISABLE);
			TIM_Cmd(TIM14, DISABLE);
			TIM_Cmd(TIM1, DISABLE);
			close_BEEP();
			break;
		}
		while(PE_I(3)==0)
		{
			init_TIM13_PF8_F(A5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(E6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(E6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(C6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(B5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(B5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(B5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(B5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(C6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			if(PE_I(3)==1)TIM13_Set_duty(0);break;
		}
		
		while(PA_I(0)==0)
		{
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(A5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(C6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(B5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_2*1000);
			
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(A5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(D6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(C6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_2*1000);
			
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(G5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(G6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(E6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(C6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(B5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(A5);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			delay_ms(NOTE_4*1000);
			
			init_TIM13_PF8_F(F6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(F6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_8*1000);
			init_TIM13_PF8_F(E6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(C6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(D6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_4*1000);
			init_TIM13_PF8_F(C6);
			TIM13_Set_duty(25);
			delay_ms(NOTE_1*1000);
			if(PA_I(0)==1)TIM13_Set_duty(0);break;
		}

		while(PE_I(2)==0)
		{
			for(PWM=100;PWM>0;PWM--)
			{
				TIM_SetCompare1(TIM14,100-PWM);  //设置比较值
				TIM_SetCompare3(TIM1,100-PWM);
				TIM_SetCompare4(TIM1,100-PWM);
				delay_ms(10);
				if(PE_I(2)==1)
				{
					TIM_SetCompare1(TIM14,100);  //设置比较值
					TIM_SetCompare3(TIM1,100);
					TIM_SetCompare4(TIM1,100);
					break;
				}
			}
			for(PWM=0;PWM<100;PWM++)
			{
				TIM_SetCompare1(TIM14,100-PWM);  //设置比较值
				TIM_SetCompare3(TIM1,100-PWM);
				TIM_SetCompare4(TIM1,100-PWM);
				delay_ms(10);
				if(PE_I(2)==1)
				{
					TIM_SetCompare1(TIM14,100);  //设置比较值
					TIM_SetCompare3(TIM1,100);
					TIM_SetCompare4(TIM1,100);
					break;
				}
			}
			if(PE_I(2)==1)
			{
				TIM_SetCompare1(TIM14,100);  //设置比较值
				TIM_SetCompare3(TIM1,100);
				TIM_SetCompare4(TIM1,100);
				break;
			}
		}
	}
}
//温湿度及距离测量
void Count(void)
{
	S=times*2*0.17;  //单位 mm
	if(jugg_temp == 0)
	{
		TIM_SetCompare1(TIM14,100-temp_buf[0]);  //设置比较值
		TIM_SetCompare3(TIM1,100-temp_buf[0]);
		TIM_SetCompare4(TIM1,100-temp_buf[0]);
		if(S==0)
		{
			printf(" 距离测量失败	|		| 温度:%d.%d℃	| 湿度:%d.%d%%\r\n",temp_buf[2],temp_buf[3],temp_buf[0],temp_buf[1]);  //测量失败
			printf("		|		|		|\r\n");
			TIM_Cmd(TIM4, DISABLE);
			PF_O(8)=0;
		}
		if(S>=1&S<30)
		{
			printf(" 距离过近	|		| 温度:%d.%d℃	| 湿度:%d.%d%%\r\n",temp_buf[2],temp_buf[3],temp_buf[0],temp_buf[1]);  //测量失败
			printf("		|		|		|\r\n");
			TIM_Cmd(TIM4, DISABLE);
			PF_O(8)=0;
		}
		if(S>=30&S<=4000)
		{
			printf("		| 距离:%dmm	| 温度:%d.%d℃	| 湿度:%d.%d%%\r\n",S,temp_buf[2],temp_buf[3],temp_buf[0],temp_buf[1]);
			printf("		|		|		|\r\n");
			init_TIM4_Warning(S);
		}
		if(S>4000)
		{
			printf(" 超出测量范围	|		| 温度:%d.%d℃	| 湿度:%d.%d%%\r\n",temp_buf[2],temp_buf[3],temp_buf[0],temp_buf[1]);
			printf("		|		|		|\r\n");
			TIM_Cmd(TIM4, DISABLE);
			PF_O(8)=0;
		}
	}
	else
	{
		if(S==0)
		{
			printf(" 距离测量失败	|		|		| 温湿度获取错误代码:%d	\r\n",jugg_temp);  //测量失败
			printf("		|		|		|\r\n");
			TIM_Cmd(TIM4, DISABLE);
			PF_O(8)=0;
		}
		if(S>=1&S<30)
		{
			printf(" 距离过近	|		|		| 温湿度获取错误代码:%d	\r\n",jugg_temp);  //测量失败
			printf("		|		|		|\r\n");
			TIM_Cmd(TIM4, DISABLE);
			PF_O(8)=0;
		}
		if(S>=30&S<=4000)
		{
			printf("		| 距离:%dmm	|		| 温湿度获取错误代码:%d	\r\n",S,jugg_temp);
			printf("		|		|		|\r\n");
			init_TIM4_Warning(S);
		}
		if(S>4000)
		{
			printf(" 超出测量范围	|		|		| 温湿度获取错误代码:%d	\r\n",jugg_temp);
			TIM_Cmd(TIM4, DISABLE);
			printf("		|		|		|\r\n");
			PF_O(8)=0;
		}
	}
	times=0;
	S=0;
}
//光敏电阻ADC转换及计算部分函数
void lux_ADC(void)
{
	uint8_t ADC_min=0,ADC_max=0;//记录光敏电阻产生的数据中的最大最小值
	uint8_t ADC_sj=0;			//读取到的光敏电阻ADC数据
	uint8_t ADC_PWM=0;			//PWM占空比
	init_ADC();					//初始化ADC
	init_KEEY();
	init_TIM14_ADC(); 			//初始化PWM
	init_TIM1_ADC();
	ADC_min = ADC_max = get_ADC(5);//最大最小值读取初始数据
	while(1)
	{
		ADC_sj = get_ADC(5);//采集数据
		/****** 进行归一化 ******/
		if(ADC_sj < ADC_min)	ADC_min = ADC_sj;
		if(ADC_sj > ADC_max)	ADC_max = ADC_sj;
		/****** 归一化结束 ******/
		ADC_PWM = (ADC_sj - ADC_min)*99/(ADC_max - ADC_min);//计算相对数据,范围:0~99
		TIM_SetCompare1(TIM14,ADC_PWM);//输入得到的数据,改变PWM占空比
		TIM_SetCompare3(TIM1,ADC_PWM);//输入得到的数据,改变PWM占空比
		TIM_SetCompare4(TIM1,ADC_PWM);//输入得到的数据,改变PWM占空比
		if(PA_I(0)==0)
		{
			TIM_Cmd(TIM2, DISABLE);
			TIM_Cmd(TIM3, DISABLE);
			TIM_Cmd(TIM4, DISABLE);
			TIM_Cmd(TIM1, DISABLE);
			TIM_ARRPreloadConfig(TIM14,DISABLE);
			TIM_ARRPreloadConfig(TIM1,DISABLE);
			TIM_Cmd(TIM14, DISABLE);
			TIM_Cmd(TIM13, DISABLE);
			USART_Cmd(USART1, DISABLE);
			close_EXTI4();
			close_EXTI0();
			init_GPIO_EF_OUT();
			init_BEEP();
			PF_BUS_O(0xFFFF);
			PE_BUS_O(0xFFFF);
			PF_O(8)=0;
			init_KEEY();
			break;
		}
	}
}
//主函数
int main(void)
{	
	mainloop();
	init_USART1(115200);
	init_TEMP();
//	init_KEEY();
//	init_BEEP();
	PF_O(8)=0;
	init_TX();
	PB_O(8)=0;
	init_RX();
	init_GPIO_EF_OUT();
	PF_BUS_O(0x0000);
	PE_BUS_O(0x0000);
	delay_ms(500);
	PF_BUS_O(0xFFFF);
	PE_BUS_O(0xFFFF);
	PF_O(8)=0;
//	init_TIM14_PF9();
//	init_TIM1_PE13();
//	init_TIM1_PE14();
	TIM_SetCompare1(TIM14,100);  //设置比较值
	TIM_SetCompare3(TIM1,100);
	TIM_SetCompare4(TIM1,100);
	printf(" by:Mike Zhou	| 网易独家音乐人	| 嵌入式软件工程师	| https://music.163.com/#/artist?id=12115205\n");
	printf("		|		|		| https://blog.csdn.net/weixin_53403301\r\n");
	init_EXTI0();
	init_EXTI4();
	init_TIM3_RX();  //默认关闭
	init_TIM2_TX();
	while(1)
	{
		while(!PB_I(9));
		TIM_Cmd(TIM3, ENABLE);
		while(PB_I(9));
		TIM_Cmd(TIM3, DISABLE);
		Count();
		jugg_temp = read_TEMP(temp_buf);
		if (PE_I(2)==0)
		{
			TIM_Cmd(TIM2, DISABLE);
			TIM_Cmd(TIM3, DISABLE);
			TIM_Cmd(TIM4, DISABLE);
			TIM_Cmd(TIM1, DISABLE);
			TIM_CtrlPWMOutputs(TIM14,DISABLE);		//使能PWM输出控制
			TIM_Cmd(TIM14, DISABLE);
			TIM_Cmd(TIM13, DISABLE);
			USART_Cmd(USART1, DISABLE);
			close_EXTI4();
			close_EXTI0();
			init_GPIO_EF_OUT();
			init_BEEP();
			PF_BUS_O(0xFFFF);
			PE_BUS_O(0xFFFF);
			PF_O(8)=0;
			init_KEEY();
			break;
		}
		if (PE_I(3)==0)
		{
			TIM_Cmd(TIM2, DISABLE);
			TIM_Cmd(TIM3, DISABLE);
			TIM_Cmd(TIM4, DISABLE);
			TIM_Cmd(TIM1, DISABLE);
			TIM_CtrlPWMOutputs(TIM14,DISABLE);		//使能PWM输出控制
			TIM_Cmd(TIM14, DISABLE);
			TIM_Cmd(TIM13, DISABLE);
			USART_Cmd(USART1, DISABLE);
			close_EXTI4();
			close_EXTI0();
			init_GPIO_EF_OUT();
			init_BEEP();
			PF_BUS_O(0xFFFF);
			PE_BUS_O(0xFFFF);
			PF_O(8)=0;
			init_KEEY();
			return 0;
		}
	}
	lux_ADC();
}
//中断0
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetFlagStatus(EXTI_Line0) == SET) //中断产生
	{
		init_BEEP();
	}
	//结束后清空标志位
	EXTI_ClearITPendingBit(EXTI_Line0);
}
//中断4
void EXTI4_IRQHandler(void)
{
	if(EXTI_GetFlagStatus(EXTI_Line4) == SET) //中断产生
	{
		close_BEEP();
	}
	//结束后清空标志位
	EXTI_ClearITPendingBit(EXTI_Line4);
}
//测距报警的定时器2服务函数
void TIM4_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM4,TIM_IT_Update) == SET)
	{
		PF_O(8)=!PF_O(8);
		PF_O(10)=!PF_O(10);
	}
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
//测距技术定时器3服务函数
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
	{
		times++;
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
//定时器2服务函数 提供TX输入
void TIM2_IRQHandler(void)   //每500ms启动一次模块
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		PB_O(8)=1;
		delay_us(20);
		PB_O(8)=0;
	}
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
//串口1中断服务函数
void USART1_IRQHandler(void) 
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{	
		char data = USART_ReceiveData(USART1);
		USART_SendData(USART1,data);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清空标志位
		if(data=='Q')
		{
			close_BEEP();
		}
		if(data=='S')
		{
			init_BEEP();
		}
		if(data=='L')
		{
			init_TIM14_PF9();
			init_TIM1_PE13();
			init_TIM1_PE14();
		}
		if(data=='D')
		{
			TIM_Cmd(TIM1, DISABLE);
			TIM_Cmd(TIM14, DISABLE);
			init_GPIO_EF_OUT();
			PF_O(9)=1;
			PE_O(13)=1;
			PE_O(14)=1;
		}
		if(data=='E')
		{
			TIM_Cmd(TIM1, DISABLE);
			TIM_Cmd(TIM14, DISABLE);
			init_GPIO_EF_OUT();
			PF_O(9)=1;
			PE_O(13)=1;
			PE_O(14)=1;
			for(int i=0;i<2;i++)
			{
				PF_O(9)=0;delay_ms(100);
				PF_O(9)=1;delay_ms(100);
				PE_O(13)=0;delay_ms(100);
				PE_O(13)=1;delay_ms(100);
				PE_O(14)=0;delay_ms(100);
				PE_O(14)=1;delay_ms(100);
				PF_O(9)=0;delay_ms(100);
				PE_O(13)=0;delay_ms(100);
				PE_O(14)=0;delay_ms(100);
				PE_O(14)=0;delay_ms(100);
				PE_O(13)=0;delay_ms(100);
				PF_O(9)=0;delay_ms(100);
				PF_O(9)=1;delay_ms(100);
				PE_O(13)=1;delay_ms(100);
				PE_O(14)=1;delay_ms(100);
			}
		}
	}
}


以下是导入的函数及库

# include "stm32f4xx.h"

void delay_ms(unsigned int ms)
{
	while(ms--)
	{
		SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
		SysTick->LOAD = 168000000/1000-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
		SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能168MHz的系统定时器
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}
void delay_us(unsigned int us)
{
	while(us--)
	{
		SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
		SysTick->LOAD = 168000000/1000/1000-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
		SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能168MHz的系统定时器
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}

#ifndef __DELAY_H__
#define __DELAY_H__

void delay_ms(unsigned int ms);
void delay_us(unsigned int us);

#endif

#ifndef __GPIO_H__
#define __GPIO_H__

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
#define PA_O(n)   	BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PA_I(n)    	BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PB_O(n)   	BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PB_I(n)    	BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PC_O(n)   	BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PC_I(n)    	BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PD_O(n)   	BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PD_I(n)    	BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PE_O(n)   	BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PE_I(n)    	BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PF_O(n)   	BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PF_I(n)    	BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PG_O(n)   	BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PG_I(n)    	BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PH_O(n)   	BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PH_I(n)    	BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PI_O(n)  	 	BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PI_I(n)   	BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

#endif

# include "stm32f4xx.h"
# include "GPIO.h"

void PA_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PA_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PA_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PA_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PB_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PB_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PB_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PB_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PC_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PC_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PC_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PC_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PD_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PD_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PD_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PD_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PE_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PE_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PE_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PE_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PF_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PF_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PF_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PF_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PG_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PG_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PG_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PG_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PH_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PH_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PH_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PH_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PI_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PI_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PI_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PI_I(i)<<i)&0xFFFF;
	}
	return num;
}

#ifndef __GPIO_BUS_H__
#define __GPIO_BUS_H__

void PA_BUS_O(unsigned int num);
unsigned int PA_BUS_I(void);

void PB_BUS_O(unsigned int num);
unsigned int PB_BUS_I(void);

void PC_BUS_O(unsigned int num);
unsigned int PC_BUS_I(void);

void PD_BUS_O(unsigned int num);
unsigned int PD_BUS_I(void);

void PE_BUS_O(unsigned int num);
unsigned int PE_BUS_I(void);

void PF_BUS_O(unsigned int num);
unsigned int PF_BUS_I(void);

void PG_BUS_O(unsigned int num);
unsigned int PG_BUS_I(void);

void PH_BUS_O(unsigned int num);
unsigned int PH_BUS_I(void);

void PI_BUS_O(unsigned int num);
unsigned int PI_BUS_I(void);

#endif

#ifndef __PITCH_H__
#define __PITCH_H__

/*利用Python来编写定义
代码:
f = open('./PITCH.h', 'w')
C=44001000/((2**(1/12))**9)
Db=44001000/((2**(1/12))**8)
D=44001000/((2**(1/12))**7)
Eb=44001000/((2**(1/12))**6)
E=44001000/((2**(1/12))**5)
F=44001000/((2**(1/12))**4)
Gb=44001000/((2**(1/12))**3)
G=44001000/((2**(1/12))**2)
Ab=44001000/(2**(1/12))
A=44001000
Bb=44001000*(2**(1/12))
B=44001000*((2**(1/12))**2)
f.write('#ifndef __PITCH_H__\n')
f.write('#define __PITCH_H__\n')
f.write('\n')
for i in range(0,10):
    f.write('#define    C'+str(i)+'    '+str(int(C/(2**(4-i))))+'\n')
    f.write('#define    Db'+str(i)+'    '+str(int(Db/2**(4-i)))+'\n')
    f.write('#define    D'+str(i)+'    '+str(int(D/2**(4-i)))+'\n')
    f.write('#define    Eb'+str(i)+'    '+str(int(Eb/2**(4-i)))+'\n')
    f.write('#define    E'+str(i)+'    '+str(int(E/2**(4-i)))+'\n')
    f.write('#define    F'+str(i)+'    '+str(int(F/2**(4-i)))+'\n')
    f.write('#define    Gb'+str(i)+'    '+str(int(Gb/2**(4-i)))+'\n')
    f.write('#define    G'+str(i)+'    '+str(int(G/2**(4-i)))+'\n')
    f.write('#define    Ab'+str(i)+'    '+str(int(Ab/2**(4-i)))+'\n')
    f.write('#define    A'+str(i)+'    '+str(int(A/2**(4-i)))+'\n')
    f.write('#define    Bb'+str(i)+'    '+str(int(Bb/2**(4-i)))+'\n')
    f.write('#define    B'+str(i)+'    '+str(int(B/2**(4-i)))+'\n')
    f.write('\n')
f.write('#endif\n')
f.close()
*/

#define	C0	1635196
#define	Db0	1732430
#define	D0	1835446
#define	Eb0	1944587
#define	E0	2060219
#define	F0	2182726
#define	Gb0	2312517
#define	G0	2450027
#define	Ab0	2595713
#define	A0	2750062
#define	Bb0	2913589
#define	B0	3086840

#define	C1	3270393
#define	Db1	3464861
#define	D1	3670893
#define	Eb1	3889175
#define	E1	4120438
#define	F1	4365452
#define	Gb1	4625035
#define	G1	4900054
#define	Ab1	5191426
#define	A1	5500125
#define	Bb1	5827179
#define	B1	6173681

#define	C2	6540787
#define	Db2	6929723
#define	D2	7341786
#define	Eb2	7778351
#define	E2	8240876
#define	F2	8730904
#define	Gb2	9250070
#define	G2	9800108
#define	Ab2	10382853
#define	A2	11000250
#define	Bb2	11654358
#define	B2	12347363

#define	C3	13081575
#define	Db3	13859446
#define	D3	14683572
#define	Eb3	15556702
#define	E3	16481752
#define	F3	17461808
#define	Gb3	18500141
#define	G3	19600217
#define	Ab3	20765706
#define	A3	22000500
#define	Bb3	23308717
#define	B3	24694726

#define	C4	26163151
#define	Db4	27718893
#define	D4	29367144
#define	Eb4	31113405
#define	E4	32963504
#define	F4	34923616
#define	Gb4	37000283
#define	G4	39200434
#define	Ab4	41531413
#define	A4	44001000
#define	Bb4	46617435
#define	B4	49389452

#define	C5	52326302
#define	Db5	55437786
#define	D5	58734288
#define	Eb5	62226810
#define	E5	65927009
#define	F5	69847233
#define	Gb5	74000566
#define	G5	78400868
#define	Ab5	83062827
#define	A5	88002000
#define	Bb5	93234871
#define	B5	98778905

#define	C6	104652604
#define	Db6	110875572
#define	D6	117468576
#define	Eb6	124453621
#define	E6	131854019
#define	F6	139694467
#define	Gb6	148001132
#define	G6	156801737
#define	Ab6	166125654
#define	A6	176004000
#define	Bb6	186469742
#define	B6	197557810

#define	C7	209305209
#define	Db7	221751144
#define	D7	234937153
#define	Eb7	248907243
#define	E7	263708038
#define	F7	279388934
#define	Gb7	296002265
#define	G7	313603475
#define	Ab7	332251309
#define	A7	352008000
#define	Bb7	372939484
#define	B7	395115620

#define	C8	418610418
#define	Db8	443502288
#define	D8	469874307
#define	Eb8	497814487
#define	E8	527416077
#define	F8	558777869
#define	Gb8	592004530
#define	G8	627206951
#define	Ab8	664502618
#define	A8	704016000
#define	Bb8	745878969
#define	B8	790231241

#define	C9	837220836
#define	Db9	887004577
#define	D9	939748614
#define	Eb9	995628975
#define	E9	1054832155
#define	F9	1117555739
#define	Gb9	1184009061
#define	G9	1254413903
#define	Ab9	1329005236
#define	A9	1408032000
#define	Bb9	1491757939
#define	B9	1580462482

#endif

#ifndef __MUSIC_NOTE_H__
#define __MUSIC_NOTE_H__

unsigned int MUSIC_BPM=120;
#define	NOTE_4	(60/MUSIC_BPM)
#define	NOTE_8	(30/MUSIC_BPM)
#define	NOTE_16	(15/MUSIC_BPM)
#define	NOTE_32	(7.5/MUSIC_BPM)
#define	NOTE_64	(3.75/MUSIC_BPM)
#define	NOTE_2	(120/MUSIC_BPM)
#define	NOTE_1	(240/MUSIC_BPM)

#endif

附录:Cortex-M架构的SysTick系统定时器精准延时和MCU位带操作

SysTick系统定时器精准延时

延时函数

SysTick->LOAD中的值为计数值
计算方法为工作频率值/分频值
比如工作频率/1000 则周期为1ms

以ADuCM4050为例:

#include "ADuCM4050.h"

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 26000000/1000-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能52MHz的系统定时器
	while(ms--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 26000000/1000/1000-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能52MHz的系统定时器
	while(us--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}

其中的52000000表示芯片的系统定时器频率 32系列一般为外部定时器频率的两倍

Cortex-M架构SysTick系统定时器阻塞和非阻塞延时

阻塞延时

首先是最常用的阻塞延时

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 50000000/1000-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系统定时器
	while(ms--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 50000000/1000/1000-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系统定时器
	while(us--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}

50000000表示工作频率
分频后即可得到不同的延时时间
以此类推

那么 不用两个嵌套while循环 也可以写成:

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 50000000/1000*ms-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系统定时器

	while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 50000000/1000/1000*us-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系统定时器
	
	while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}

但是这种写法有个弊端
那就是输入ms后,最大定时不得超过计数值,也就是不能超过LOAD的最大值,否则溢出以后,则无法正常工作

而LOAD如果最大是32位 也就是4294967295

晶振为50M的话 50M的计数值为1s 4294967295计数值约为85s

固最大定时时间为85s

但用嵌套while的话 最大可以支持定时4294967295*85s

非阻塞延时

如果采用非阻塞的话 直接改写第二种方法就好了:

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 50000000/1000*ms-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系统定时器

	//while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	//SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 50000000/1000/1000*us-1; // Count from 255 to 0 (256 cycles)  载入计数值 定时器从这个值开始计数
	SysTick->VAL = 0; // Clear current value as well as count flag  清空计数值到达0后的标记
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系统定时器
	
	//while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	//SysTick->CTRL = 0; // Disable SysTick  关闭系统定时器
}

将等待和关闭定时器语句去掉
在使用时加上判断即可变为阻塞:

delay_ms(500);
while ((SysTick->CTRL & 0x00010000)==0);
SysTick->CTRL = 0;

在非阻塞状态下 可以提交定时器后 去做别的事情 然后再来等待

不过这样又有一个弊端 那就是定时器会自动重载 可能做别的事情以后 定时器跑过了 然后就要等85s才能停下

故可以通过内部定时器来进行非阻塞延时函数的编写

基本上每个mcu的内部定时器都可以配置自动重载等功能 网上资料很多 这里就不再阐述了

位带操作

位带代码

M3、M4架构的单片机 其输出口地址为端口地址+20 输入为+16
M0架构的单片机 其输出口地址为端口地址+12 输入为+8
以ADuCM4050为列:

位带宏定义
#ifndef __GPIO_H__
#define __GPIO_H__
#include "ADuCM4050.h"
#include "adi_gpio.h"

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

#define GPIO0_ODR_Addr    (ADI_GPIO0_BASE+20) //0x40020014
#define GPIO0_IDR_Addr    (ADI_GPIO0_BASE+16) //0x40020010

#define GPIO1_ODR_Addr    (ADI_GPIO1_BASE+20) //0x40020054
#define GPIO1_IDR_Addr    (ADI_GPIO1_BASE+16) //0x40020050

#define GPIO2_ODR_Addr    (ADI_GPIO2_BASE+20) //0x40020094
#define GPIO2_IDR_Addr    (ADI_GPIO2_BASE+16) //0x40020090

#define GPIO3_ODR_Addr    (ADI_GPIO3_BASE+20) //0x400200D4
#define GPIO3_IDR_Addr    (ADI_GPIO3_BASE+16) //0x400200D0

#define P0_O(n)   	BIT_ADDR(GPIO0_ODR_Addr,n)  //输出 
#define P0_I(n)    	BIT_ADDR(GPIO0_IDR_Addr,n)  //输入 

#define P1_O(n)   	BIT_ADDR(GPIO1_ODR_Addr,n)  //输出 
#define P1_I(n)    	BIT_ADDR(GPIO1_IDR_Addr,n)  //输入 

#define P2_O(n)   	BIT_ADDR(GPIO2_ODR_Addr,n)  //输出 
#define P2_I(n)    	BIT_ADDR(GPIO2_IDR_Addr,n)  //输入 

#define P3_O(n)   	BIT_ADDR(GPIO3_ODR_Addr,n)  //输出 
#define P3_I(n)    	BIT_ADDR(GPIO3_IDR_Addr,n)  //输入 

#define Port0			(ADI_GPIO_PORT0)
#define Port1			(ADI_GPIO_PORT1)
#define Port2			(ADI_GPIO_PORT2)
#define Port3			(ADI_GPIO_PORT3)

#define Pin0			(ADI_GPIO_PIN_0)
#define Pin1			(ADI_GPIO_PIN_1)
#define Pin2			(ADI_GPIO_PIN_2)
#define Pin3			(ADI_GPIO_PIN_3)
#define Pin4			(ADI_GPIO_PIN_4)
#define Pin5			(ADI_GPIO_PIN_5)
#define Pin6			(ADI_GPIO_PIN_6)
#define Pin7			(ADI_GPIO_PIN_7)
#define Pin8			(ADI_GPIO_PIN_8)
#define Pin9			(ADI_GPIO_PIN_9)
#define Pin10			(ADI_GPIO_PIN_10)
#define Pin11			(ADI_GPIO_PIN_11)
#define Pin12			(ADI_GPIO_PIN_12)
#define Pin13			(ADI_GPIO_PIN_13)
#define Pin14			(ADI_GPIO_PIN_14)
#define Pin15			(ADI_GPIO_PIN_15)

void GPIO_OUT(unsigned int port,unsigned int pin,unsigned int flag);
void GPIO_BUS_OUT(unsigned int port,unsigned int num);

void P0_BUS_O(unsigned int num);
unsigned int P0_BUS_I(void);

void P1_BUS_O(unsigned int num);
unsigned int P1_BUS_I(void);

void P2_BUS_O(unsigned int num);
unsigned int P2_BUS_I(void);

void P3_BUS_O(unsigned int num);
unsigned int P3_BUS_I(void);

#endif

总线函数
#include "ADuCM4050.h"
#include "adi_gpio.h"
#include "GPIO.h"

void GPIO_OUT(unsigned int port,unsigned int pin,unsigned int flag)
{
	switch(port)
	{
		case 0:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		case 1:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		case 2:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		case 3:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		default:port=0;break;
	}	
}

void GPIO_BUS_OUT(unsigned int port,unsigned int num)  //num最大为0xffff
{
	int i;
	for(i=0;i<16;i++)
	{
		GPIO_OUT(port,i,(num>>i)&0x0001);
	}
}


void P0_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P0_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P0_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P0_I(i)<<i)&0xFFFF;
	}
	return num;
}

void P1_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P1_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P1_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P1_I(i)<<i)&0xFFFF;
	}
	return num;
}

void P2_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P2_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P2_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P2_I(i)<<i)&0xFFFF;
	}
	return num;
}

void P3_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P3_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P3_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P3_I(i)<<i)&0xFFFF;
	}
	return num;
}

一、位带操作理论及实践

位带操作的概念其实30年前就有了,那还是 CM3 将此能力进化,这里的位带操作是 8051 位寻址区的威力大幅加强版

位带区: 支持位带操作的地址区

位带别名: 对别名地址的访问最终作 用到位带区的访问上(注意:这中途有一个 地址映射过程)

位带操作对于硬件 I/O 密集型的底层程序最有用处

支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在CM4中,有两个区中实现了位带。其中一个是SRAM区的最低1MB范围,第二个则是片内外设区的最低1MB范围。这两个区中的地址除了可以像普通的RAM一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个32位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。

位操作就是可以单独的对一个比特位读和写,类似与51中sbit定义的变量,stm32中通过访问位带别名区来实现位操作的功能
STM32中有两个地方实现了位带,一个是SRAM,一个是片上外设。
在这里插入图片描述
(1)位带本质上是一块地址区(例如每一位地址位对应一个寄存器)映射到另一片地址区(实现每一位地址位对应一个寄存器中的一位),该区域就叫做位带别名区,将每一位膨胀成一个32位的字。
(2)位带区的4个字节对应实际寄存器或内存区的一个位,虽然变大到4个字节,但实际上只有最低位有效(代表0或1)

只有位带可以直接用=赋值的方式来操作寄存器 位带是把寄存器上的每一位 膨胀到32位 映射到位带区 比如0x4002 0000地址的第0个bit 映射到位带区的0地址 那么其对应的位带映射地址为0x00 - 0x04 一共32位 但只有LSB有效 采用位带的方式用=赋值时 就是把位带区对应的LSB赋值 然后MCU再转到寄存器对应的位里面 寄存器操作时 如果不改变其他位上面的值 那就只能通过&=或者|=的方式进行

在这里插入图片描述

要设置0x2000 0000这个字节的第二个位bit2为1,使用位带操作的步骤有:
1、将1写入位 带别名区对应的映射地址(即0x22000008,因为1bit对应4个byte);
2、将0x2000 0000的值 读取到内部的缓冲区(这一步骤是内核完成的,属于原子操作,不需要用户操作);
3、将bit2置1,再把值写 回到0x2000 0000(属于原子操作,不需要用户操作)。

关于GPIO引脚对应的访问地址,可以参考以下公式
寄存器位带别名 = 0x42000000 + (寄存器的地址-0x40000000)32 + 引脚编号4

如:端口F访问的起始地址GPIOF_BASE

#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE)

在这里插入图片描述

但好在官方库里面都帮我们定义好了 只需要在BASE地址加上便宜即可

例如:

GPIOF的ODR寄存器的地址 = GPIOF_BASE + 0x14

寄存器位带别名 = 0x42000000 + (寄存器的地址-0x40000000)32 + 引脚编号4

设置PF9引脚的话:

uint32_t *PF9_BitBand =
*(uint32_t *)(0x42000000 + ((uint32_t )&GPIOF->ODR– 0x40000000) *32 + 9*4)

封装一下:

#define PFout(x) *(volatile uint32_t *)(0x42000000 + ((uint32_t )&GPIOF->ODR – 0x40000000) *32 + x*4)

现在 可以把通用部分封装成一个小定义:

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

那么 设置PF引脚的函数可以定义:

#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414   
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 

#define PF_O(n)   	BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PF_I(n)    	BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

若使PF9输入输出则:

PF_O(9)=1;  //输出高电平
uint8_t dat = PF_I(9);  //获取PF9引脚的值

总线输入输出:

void PF_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PF_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PF_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PF_I(i)<<i)&0xFFFF;
	}
	return num;
}

STM32的可用下面的函数:

#ifndef __GPIO_H__
#define __GPIO_H__
#include "stm32l496xx.h"

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
#define PA_O(n)   	BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PA_I(n)    	BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PB_O(n)   	BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PB_I(n)    	BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PC_O(n)   	BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PC_I(n)    	BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PD_O(n)   	BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PD_I(n)    	BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PE_O(n)   	BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PE_I(n)    	BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PF_O(n)   	BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PF_I(n)    	BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PG_O(n)   	BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PG_I(n)    	BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PH_O(n)   	BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PH_I(n)    	BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PI_O(n)			BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PI_I(n)   	BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

void PA_BUS_O(unsigned int num);
unsigned int PA_BUS_I(void);

void PB_BUS_O(unsigned int num);
unsigned int PB_BUS_I(void);

void PC_BUS_O(unsigned int num);
unsigned int PC_BUS_I(void);

void PD_BUS_O(unsigned int num);
unsigned int PD_BUS_I(void);

void PE_BUS_O(unsigned int num);
unsigned int PE_BUS_I(void);

void PF_BUS_O(unsigned int num);
unsigned int PF_BUS_I(void);

void PG_BUS_O(unsigned int num);
unsigned int PG_BUS_I(void);

void PH_BUS_O(unsigned int num);
unsigned int PH_BUS_I(void);

void PI_BUS_O(unsigned int num);
unsigned int PI_BUS_I(void);

#endif

#include "GPIO.h"

void PA_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PA_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PA_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PA_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PB_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PB_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PB_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PB_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PC_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PC_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PC_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PC_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PD_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PD_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PD_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PD_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PE_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PE_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PE_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PE_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PF_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PF_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PF_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PF_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PG_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PG_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PG_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PG_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PH_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PH_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PH_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PH_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PI_BUS_O(unsigned int num)  //输入值num最大为0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PI_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PI_BUS_I(void)  //输出值num最大为0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PI_I(i)<<i)&0xFFFF;
	}
	return num;
}

二、如何判断MCU的外设是否支持位带

根据《ARM Cortex-M3与Cortex-M4权威指南(第3版)》中第6章第7节描述
在这里插入图片描述
也就是说 要实现对GPIO的位带操作 必须保证GPIO位于外设区域的第一个1MB中
第一个1MB应该是0x4010 0000之前 位带不是直接操作地址 而是操作地址映射 地址映射被操作以后 MCU自动会修改对应寄存器的值

位带区只有1MB 所以只能改0x4000 0000 - 0x400F FFFF的寄存器
像F4系列 GPIO的首地址为0x4002 0000 就可以用位带来更改

STM32L476的GPIO就不行:
在这里插入图片描述
AHB2的都不能用位带
ABP 还有AHB1都可以用
在这里插入图片描述
但是L476的寄存器里面 GPIO和ADC都是AHB2

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
实现一个基于STM32按键电子密码锁可以分为以下步骤: 1. 硬件设计:根据需求选择合适的STM32型号和按键、LED等外设,设计电路原理图和PCB布局。 2. 软件开发:使用Keil等集成开发环境编写STM32C语言程序,包括按键扫描、密码输入、密码验证、锁开关控制等功能。 3. 调试测试:将程序烧录到STM32芯片中,通过串口调试工具等方式验证程序的正确性和稳定性。 下面是一个简单的示例程序,以实现4位数字密码锁为例: ```c #include "stm32f10x.h" // 按键GPIO端口和引脚定义 #define KEY_GPIO_PORT GPIOA #define KEY_GPIO_PIN GPIO_Pin_0 // LED GPIO端口和引脚定义 #define LED_GPIO_PORT GPIOB #define LED_GPIO_PIN GPIO_Pin_0 // 密码长度和正确密码定义 #define PASSWORD_LEN 4 const uint8_t PASSWORD[PASSWORD_LEN] = {1, 2, 3, 4}; // 按键状态枚举定义 typedef enum { KEY_RELEASED = 0, KEY_PRESSED } KeyStateTypeDef; // 按键扫描函数 KeyStateTypeDef KeyScan(void) { static uint8_t keyStatus = KEY_RELEASED; if (GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN) == Bit_RESET) { if (keyStatus == KEY_RELEASED) { keyStatus = KEY_PRESSED; return KEY_PRESSED; } } else { keyStatus = KEY_RELEASED; } return KEY_RELEASED; } // LED控制函数 void LedControl(uint8_t state) { if (state == Bit_SET) { GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN); } else { GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN); } } int main(void) { uint8_t passwordInput[PASSWORD_LEN] = {0}; uint8_t passwordIndex = 0; // 初始化GPIO端口 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 按键输入,浮空输入 GPIO_InitStructure.GPIO_Pin = KEY_GPIO_PIN; GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // LED输出,推挽输出 GPIO_InitStructure.GPIO_Pin = LED_GPIO_PIN; GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure); // 主循环 while (1) { // 按键扫描 if (KeyScan() == KEY_PRESSED) { // 密码输入 if (passwordIndex < PASSWORD_LEN) { passwordInput[passwordIndex++] = passwordIndex; LedControl(Bit_SET); } } // 密码验证 if (passwordIndex == PASSWORD_LEN) { uint8_t i; for (i = 0; i < PASSWORD_LEN; i++) { if (passwordInput[i] != PASSWORD[i]) { break; } } if (i == PASSWORD_LEN) { // 密码正确,打开锁 LedControl(Bit_RESET); } // 重置密码输入状态 passwordIndex = 0; passwordInput[0] = passwordInput[1] = passwordInput[2] = passwordInput[3] = 0; } } } ``` 以上示例程序仅实现了按键扫描和密码验证的功能,你可以根据实际需求添加更多功能,例如LCD显示、EEPROM存储、报警等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网易独家音乐人Mike Zhou

光电帝国,光联万物!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值