标题: while(1)循环是不是很慢 [打印本页]

作者: dcc60    时间: 2025-5-31 21:06
标题: while(1)循环是不是很慢
DS1302时钟,在while(1)里有两个"if"检测按键,没有按键时用switch/case显示时钟,结果发现时钟不同步,秒进位时,有时候“小时”或“分钟”会延迟1秒左右,这是while循环有延迟吗?

作者: fj51hei    时间: 2025-5-31 21:46
肯定不是,while(1)只是大循环而已!
作者: man1234567    时间: 2025-5-31 22:33
可能是防抖功能的设计问题
作者: cy009    时间: 2025-5-31 23:38
时间有延时与while(1)无关,秒溢出,分+1延时,应该是你的1302读写函数有延时了。
作者: 188610329    时间: 2025-5-31 23:54
是你读DS1302代码的问题
作者: chchking    时间: 2025-6-1 06:15
延迟对的,信号并不是时时的,关键看处理什么控制什么,又不是f16
作者: xiaobendan001    时间: 2025-6-1 07:51
是一个循环,慢不慢,看你代码啊
作者: dcc60    时间: 2025-6-1 13:45
xiaobendan001 发表于 2025-6-1 07:51
是一个循环,慢不慢,看你代码啊

帮忙看看,谢谢!

  1.         while (1)      
  2. {       
  3.       if (TM1639_KEY_B1==1)
  4. {
  5.     _nop_();
  6.     while(TM1639_KEY_B1==1);//按住不放
  7.     _nop_();
  8.         SetSelect++;//松手后
  9.        
  10.                                 if(SetSelect>=7){SetSelect=0;DS1302_GengxinTime();}        //更新时间                       
  11.                                
  12. //                                        LED_OF[TimeWei-1]=0xff;        //离开该位显示,防止正好熄灭       
  13.                                 LED_OF[0]=0xff;
  14.                                 LED_OF[1]=0xff;                                
  15.                                 LED_OF[3]=0xff;        
  16.                                 LED_OF[4]=0xff;
  17.                                 LED_OF[6]=0xff;                                
  18.                                 LED_OF[7]=0xff;                                        
  19. }
  20.                         switch(SetSelect)
  21.                         {
  22.                                 case 0:        TimeShow(); break;        //读取并显示时间
  23.                                 case 1:        TimeWei=0;        break;        //10时               
  24.                                 case 2:        TimeWei=1;        break;        // 时               
  25.                                 case 3:        TimeWei=3;        break;                //10分       
  26.                                 case 4: TimeWei=4;        break;                //分       
  27.                                 case 5:        TimeWei=6;        break;        //10秒                       
  28.                                 case 6: TimeWei=7;        break;        //秒       
  29.                         }
  30.                
  31. if (TM1639_KEY_B2==1)
  32.         {
  33.     _nop_();
  34.     while(TM1639_KEY_B2==1);//按住不放
  35.     _nop_();
  36.                
  37.     Shezhi();        //设置时间
  38.         }       
  39.                
  40. }
复制代码




