找回密码
 立即注册
查看: 1419|回复: 10

定时器与按键功能融合时,遥控按键可以用,按钮按键不可以使用?

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:536
  • 最近打卡:2025-06-19 08:41:10
已绑定手机

158

主题

592

回帖

1043

积分

金牌会员

积分
1043
发表于 2024-1-26 17:29:23 | 显示全部楼层 |阅读模式
程序修改如下图:

把按键服务子程序,有while的主循环里,移至定时器1内,实现了遥控按键快速切换响应,但是手动按键却时好时坏,定时器定时100us进入一次,没有移动前,语音播报时,遥控按键遥控无效,移动就不受语音播报影响了??
1.png
2.png
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:294
  • 最近打卡:2025-03-06 09:25:41

8

主题

318

回帖

1837

积分

金牌会员

积分
1837
发表于 2024-1-26 17:43:00 | 显示全部楼层
先说说用啥芯片?
89C52的话
中断里啥都不干,进出一次都已经消耗50us了
100us进一次
代表占用CPU 50%
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:536
  • 最近打卡:2025-06-19 08:41:10
已绑定手机

158

主题

592

回帖

1043

积分

金牌会员

积分
1043
发表于 2024-1-27 16:24:00 | 显示全部楼层
Lkck*** 发表于 2024-1-26 17:43
先说说用啥芯片?
89C52的话
中断里啥都不干,进出一次都已经消耗50us了

使用的是STC8G1K08和STC8H1K28这两种芯片,一直改,效果都不好,挺烦的,
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:502
  • 最近打卡:2025-06-19 11:09:19
已绑定手机
已实名认证

112

主题

2405

回帖

6066

积分

版主

积分
6066
发表于 2024-1-27 21:19:59 | 显示全部楼层
while主循环中实现的是单线程顺序执行结构 ,如果加入了中断则可以认为是中断和主循环并行执行结构,不过中断的优先级高。

你说的语音播报有可能是堵塞操作。就是语音播报的时候单片机不能干其他的了。所以之前语音播报的时候不能做其他操作。
还有一个问题是,尽管需要快速的按键响应,但是中断也没有必要设置到100us。实际上设置1ms或者更长都可以的。
因为人的最快反应速度也就在100ms左右。小于10ms的按下到反馈链路人就感觉不到了。
如果你仍然觉得程序有问题。可以把程序发上来。我帮忙给你改改结构。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:536
  • 最近打卡:2025-06-19 08:41:10
已绑定手机

158

主题

592

回帖

1043

积分

金牌会员

积分
1043
发表于 2024-1-28 08:26:05 | 显示全部楼层
王*** 发表于 2024-1-27 21:19
while主循环中实现的是单线程顺序执行结构 ,如果加入了中断则可以认为是中断和主循环并行执行结构,不过中 ...

感谢的老师指导,你说很对,我的语音触发是阻塞式的,定时器原本是1ms进入一次,把按键扫描和按键服务程序放进定时器(定时器改成100us进入一次)后,按键切换速度是可以,状态指示有点延迟,电动按键就时灵,时不灵,我在想,把遥控按键服务和电动按键分成两个函数,遥控服务放入到定时器,电动按键放到while主循环里面,试一下,

点评

那么你想要语音播报的时候仍然拥有控制还是语音播报的时候只能播报? 其实定时器应该是1ms进入一次,且只进行按键扫描,扫描的结果通过全局变量或者数组暂存起来。等进入主循环后再进行按键操作结果的解析。 定时器  详情 回复 发表于 2024-1-28 09:40
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:536
  • 最近打卡:2025-06-19 08:41:10
已绑定手机

158

主题

592

回帖

1043

积分

金牌会员

积分
1043
发表于 2024-1-28 08:38:22 | 显示全部楼层
38009*** 发表于 2024-1-28 08:26
感谢的老师指导,你说很对,我的语音触发是阻塞式的,定时器原本是1ms进入一次,把按键扫描和按键服务程 ...

