找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4828|回复: 79
收起左侧

单片机C语言程序奇怪的问题,我没有考虑到什么?

[复制链接]
ID:776619 发表于 2022-6-2 20:55 | 显示全部楼层 |阅读模式
       原理:开机时读入1302时间,记住分钟初值,同时打开继电器,接通wifi电源。在while(1)循环内不断的看1302的分钟
值,如果大于5分钟就关wifi。现在出现的问题是开机差不多不满1分钟就关机了。if内的条件
((gds1302_time[1]/16*10+gds1302_time[1]%16-5)>(offpower)),如果把大于号改==就可以实现5分钟关wifi。


       现在想请问一下高手为什么我在条件里用>号不可以呢?==就可以?

单片机源程序如下:

...............;
unsigned char gds1302_time[7];                               //1302时钟数组
............;
unsigned char offpower;                                         //开机时分钟值
sbit  wifi_power=P1^5;                                         //继电器
..........;
main()
{
.........;
.........;
ds1302_read_time();                                                       //读入1302时间值,放数组gds1302_time里,[1]里的是分钟。
offpower=gds1302_time[1]/16*10+gds1302_time[1]%16; //分钟转为数值,此变量为开机分钟初始值
if (offpower>49) offpower=0;                                         //将与下面的量比定时最大十分钟

wifi_power=0;                                                                //打开继电器,wifi通电。
...................;
...................;
while (1)
    {
      ..........;
      .........;
     ds1302_read_time();                                                                    //动态读入时间值
     if ((gds1302_time[1]/16*10+gds1302_time[1]%16-5)>(offpower))  //转化为现时分钟后与开机时分钟比较(现定时5                                                                                                      //分钟)
                {                                                                                    //大于5分钟后关wifi电源
                 wifi_power=1;
                 offpower=0xff;                                                              //同时比较初值设为255,因为1302时钟原理,它永
                                                                                                    //远不会大于59,以后只要不关机再开,永远不合if
                                                                                                    //条件。
                }         
     ..................;
     .................;
     }

}



回复

使用道具 举报

ID:776619 发表于 2022-6-2 21:57 | 显示全部楼层
     想了一下,初值取模有点问题如果是定时10分钟,应当是offpower>49时,offpwoer应当是offpwoer+10-60。当然我在上面列出的程序是定时5分钟,则为offpower>55时,offpwoer应当是offpwoer+5-60。
     现在不说模的问题,是在时间为20几分钟时开机它不按我的定时分钟关电,而是差不多1分钟就关电了,改>于号为==就可以。
回复

使用道具 举报

ID:883242 发表于 2022-6-2 22:07 | 显示全部楼层
如果没有仿真器,那么用串口把(gds1302_time[1]/16*10+gds1302_time[1]%16-5)和(offpower)两个值打印出来看看。
回复

使用道具 举报

ID:230742 发表于 2022-6-2 22:24 | 显示全部楼层
如果只是5分钟后关闭什么东西,不用1302也行。直接用定时器计时简单一点。
回复

使用道具 举报

ID:776619 发表于 2022-6-2 22:25 | 显示全部楼层
Hephaestus 发表于 2022-6-2 22:07
如果没有仿真器,那么用串口把(gds1302_time[1]/16*10+gds1302_time[1]%16-5)和(offpower)两个值打印出来看 ...

好主意,在满足条件语句里打印。但现在我想问的是为什么>不行,==就可以,是不是单片机把条件当作赋值语句什么的了,比如我在这里改>号为单=号,大多数情况它的条件不为零,它会同样是一执行到就关电。
回复

使用道具 举报

ID:776619 发表于 2022-6-2 22:32 | 显示全部楼层
啤酒瓶子老大 发表于 2022-6-2 22:24
如果只是5分钟后关闭什么东西,不用1302也行。直接用定时器计时简单一点。

不想浪费定时器资源。我这个是1302时钟程序,wifi每天对时,当然对时完成wifi会关电。现在是在wifi连不上网的时候就不对时了,一定时间关wifi,节能。
回复

使用道具 举报

ID:776619 发表于 2022-6-2 22:36 | 显示全部楼层
Hephaestus 发表于 2022-6-2 22:07
如果没有仿真器,那么用串口把(gds1302_time[1]/16*10+gds1302_time[1]%16-5)和(offpower)两个值打印出来看 ...

其实打印出来也没有用,开机到条件满足就一两分钟,打印出来的数据对分析作用不太大。无非是我的初值加1两分钟。
回复

