188610329 发表于 2021-11-12 14:09 不管它了,我相信如果真的有一天需要用到这个功能的话,我会解决时间延迟的问题的。知道能实现这个定时启动停止就行了 ![]() |
zhangzhao2423 发表于 2021-11-12 13:50 我在另一个 关于中断的帖子里 提到过。 51系的单片机,属于8位机,一次只能处理8位数据,因此,如果有变量需要在 中断与主程序之间传递参数的话,这个变量,应当避免使用16位变量,(尤其是C编程的情况下)会出现你无法控制的错误。 而你htime 恰恰就是在中断和主程序之间传递参数的变量,那么他应该是 u8 而不应该是 u16。而count 仅仅只是在中断中使用,所以虽然16位耽误时间,但是不会产生你不可控的错误。 最后,htime 即便改成了u8 if判断中也要用 >= 而不能用==,这是原则问题(因为htime++ 不是在while(1)里面实施的)。而反过来,count >= 即便改成 == 也没有关系,因为 count++ 是在T0中断中实施的。 |
188610329 发表于 2021-11-12 12:06 你意思说进入中断一次,htime的值累计也有误差,因为有count=0这个指令也耗时间是吧。 第二个方案感觉减少了定时误差。 |
zhangzhao2423 发表于 2021-11-12 10:07 2个方案: 1) 宁可 count 变成 >=2000 的判断, 也要把 htime 用u8 来定义 变成150, 2)while(--j) 之前 TR0 =0; htime = 0; 之后 TR0 = 1; |
zhangzhao2423 发表于 2021-11-11 15:46 你htime是哪里累加的? pcon的循环,那个j确定是 u8定义么? |
188610329 发表于 2021-11-11 12:43 运行下来有飘移,时间不准。我程序是关一个小时,开五分钟。动作是有,但是开启单片机的时间每次都向后延迟,误差累计的越来越大。 |
188610329 发表于 2021-11-11 12:43 嗯嗯,是的。我把它成大于等于 |
| 行, 你睡觉和干活都在 while(1) 里就没问题了, 剩下的就是 htime 和 j 的调整, 以及htime 的计数逻辑了,if判断来讲,最好用 htime >= 240 代替 htime == 240 |
188610329 发表于 2021-11-11 11:01 我知道,我想用定时器0来控制,我正在写这个程序,等会儿试运行看看。 |
zhangzhao2423 发表于 2021-11-11 09:00 我想,你应该知道,主程序一旦运行进入了 while(1) 就永远不会出来,所以,如果,你把睡眠这部分,和你要执行的这部分,分别放在 while(1) 的内外…… , 那么,除了重新启动,你是无法让单片机周而复始的执行的。 |
188610329 发表于 2021-11-10 16:10 其实我觉得最主要的就是醒了,处理好数据后继续睡,然后隔一个星期再醒,这样周而复始。我今天就是处理这个问题。 |
zhangzhao2423 发表于 2021-11-10 15:53 ……………… 那你想过没有,一周之后,怎么让他再睡下? |
zhangzhao2423 发表于 2021-11-10 15:37 换句说,加了一个星期 掉电唤醒的 while(1) 一个星期只会循环一次。这么说,理解了没? |
zhangzhao2423 发表于 2021-11-10 15:37 对的,永远不会走出 while(1)的,所以,我是让你把定期运行的代码放在 while(1) 里面的最上方的,代替LED0的位置的。 |
zhangzhao2423 发表于 2021-11-10 14:33 首先,掉电,不是断电,掉电是指,单片机进入不怎么用电的状态,单片机本身还是通着电的,所以不需要Eeprom之类的保存任何东西,内存里的东西不会丢失,其次,都说了,先加个LED观察状态,你这代码唯独没有观察状态,你怎么知道掉电成功没成功? 到时间,是从 PCON = 0x02 下一句开始执行,不存在重新开始执行。 最后,你说让 j= 5; 那么 j=5 在哪里? 你看看我给你的代码 j = 240; 在什么地方? 改动代码前,你是不是应该先对代码进行理解? |
|
本帖最后由 188610329 于 2021-11-10 15:36 编辑 先说明一下, 定时唤醒,只能最多睡15秒左右,就会醒,这是硬件限制,没有办法,我们能做的,就像逼不爱午睡的小孩午睡,你醒了,我安抚一下,接着再把被子一蒙头,你给我继续睡,直到睡够午睡时间。所以要睡一周,就是反复醒了睡的过程,程序大致如下,你可以参考。实验时可以改小 i 和 j 的数字。更快的观察到效果。 void main() { uchar i,j; while(1) { LED0 = !LED0; //此处 你需要定期执行的程序, 这里用 翻转LED0 代替 i = 168; // 一周168小时 while(--i) { j = 240; //每小时有 60分钟,即 240 个 15秒 while(--j) { WKTCH =0xff; //WKTCL 不需要管,不需要那些鸡毛蒜皮的时间 PCON |= 0x02; _nop_(); LED2 = !LED2; //次处用来确定每15秒醒来,正式使用时去掉 } LED1 = !LED1; //次处用来确定每小时醒来,正式使用时去掉 } } } |
188610329 发表于 2021-11-10 10:12 是的,只被定时器唤醒,掉电一个星期后再唤醒,不受其他影响。 |
188610329 发表于 2021-11-10 10:12 只被定时器唤醒,定时醒,定时睡,外面打雷下雨不管。按时休息工作。且只被定时器控制 |
zhangzhao2423 发表于 2021-11-10 10:05 你除了定时器唤醒,还打算被其他,比如外部中断之类的随时唤醒么? 即,睡了之后,不到一周不起, 还是,如果没有突发事件,就睡一周,有突发事件就处理,完了之后接着睡,或完了之后重新开始睡一周,这三种情况的哪种? |
188610329 发表于 2021-11-9 17:38 是的,这是STC手册。那个C8051F020是另外一个项目的。这个STC是我自学的一个开发板上的。我学了看门狗与自启动这一块,但是时间上我想能控制多久就多久。按上面一楼写的程序,没有运行成功。 |
devcang 发表于 2021-11-9 17:10 我不太懂啊,程序是这样的,PCON|=2,打开CPU掉电模式,系统唤醒定时器在运行,此时已经运行了无数次WHILE(1)函数,当15S过后,不是立即开启CPU吗?为什么会与IF语句做比较呢? |
|
你这是STC的手册, 首先,掉电换醒定时器,非常的不准, 说是32.768K的晶振频率,实际上,很多在36K左右,我见过最离谱的有38K,都能做红外载波发生器了。所以,如果你要用这个做长眠的话……,最好做个采样测试(比如for循环40次,就是理论上的 10分钟,看看相差多少,再调整一下,妥了之后,乘以1008,就是1个星期了),不然你定1个星期,最后极有可能5天就醒了。 |
|
a=7*24*60*60= 604800 (秒) a/15=40320(个周期),一个无符号整数变量,够用 void main(){ unsigned int a=0; WKTCH=0xff; //包含使能位在内了。 WKTCL=0xff; while(1){ PCON|=2; _nop_(); _nop_(); _nop_(); _nop_(); if(++a<40320){ continue; } //这1个星期了,该干嘛 } } |