/*******按键检测扫描程序*********/
void Key_scan()
{
/**********按键1检测**************/       
        if(key1==1)//按键1未被按下检测
        { //按键1短按,吸合电磁阀
                key_lock1=0;  //按键1自锁标志清零
                delay_cnt1=0; //按键1去抖动延时计数器清零        
          if(key_lock1_Short==1) //短按的触发标志等于1,检测短按已经松开
                {
                  key_lock1_Short=0;//短按的触发标志清零
                  key_sec=1;//触发1号键,按键1吸合电磁阀       
                }
        }//按键1花
        else //key1==0 按键按下
        {
                if(key_lock1==0)//有按键按下,且已经解锁
                {
                        ++delay_cnt1;//去抖自增
                        if(delay_cnt1>cnt_delay_cnt1)//滤波检测
                        {       
                                key_lock1_Short=1;//短按锁紧
                                if(delay_cnt1>cnt_delay_cnt3)//长按检测
                                {
                                        key_lock1_Short=0;
                                        delay_cnt1=0;//按键去抖动延时计数器清零
                                        key_lock1=1;//自锁按键置1,避免一直触发
                                        key_sec=6;//触发是6按键选择值
                                }//长按去抖判断
                        }//短按去抖判断
                }//进入按下判断
        }//按键1 else花
       
/**********按键2检测**************/
        if(key2==1)        //按键2是P3.7
        {
                key_lock2=0;//按键自锁标志清零
                delay_cnt2=0;//按键去抖动延时计数器清零        
        }
        else
        {
                if(key_lock2==0)//key_lock2是按键自锁标志2 有按键按下,且是第一次被按下
                {
                        ++delay_cnt2;//去抖动延时计数2自增
                        if(delay_cnt2>cnt_delay_cnt1) //cnt_delay_cnt1是按键去抖动延时阀值
                        {       
                                delay_cnt2=0;//去抖动延时计数清零
                                key_lock2=1;//自锁按键置1,避免一直触发
                          key_sec=2;//触发2号键                          
                        }
                }
        }
       
/**********位置传感器1检测是按照按键3判断(C1=P3^3; 位置1 查原理图)*********/
        if(C1==1)// 位置1未到位
        {
                ++delay_cnt6;//位置1检测未到位去抖动延时计数6自增
                if(delay_cnt6>cnt_delay_cnt1)//按键去抖动延时阀值240 稳定检测未到位则清零位;
                {
                        key_lock3=0;//位置1按键锁3解锁清零
                        delay_cnt6=0;//位置1按键去抖动计数清零   
                }//位置1未到位清零花
                delay_cnt3=0;//位置1到位延时去抖计数3清零   
        }//未到位判断花
        else if(C1==0)//检测位置1到位
        {
                delay_cnt6=0;//位置1检测未到位去抖动延时计数6
                ++delay_cnt3;//位置1检测到位延时计数自增
                if(delay_cnt3>cnt_delay_cnt1)//按键延时去抖阀值  240
                {       
                        delay_cnt3=0;//延时计数清零
                        key_lock3=1;//位置1按键锁3置位锁紧,避免一直触发
                }//位置1检测到位处理花
        }//位置1检测到位判断花

/***位置传感器2检测按照按键4判断*****/

        if(C2==1)//位置2未检测到位
        {
                ++delay_cnt7;//位置2检测未到位延去抖
                if(delay_cnt7>cnt_delay_cnt1)//cnt_delay_cnt1是按键延时去抖阀值
                {       
                        delay_cnt7=0;//位置2延时计数清零
                        key_lock4=0;//位置2按键锁4清零解锁,
                }
                delay_cnt4=0;//位置2检测到位按键去抖动延时计数器清零        
        }
        else if(C2==0)//位置2检测到位
        {
                ++delay_cnt4;//位置2到位延时去抖计数自增
                if(delay_cnt4>cnt_delay_cnt1)//延时计数大于去动阈值,去抖完成
                {       
                        delay_cnt4=0;//位置2到位延时去抖计数清零
                        key_lock4=1;//位置2按键锁4置位,避免一直触发
                }
                delay_cnt7=0;//位置2未到位延时计数清零
        }
       
       
/****无线信号检测按照按键5检测(WX=P3^2对应的按键5;)******/
        if(WX==1)        //未检测无线信号,标志清零
        {
                key_lock5=0;  //按键自锁标志5清零
                delay_cnt5=0; //按键去抖动延时计数器5清零        
        }
        else //WX==0 检测到标志的去抖,判断
        {
                if(key_lock5==0)  //判定自锁标志5状态为0,开始去抖动
                {
                        ++delay_cnt5;  //延时去抖计数自增
                        if(delay_cnt5>cnt_delay_cnt2)//延时去抖完毕
                        {       
                                delay_cnt5=0;//延时去抖计数清零
                                key_lock5=1;//自锁按键置位,避免一直触发
                          key_sec=5;//无线信号                  
                        }//触发按键及标志清零花
                }//检测到无线信号花
        }//检测无线信号花
       
}//按键扫描检测花