使用道具 举报

ID:645485 发表于 2022-6-2 22:45 | 显示全部楼层
本帖最后由 tongguan123 于 2022-6-2 23:14 编辑
Hephaestus 发表于 2022-6-2 22:07
如果没有仿真器,那么用串口把(gds1302_time[1]/16*10+gds1302_time[1]%16-5)和(offpower)两个值打印出来看 ...

首先说明一下,我也是一名初学者啊。
你所说的通过串口把这两个值打印出来,是不是在编程序时候,分别将这两个公式计算的值赋值给两个变量,然后通过串口发送出来???
回复

使用道具 举报

ID:161164 发表于 2022-6-2 23:07 | 显示全部楼层
要不改成这样试试
  1. while (1)
  2.     {
  3.       ..........;
  4.       .........;
  5.      ds1302_read_time();                                                                    //动态读入时间值
  6.          CurrentTime = gds1302_time[1]/16*10+gds1302_time[1]%16;//<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  7.      if (CurrentTime - offpower >= 5)  //转化为现时分钟后与开机时分钟比较(现定时5                                                                                                      //分钟)
  8.                 {                                                                                    //大于5分钟后关wifi电源
  9.                  wifi_power=1;
  10.                  offpower=0xff;                                                              //同时比较初值设为255,因为1302时钟原理,它永
  11.                                                                                                     //远不会大于59,以后只要不关机再开,永远不合if
  12.                                                                                                     //条件。
  13.                 }         
  14.      ..................;
  15.      .................;
  16.      }
复制代码




回复

使用道具 举报

ID:776619 发表于 2022-6-2 23:09 | 显示全部楼层
tongguan123 发表于 2022-6-2 22:45
首先说明一下,我也是一名初学者啊。
你所说的通过串口把这两个值打印出来,是不是在编程序时候, ...

条件满足时在进入里面的语句加才有效,要不循环内我的时间值在不断的读不断的变。
回复

使用道具 举报

ID:645485 发表于 2022-6-2 23:13 | 显示全部楼层
作为一名菜鸟,只能这样分析了,看图说话!



无标题.png

所以-------------------------------------

回复

使用道具 举报

ID:645485 发表于 2022-6-2 23:17 | 显示全部楼层
wolfinn 发表于 2022-6-2 21:57
想了一下,初值取模有点问题如果是定时10分钟,应当是offpower>49时,offpwoer应当是offpwoer+10-60。 ...
所以你那个取模应该是没问题的。
回复

使用道具 举报

ID:776619 发表于 2022-6-2 23:18 | 显示全部楼层
lkc8210 发表于 2022-6-2 23:07
要不改成这样试试

谢谢你,我估计你这想法也是可以的,因为我用==也是可以通过的。

其实写这程序出来只是提供一个思路,怎样运行一段时间关一个东西,我这里利用上了1302时钟的分钟功能,当然用定时器0也是可以的。
程序用于GPS、Wifi双模块每天定时对1302对时,关电再也可以对时一次。

我想了解的是逻辑语句的>号和==为什么会有这效果,是不是==号有强制数据转换功能。而>号就没有。而表达式的左边是不是为INT整形了,而右边是字符形,不转换类型的话是不是INT整形永远大于任何一个字符形。
回复

使用道具 举报

ID:645485 发表于 2022-6-2 23:21 | 显示全部楼层
wolfinn 发表于 2022-6-2 23:09
条件满足时在进入里面的语句加才有效,要不循环内我的时间值在不断的读不断的变。
ok,了解!Thanks, my brother!
回复

使用道具 举报

ID:776619 发表于 2022-6-2 23:22 | 显示全部楼层
tongguan123 发表于 2022-6-2 23:17
所以你那个取模应该是没问题的。

程序里没有写-60,当然这里不是讨论这个模的问题,最多是在变模处会有1~10分钟的不规则定时。
回复

使用道具 举报

ID:776619 发表于 2022-6-2 23:27 | 显示全部楼层
tongguan123 发表于 2022-6-2 23:13
作为一名菜鸟,只能这样分析了,看图说话!

你错了,如你所说,1302取出的数是0x24,而不是24,所以如果要数码管显示的话得2后直接查2的段码显示就行,余4也同样查4的段码。如在LED等显示要加0x30或48,或‘ ’空格。2要加,4也要加。
回复

使用道具 举报

