找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3545|回复: 7
收起左侧

STM8(STM32)单片机如何实现按键锁定程序

[复制链接]
ID:728915 发表于 2021-5-14 18:21 | 显示全部楼层 |阅读模式
各位大佬好,在使用STM8的时候遇到一个问题,想用比较简便的方法解决:
/*  目标:想使用一个拨码开关来控制所有的按键锁定:
                                               1.在任何时候,只要【拨码开关】置“0”,按键输入就无效;
                                               2.在任何时候,只有【拨码开关】置“1”,按键输入才有效。
(个人想法:能不能在 #define 一个名词(Ka)的时候,让它先判断【拨码开关 BM1 】的状态,符合条件再对【按键 K1 】读取。)
然后再使用这个名词,在函数里完成【按键 K1 】的状态读取,按照这种思路,我目前的写法,编译时报错。
请教各位大佬,有没有比较简便的方法来实现这种功能,不局限于STM8,STM32也可以。谢谢!*/

//以下基于STM8。使用的软件是 IAR
#include <stm8s.h>
#include <stm8s_gpio.h>

//【按键】说明K1为:读取PC1口 输入数据(为0或者不为0)
#define K1 (GPIO_ReadInputData(GPIOC)&GPIO_PIN_1)

//【灯】灯L1亮_灭,PB3口高电平时控制三极管导通灯亮,低电平时三极管关断灯灭
#define ON  1
#define OFF 0
#define L1(ON_OFF)  if(ON_OFF==ON)GPIO_WriteHigh(GPIOB, GPIO_PIN_3);\
                       else GPIO_WriteLow(GPIOB, GPIO_PIN_3)

//【拨码开关】 说明BM1为:读取PB6口 输入数据(为0或者不为0)
#define BM1 (GPIO_ReadInputData(GPIOB)&GPIO_PIN_6)


//用【拨码开关】作为按键锁定:当BM1不为0(拨码开关置“1”)时,读取【按键 K1 】输入。
#define Ka if(BM1!=0)GPIO_ReadInputData(GPIOC)&GPIO_PIN_1

//IO口初始化
void GPIO_Config()
  {

  /灯L1初始化:PB3低电平输出
  GPIO_Init(GPIOB, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST);  

  //按键初始化:PC1无中断无浮点上拉输入
  GPIO_Init(GPIOC, GPIO_PIN_1, GPIO_MODE_IN_PU_NO_IT);

   //拨码开关初始化:PB6无中断无浮点上拉输入
  GPIO_Init(GPIOB, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT);
  }

//主函数
int main(void)
{  
  GPIO_Config();   //IO口初始化
  while(1)
  {
   if(K1==0)   //检测【按键 K1 】状态,按下时为“0”,松开时不为“0”
   {
     L1(OFF);   //【灯 L1】灭
   }

   if(Ka!=0)     
   {
     L1(ON);
   }
  }
}


//STM8解决u8/u32定义报错问题
#ifdef USE_FULL_ASSERT