/**************按键服务子程序*****************/
void key_server()//按键服务子程序
{       
        if(key_sec==1)//直行键
        {       
               
                key_sec=0;//触发键值清0
                Flag_work=1;//工作标志置1
                if(Flag_position==1)//1直行
                {
               
                d1=1;//关闭电磁阀1
                d2=1; //关闭电磁阀2

                }
                else //Flag_position==0  拐弯变直行动作
                {
               
    led_L=1;//关闭左箭头指示灯
                led_U=1;//关闭上箭头指示灯
                led_O=1;//关闭红色圆形指示灯       
                d1=1;//关闭电磁阀1 d1 =P1^0;
                d2=0;//开启电磁阀2 d2 =P1^1;
                Flag_position=1;//道岔位置直行
                Time_error=0;//定时器报错清零       

                }  
               
        }//按键1判断花
       
        if(key_sec==2)//拐弯按键
        {       
                key_sec=0;        //触发键值清0
                Flag_work=1;//工作标志置1
                if(Flag_position==0)
                {
                       
                d1=1;//关闭电磁阀1
                d2=1; //关闭电磁阀2
                       
                }
                else //Flag_position==1  直行变拐弯动作
                {
                led_L=1;//关闭左箭头指示灯灭(P1^4)
                led_U=1;//关闭上箭头指示灯灭(P1^5)
                led_O=1;//关闭红色圆形指示灯
                d1=0;//开启右电磁阀1 (0开1关)伸展拐弯
                d2=1;//关闭左电磁阀2 (0开1关)回缩
                Flag_position=0;//道岔位置左拐
                Time_error=0;//报错次数清零
               
          }               
        }       
/*******无线信号键值的判断处理*********/
        if(key_sec==5)//按键选择值是5无线信号触发
        {       
                  key_sec=0;//触发键值清0
                  Flag_work=1;//工作标志
                       
                if(Flag_position==0) //由拐弯到直行动作
                {       
                                       
                        //拐弯变成直行
                        Flag_position=1;//道岔位置直行
                        d1=1;//关闭电磁阀1伸展
                        d2=0;//开启电磁阀2回缩动作
                        led_L=1;//关闭左箭头指示灯
                        led_U=1;//关闭上箭头指示灯
                       

                }//拐弯位置判断子花       
               
                else //Flag_position==1  直行变拐弯动作
                {
                       
                        //直行变成拐弯
                        Flag_position=0;//道岔位置在拐弯
                        d1=0;//开启电磁阀1 (0开1关)
                        d2=1;//关闭电磁阀2
                        led_L=1;//关闭灯led_L
                        led_U=1;//关闭灯led_U=1


                }//直行位置判断子花
               
        }//判断无线触发编码判断花
       
/**********对码学习键值判断处理****************/
        if(key_sec==6)//按键选择值是6        //调节数字  对码学习 查找:key_sec=6   P103行按键检测
        {       
                key_sec=0;//按键选择变量清零 //触发键值清0
                YY_OUT=0;//开启语音输出(低开高关)判断显示主控的语音输入口长按
                Delay1000ms();//延时1秒
                YY_OUT=1;//关闭语音输出
        }
       
}//按键服务程序结束花
//********************各个功能子程序*******************************//