ID:645485 发表于 2022-6-2 23:31 | 显示全部楼层
wolfinn 发表于 2022-6-2 23:22
程序里没有写-60,当然这里不是讨论这个模的问题,最多是在变模处会有1~10分钟的不规则定时。
因为你设置的时间刚好是五分钟就要执行关闭WIFI电源,所以按照你那个if里面取模公式,必须要等于==offpower,才满足条件,即条件为真,才执行里面的语句!
回复

使用道具 举报

ID:645485 发表于 2022-6-2 23:39 | 显示全部楼层
000.png 所以这条语句应该不会执行吧?   if (offpower>49) offpower=0;      //将与下面的量比定时最大十分钟
回复

使用道具 举报

ID:776619 发表于 2022-6-2 23:48 | 显示全部楼层
tongguan123 发表于 2022-6-2 23:31
因为你设置的时间刚好是五分钟就要执行关闭WIFI电源,所以按照你那个if里面取模公式,必须要等于==offpowe ...

你没有明白,我不是要求必须要==才关电,而是>于也可以,只要关了就行。
比如我取初值时为58,程序里认为大于49了,初值为0.然后过三分钟,时间为01,大于00了,关电,达不到10分钟的定时要求。加上模就不同了,58+10-60=08分钟,到09才关电.

同样5分钟的定时模也一样。我取初值时为58,程序里认为大于55了,初值为0.然后过三分钟,时间为01,大于00了,关电,达不到5分钟的定时要求。加上模就不同了,58+5-60=03分钟,到04才关电.
回复

使用道具 举报

ID:883242 发表于 2022-6-2 23:50 | 显示全部楼层
tongguan123 发表于 2022-6-2 23:39
所以这条语句应该不会执行吧?   if (offpower>49) offpower=0;      //将与下面的量比定时最大十分钟

你明显不对,如果是59分,那么是0x59/16*10
回复

使用道具 举报

ID:776619 发表于 2022-6-2 23:50 | 显示全部楼层
tongguan123 发表于 2022-6-2 23:39
所以这条语句应该不会执行吧?   if (offpower>49) offpower=0;      //将与下面的量比定时最大十分钟

时间分钟是59,但是1302读出的是0x59,而不是值是59,值是5*16+9=89
回复

使用道具 举报

ID:883242 发表于 2022-6-2 23:52 | 显示全部楼层
tongguan123 发表于 2022-6-2 22:45
本帖最后由 tongguan123 于 2022-6-2 23:14 编辑

首先说明一下,我也是一名初学者啊。

对啊!这样才能知道这两个值到底是什么,而不是楼主梦想中的值。
回复

使用道具 举报

ID:645485 发表于 2022-6-3 00:02 | 显示全部楼层
wolfinn 发表于 2022-6-2 23:50
时间分钟是59,但是1302读出的是0x59,而不是值是59,值是5*16+9=89

OK!
回复

使用道具 举报

ID:776619 发表于 2022-6-3 00:05 | 显示全部楼层
tongguan123 发表于 2022-6-2 23:39
所以这条语句应该不会执行吧?   if (offpower>49) offpower=0;      //将与下面的量比定时最大十分钟

你别跟我纠结模的问题啦,在40以下不跟模运算有关的用 >都出现点问题,模我改了以后没问题的了。还有你对1302取出的数不了解,它用的是BCD码表示一位数值,是多少分钟就是0x多少,小时、年、月、日、秒都一样。BCD是用四位二进制表示一位数字,我们就理解直读就行。比如0x59,就是0101 1001,为什么这么表示而不用89(10进制)。用BCD码以后显示运算方便啊。好象书上写过最快的是移位和位运算吧,如果右移四,      
0000 0101 5这个数不是出来了?再位运算与0F,0000 1001不是出来了。当然我在程序里用什么除16乘10再加16的余数也是一样的。
回复

使用道具 举报

ID:776619 发表于 2022-6-3 00:07 | 显示全部楼层
只是讨论,讨论才让人明白,并不是显示我多懂,是想让我懂的东西别人也懂了。
回复

使用道具 举报

ID:645485 发表于 2022-6-3 00:12 | 显示全部楼层
wolfinn 发表于 2022-6-3 00:05
你别跟我纠结模的问题啦,在40以下不跟模运算有关的用 >都出现点问题,模我改了以后没问题的了。还有你对 ...

好吧!
回复

使用道具 举报

ID:776619 发表于 2022-6-3 00:13 | 显示全部楼层

