搜索
查看: 2122|回复: 9

[求助] 顺序开灯程序速度问题_STM8S103F3

[复制链接]

该用户从未签到

1

主题

7

帖子

0

蝴蝶豆

初级会员

最后登录
2019-4-3
发表于 2019-4-2 14:57:09 | 显示全部楼层 |阅读模式
5ST金币
本帖最后由 corvettey 于 2019-4-3 04:23 编辑

我写了一个按顺序开灯的程序。三个灯都会按照顺序被打开,并再也不会亮起,即使再次按开关。
问题是每当开关被按下,第一个灯需要等到0~5秒的时间才能打开。有时候马上就会亮起,有时候需要等待2秒,等等。


我个人感觉应该是程序速度优化问题,可是我并不能找出问题。

我使用了C和IAR写程序。

麻烦大佬帮忙看看,感谢。


代码如下:

#include "IOSTM8S103F3.h"

void LightPC5();
void lightPC6();
void LightPC7();
void delay(int CountForDelay);
void SequentialLighting();
void PinConfiguration();
int PseudoSwitch = 0;  //这个全局变量控制第二三个LED的输入,使开关只用按一次而不用长按才能开灯


void main()
{      
  PinConfiguration();

  SequentialLighting();
}

void PinConfiguration()
{
    //设置PC5为推挽输出控制LED
    PC_ODR = 0;

    PC_DDR_DDR5 = 1;  

    PC_CR1_C15 = 1;

    PC_CR2_C25 = 1;
        
    //设置PC6为推挽输出控制LED
    PC_ODR = 0;

    PC_DDR_DDR6 = 1;  

    PC_CR1_C16 = 1;

    PC_CR2_C26 = 1;  
        
    //设置PC7为推挽输出控制LED
    PC_ODR = 0;

    PC_DDR_DDR7 = 1;  

    PC_CR1_C17 = 1;

    PC_CR2_C27 = 1;              

    //设置PD5为上拉模式的开关
    PC_ODR = 0;

    PD_DDR_DDR5 = 0;
         
    PD_CR1_C15 = 1;

    PD_CR2_C25 = 0;
}

void SequentialLighting(void)
{     
  int CounterForOrder = 0;   /*这个计数器变量确保三个灯严格按照顺序点亮(我不知道有没有更好的办法所以用了这个笨办法)*/

  while (1)
    {      
     if(CounterForOrder==0)   //点亮第一个灯,PC7控制
     {  
        LightPC7();
        CounterForOrder++;
        delay(700);
      }

      if(CounterForOrder==1)  //点亮第二个灯,PC5控制
      {  
        LightPC5();                     
        CounterForOrder++;
        delay(700);
      }

      if(CounterForOrder==2)  //点亮第三个灯,PC6控制
      {
        LightPC6();                     
        CounterForOrder=0;
        delay(700);
      }

      }
}


void LightPC7(void)
{

  PC_ODR_bit.ODR7 = !PD_IDR_bit.IDR5;    //PC7读取开关状态

  if(PC_ODR_bit.ODR7==1){    //如果PC7点亮LED

    delay(30);                         //保持很短的时间

    //关闭PC7控制的LED,即使开关再被按下,这个LED也不会亮起         
    PC_ODR = 0;

    PC_DDR_DDR7 = 0;     

    PC_CR1_C17 = 0;      

    PC_CR2_C27 = 0;

    PseudoSwitch = 1;       /*保证开关只用开一次的变量被激活,意味着开关会被一直认为是开启,即使现实中开关已松开*/

  }
}


void LightPC5(void)
{
  PC_ODR_bit.ODR5 = PseudoSwitch;    //PC5直接读取开关变量的值,用开关变量打开PC5控制的LED

  if(PC_ODR_bit.ODR5==1){        //如果PC5控制的LED被点亮

    delay(30);                              //保持一小会儿

    //关闭PC5控制的LED,即使开关再被按下,这个LED也不会亮起           
    PC_ODR = 0;              

    PC_DDR_DDR5 = 0;     

    PC_CR1_C15 = 0;      

    PC_CR2_C25 = 0;
  }
}


