OpenEdv-开源电子网

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

按键长按短按识别的同一程序,在裸奔程序中能正常运行,而在移植了OS的任务中不能正常运行

[复制链接]

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
发表于 2020-3-1 12:25:00 | 显示全部楼层 |阅读模式
1金钱
按键长按短按识别的同一程序,在裸奔程序中能正常运行,而在移植了OS的任务中不能正常运行,就是下面的按键扫描程序void KEY_Scan(void)


if(KEY2_DOWN)
         {
                key3_cnt=0;
                key3_Lock=0;                //自锁
               
                  if(key3_Flag==1)  //短按触发标志
          {
                      key3_Flag=0;
                 Key3Sec_1=!Key3Sec_1;    //短按值
   
          }
          }
else if(key3_Lock==0)
                {       
          key3_cnt++;
        
          if(key3_cnt>20)
                     {
             key3_Flag=1;   //激活按键短按的有效标志
                         
                     }
                    
                if(key3_cnt>3000)
               {
                  key3_Flag=0;             //清除按键短按的有效标志
                          key3_cnt=0;
                key3_Lock=1;            //自锁按键置位,避免一直触发
                        Key3Sec_2++;    //长按值
                        if(Key3Sec_2>6)Key3Sec_2=0;
                        LED_Flag=!LED_Flag;
          }


                };






程序放到带的OS单片机程序中只有长按值有效,短按无效,在裸奔程序中上面程序是放到定时器中间中的,在OS系统的单片机程序是放在任务中执行的




最佳答案

