中级会员
 
- 积分
- 218
- 金钱
- 218
- 注册时间
- 2015-1-19
- 在线时间
- 28 小时
|
上次更新用SysTick生成精准延时之后,本次根据上期的代码,来进行一次外设的综合实验,包括蜂鸣器,LED,按键(外部中断+查询),使用的是战舰开发板,但是并没有使用战舰的代码。 当然还是有一个小问题,哪位朋友知道留言告诉我,不胜感激!!!
代码主要实现的就是:
主函数超循环中LED0以500ms周期闪烁,并且不断用查询法判断KEY1是否按下,如果按下蜂鸣器鸣叫,同时KEY0作为外部中断来进行按键的判断,进入中断后,LED1状态取反。
先上部分关键代码,随后说说自己的问题: led驱动:
[mw_shl_code=c,true]#ifndef __LED_H
#define __LED_H
#include "Delay.h"
#include "stm32f10x.h"
#define ON 1
#define OFF 0
void LED_Init(void);
void LED0_Run(u8 mode,u32 ms);
void LED1_Run(u8 mode,u32 ms);
#endif
[/mw_shl_code]
[mw_shl_code=c,true]#include "led.h"
/***
* 功能:LED初始化
* 参数:None
* 返回值:None
**/
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义IO结构,用于IO的初始化赋值
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE,ENABLE); //开相关IO时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //制定LED管脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置频率
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_5); //默认LED不亮
GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
/***
* 功能:LED0根据设定状态延时
* 参数:mode:ON,OFF ms:ms毫秒
* 返回值:None
**/
void LED0_Run(u8 mode,u32 ms)
{
if(mode)
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
else
GPIO_SetBits(GPIOB,GPIO_Pin_5);
Delay_ms(ms);
}
/***
* 功能:LED1根据设定状态延时
* 参数:mode:ON,OFF ms:ms毫秒
* 返回值:None
**/
void LED1_Run(u8 mode,u32 ms)
{
if(mode)
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
else
GPIO_SetBits(GPIOE,GPIO_Pin_5);
Delay_ms(ms);
}
[/mw_shl_code]
按键/外部中断驱动
[mw_shl_code=c,true]#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
#include "Delay.h"
void Key_Init(void);
void NVIC_Config(void);
char Key_Scan(void);
#endif[/mw_shl_code]
[mw_shl_code=c,true]#include "key.h"
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使用IO复用就要开复用时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置上拉
GPIO_Init(GPIOE,&GPIO_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line4;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式,还有一种是事件模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); //将IO和对应的外部中断联系起来
NVIC_Config(); //中断配置,这里我设置的是第2组
}
//按键扫描
char Key_Scan(void)
{
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3))
{
Delay_ms(10);
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3))
return 1;
else
return 0;
}
return 0;
}
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //设置中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //设置子优先级(响应优先级)为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开该中断源的中断使能
NVIC_Init(&NVIC_InitStructure);
}
void EXTI4_IRQHandler(void)
{
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0)
GPIOE->ODR ^= GPIO_Pin_5; //状态取反
EXTI_ClearITPendingBit(EXTI_Line4); //标志位清除
/*****************以下为问题代码****************/
// EXTI->IMR &= ~EXTI_Line4; //外部中断4中断失能
// Delay_ms(10);
// if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0) //确保是否产生了EXTI Line中断
// {
// GPIOE->ODR ^= GPIO_Pin_5;
// EXTI_ClearITPendingBit(EXTI_Line4); //清除中断标志位
// }
// EXTI->IMR |= EXTI_Line4; //外部中断4使能
}
[/mw_shl_code]
蜂鸣器驱动
[mw_shl_code=c,true]#ifndef __BEEP_H
#define __BEEP_H
#include "stm32f10x.h"
void Beep_Init(void);
#endif
[/mw_shl_code]
[mw_shl_code=c,true]#include "beep.h"
void Beep_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
}
[/mw_shl_code]
主函数:
[mw_shl_code=c,true]#include "Delay.h"
#include "led.h"
#include "key.h"
#include "beep.h"
int main()
{
SysTick_Init();
Beep_Init();
LED_Init();
Key_Init();
for(;;)
{
if(Key_Scan()==1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_8);
Delay_ms(300);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
Delay_ms(300);
}
LED0_Run(ON,500);
LED0_Run(OFF,500);
}
}
[/mw_shl_code]
在开发过程中,如果是裸机的程序去跑的话,最让人头疼的就是主函数中延时会对整个系统的实时性产生很糟糕的影响,其中一个比较典型的就是按键在主函数中进行扫描(当然可以使用定时器定时查询或者外部中断,这里并不考虑这种情况),假设一个完整的循环需要1s,那么由于你按键按下的时间是随机的,最好的情况是,你刚按下就被扫描到了,最糟糕的情况是,扫描刚刚执行,你还要等上1s钟才行。
现在我说说我遇到的问题:
众所周知,按键按下会有一段时间的电平跳变,如果用中断去采集按键的话,最让人头疼的就是,按一下会有多次外部中断动作发生,因此最常用的就是进入中断线延时一会,战舰就是这么做的,但是当我用我自己封装的延时函数进行延时时,程序会卡死,也就是说主函数中的LED和蜂鸣器状态会一直卡死在进中断时的样子,而且不可退出,但是外部中断仍能发生,并且中断程序执行正确。
也就是说问题代码出现在:Delay_ms();但是这个功能是正确的 ,为什么会出现这种问题很有意思,哪位知道可以告诉我一下。
|
|