好吧,再说回转问题,是不是拿89当59运算呢。不是的,还是得算回59,就是89/16,再89%16,当然可以写0x59/16+0x59%16直观点,砍一个位的数就行。
回复

使用道具 举报

ID:776619 发表于 2022-6-3 00:28 | 显示全部楼层

再说一个,比如我们要LED十六进制显示出一个数,我们知道它的值是0x6B(107十进制),先原样字符0x,再经过运算得6(0x36,即6+0x30),再输出B(是不是0x3B?不是的,0~9要字符显示是加0x30,余数大于10以上的A~F要加0x37才正常显示。如要显示0x6b,这样B小写,同样余数大于10以上的a~f也不能加0x37了,要加什么,我还没算,自己查ASCII表也可以算出来。
回复

使用道具 举报

ID:624769 发表于 2022-6-3 00:34 | 显示全部楼层
我不知道为什么你要用这么复杂的算法……
不知道乘除法非常费资源的么? 而且跨60的时候,还要策略去补偿,
只是要计算多少分钟,这样不是最稳妥?

void main()
{
offpower = 100;

while(1)
{
........................
     if(offpower)       //非0才进入
     {
           if(temp != gds1302_time[1])
           {
                    temp = gds1302_time[1];
                    if(++offpower  > 105)
                    {
                              wifi_power=1;
                              offpower = 0;  
                     }
            }
}
}

回复

使用道具 举报

ID:776619 发表于 2022-6-3 00:37 | 显示全部楼层
wolfinn 发表于 2022-6-3 00:28
再说一个,比如我们要LED十六进制显示出一个数,我们知道它的值是0x6B(107十进制),先原样字符0x,再经 ...

小写表示a~f要加0x57。
回复

使用道具 举报

ID:776619 发表于 2022-6-3 00:50 | 显示全部楼层
188610329 发表于 2022-6-3 00:34
我不知道为什么你要用这么复杂的算法……
不知道乘除法非常费资源的么? 而且跨60的时候,还要策略去补偿 ...

多谢指导,你的才真的高。学习。
总会有问题的,你怎不查下为什么我会出这种小问题?是数据左右不同?
另外单片机用数组多了会有数据重叠现象,当然对结果没有大影响,就是会影响LED显示,有什么解决方法?
回复

使用道具 举报

ID:624769 发表于 2022-6-3 13:12 | 显示全部楼层
wolfinn 发表于 2022-6-3 00:50
多谢指导,你的才真的高。学习。
总会有问题的,你怎不查下为什么我会出这种小问题?是数据左右不同?
...

查问题, 是需要标本的……, 楼上好多层都让你回传数据,你觉得没有意义。那么很多东西是没有办法分析的……

给你前面那个代码,说实话,其实我是打算在你不愿意采集标本的前提下,通过我比较确认的代码变相的采集标本。

非要拿你的代码来说的话……,至少我看下来,除了:
if (offpower>49) offpower=0;                                         //将与下面的量比定时最大十分钟
这个带来很多问题之外,
理论上,如果你在 20分左右的时候,开机,应该是可以5分钟关机的。

非要我给你一个方案的话,我以为:

ds1302_read_time();                                                                    //动态读入时间值
if((gds1302_time[1] < 0x60) && ((gds1302_time[1] & 0x0f)< 0x0A))     //这里增加一个判断{
     if ((gds1302_time[1]/16*10+gds1302_time[1]%16-5)>(offpower))  //转化为现时分钟后与开机时分钟比较(现定时5                                                                                                      //分钟)
                {                                                                                    //大于5分钟后关wifi电源
                 wifi_power=1;
                 offpower=0xff;                                                              //同时比较初值设为255,因为1302时钟原理,它永
                                                                                                    //远不会大于59,以后只要不关机再开,永远不合if
                                                                                                    //条件。
                }

}

应该可以解决你的问题。
至于原因,我相信,当你这么写确实解决问题了之后,你就明白为什么了。
回复

使用道具 举报

ID:776619 发表于 2022-6-3 20:26 | 显示全部楼层
188610329 发表于 2022-6-3 13:12
查问题, 是需要标本的……, 楼上好多层都让你回传数据,你觉得没有意义。那么很多东西是没有办法分析的 ...

唉,转模处不讨论,这东西经过我进行转模处理后是没有问题的了。我是想让高手你以你的经验看看条件中同样是关系表达式,为什么用>号不行,==号反倒可以,同时我也试过了>=也同样不行的哈。如果是纯粹地为了让程序运行得了,通得过。用==就是了,或者用你那高效率的奇妙写法就行。可能还是数据转换的问题,因为我是直接表达式,如果放一有类型变量后再比较可能会好。
回复

使用道具 举报

ID:624769 发表于 2022-6-3 23:28 | 显示全部楼层
wolfinn 发表于 2022-6-3 20:26
唉,转模处不讨论,这东西经过我进行转模处理后是没有问题的了。我是想让高手你以你的经验看看条件中同样 ...

所以,我就是问, 按我上面写的加一个判断, 大于是不是可以了? 这个也很难回答么?
回复

使用道具 举报

ID:776619 发表于 2022-6-4 11:30 | 显示全部楼层
188610329 发表于 2022-6-3 23:28
所以,我就是问, 按我上面写的加一个判断, 大于是不是可以了? 这个也很难回答么?

我历来都是说不触发模的情况下20多分钟也不行,所以你说的有关加个检查模的那条命令这没有必要试。另外我不想用串口输出两个值是因为输出要做格式化处理,我隐隐感觉这可能是左边的公式没有数据类型,可能是系统做转化的问题,而我用输出同样是找不到答案的。用头脑可以运行出时间没有超过两分钟。另外我有点不好意思,好象我在逼着你回答一样。我后来也把左边自己加上(int)和 (unsigned char)自己强廹让它数据转化,也不行。
        以后我少点发这种请教的问题了,其实我目的也不在请教,只是想说明自己遇到过这种情况,如有高手点一下最好,如果同样是菜鸟回复就算不解决不了问题,我在回应中舒缓下神经,说不定一闪光自己能解决了。
回复

使用道具 举报

ID:624769 发表于 2022-6-4 12:26 | 显示全部楼层
wolfinn 发表于 2022-6-4 11:30
我历来都是说不触发模的情况下20多分钟也不行,所以你说的有关加个检查模的那条命令这没有必要试。另外我 ...

行吧,如无意外,最后一次对此问题展开讨论。
在所有的判定当中, == 是最为严格的, 当测试 == 能正常动作时,不管你换成大于和小于理论上都是能正常动作的。所以,加任何强转什么的都是毫无必要的。这是无用功!!!你以为你做了很多,其实,等于什么都没做。
那么,== 能够正确的判定, 为什么换了 > 就出问题了呢? 问题肯定不在判定的公式上,而是天平两边的东西和你预料的不同,在极为严格的 == 下,被狸猫换太子的数据,不会让==准许进入if分支,但是,如果不严格 > 就会允许进入到 if 分支。
不知基于什么原因,但凡对你的数据源有一点怀疑,就好像刺痛你的神经源一样。但是,事实上,如果上面的描述你没有刻意隐藏一些其他信息的话,基本可以确定,就是你数据源有乱入数据。不过,既然你也说了,你不打算知道问题的真相,那么,就当我瞎起劲就是了。
反正,你解决问题也好,了解真相也好,对于我是没有办法好处的。
回复

使用道具 举报

ID:776619 发表于 2022-6-4 13:29 | 显示全部楼层
188610329 发表于 2022-6-4 12:26
行吧,如无意外,最后一次对此问题展开讨论。
在所有的判定当中, == 是最为严格的, 当测试 == 能正常 ...

好吧,谢谢你,左边是一个现算值,右边一个算好的变量值,数据乱入?不想吵了,谢谢你,浪费了你的时间。
回复

使用道具 举报

ID:99525 发表于 2022-6-4 14:27 | 显示全部楼层
比较前,把等号左边的值送串口看一眼很难吗?争来争去,没有数据徒伤和气,有什么意义?
回复

使用道具 举报

ID:121859 发表于 2022-6-4 14:38 | 显示全部楼层
关键的问题是当,分值大于49时,被赋予了值为0,当然就会出问题了。所以要分别处理大于49和小于49的情况。
回复

使用道具 举报

ID:776619 发表于 2022-6-4 15:31 | 显示全部楼层
没必要送串口了,打印出来也分析不出什么引起的。单片机很忠实的。条件运算的结果肯定是为真(1),转换后的数我认为就是数据自动转换的问题了,经换换后的数肯定是大于初值的,至于==的情况只有一个满足,所以用==可以获得我要的定时结果。我在网上搜了一下,左右数据类型不同的情况比较确实会自动转换。按说法应该是负数转换才会出错,也就是在后面读的分钟在00~定时值时,左边是负值,转换后永远大于初值。至于不为负转换后也这样我就不明白了。
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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