打印
[51单片机]

51单片机如何只执行一次?

[复制链接]
7057|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
armxu|  楼主 | 2014-6-7 15:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
dirtwillfly| | 2014-6-7 15:54 | 只看该作者
把看门狗关了

使用特权

评论回复
板凳
ayb_ice| | 2014-6-7 16:04 | 只看该作者
void main(void)
{
    once();

    while(1);

}

使用特权

评论回复
评论
autopccopy 2014-6-7 21:54 回复TA
正解!系统在while(1);中循环!(不要开中断哦) 
地板
armxu|  楼主 | 2014-6-7 16:07 | 只看该作者
我用的是STC15F104W,我在ISP下载软件中取消了看门狗,但还是没用。请问大家有什么好办法?谢谢

使用特权

评论回复
5
armxu|  楼主 | 2014-6-7 16:09 | 只看该作者
ayb_ice 发表于 2014-6-7 16:04
void main(void)
{
    once();

这个程序怎么解释?

使用特权

评论回复
6
ningling_21| | 2014-6-7 16:20 | 只看该作者
armxu 发表于 2014-6-7 16:09
这个程序怎么解释?

这就是只执行一次的程序结构.


你把while(1) 注释掉 肯定会不断循环执行了...

使用特权

评论回复
7
西门看雪| | 2014-6-7 16:54 | 只看该作者
你在while(1)的地方让单片机进入睡眠状态不要唤醒就可以了。

使用特权

评论回复
8
西门看雪| | 2014-6-7 16:56 | 只看该作者
ayb_ice 发表于 2014-6-7 16:04
void main(void)
{
    once();

把while(1)注释掉,当main函数结束之后,程序还会继续往下执行的,一直执行到Flash尽头,然后又从头开始。

使用特权

评论回复
9
叶伤| | 2014-6-8 10:57 | 只看该作者
没有while的话执行完main就会复位重新执行。使用了已定义未赋值的指针也是会复位。使用未定义函数也会。


只执行一次可以看看
void main()
{
    user();
    while(1)
    {
        _nop_();
    }
}

使用特权

评论回复
10
armxu|  楼主 | 2014-6-8 16:37 | 只看该作者
keil 版本:uVision 4



      单片机是没有上操作系统的东西,在keil中编写的代码都是裸机代码,深入编写裸机代码有助于了解硬件的特性。

      若不是硬件特性已定的情况之下的其它流程都是代码作祟。忽然想到来探探51单片机的执行流程。这个念头起源于最初见到每个51程序里面的主函数里面最终都挂一个while(1);语句。为何要加一句while死循环让程序停留在main函数中呢。将while(1);语句去掉有什么影响么?

  

写一个很简单的程序试一下。
[plain] view plaincopyprint?


    #include <reg52.h>  
      
      
    void delay_ms( int ms );  
      
    int main()  
    {  
         
        P1  = ~P1;  
        delay_ms( 500 );   
         
        while(1);  
        return 0;            
    }  
      
      
    //-----------------------  
    //约延迟ms毫秒  
    //-----------------------  
    void delay_ms( int ms )  
    {  
        int i, j;  
        for( i = ms; i > 0; i-- ){  
            for( j = 110; j > 0; j-- ){  
                ;  
            }  
        }  
    }  





执行以上程序,由P1端口控制的流水灯闪了一下。程序最终进入while(1);里纠缠去了,这个到好解释。

现将while(1);语句屏蔽掉。我还以为程序不能被正确执行了呢,因为退出了main主函数,就像Render需要循环来实现一样(尽管刚刚闪灯的程序不在循环之内,但我还是不由产生了这一错觉)。程序执行的结果是:流水灯不停的闪烁!

  

看到这个现象后的猜想及动作^-^:

(1)    这块板坏了吧!(在带操作系统如linux字符界面下运行一个不带死循环的C语言文件完毕后就会返回到linux shell程序中)。赶紧换个板再测试一下,显然还是一样的结果。

(2)    单片机中将一直执行main函数中的最后一个(些)语句?(基于带OS平台下运行标准C语言文件的经验,可从来没有想过是main函数被多次调用或多次进入)

(3)    单片机内将C语言指令取出来加载到单片机内,单片机内自动生成一个主程序循环执行C语言中main函数的内容?(虽然很荒唐,还是想了)

(4)    赶快谷歌百度一下单片机的执行流程(虽然在谷歌百度时以“51单片机程序执行流程”搜索,没有搜到相关内容)。换朴实的搜索词:“51单片机 main”。然后就出现跟我一样带有疑问的问题:为什么main函数中不加while(1);语句之后程序会反复执行呢?回答的关键词包括“程序跑飞、看门狗、复位”。

(5)    趁上嵌入式的机会将“51单片机程序执行流程”搬出来并向老师讲述了我所写程序的得到的现象,包括我怎么验证呀等等。

  

老师的回答:Keil C51程序自动加载了一个名为”STARTUP.A51”的文件,在这个文件里面进行了一系列的初始化操作后进入用户编写的C语言程序入口main函数中,main函数执行完毕后,STARTUP.A51文件后有一句跳转到程序入口main函数的语句,所以会再次进入C语言主程序main函数中执行相关内容。





然后我用keil软件模拟了运行一下以上那一段代码:





程序开始运行就在程序入口main函数的第一条语句之处,Disassembly窗口是c语言代码与汇编代码相对应的窗口,前面是地址,后面的是C语言对应的汇编语句。下面的窗口是相应文件的运行代码的位置,由黄色箭头指向当前正要执行的代码。然后点击单步运行工具条,指导跳出main函数为止,程序跳转到STARTUP.A51中的以下代码位置:





继续点击单步调试直到进入一个循环中:





这里是一个循环,根据DJNZ指令的功能:每执行一次DJNZ RO, IDATALOOP就将R0的值减1,若R0的值不为0则就跳到IDATALOOP地址去。很显然这是一个循环,那么RO的值是多少呢,在以下窗口显示:





可见r0的初值为0x7f,这里将要循环0x7f(128)次,具体在这里r0值的含义可查看一下子的。那么在这个循环之后程序又将去哪里呢?跳过这个循环后程序运行的地方如下:





再单步运行一次:





根据Disassembly的内容,此条语句执行了就又要回到main函数中去了,执行一下试试:





是的!

  

所以,在51单片机中,程序的执行流程就是会不断( 以r0的值作为延迟条件, 具体含义可继续探索 )的进入main函数中执行main函数中的代码。

  

为什么我们在linux等上面运行不带死循环的C语言代码后程序就会自行终止呢?这是不同的操作流程:

(1)    C51单片机不带OS(操作系统),代码的执行形势在此看来就由STARTUP.A51来安排了,没有一个更大的程序来管理怎么调用main函数。

(2)    像Linux这类的平台是带了OS的,运行一个C语言程序对linux来说就是一个任务,除了运行C语言程序这个任务外还有其它的任务。当运行一个C语言程序完毕时,此次的任务也算是完成了。如在linux shell界面运行一个文件名为“hello.c”功能为输出“hello world!”的C语言程序,过程如下:

编译:gcc hello.c  –o  hello

运行:./hello

在运行hello可执行文件时,可以当做是shell调用了hello这个可执行程序。在hello运行完毕后,将返回值等返回给shell界面。整个C语言文件的生死全有linux  shell程序管理。

  

归其原因,还是代码规定的机制不一样吧。

  

此次笔记记录完毕。





单片机

使用特权

评论回复
11
armxu|  楼主 | 2014-6-8 16:54 | 只看该作者
我在做一个红外遥控器,我是想让单片机只发出一次遥控指令,不想循环发出。我开始以为取消WHILE(1)指令就可实现功能,但万没想到指令还是循环发射。所以遇到不解的问题要仔细查找原因。

使用特权

评论回复
12
chunyang| | 2014-6-8 18:46 | 只看该作者
MCU的程序都是循环的,至少得有主循环,否则程序指针超出最后一条指令后就会失控。如果想在调试时仅运行某段程序一次,可以在主循环或其它相关处加一条指向自身的空循环代码,这样程序运行到这里就“停滞”了。
调程序确实有很多技巧,特别是不用仿真设备时,完全可以编制一些临时的工艺性代码来进行局部调试。

使用特权

评论回复
13
chenhengjin| | 2014-6-8 21:29 | 只看该作者
单片机如果不用while(1)的话,程序会跑飞吧,我一般让执行一次的话就这样做

#include<reg52.h>

int main(void)
{
    user();   //代表执行的程序
   
    while(1); //执行死循环
}

使用特权

评论回复
14
hxye006400| | 2014-6-8 22:32 | 只看该作者
我也碰到这个问题,以前没注意,今一查,是个复杂问题,学习了。

使用特权

评论回复
15
261854681| | 2014-6-8 23:20 | 只看该作者
简单问题吧:
while(1)
{
if(A==1)  
   user()
     {A=0;
             ;
      }


}〃A什么时赋1:user什么时候执行,想执行几次都可以在别的地方赋1即可?

使用特权

评论回复
16
122592240| | 2015-9-23 15:39 | 只看该作者
armxu 发表于 2014-6-8 16:37
keil 版本:uVision 4


这才是正解,谢谢层主!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

104

帖子

1

粉丝