OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 8306|回复: 19

按键短按灯亮六秒后灭,长按三秒灯亮三秒后灭

[复制链接]

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
发表于 2018-10-10 11:53:30 | 显示全部楼层 |阅读模式
本帖最后由 jiangyy 于 2018-10-10 11:55 编辑

  今天闲着无聊,一个新手请教我一个问题:短按 SW1 后,LED1亮6秒然后灭。长按SW1三秒后松开,LED1亮3秒后灭。闲着无聊,就写了一下。我的思路大概是这样的:外部中断+定时器
1.定时器3
  配置好后定时器3,默认不使能定时器。
void TIM3_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  TIM_TimeBaseInitStructure.TIM_Period = arr;  
  TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  
  TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
  TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
  TIM_Cmd(TIM3,DISABLE);
  NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
2.SW1引脚配置成外部中断
void EXTIX_Init(void)
{
  NVIC_InitTypeDef   NVIC_InitStructure;
  EXTI_InitTypeDef   EXTI_InitStructure;
  KEY_Init(); //这里按键配置就不说了
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;//LINE0
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;//ʹÄÜLINE0
  EXTI_Init(&EXTI_InitStructure);
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  
}
  3.中断服务函数处理
(1)定时器中断服务函数
u16 ucTimer = 0;
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
{
  ucTimer++;
  if(WK_UP)
  {
   if(ucTimer ==300)//3S
   {
    handle_Led(ON,3);
    ucTimer = 0;
    TIM_Cmd(TIM3,DISABLE);
   }
  }
  else
  {
   handle_Led(ON,6);
   ucTimer = 0;
   TIM_Cmd(TIM3,DISABLE);
  }
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
  (2)外部中断函数
void EXTI0_IRQHandler(void)
{
delay_ms(10);
if(WK_UP)
{
  TIM_Cmd(TIM3,ENABLE);
}
EXTI_ClearITPendingBit(EXTI_Line0);
}

4.LED函数
void Led_ON(void)
{
  GPIO_ResetBits(GPIOF, GPIO_Pin_9); // 1- ON
}

void Led_OFF(void)
{
  GPIO_SetBits(GPIOF, GPIO_Pin_9); // 0- OFF
}
void handle_Led(u8 ucSwitch, u8 usCnt)
{
if (ucSwitch == ON)
{
  int i;
  for(i = 0; i < usCnt; i++)
  {
    Led_ON();
    delay_ms(1000);
  }
   Led_OFF();
}
else
{
   Led_OFF();
}
}

5.主函数
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init(168);
uart_init(115200);  
LED_Init();   
EXTIX_Init();   
TIM3_Int_Init(100-1,8400-1); //10ms
while(1)
{
  LED1 = !LED1;
  delay_ms(1000);
}
}

  简单程序,练练手。不知道其他高手有没有其他有效的办法,请分享一下。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

31

帖子

0

精华

高级会员

Rank: 4

积分
535
金钱
535
注册时间
2018-8-2
在线时间
54 小时
发表于 2018-10-10 13:37:57 | 显示全部楼层
简单一点,在系统1ms滴答里面检测按键是否被按下,并用一个变量记录按键按下的时间,之后的亮灭灯操作就再定义一个变量在滴答里面自减就好了
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-10 13:56:29 | 显示全部楼层
tgw860910 发表于 2018-10-10 13:37
简单一点,在系统1ms滴答里面检测按键是否被按下,并用一个变量记录按键按下的时间,之后的亮灭灯操作就再 ...

具体怎么实现?有代码分享的吗?查了有关资料,关于滴答定时器资料很少
回复 支持 反对

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-10-10 16:02:00 | 显示全部楼层
本帖最后由 1208 于 2018-10-10 16:58 编辑

楼主,程序实现效果如何
怎么不把程序压缩包一起展示出来
这是我以前写的帖子http://www.openedv.com/forum.php ... d=274729&extra=
业精于勤荒于嬉;行成于思毁于随!
回复 支持 反对

使用道具 举报

0

主题

31

帖子

0

精华

高级会员

Rank: 4

积分
535
金钱
535
注册时间
2018-8-2
在线时间
54 小时
发表于 2018-10-10 16:59:24 | 显示全部楼层
jiangyy 发表于 2018-10-10 13:56
具体怎么实现?有代码分享的吗?查了有关资料,关于滴答定时器资料很少

