OpenEdv-开源电子网

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

求一个c程序的解决方法

[复制链接]

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-8
在线时间
7 小时
发表于 2018-7-16 10:59:26 | 显示全部楼层 |阅读模式
3金钱
想用一个按键实现一个流水灯的开关,按一个流水灯开启,再按一次流水的灭。
一开始写的程序是
while(1)
        {
                gggg=KEY_Scan();       //用按键扫描赋值给一个标志位,按一下按键标志位就取反。为1就流水灯,为0就关闭。
          if(gggg){
                   D1=1;
                         delay_ms(300);
                         D1=0;
                         D2=1;
                         delay_ms(300);
                          D2=0;
                         D3=1;
                         delay_ms(300);
                          D3=0;
                         D4=1;
                         delay_ms(300);
                         D4=0;
             delay_ms(300);
                }
                else
                        { D1=1;D4=1;D2=1;D3=1;delay_ms(300);
                }
        }

但是这样就有一个问题,只有当程序执行完一遍后才会再次执行gggg=KEY_Scan() 这个赋值语句。也就是说我只有在特定的时候按键才会改变流水灯的开关。
试过用外部中断来编写,可是还是不行。按下确实可以立即进入中断程序,可是中断程序不能实现流水灯(执行完一遍后一定要跳出中断程序。
如果中断程序中写一个标志位,这就和上面的程序一样。只有当程序执行完一遍才会去执行判断标志位的程序。不能实现立即开关。

最佳答案

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

大概看了下,这样应该可以解决你的问题!:就是把你之前的延时用“while(gggg&&delay_count
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

35

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
231
金钱
231
注册时间
2015-12-2
在线时间
24 小时
发表于 2018-7-16 10:59:27 | 显示全部楼层
大概看了下,这样应该可以解决你的问题!:就是把你之前的延时用“while(gggg&&delay_count<30)”代替,然后再内部进行按键的状态查询,,如果想要更加实时那就把 下面的基本延时“delay_ms(10);                 //基本延时”改的更小应该就OK!

while(gggg&&delay_count<30)
                         {
                                 delay_count++;                //一个时间累积
                                 gggg=KEY_Scan();        //按键扫描
                                 delay_ms(10);                 //基本延时
                         }
回复

使用道具 举报

70

主题

6763

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
13125
金钱
13125
注册时间
2012-11-26
在线时间
3814 小时
发表于 2018-7-16 11:02:22 | 显示全部楼层
照你这样写流水灯得累死,而且裸奔的程序,本来就是从上到下执行,你不知道?
回复

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-8
在线时间
7 小时
 楼主| 发表于 2018-7-16 11:03:10 | 显示全部楼层
jermy_z 发表于 2018-7-16 11:02
照你这样写流水灯得累死,而且裸奔的程序,本来就是从上到下执行,你不知道?

那要怎么才能实现立即开关的流水灯。一个按键
回复

使用道具 举报

35

主题

560

帖子

2

精华

资深版主

Rank: 8Rank: 8

积分
17784
金钱
17784
注册时间
2018-3-3
在线时间
523 小时
发表于 2018-7-16 12:57:46 | 显示全部楼层
用定时器执行流水灯。定时器时间可以设定为300ms溢出。然后在中断函数判断键值决定是否运行流水灯。
main就获取按键值就行,这样就不会卡了
/*
*
*
*
*
*
*/
回复

使用道具 举报

0

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2018-4-14
在线时间
11 小时
发表于 2018-7-16 13:29:26 | 显示全部楼层
按键复用到外部中断
回复

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-8
在线时间
7 小时
 楼主| 发表于 2018-7-16 14:32:40 | 显示全部楼层
Psheng 发表于 2018-7-16 12:57
用定时器执行流水灯。定时器时间可以设定为300ms溢出。然后在中断函数判断键值决定是否运行流水灯。
main ...

能说的具体点吗?有点不懂
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-7-16 14:44:33 | 显示全部楼层
本帖最后由 275891381 于 2018-7-16 14:45 编辑

最简单就是把if(gggg) 和else 改成两个while(1)  把delay(300) 改成for {}30个delay(10);加  gggg=KEY_Scan(); 【KEY_Scan内部有延时就减少延时次数凑个300ms】有按键跳出while1就进入另个个while1了}   不过不建议这么搞,还是中断或者定时器扫描按键把
回复

使用道具 举报

3

主题

1155

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7464
金钱
7464
注册时间
2015-1-15
在线时间
1368 小时
发表于 2018-7-16 15:52:24 | 显示全部楼层
学习到放弃
回复

使用道具 举报

9

主题

796

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2038
金钱
2038
注册时间
2017-8-2
在线时间
522 小时
发表于 2018-7-16 16:49:56 | 显示全部楼层
怕是你按键扫描程序有问题

程序结构改改,看着难受
猪猪熊呢?
回复

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-8
在线时间
7 小时
 楼主| 发表于 2018-7-16 17:02:16 | 显示全部楼层
323232 发表于 2018-7-16 16:49
怕是你按键扫描程序有问题

程序结构改改,看着难受

你没懂我的问题,程序就是说一个在while(1)中通过判断标志位执行两种模式(为1就是流水灯为0就是全灭)。用按键设置外部中断给标标志位取反。
但是在执行流水灯的时候因为要有延时(假设此时执行到流水灯程序中的第一行),所以虽然此时标志位通过按键中断取反了。但是程序只有执行到流水灯程序的最后一行,才会去再次判断标志位进行选择流水灯开还是关。
回复

使用道具 举报

9

主题

796

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2038
金钱
2038
注册时间
2017-8-2
在线时间
522 小时
发表于 2018-7-16 17:12:08 | 显示全部楼层
Aklzyzjchzddzjh 发表于 2018-7-16 17:02
你没懂我的问题,程序就是说一个在while(1)中通过判断标志位执行两种模式(为1就是流水灯为0就是全灭) ...

推荐你把流水灯里的延时换掉,用中断和switch写。   按键扫描函数里的软件延时去抖最好改成状态机去抖
猪猪熊呢?
回复

使用道具 举报

1

主题

35

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
231
金钱
231
注册时间
2015-12-2
在线时间
24 小时
发表于 2018-7-16 17:20:40 | 显示全部楼层
u8 i=0;
        u8 delay_count=0;
        while(1)
        {       
                gggg=KEY_Scan();       //用按键扫描赋值给一个标志位,按一下按键标志位就取反。为1就流水灯,为0就关闭。
                while(gggg)
                {
                         D1=1;
                        //延时并且可以检测按键状态
                         while(gggg&&delay_count<30)
                         {
                                 delay_count++;                //一个时间累积
                                 gggg=KEY_Scan();        //按键扫描
                                 delay_ms(10);                 //基本延时
                         }
                         D1=0;
                         D2=1;
                         //延时并且可以检测按键状态
                         while(gggg&&delay_count<30)
                         {
                                 delay_count++;                //一个时间累积
                                 gggg=KEY_Scan();        //按键扫描
                                 delay_ms(10);                 //基本延时
                         }
                                D2=0;
                         D3=1;
                         //延时并且可以检测按键状态
                         while(gggg&&delay_count<30)
                         {
                                 delay_count++;                //一个时间累积
                                 gggg=KEY_Scan();        //按键扫描
                                 delay_ms(10);                 //基本延时
                         }
                                D3=0;
                         D4=1;
                         //延时并且可以检测按键状态
                         while(gggg&&delay_count<30)
                         {
                                 delay_count++;                //一个时间累积
                                 gggg=KEY_Scan();        //按键扫描
                                 delay_ms(10);                 //基本延时
                         }
                         D4=0;
                         //延时并且可以检测按键状态
                         while(gggg&&delay_count<30)
                         {
                                 delay_count++;                //一个时间累积
                                 gggg=KEY_Scan();        //按键扫描
                                 delay_ms(10);                 //基本延时
                         }
                }
                //如果按键是另一种状态时全灭
                D1=1;
                D4=1;
                D2=1;
                D3=1;
                delay_ms(10);
        }
回复

使用道具 举报

9

主题

796

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2038
金钱
2038
注册时间
2017-8-2
在线时间
522 小时
发表于 2018-7-16 17:30:16 | 显示全部楼层
本帖最后由 323232 于 2018-7-16 17:32 编辑

int index=0,temp_50ms=0;
while(1)
        {
                gggg=KEY_Scan();       //用按键扫描赋值给一个标志位,按一下按键标志位就取反。为1就流水灯,为0就关闭。
          if(gggg){
                  switch(index)
                 {
                     case 01=1;D2=0;D3=0;D4=0;break;
                     case 11=0;D2=1;D3=0;D4=0;break;
                     case 21=0;D2=0;D3=1;D4=0;break;
                     case 31=0;D2=0;D3=0;D4=1;break;
                 }
                }
                else
                        { D1=1;D4=1;D2=1;D3=1;
                }
        }

50ms的定时器中断:

       if(++temp_50ms>6)
       {
           temp_50ms=0;
           if(++index>3)
              index=0;
       }


状态机按键不必要。加了之后很防抖就是了。
猪猪熊呢?
回复

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-8
在线时间
7 小时
 楼主| 发表于 2018-7-16 17:31:58 | 显示全部楼层
1352055936 发表于 2018-7-16 17:23
大概看了下,这样应该可以解决你的问题!:就是把你之前的延时用“while(gggg&&delay_count

就是7楼说的意思差不多吧。也算是一种办法吧。  我很好奇这种问题应该很容易遇到吧,没有一个根本的解决办法吗?(不管怎么说很感谢你写了这么多)
回复

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3566
金钱
3566
注册时间
2016-1-8
在线时间
544 小时
发表于 2018-7-16 17:33:45 | 显示全部楼层
一个好的代码是不会用delay的,你还用了300ms  3个加起来都1s了,用定时器完成吧。
回复

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-8
在线时间
7 小时
 楼主| 发表于 2018-7-16 17:34:38 | 显示全部楼层
323232 发表于 2018-7-16 17:30
int index=0,temp_50ms=0;
while(1)
        {

刚刚把楼上设置为最佳回答。。。。
回复

使用道具 举报

9

主题

796

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2038
金钱
2038
注册时间
2017-8-2
在线时间
522 小时
发表于 2018-7-16 17:35:45 | 显示全部楼层
执行1条语句1us,  你一个延时300ms,姑且算你按键扫描函数1ms,你自己算一下你按键的时候,按下去时整个程序在延时的几率大还是在按键扫描的几率大
猪猪熊呢?
回复

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-8
在线时间
7 小时
 楼主| 发表于 2018-7-16 17:40:23 | 显示全部楼层
Sun_Fly 发表于 2018-7-16 17:33
一个好的代码是不会用delay的,你还用了300ms  3个加起来都1s了,用定时器完成吧。

c语言初学者,见谅。楼上已经给了很好的解决办法了。
回复

使用道具 举报

1

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2018-7-4
在线时间
7 小时
发表于 2018-7-16 17:52:40 | 显示全部楼层
最好的办法是,单步循环累加来进行灯的点亮时间,每个循环延迟时间可设为1ms,这样你每个循环周期执行的时间都很短,不影响按键捕获及其他处理。
回复

使用道具 举报

31

主题

1955

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4520
金钱
4520
注册时间
2018-5-11
在线时间
946 小时
发表于 2018-7-16 18:38:47 | 显示全部楼层
如果有8个灯,估计楼主会崩溃
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

29

主题

338

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1181
金钱
1181
注册时间
2018-4-13
在线时间
170 小时
发表于 2018-7-16 18:59:22 | 显示全部楼层
如果想要实时性好些,就需要改动延时基本做法,不能采用干耗时的方法。
1、可以用按键中断,这个是基本做法。
2、SysTick做共用,延时函数只对其做脉冲累加,检查脉冲数量。无论多少个延时都不影响其他处理环节。这样不用按键中断,只需不断检查按键状态就可以了。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-16 07:28

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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