/**********************主程序***************************************/
void main()
{       
//Buzzer_dr=0;//蜂鸣器初始化
        Init_IO();//IO初始化
//  Init_Timer0();
        Timer1Init();////1毫秒@11.0592MHz 定时器初始化
//  Init_Uart1();
        d1=1;//关闭电磁阀1
        d2=1;//关闭电磁阀2
        YY_OUT=1;//关闭语音输出
        YY_OUT_2=1;//关闭语音输出2


  while(1)
        {       
//          key_server();//按键触发值任务处理
                if(Flag_Second==1)//Flag_Second是秒计数标志  Flag_Second=1 定时器1中断
                {
                        U8 j;       
                        U8 i;       
                        Flag_Second=0;//秒计时标志清零       
                        if(Flag_work==1) //工作标志置1
                        {
                                led_O=~led_O;//灯led_O取反
                                Time_S++;//秒计数自增
                                if(Time_S>=5)//秒计数大于等于5,则
                                {
                                        Flag_work=0;//工作标志清零,不工作状态/工作异常状态  Flag_work==0
                                  Time_S=0;//秒计数清零  
                                }
                        }//工作标志为1花
                        else//Flag_work==0
                        {
/***************检测到位有关*******************************/
                                if(key_lock3==0 && key_lock4==0 )//按键自锁标志3和4都为0,就是应该检测到的没有检测到,所以两个都是0
                                {
                                        led_O=~led_O;//灯O取反
                                        led_L=1;//关闭led_L
                                        led_U=1;//关闭led_L
                                        Time_error++;//报错次数自增
                                }
                               
                                //key_lock3位置1和key_lock4位置2都是1锁紧状态,故障状态
                                if(key_lock3==1 && key_lock4==1 )//按键自锁标志3和4都为1,正常是不出现的;
                                {
                                        led_O=~led_O;//O型灯翻转
                                        led_L=1;//关闭左箭头指示灯
                                        led_U=1;//关闭上箭头指示灯
                                        Time_error++;//报错次数
                                }       
                               
                               
                        }//else判断Flag_Second==0时花
                       
      //控制语音播报
                        if(Time_error>=10) //报错次数大于等于10;
                        {                               
                                Time_error=0;//报错计数清零
                                YY_OUT=0;//开启语音播报
                                led_L=1;//关闭左箭头指示灯
                                led_U=1;//关闭上箭头指示灯
                                led_O=1;//关闭红色圆形指示灯
                                delayms(100);//延时100ms
                                YY_OUT=1;//关闭语音播报
                                delayms(200);//延时时间

                        }         
                                            
      //按键自锁标志3等于0,且4为1,且工作标志0  key_lock4=C2=拐弯;key_lock3=C1=直行;
                        if(key_lock3==0 && key_lock4==1 && Flag_work==0)//拐弯检测
                        {
                               
                                j=0;
                                led_L=0;//开启拐弯指示灯
                                led_U=1;//关闭直行指示灯
                                led_O=1;//关闭圈型指示灯
                                d1=1;//关闭电磁阀1
                                d2=1;//关闭电磁阀2
                                Time_error=0;//报错计数清零
                                Flag_position=0;//道岔位置直
                               
                                if(i<3)
                                {
                          YY_OUT_2=0;//开启语音播报
              delayms(1000);//延时1000ms
                    YY_OUT_2=1;//关闭语音播报
                                delayms(1000);//延时1000ms,
                                i++;
                                }

                        }
                       
                        if(key_lock3==1 && key_lock4==0  && Flag_work==0)//直行检测
                        {  
                               
               
                                i=0;
                                led_L=1;//关闭左拐箭头指示灯
                                led_U=0;//开启直行指示灯
                                led_O=1;//关闭圆形红色指示灯
                                d1=1;//关闭电磁阀1
                                d2=1;//关闭电磁阀2                               
                                Time_error=0;//报错计数清零
                                Flag_position=1;//道岔位置为直行;
                               
                                if(j<3)
                                {
                          YY_OUT_2=0;//开启语音播报
              delayms(100);//延时100ms
                    YY_OUT_2=1;//关闭语音播报
                                delayms(1900);//延时1900ms,
        j++;                                       
                                }
                               
                           }
                         
                }//秒标志等于1花
        }//while花       
}//主函数花
/*********定时器T1中断函数********/