作者: dcc60    时间: 2025-6-1 13:47
  1. void TimeShow()
  2. {
  3.      DS1302_ReadTime();//读取时间
  4.           LED_BCD[0] =DS1302_Time[0];                  //最高位,10时               
  5.           LED_BCD[1] =DS1302_Time[1];         

  6.           LED_BCD[3] =DS1302_Time[3];                        
  7.           LED_BCD[4] =DS1302_Time[4];                       

复制代码


显示时间代码

作者: dcc60    时间: 2025-6-1 13:49
man1234567 发表于 2025-5-31 22:33
可能是防抖功能的设计问题

是有两个延迟,不过是按键按下后才起作用。
作者: dcc60    时间: 2025-6-1 13:50
cy009 发表于 2025-5-31 23:38
时间有延时与while(1)无关,秒溢出,分+1延时,应该是你的1302读写函数有延时了。

有点头晕,下面有代码,能不能帮忙看看。。。
作者: dcc60    时间: 2025-6-1 13:51
188610329 发表于 2025-5-31 23:54
是你读DS1302代码的问题

一开始没问题,后来加了按键检测后出现的,不知道哪个环节出的。
作者: 单片机重购    时间: 2025-6-1 16:53
dcc60 发表于 2025-6-1 13:51
一开始没问题,后来加了按键检测后出现的,不知道哪个环节出的。

其实加了按键检测是不太灵敏的,首先按键检测是是基于一个模块的,但是你如果添加了多个模块的话,按键检测到底是应用于谁了,所以基于按键检测模块的书写,一般是只能需求一个模块的,多个模块添加进来,是会使软件整混的,应用于仿真和实物都是不太灵敏的。

作者: WL0123    时间: 2025-6-1 17:31
dcc60 发表于 2025-6-1 13:51
一开始没问题,后来加了按键检测后出现的,不知道哪个环节出的。

TM1639读到的键值是1个字节,并不是位信号0/1。没有看到相关代码,无法判断与你所说的延迟1秒是否有关。
作者: 苦尽    时间: 2025-6-1 17:40
肯定不是,while(1)只是大循环而已
作者: dcc60    时间: 2025-6-1 18:15
WL0123 发表于 2025-6-1 17:31
TM1639读到的键值是1个字节,并不是位信号0/1。没有看到相关代码,无法判断与你所说的延迟1秒是否有关。

估计是我搞错了。
下次把按键改为单片机引脚。
作者: dcc60    时间: 2025-6-1 18:17
单片机重购 发表于 2025-6-1 16:53
其实加了按键检测是不太灵敏的,首先按键检测是是基于一个模块的,但是你如果添加了多个模块的话,按键检 ...

太复杂了。
谢谢支持,再研究研究。
作者: Hephaestus    时间: 2025-6-2 18:48
就是while按键那两句卡住的。
作者: dcc60    时间: 2025-6-3 10:27
Hephaestus 发表于 2025-6-2 18:48
就是while按键那两句卡住的。

下次删了试试。
作者: 单片机重购    时间: 2025-6-3 17:10
有时候不用while(1)进行循环,用其它语言指令对单片机进行书写也是可以使得单片机的程序可以运行起来
作者: liuxian666    时间: 2025-6-3 18:41
这个函数本身没有快慢的说法,主要看内部函数
作者: 2631449463    时间: 2025-6-3 22:48
试一下移除按键检测中的延时消抖,改为状态机方式。
作者: aking991    时间: 2025-6-4 08:32
你可以不用while试试,因为用这个就是在死等,等超时了才重新来
作者: dcc60    时间: 2025-6-4 10:58
aking991 发表于 2025-6-4 08:32
你可以不用while试试,因为用这个就是在死等,等超时了才重新来

在计时器里试过,没有延迟。
问题是以前也没有延迟,按说,即便延迟,应该时分秒一起延迟才对。
作者: dcc60    时间: 2025-6-4 11:51
Hephaestus 发表于 2025-6-2 18:48
就是while按键那两句卡住的。

试过了,不是按键问题。
作者: dcc60    时间: 2025-6-4 11:53
单片机重购 发表于 2025-6-3 17:10
有时候不用while(1)进行循环,用其它语言指令对单片机进行书写也是可以使得单片机的程序可以运行起来

是的,放在定时器里就没延迟。
作者: dcc60    时间: 2025-6-4 11:55
2631449463 发表于 2025-6-3 22:48
试一下移除按键检测中的延时消抖,改为状态机方式。

试了,可能还是其它问题。
作者: jzh1    时间: 2025-6-4 12:06
在DS1302时钟程序中,当`while(1)`循环内用两个`if`检测按键,且无按键时通过`switch/case`显示时钟,出现时间不同步(如秒进位时小时或分钟延迟1秒左右),**主要原因是按键检测逻辑导致主循环阻塞,影响了时钟数据的及时读取和刷新**。以下是具体分析和解决思路:   ### **一、问题根源:主循环阻塞导致时钟更新延迟** 1. **按键检测的潜在阻塞**      如果`if`语句中直接使用**延时消抖**(如`delay(20ms)`)或复杂逻辑,会导致整个`while(1)`循环卡顿。例如:      ```c    while(1) {        if(按键按下) {            delay(20ms); // 阻塞20ms,期间无法读取时钟            // 处理按键        }        // 读取DS1302时钟并显示    }    ```      此时,若按键按下,程序会在`delay`处停留20ms,导致**DS1302的秒更新可能被错过**,进而出现显示延迟。  2. **循环频率与时钟更新不匹配**      DS1302的秒数据每秒更新一次,若主循环执行周期较长(如因按键检测耗时),可能导致:      - 秒进位时,程序尚未读取到最新数据,仍在显示旧值;      - 下一次循环读取时,秒已进位,但分钟/小时的计算依赖旧秒值,导致延迟。   ### **二、解决方案:非阻塞式按键检测与定时刷新时钟** #### **1. 核心思路**   - **用定时器中断扫描按键**,避免主循环阻塞;   - **定时读取DS1302时钟**(如每100ms一次),确保数据更新频率稳定。  #### **2. 具体实现步骤**   ##### **(1)改用定时器中断检测按键(非阻塞式)**   - **原理**:通过定时器(如1ms中断)周期性扫描按键状态,用状态机记录按键按下、消抖、释放的过程,避免主循环中直接延时。   - **示例逻辑**:     ```c   unsigned char key_state = 0; // 0=未按下,1=按下消抖中,2=确认按下,3=释放等待   unsigned char key_flag = 0;  // 按键触发标志    // 定时器1ms中断函数   void Timer0_ISR() interrupt 1 {       if(按键按下) {           switch(key_state) {               case 0: key_state = 1; break; // 首次检测到按下,进入消抖               case 1: key_state = 2; key_flag = 1; break; // 消抖完成,标记按键触发           }       } else {           key_state = 0; // 按键释放,重置状态       }   }   ```  ##### **(2)定时读取DS1302时钟数据**   - **原理**:在主循环中用计数器控制读取频率(如每100ms读取一次),避免频繁读取占用资源。   - **示例逻辑**:     ```c   unsigned int tick = 0; // 计数器   unsigned char time_buf[7]; // 存储时分秒等数据    while(1) {       if(tick >= 100) { // 每100ms读取一次(100ms=0.1秒,可根据需求调整)           tick = 0;           DS1302_ReadTime(time_buf); // 读取时钟数据       }              // 显示时钟(switch/case逻辑)       switch(mode) {           case 0: 显示正常时间; break;           case 1: 显示调时界面; break;           // ...其他模式       }              tick++; // 每循环一次自增,控制读取频率       // 其他非阻塞操作(如少量延时或任务)   }   ```  ##### **(3)优化显示逻辑**   - 确保`switch/case`中的显示函数(如数码管驱动)执行速度快,避免包含耗时操作(如长延时)。   - 若显示需要动态效果(如闪烁),可通过定时器中断控制,而非在主循环中阻塞。   ### **三、其他可能原因及排查方向** 1. **DS1302通信时序问题**      - 检查读写函数是否严格遵循DS1302的时序要求(如时钟沿、复位信号顺序),避免因通信错误导致数据读取失败。   2. **变量缓存与临界资源**      - 若在中断中修改时间数据,需用`volatile`关键字声明变量,并在主循环读取时关闭中断,避免数据不一致。   3. **晶振稳定性**      - DS1302的走时精度依赖外部晶振(如32.768kHz),若晶振质量差或电容匹配不当,可能导致实际秒长偏移,需硬件排查。   ### **四、总结**   - **核心问题**:按键检测的阻塞式逻辑导致主循环无法及时读取和刷新时钟数据。   - **解决关键**:用定时器中断实现非阻塞按键扫描,主循环专注于定时读取时钟和快速显示,确保每秒至少读取一次时钟数据(如每100ms读取一次,每秒可读取10次),避免秒进位被遗漏。   - **扩展建议**:若系统支持多任务(如RTOS),可将按键处理、时钟读取、显示分别分配到独立任务,通过消息队列或信号量同步,进一步提升实时性。
作者: dcc60    时间: 2025-6-4 13:38
jzh1 发表于 2025-6-4 12:06
在DS1302时钟程序中,当`while(1)`循环内用两个`if`检测按键,且无按键时通过`switch/case`显示时钟,出现 ...

谢谢支持。说的很详细。
经过反复试验,发现循环之前的主函数运行时间太长(1-2秒左右),可能是造成不同步的主要原因。时分秒是直接读取DS1302时间,不是按秒进位,理应“快、慢”同步才对,不知道为什么分钟或小时会慢1秒。




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1