滴答定时器的调用,在标准库里是这个函数 SysTick_Handler,一般在系统初始化的时候先 SysTick_Config(SystemCoreClock / 1000) 就可以了;在HAL库里是这个函数 HAL_SYSTICK_Callback,用CUBE生成的代码里都是已经配置好的;至于之后怎样处理按键就按你现在的做法去做就好,稍微修改一下就行;用系统滴答只是可以让你少配置定时器和一些外部中断而已
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-11 11:30:23 | 显示全部楼层
1208 发表于 2018-10-10 16:02
楼主,程序实现效果如何
怎么不把程序压缩包一起展示出来
这是我以前写的帖子http://www.openedv.com/f ...

公司的电脑加了密,放上去都是乱码。主要代码在上面写的
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-11 11:36:16 | 显示全部楼层
tgw860910 发表于 2018-10-10 16:59
滴答定时器的调用,在标准库里是这个函数 SysTick_Handler,一般在系统初始化的时候先 SysTick_Config(Sy ...

那不是相当于用一个定时器就可以搞定了,不需要外部中断处理。在定时器中断服务函数里面,我只判断按键是否按下,检测IO口是否一直处于高电平。
u16 ucTimer = 0;
void TIM3_IRQHandler(void)
{
  ucTimer ++;
  if(WAKE_UP)
  {
     if(ucTimer ==300)//3S
    {
     handle_Led(ON,3);
     ucTimer = 0;
    }
  }
}

那就是一直开着定时器,只是用一个全局变量来判断时间是否到了,到了就讲这个全局变量清零,作出灯的操作。和你说的差不多吧?
回复 支持 反对

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-10-11 11:45:34 | 显示全部楼层
jiangyy 发表于 2018-10-11 11:30
公司的电脑加了密,放上去都是乱码。主要代码在上面写的

没事,昨晚代码被我调试出来了,挺不错的
业精于勤荒于嬉;行成于思毁于随!
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-11 11:51:22 | 显示全部楼层
1208 发表于 2018-10-10 16:02
楼主,程序实现效果如何
怎么不把程序压缩包一起展示出来
这是我以前写的帖子http://www.openedv.com/f ...

按键KEY0单击、双击、长按和串口实现灯的控制状态,按键KEY1中断,控制灯亮5秒后熄灭
你的设计要求对吧?
我觉得按键IO口作为输入捕获就可以了。串口控制那个很简单(一个字节接受判断就可以处理)。
至于设计思路,我到时候再想想。要么一个上升沿检测,计算时间差,或者两个上升沿检测
回复 支持 反对

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-10-11 12:02:34 | 显示全部楼层
jiangyy 发表于 2018-10-11 11:51
按键KEY0单击、双击、长按和串口实现灯的控制状态,按键KEY1中断,控制灯亮5秒后熄灭
你的设计要求对吧 ...

是对的,可以实现的,按键的灵敏性还有待提高
串口控制确实简单,可以一步到位
就是按键需要判断
这个按键IO作为输入捕获还没试过
要是你
你会怎么写
很期待
业精于勤荒于嬉;行成于思毁于随!
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-11 14:45:05 | 显示全部楼层
1208 发表于 2018-10-11 12:02
是对的,可以实现的,按键的灵敏性还有待提高
串口控制确实简单,可以一步到位
就是按键需要判断

你是用我的代码调试出来的,还是你自己以前写的?后面我再想想用输入捕获看看
回复 支持 反对

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-10-11 16:09:12 | 显示全部楼层
jiangyy 发表于 2018-10-11 14:45
你是用我的代码调试出来的,还是你自己以前写的?后面我再想想用输入捕获看看

我之前那个已经写好的,可以实现的
删掉我之前写的,换成你的程序就可以实现你的功能
我也想看下输入捕获
不过这时间差和上升沿得要怎么处理
你想好了么
业精于勤荒于嬉;行成于思毁于随!
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-11 16:20:05 | 显示全部楼层
1208 发表于 2018-10-11 16:09
我之前那个已经写好的,可以实现的
删掉我之前写的,换成你的程序就可以实现你的功能
我也想看下输入捕 ...

比较忙,忙着搞fatfs,一直写入失败。要不你加我QQ2223210985,QQ聊。到时候想好了黏贴上这里。
回复 支持 反对

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-10-11 17:54:24 | 显示全部楼层
jiangyy 发表于 2018-10-11 16:20
比较忙,忙着搞fatfs,一直写入失败。要不你加我QQ2223210985,QQ聊。到时候想好了黏贴上这里。

好的
业精于勤荒于嬉;行成于思毁于随!
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-12 16:24:05 | 显示全部楼层

开启一个定时器就可以了,定时器常开。核心代码如下:
u16 ucTimer_led = 0;

void TIM3_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //&Ograve;&ccedil;&sup3;&ouml;&Ouml;&ETH;&para;&Iuml;
        {
               
                if(WK_UP)
                {
                        ucTimer_led++;
                }
                else
                {
                        if(ucTimer_led > 300)        //ucTimer_led >3s
                        {
                                handle_Led(ON,3);
                        }
                        else if(ucTimer_led <50 && ucTimer_led >30)//0.3s< ucTimer_led <0.5s
                        {
                                handle_Led(ON,6);
                        }
                        ucTimer_led = 0;
                }               
        }
        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  
}
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-12 16:49:18 | 显示全部楼层
上面代码有一些BUG, if(WK_UP){...}没有做上限,如果一直按着不放,会有问题的。更改的代码如下:
u16 ucTimer_led = 0;