查看完整内容[请看2#楼]

感谢大家支持,问题终于解决,并不是增加节拍问题
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-1 12:25:01 | 显示全部楼层
感谢大家支持,问题终于解决,并不是增加节拍问题
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-1 15:48:43 | 显示全部楼层
既然用RTOS编程就要摒弃传统编程模式,你不能把传统编程模式的程序代码简单的放到任务中就算完事啦!
回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-1 17:10:53 | 显示全部楼层
有没有RTOS编程的按键识例程
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-2 10:30:02 | 显示全部楼层
1、你要把按键完整的程序贴出来呀!还有,RTOS编程下,任务之间通信(一个任务写全局变量,另外一个任务读全局变量)时,要确保变量原子的完整性。

    2、程序放到带的OS单片机程序中只有长按值有效,短按无效,在裸奔程序中上面程序是放到定时器中间中的,在OS系统的单片机程序是放在任务中执行的。
      你怎么把按键程序代码放到 【定时器中断服务程序中】呢?
      你这么写代码是要被老师挨板子的,完全可以在 【定时器中断服务程序中】置个标识,然后在主程序中检测标识,如果有标识就执行呀!

   
回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-2 15:26:36 | 显示全部楼层
#include <stdio.h>
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include  "NOK5110.h"
#include "timer.h"


/*************************************************************************/
#define START_TASK_PRIO     1            //任务优先级
#define START_STK_SIZE      128         //任务堆栈大小
TaskHandle_t StartTask_Handler;          //任务句柄
void start_task(void *pvParameters);     //任务函数

#define KEY_TASK_PRIO      12
#define KEY_STK_SIZE       128
TaskHandle_t KEYTask_Handler;
void key_task(void *p_arg);

#define TASK1_TASK_PRIO      6
#define TASK1_STK_SIZE       128
TaskHandle_t TASK1Task_Handler;
void task1_task(void *p_arg);

#define TASK2_TASK_PRIO      9
#define TASK2_STK_SIZE       128
TaskHandle_t TASK2Task_Handler;
void task2_task(void *p_arg);

#define TASK3_TASK_PRIO      9
#define TASK3_STK_SIZE       128
TaskHandle_t TASK3Task_Handler;
void task3_task(void *p_arg);

#define TASK4_TASK_PRIO      6
#define TASK4_STK_SIZE       128
TaskHandle_t TASK4Task_Handler;
void task4_task(void *p_arg);


#define TASK5_TASK_PRIO      7
#define TASK5_STK_SIZE       128
TaskHandle_t TASK5Task_Handler;
void task5_task(void *p_arg);

#define TASK6_TASK_PRIO      8
#define TASK6_STK_SIZE       128
TaskHandle_t TASK6Task_Handler;
void task6_task(void *p_arg);

#define TASK7_TASK_PRIO      9
#define TASK7_STK_SIZE       128
TaskHandle_t TASK7Task_Handler;
void task7_task(void *p_arg);

#define TASK8_TASK_PRIO      10
#define TASK8_STK_SIZE       128
TaskHandle_t TASK8Task_Handler;
void task8_task(void *p_arg);


#define TASK9_TASK_PRIO      11
#define TASK9_STK_SIZE       128
TaskHandle_t TASK9Task_Handler;
void task9_task(void *p_arg);

#define TASK10_TASK_PRIO      12
#define TASK10_STK_SIZE       128
TaskHandle_t TASK10Task_Handler;
void task10_task(void *p_arg);



void k2_Scan()
{
        static int k2_cnt=0;
        static u8  k2_Lock=0;
        static u8  k2_Flag=0;
       
  if(KEY2)
         {
                k2_cnt=0;
                k2_Lock=0;                //自锁
       
                  if(k2_Flag==1)  //短按触发标志
          {
                      k2_Flag=0;
                 K2Sec_1=1;                    //触发一号键的短按
                 //printf("短按值:%d\r\n",K2Sec_1);
          }
          }
else if(k2_Lock==0)
                {       
          k2_cnt++;
        
          if(k2_cnt>20)
                     {
             k2_Flag=1;   //激活按键短按的有效标志
                                printf("激活值:%d\r\n",k2_Flag);
                     }
                    
                if(k2_cnt>1000)
               {
                  k2_Flag=0;             //清除按键短按的有效标志
                          k2_cnt=0;
                k2_Lock=1;            //自锁按键置位,避免一直触发
                        K2Sec_2++;
                        if(K2Sec_2>3)K2Sec_2=0;
                    
          }

                };

       
}
       


/*************************************************************************/
int main(void)
{
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);   //设置系统中断优先级分组4
        delay_init();
        uart_init(115200);

        KEY_Init();

         xTaskCreate((TaskFunction_t    )start_task,           //任务函数
                     (const char*       )"start_task",         //任务名称
                                                         (uint16_t          )START_STK_SIZE,       //任务堆栈大小
                                                         (void *            )NULL,                 //传递给任务函数的参数
                                                         (UBaseType_t       )START_TASK_PRIO,      //任务优先级
                                                         (TaskHandle_t *    )&StartTask_Handler);  //任务句柄
         vTaskStartScheduler();                                //开启任务调度
                                       
}
void start_task(void *pvParameters)
{
        taskENTER_CRITICAL();                                   //进入临界区
        //创建LED0任务
               
        xTaskCreate((TaskFunction_t    )key_task,                         //任务1
                    (const char*       )"key_task",
                                                        (uint16_t          )KEY_STK_SIZE,
                                                        (void *                                                 )NULL,
                                                        (UBaseType_t       )KEY_TASK_PRIO,
                                                        (TaskHandle_t*     )&KEYTask_Handler);   
                                                       

       
                                                                                                                 
    vTaskDelete(StartTask_Handler);                      //删除开始任务
        taskEXIT_CRITICAL();                                   //退出临界区
       
       
}

void key_task(void * pvParameters)
{

         
        while(1)
        {
               
       
                  k2_Scan();
             
        }
       
       
}




回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-2 15:44:36 | 显示全部楼层
上面按键长短按识别程序在裸系统中能运行,在OS中无法正常运行
回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-2 16:02:29 | 显示全部楼层
下面这个程序是个按键长按短按识别程序 ,程序在裸系统中能正常,在OS中无法正常运行,贴出OS程序求高手指点、
#include <stdio.h>
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include  "NOK5110.h"
#include "timer.h"


/*************************************************************************/
#define START_TASK_PRIO     1            //任务优先级
#define START_STK_SIZE      128         //任务堆栈大小
TaskHandle_t StartTask_Handler;          //任务句柄
void start_task(void *pvParameters);     //任务函数