void LightPC6(void)
{
  PC_ODR_bit.ODR6 = PseudoSwitch;

  if(PC_ODR_bit.ODR6==1){  

    delay(30);            

    PC_ODR = 0;

    PC_DDR_DDR6 = 0;     

    PC_CR1_C16 = 0;      

    PC_CR2_C26 = 0;
  }
}

//延时程序
void delay(int CountForDelay)
{
    volatile int i,j;

    for (i=0; i<CountForDelay; i++) for(j=0;j<200;j++);
}


回复

使用道具 举报

该用户从未签到

5

主题

246

帖子

172

蝴蝶豆

金牌会员

最后登录
2021-3-26
发表于 2019-4-4 20:30:54 | 显示全部楼层
void LightPC7(void)
{
  while(PD_IDR_bit.IDR5);

  PC_ODR_bit.ODR7 = 1;

    delay(30);                         //保持很短的时间

    //关闭PC7控制的LED,即使开关再被按下,这个LED也不会亮起         
    PC_ODR = 0;

    PC_DDR_DDR7 = 0;     

    PC_CR1_C17 = 0;      

    PC_CR2_C27 = 0;

    PseudoSwitch = 1;       /*保证开关只用开一次的变量被激活,意味着开关会被一直认为是开启,即使现实中开关已松开*/

  }

评分

参与人数 1蝴蝶豆 +3 收起 理由
STMCU + 3

查看全部评分

回复

使用道具 举报

该用户从未签到

5

主题

904

帖子

58

蝴蝶豆

论坛元老

最后登录
2021-3-30
发表于 2019-4-9 09:27:12 | 显示全部楼层
你應該要有防彈跳機制 ,不然會有意想不到的事發生 ,  接著 delay 用 timer 去算 ,  不然時間會很不穩定

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

回复

使用道具 举报

该用户从未签到

76

主题

759

帖子

17

蝴蝶豆

论坛元老

最后登录
2022-5-20
发表于 2019-4-9 09:32:29 | 显示全部楼层
本帖最后由 any012 于 2019-4-9 09:35 编辑

PC_ODR_bit.ODR7 = !PD_IDR_bit.IDR5;    //PC7读取开关状态

是在这里读取PD5的输入状态吧?
如果是的话,那么你按下按钮的时,需要程序恰好走到这里,PC7才能根据按钮状态进行响应。而主程序里有延时函数,wihile(1)里的部分循环一周可能需要的时间较长。
按钮可以用中断方式。

或者,把三个Delay(700)去掉,这样while循环里可以快一点,可以在判断灯确实被点亮过以后再进行延时。

评分

参与人数 1蝴蝶豆 +3 收起 理由
STMCU + 3

查看全部评分

回复