void TIM3_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
        {
               
                if(WK_UP)
                {
                        ucTimer_led++;
                        if(ucTimer_led > 500)
                        {
                                ucTimer_led= 0;
                                return;
                        }                       
                }
                else
                {
                        if(ucTimer_led > 300 && ucTimer_led < 400)        //3s< ucTimer_led < 4s
                        {
                                handle_Led(ON,3);
                        }
                        else if(ucTimer_led <100 && ucTimer_led >50)//0.5s< ucTimer_led <1s
                        {
                                handle_Led(ON,6);
                        }
                        ucTimer_led = 0;
                }               
        }
        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  
}
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-12 17:05:49 | 显示全部楼层
有高手说,在这个地方会有隐形的BUG,如下:
if(WK_UP)
{
   ucTimer_led++;
   if(ucTimer_led > 500)
   {
      ucTimer_led= 0;
     return;
   }                        
}

他说,那个变量uctimer_led会一直加  到了500后,被  清0 ,然后还是会加,又到500,…………如果你中间松手,有可能就会在500以内的某个值。可我测试的时候,没发现不正常。按着大概在3-4S的时候,会亮,一直按着不会亮。后来我改了一下代码,如下:
if(WK_UP)
{
   ucTimer_led++;
   if(ucTimer_led > 500)
   {
      ucTimer_led= 500;
   }                        
}
测试结果,一样。请问高手们指点迷津,有什么隐形的BUG吗?
回复 支持 反对

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-10-15 12:43:26 | 显示全部楼层
我把你这个加到外部中断里面,比在定时器里好一点,但也会出现按键失灵
[mw_shl_code=c,true]extern u16 ucTimer_led;
//外部中断0服务程序
void EXTI0_IRQHandler(void)
{

        if(WK_UP==1)
        {
                   TIM_Cmd(TIM3,ENABLE);
                        ucTimer_led++;
                   if(ucTimer_led > 500)
                   {
                          ucTimer_led= 500;                                                                  
                   }                        
        }
        else
        {
                        if(ucTimer_led > 200 && ucTimer_led < 400)        //3s< ucTimer_led < 4s
                        {
                                        handle_Led(ON,1);
                        }
                        else if(ucTimer_led <100 && ucTimer_led >5)//0.5s< ucTimer_led <1s
                        {
                                        handle_Led(ON,6);
                        }
                        ucTimer_led = 0;
        }               
        
EXTI_ClearITPendingBit(EXTI_Line0);
}[/mw_shl_code]

探索者:实验8 定时器中断实验.zip

4.71 MB, 下载次数: 19

业精于勤荒于嬉;行成于思毁于随!
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2106
金钱
2106
注册时间
2017-2-11
在线时间
307 小时
 楼主| 发表于 2018-10-15 14:49:29 | 显示全部楼层
1208 发表于 2018-10-15 12:43
我把你这个加到外部中断里面,比在定时器里好一点,但也会出现按键失灵
[mw_shl_code=c,true]extern u16 u ...

框架在于构造,细节在于优化
回复 支持 反对

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-10-15 15:53:56 | 显示全部楼层
jiangyy 发表于 2018-10-15 14:49
框架在于构造,细节在于优化

哈哈!所以我想看你细节如何优化
业精于勤荒于嬉;行成于思毁于随!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 12:25

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表