#define KEY_TASK_PRIO      12
#define KEY_STK_SIZE       128
TaskHandle_t KEYTask_Handler;
void key_task(void *p_arg);




void k2_Scan()
{
        static int k2_cnt=0;
        static u8  k2_Lock=0;
        static u8  k2_Flag=0;
       
  if(KEY2)
         {
                k2_cnt=0;
                k2_Lock=0;                //自锁
       
                  if(k2_Flag==1)  //短按触发标志
          {
                      k2_Flag=0;
                 K2Sec_1=1;                    //触发一号键的短按
                 printf("短按值:%d\r\n",K2Sec_1);
          }
          }
else if(k2_Lock==0)
                {       
          k2_cnt++;
        
          if(k2_cnt>20)
                     {
             k2_Flag=1;   //激活按键短按的有效标志
                                printf("激活值:%d\r\n",k2_Flag);
                     }
                    
                if(k2_cnt>1000)
               {
                  k2_Flag=0;             //清除按键短按的有效标志
                          k2_cnt=0;
                k2_Lock=1;            //自锁按键置位,避免一直触发
                        K2Sec_2++;
                        if(K2Sec_2>3)K2Sec_2=0;
                            printf("长按值:%d\r\n",k2_Flag);
          }

                };

       
}
       


/*************************************************************************/
int main(void)
{
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);   //设置系统中断优先级分组4
        delay_init();
        uart_init(115200);

        KEY_Init();

         xTaskCreate((TaskFunction_t    )start_task,           //任务函数
                     (const char*       )"start_task",         //任务名称
                                                         (uint16_t          )START_STK_SIZE,       //任务堆栈大小
                                                         (void *            )NULL,                 //传递给任务函数的参数
                                                         (UBaseType_t       )START_TASK_PRIO,      //任务优先级
                                                         (TaskHandle_t *    )&StartTask_Handler);  //任务句柄
         vTaskStartScheduler();                                //开启任务调度
                                       
}
void start_task(void *pvParameters)
{
        taskENTER_CRITICAL();                                   //进入临界区
        //创建LED0任务
               
        xTaskCreate((TaskFunction_t    )key_task,                         //任务1
                    (const char*       )"key_task",
                                                        (uint16_t          )KEY_STK_SIZE,
                                                        (void *                                                 )NULL,
                                                        (UBaseType_t       )KEY_TASK_PRIO,
                                                        (TaskHandle_t*     )&KEYTask_Handler);   
                                                       

       
                                                                                                                 
    vTaskDelete(StartTask_Handler);                      //删除开始任务
        taskEXIT_CRITICAL();                                   //退出临界区
       
       
}

void key_task(void * pvParameters)
{

         
        while(1)
        {
               
       
                  k2_Scan();
             
        }
       
       
}





回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-3 08:49:14 | 显示全部楼层
本帖最后由 霸王猫 于 2020-3-3 14:10 编辑

void key_task(void * pvParameters)
{

         
        while(1)
        {
                     
                  k2_Scan();
                 vTaskDelay(100 / portTICK_RATE_MS);  //增加延时节拍函数
              
        }

   请增加增加延时节拍函数vTaskDelay(100 / portTICK_RATE_MS),(1)、可以进行任务切换,否则你其它任务无法执行 (2)、相当于前后台程序中,你将这段程序放在定时器中执行,每隔100个时钟节拍执行一次(一个时钟节拍=1毫秒)
        
        
}
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-3 10:01:28 | 显示全部楼层
本帖最后由 霸王猫 于 2020-3-3 10:09 编辑

兄弟,看来你RTOS操作系统还没有入门呀,就强行在项目中使用操作系统编程呀!

   给你提供2本书,可以加快你跨入RTOS操作系统大门。

   1、嵌入式实时操作系统μCOS-Ⅱ原理及应用   作者:任哲  北京航空航天大学出版社
        主要通过编程实例的方式讲解RTOS的每个API该如何使用,学完这本书,然后把书上的例子你都输入到电脑中运行,