void assert_failed(u8* file, u32 line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/*********************************************************************************************************/
报错信息如下:
屏幕截图(59).png

回复

使用道具 举报

ID:824490 发表于 2021-5-15 11:10 | 显示全部楼层
你的想法没错,在按键扫描函数的开始加入对这个开关的判断,为0就跳过按键扫描
回复

使用道具 举报

ID:919615 发表于 2021-5-15 15:22 | 显示全部楼层

你的想法没错,在按键扫描函数的开始加入对这个开关的判断,为0就跳过按键扫描
回复

使用道具 举报

ID:728915 发表于 2021-5-15 15:50 | 显示全部楼层
名字不是重点 发表于 2021-5-15 11:10
你的想法没错,在按键扫描函数的开始加入对这个开关的判断,为0就跳过按键扫描

是的,可以通过函数来先行判断,但仅通过定义来先一步实现按键锁定判断好像行不通。
另外,是不是除了主函数里或者极个别情况下,尽量不要使用while、或者for之类的循环语句,会过分占用CPU资源,
比如我下面的按键函数:

//按键判断,带拨码开关BM3按键锁定
int Anjian(void)   //返回值: K1(设置键)短/长按:1/11; K2(+键)短/长按:2/22; K3(-键)短/长按:3/33
{  
  u16 i=0;
  if(BM3!=0)
  {
    while(1)
    {
      if(BM3==0)
      {
        break;
      }
      if(K1==0)   //K1(设置键)按下
      {
        while(1)
        {
          if(K1==0)
          {
            i++;
            delay_cms(1);    //方便 计算 按键K1(设置键)计数时长
            if(i>=60000)   
            {
              i=55555;      //防止达到 计数上限   
            }
          }
         
          if(K1!=0)
          {
            if(i<=179)
            {            
              return 1;     //判断K1(设置键)为:短按(约3秒以内)
            }
            if(i>=180)
            {        
               return 11;   //判断K1(设置键)为:长按(约4秒以后)                 
            }                 
          }
        }
      }
      
      if(K2==0)   //K2(+键)按下
      {
        while(1)
        {
          if(K2==0)
          {
            i++;
            delay_cms(1);    //方便 计算 按键K2(+键)计数时长
            if(i>=60000)   
            {
              i=55555;      //防止达到 计数上限   
            }
          }
         
          if(K2!=0)
          {
            if(i<=179)
            {            
              return 2;     //判断K2(+键)为:短按(约3秒以内)
            }
            if(i>=180)
            {        
               return 22;   //判断K2(+键)为:长按(约4秒以后)                  
            }                 
          }
        }
      }

      if(K3==0)   //K3(-键)按下
      {
        while(1)
        {
          if(K3==0)
          {
            i++;
            delay_cms(1);    //方便 计算 按键K3(-键)计数时长
            if(i>=60000)   
            {
              i=55555;      //防止达到 计数上限   
            }
          }
         
          if(K3!=0)
          {
            if(i<=179)
            {            
              return 3;     //判断K3(-键)为:短按(约3秒以内)
            }
            if(i>=180)
            {        
               return 33;   //判断K3(-键)为:长按(约4秒以后)                  
            }                 
          }
        }
      }   
    }     
  }  
}
回复

使用道具 举报

ID:824490 发表于 2021-5-16 15:27 | 显示全部楼层
本帖最后由 名字不是重点 于 2021-5-16 15:33 编辑
我,菜鸡 发表于 2021-5-15 15:50
是的,可以通过函数来先行判断,但仅通过定义来先一步实现按键锁定判断好像行不通。
另外,是不是除了主 ...

你这个函数有点绕。。。
一般常来说,超过3个并联关系,最好是要用Switch。。。case来做分支。
uchar key_value;
key_value=key_scan();
switch (key_value)
{
case: 0x01
.
.
break;
case: 0x11
.
.
break;

case.
.
.
}
回复

使用道具 举报

ID:824490 发表于 2021-5-16 15:32 | 显示全部楼层
我,菜鸡 发表于 2021-5-15 15:50
是的,可以通过函数来先行判断,但仅通过定义来先一步实现按键锁定判断好像行不通。
另外,是不是除了主 ...

定义一个娈量 uchar Key_vaule;
把K1的状态存为Key_vaule的bit0,按下为0,未按下为1,同理,K2存为bit1...
这样一来再配合switch。case 很方便做组合键,也能做长短按。
回复

使用道具 举报

ID:824490 发表于 2021-5-16 15:35 | 显示全部楼层
          key=key_scan();
                        switch (key)
                        {
                                case 0:
                                        break;
                                case 1://ENT
                                        item++;
                                  if (item>3)
                                        {
                                                RTC_Set(tyear,tmonth,tdate,calendar.hour,calendar.min,calendar.sec);//写入时间;
                                                OLED_Screen_Fill(0x00);
                                                ret=1;
                                        }       
                                        break;
                                case 2: //+
                                        switch (item)
                                        {
                                                case 1:
                                                        if (tyear==2029) tyear=1970;
                                                  else             tyear++;
                                                  break;
                                                case 2:
                                                        if(tmonth==12)   tmonth=1;
                                                  else                                     tmonth++;
                                                  break;
                                                case 3:
                                                        max_date=DFM[tmonth-1];
                                                  if((Is_Leap_Year(tyear)==1)&&(tmonth==2))  max_date=29;
                                                        if(tdate==max_date)    tdate=1;
                                                  else                                     tdate++;
                                                 break;
                                        }
                                        break;
                                case 3://-
                                        switch (item)
                                        {
                                                case 1:
                                                 if (tyear==1970)  tyear=2099;
                                                 else               tyear--;
                                                 break;
                                                case 2:
                                                 if(tmonth==1)    tmonth=12;
                                                 else             tmonth--;
                                                 break;
                                                case 3:
                                                 max_date=DFM[tmonth-1];
                                                 if((Is_Leap_Year(tyear)==1)&&(tmonth==2))  max_date=29;
                                                 if (tdate==1)   tdate=max_date;
                                                 else             tdate--;
                                                 break;
                                        }
                                        break;
                                default:
                                        break;
                        }               
回复

使用道具 举报

ID:728915 发表于 2021-5-16 20:55 | 显示全部楼层
名字不是重点 发表于 2021-5-16 15:27
你这个函数有点绕。。。
一般常来说,超过3个并联关系,最好是要用Switch。。。case来做分支。
uchar k ...

噢噢,受教了,谢谢!
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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