使用道具 举报

  • TA的每日心情
    开心
    2017-12-6 11:47
  • 签到天数: 1 天

    [LV.1]初来乍到

    49

    主题

    3724

    帖子

    429

    蝴蝶豆

    论坛元老

    最后登录
    2021-8-7
    发表于 2019-4-9 09:55:27 | 显示全部楼层
    程序思路非常混乱,把按键扫描和点灯事件分开处理。
    回复

    使用道具 举报

    该用户从未签到

    74

    主题

    3420

    帖子

    82

    蝴蝶豆

    社区小助手

    最后登录
    2023-11-12
    发表于 2019-4-9 09:56:16 | 显示全部楼层
    楼主的main()里怎么没有while()循环函数?

    评分

    参与人数 1蝴蝶豆 +2 收起 理由
    STMCU + 2

    查看全部评分

    回复

    使用道具 举报

  • TA的每日心情
    开心
    2017-12-6 11:47
  • 签到天数: 1 天

    [LV.1]初来乍到

    49

    主题

    3724

    帖子

    429

    蝴蝶豆

    论坛元老

    最后登录
    2021-8-7
    发表于 2019-4-9 10:08:36 | 显示全部楼层
    本帖最后由 toofree 于 2019-4-9 10:20 编辑

    程序思路非常混乱,把按键扫描和点灯事件分开处理。并且点完灯,也不需要把IO方向切到输入。
    目的就是让按一次按键后,三个灯依次各自先点亮后熄灭;并且是一次性事件,再次有按键也不会执行相同操作。
    1. void SequentialLighting(void)
    2. {     
    3.   int CounterForOrder = 0;   /*这个计数器变量确保三个灯严格按照顺序点亮(我不知道有没有更好的办法所以用了这个笨办法)*/

    4.   while (1)
    5.     {
    6.       if (!PD_IDR_bit.IDR5) //按键扫描
    7.       {      
    8.         if (CounterForOrder == 0) //有按键按下,并且CounterForOrder == 0,则CounterForOrder置1
    9.           CounterForOrder++;  
    10.       }
    11.       delay(10);            //按键扫描延时
    12.               
    13.       if(CounterForOrder==1)   //点亮第一个灯,PC7控制
    14.       {  
    15.         LightPC7();
    16.         CounterForOrder++;
    17.         delay(700);
    18.       }

    19.       if(CounterForOrder==2)  //点亮第二个灯,PC5控制
    20.       {  
    21.         LightPC5();                     
    22.         CounterForOrder++;
    23.         delay(700);
    24.       }

    25.       if(CounterForOrder==3)  //点亮第三个灯,PC6控制
    26.       {
    27.         LightPC6();                     
    28.         CounterForOrder=++;   //执行完这条后,CounterForOrder == 4, 不能恢复到0,因此执行按键扫描时 if(CounterForOrder == 0)不会成立
    29.         delay(700);
    30.       }

    31.     }
    32. }

    33. void LightPC7(void)
    34. {
    35.   PC_ODR_bit.ODR7 = 1;    //打开LED
    36.   delay(30);                         //保持很短的时间  
    37.   PC_ODR_bit.ODR7 = 0;    //关闭LED
    38. }

    39. void LightPC5(void)
    40. {
    41.   PC_ODR_bit.ODR5 = 1;    //打开LED
    42.   delay(30);                         //保持很短的时间  
    43.   PC_ODR_bit.ODR5 = 0;    //关闭LED
    44. }

    45. void LightPC6(void)
    46. {
    47.   PC_ODR_bit.ODR6 = 1;      //打开LED
    48.   delay(30);                         //保持很短的时间  
    49.   PC_ODR_bit.ODR6 = 0;      //关闭LED
    50. }
    复制代码


    评分

    参与人数 1蝴蝶豆 +1 收起 理由
    STMCU + 1

    查看全部评分

    回复

    使用道具 举报

    该用户从未签到

    76

    主题

    759

    帖子

    17

    蝴蝶豆

    论坛元老

    最后登录
    2022-5-20
    发表于 2019-4-9 10:08:53 | 显示全部楼层
    wenyangzeng 发表于 2019-4-9 09:56
    楼主的main()里怎么没有while()循环函数?

    有的,只不过在SequentialLighting()函数里。
    回复

    使用道具 举报

    该用户从未签到

    35

    主题

    1447

    帖子

    22

    蝴蝶豆

    金牌会员

    最后登录
    2021-2-24
    发表于 2019-4-9 10:43:21 | 显示全部楼层
    本帖最后由 damiaa 于 2019-4-9 11:02 编辑

    整复杂了。
    回复

    使用道具 举报

    该用户从未签到

    1

    主题

    1174

    帖子

    36

    蝴蝶豆

    论坛元老

    最后登录
    2021-4-9
    发表于 2019-4-9 12:23:58 | 显示全部楼层
    本帖最后由 sylar.z 于 2019-4-9 12:25 编辑

    你的PseudoSwitch在LightPC7(void)第一次执行点亮后,始终等于1,没有清除状态。因此只有PC7灯会根据按键变化。PC5灯和PC6灯都会在每一次进入函数的时候执行持续delay(30)的点亮状态,然后关闭。delay(30)的时间是多久?是否短到无法点亮LED灯。
    至于点亮第一个灯需要等到0~5秒,是因为从按键到点亮,你有0-3个delay(700)的范围的延时。

    评分

    参与人数 1蝴蝶豆 +2 收起 理由
    STMCU + 2

    查看全部评分

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

    GMT+8, 2024-4-29 11:47 , Processed in 0.202655 second(s), 37 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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