你就知道UCOSII是干什么的啦,能够熟练使用主要的API该怎么用。

   2、基于嵌入式实时操作系统的程序设计技术   作者:周慈航  北京航空航天大学出版社
        主要用于实战编程。讲解了实际应用中该如何组合使用UCOSII中的API进行编程,实现相应的功能。
        同时更重要的是作者对UCOSII中的API进行了高度概括、归纳和总结,然后分成几章。每一章都讲解了这些API主要想使用什么功能,用途是什么。
        总之,第二本书《基于嵌入式实时操作系统的程序设计技术   作者:周慈航》是你学完理论,跨入实际应用不可多得的一本好书,我至今在市面上还没有发现比这本书写得更好的书籍。

回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-4 11:31:53 | 显示全部楼层
我正在学习中,看了好多OS的例子,就是没有按键长按短按识别的例程,
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-4 12:05:43 | 显示全部楼层
本帖最后由 霸王猫 于 2020-3-4 12:09 编辑
wis98 发表于 2020-3-4 11:31
我正在学习中,看了好多OS的例子,就是没有按键长按短按识别的例程,

   兄弟,你的按键任务打个比方100毫秒执行一次 vTaskDelay(100 / portTICK_RATE_MS)

      设置一个计时器key3_cnt,计时即可。
            只是FREERTOS的vTaskDelay函数计时不太准确,但是不会影响你判断长按键还是短按键)

     void key_task(void * pvParameters)
{
     
        while(1)
        {
                  k2_Scan();
                  key3_cnt++;
                 vTaskDelay(100 / portTICK_RATE_MS);  //增加延时节拍函数
        }

    该按键任务每隔100毫秒执行一次,key3_cnt++,则当key3_cnt从0加到10时,代表按键被连续按下1秒。


   其实编写按键长按短按识别的例程和你在前后台编程差不多。
         1、前后台时,你把按键程序放在定时中断程序中,不就是为了确保100毫秒执行一次吗(定时中断时长=100毫秒)?你程序中的计时器每加1次,就过去了100毫秒,计时器从0加到30,就代表按键被连续按下3秒。
          2、在FREERTOS下,任务中调用vTaskDelay(10 0/ portTICK_RATE_MS);  //延时节拍100毫秒函数
                  和你在定时中断中调用是同样的道理。
               FREERTOS下,按键任务中调用vTaskDelay(100 / portTICK_RATE_MS),表示执行到该API函数后,CPU让出该按键任务的控制权,让CPU去调度其它任务,这100毫秒钟内不可能调度该按键任务啦!



回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-5 09:46:59 | 显示全部楼层
谢谢高手指点,
回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-6 11:07:55 | 显示全部楼层
根据高手指点修改了长按短按识别程序,放到任务中,只有短按能识别,长按还是无法识别,程序如下:

#define const_key_time_short1  20    //短按的按键去抖动延时的时间
#define const_key_time_long1   400     //长按的按键去抖动延时的时间

#define const_key_time_short2  20    //短按的按键去抖动延时的时间
#define const_key_time_long2   400     //长按的按键去抖动延时的时间

void task4_task(void * pvParameters)
{
          static int uiKeyTimeCnt1=0;
    //static int uiKeyCtntyCnt1=0;
    //static int uiCtntySynSet1=0;
    //static int uiCtntyTimeSet1=0;
    //static int uiSynCtntyCnt1=0;
        static u8  ucKeyLock1=0;
        static u8  ucShortTouchFlag1=0;
   
  while(1)       
        {
       
       

  if(KEY2==1)//IO是高电平,说明两个按键没有全部被按下,这时要及时清零一些标志位
  {
      ucKeyLock1=0; //按键自锁标志清零
      uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。   
            if(ucShortTouchFlag1==1)  //短按触发标志
          {
             ucShortTouchFlag1=0;
                 K2Sec_1=1;    //触发一号键的短按
          }
  }
  else if(ucKeyLock1==0)//有按键按下,且是第一次被按下
  {
     uiKeyTimeCnt1++; //累加定时中断次数
     if(uiKeyTimeCnt1>const_key_time_short1)
     {
            ucShortTouchFlag1=1;   //激活按键短按的有效标志  
     }

     if(uiKeyTimeCnt1>const_key_time_long1)
     {
            ucShortTouchFlag1=0;  //清除按键短按的有效标志

        uiKeyTimeCnt1=0;
        ucKeyLock1=1;  //自锁按键置位,避免一直触发

        K2Sec_1=2;    //触发1号键的长按
              
     }

  }


printf("task-2:%d\r\n",K2Sec_1);

           vTaskDelay(100 / portTICK_RATE_MS);  //增加延时节拍函数
        }
}
回复

使用道具 举报

4

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
184
金钱
184
注册时间
2017-10-13
在线时间
71 小时
 楼主| 发表于 2020-3-6 11:09:28 | 显示全部楼层
根据高手指点修改了长按短按识别程序,放到任务中,只有短按能识别,长按还是无法识别,程序如下:

#define const_key_time_short1  20    //短按的按键去抖动延时的时间
#define const_key_time_long1   400     //长按的按键去抖动延时的时间

#define const_key_time_short2  20    //短按的按键去抖动延时的时间
#define const_key_time_long2   400     //长按的按键去抖动延时的时间

void task4_task(void * pvParameters)
{
          static int uiKeyTimeCnt1=0;
    //static int uiKeyCtntyCnt1=0;
    //static int uiCtntySynSet1=0;
    //static int uiCtntyTimeSet1=0;
    //static int uiSynCtntyCnt1=0;
        static u8  ucKeyLock1=0;
        static u8  ucShortTouchFlag1=0;
   
  while(1)       
        {
       
       

  if(KEY2==1)//IO是高电平,说明两个按键没有全部被按下,这时要及时清零一些标志位
  {
      ucKeyLock1=0; //按键自锁标志清零
      uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。   
            if(ucShortTouchFlag1==1)  //短按触发标志
          {
             ucShortTouchFlag1=0;
                 K2Sec_1=1;    //触发一号键的短按
          }
  }
  else if(ucKeyLock1==0)//有按键按下,且是第一次被按下
  {
     uiKeyTimeCnt1++; //累加定时中断次数
     if(uiKeyTimeCnt1>const_key_time_short1)
     {
            ucShortTouchFlag1=1;   //激活按键短按的有效标志  
     }

     if(uiKeyTimeCnt1>const_key_time_long1)
     {
            ucShortTouchFlag1=0;  //清除按键短按的有效标志

        uiKeyTimeCnt1=0;
        ucKeyLock1=1;  //自锁按键置位,避免一直触发

        K2Sec_1=2;    //触发1号键的长按
              
     }

  }


printf("task-2:%d\r\n",K2Sec_1);

           vTaskDelay(100 / portTICK_RATE_MS);  //增加延时节拍函数
        }
}
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-6 11:50:32 | 显示全部楼层
你的按键程序太复杂啦!

   建议做个结构体,结构体如下:

       uint8_t key_code;//按键码
       uint8_t key_type;//按键类型  0=短按键,1=长按键
       uint16_t key_time;// 如果是长按键,则为按键计时时间

  然后初始化时,先把每个按键的键码、键类型和按键时间分别填写到【结构体数组】中,按键扫描时,如果发现有按键按下,
然后在【结构体数组】中去查找,它是短按键还是长按键。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-6 12:01:06 | 显示全部楼层
还有,你仍然在用前后台编程思路在FREERTOS下编程,想转变思路却实很难,但是如果你多搞项目,会解决滴!

    下面是《基于嵌入式实时操作系统的程序设计技术-周慈航(第1版)》上的在UCOSII下的按键设计,你参考一下。
1.png 2.png 3.png



回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-6 12:09:07 | 显示全部楼层
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-3-7 17:17:02 | 显示全部楼层
FREERTOS下的按键处理方式讨论
http://www.stmcu.org.cn/module/forum/thread-601188-1-1.html
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-25 21:48

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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