void Time1_isr() interrupt 3 using 1 //1ms进入一次中断,扫描按键,定时器1中断
{       
        Key_scan();//先判断按键扫描函数,是否有按键按下;
        key_server();//按键触发值任务处理       
        ++interrupt_cnt; //1秒钟需要的中断次数累加
        if(interrupt_cnt>=400) //cnt_1s一秒钟需要多少次定时中断。时间的精度校正就是靠修改cnt_1s这个数据。
        {       
                interrupt_cnt=0;//中断计数清零
                Flag_Second=1;//定时1到时间,秒标志置1
        }
}

定时器部分
/*************************
系统频率:11.0592MHz   定时器T1
定时长度:100us  定时模式:16位自动重装
误差率:0.00%    定时时钟:1T(FOSC)
************************/
void Timer1Init(void)//1毫秒@11.0592MHz
{
        //定时器配置;
        AUXR |= 0x40;//定时器时钟1T模式(即CPU时钟不分频分频(FOSC/1))
        TMOD &= 0x0F;//设置定时器1模式:只有TR1=1才允许计时,定时模式,16位自动重装
        TL1 = 0xAE;                                //设置定时初始值
        TH1 = 0xFB;                                //设置定时初始值
        TF1 = 0;//定时器1溢出标志位TF1清除
        TR1 = 1;//定时器1开始计时
        //开中断
        ET1 = 1;//开定时器中断
        EA=1;//开总中断/CPU开中断
}
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:502
  • 最近打卡:2025-06-19 11:09:19
已绑定手机
已实名认证

112

主题

2405

回帖

6066

积分

版主

积分
6066
发表于 2024-1-28 09:40:31 | 显示全部楼层
38009*** 发表于 2024-1-28 08:26
感谢的老师指导,你说很对,我的语音触发是阻塞式的,定时器原本是1ms进入一次,把按键扫描和按键服务程 ...

那么你想要语音播报的时候仍然拥有控制还是语音播报的时候只能播报?
其实定时器应该是1ms进入一次,且只进行按键扫描,扫描的结果通过全局变量或者数组暂存起来。等进入主循环后再进行按键操作结果的解析。
定时器适合放对实时性要求较高的任务,但是不宜放入延时这种执行时间较长的任务。比如说状态显示就很适合放进定时器中断里面。
这个主要还是看你程序想要如何实现。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:536
  • 最近打卡:2025-06-19 08:41:10
已绑定手机

158

主题

592

回帖

1043

积分

金牌会员

积分
1043
发表于 2024-1-28 18:19:42 | 显示全部楼层
王*** 发表于 2024-1-28 09:40
那么你想要语音播报的时候仍然拥有控制还是语音播报的时候只能播报?
其实定时器应该是1ms进入一次,且只 ...

我是想播报时,依然可以正常的遥控控制和电动按钮控制,播报是跟随控制的状态的,控制可以打断播报,目前是播报可以打断控制的,就不是我想要的,

点评

你里面的延时属于堵塞延时,想要让系统变得流畅需要使用软定时器实现非堵塞的延时。你要不介意的画可以发来工程文件,我给你写一个你看看能不能实现效果。  详情 回复 发表于 2024-1-28 22:34
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:502
  • 最近打卡:2025-06-19 11:09:19
已绑定手机
已实名认证

112

主题

2405

回帖

6066

积分

版主

积分
6066
发表于 2024-1-28 22:34:51 | 显示全部楼层
38009*** 发表于 2024-1-28 18:19
我是想播报时,依然可以正常的遥控控制和电动按钮控制,播报是跟随控制的状态的,控制可以打断播报,目前 ...

你里面的延时属于堵塞延时,想要让系统变得流畅需要使用软定时器实现非堵塞的延时。你要不介意的画可以发来工程文件,我给你写一个你看看能不能实现效果。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:536
  • 最近打卡:2025-06-19 08:41:10
已绑定手机

158

主题

592

回帖

1043

积分

金牌会员

积分
1043
发表于 2024-1-29 08:27:47 | 显示全部楼层
王*** 发表于 2024-1-28 22:34
你里面的延时属于堵塞延时,想要让系统变得流畅需要使用软定时器实现非堵塞的延时。你要不介意的画可以发 ...

你加我QQ号:380091044,我发给你,
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-19 13:50 , Processed in 0.142811 second(s), 108 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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