0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

干货 | 关于单片机上for循环中运用ACC的隐蔽错误

2oON_changxuemc 来源:YXQ 2019-06-20 10:47 次阅读

先上代码:第一个为错误代码,第二个为正确代码。这是用来向ds1302芯片写入命令或数据的函数。实现把8位的数据dat一位一位地写入ds1302的io口。其中ACC0为ACC的第0位。

认真对比这两个代码,可能会觉得没区别,而且这两个代码都可以通过编译(加上reg52.h和一些宏定义)。我也是一直认为for()这里边没有错误,结果。。。试着修改时钟信号,增加延时之类的,调了好久还是错,严重打击我的自信心。这两个代码的区别就只有for(i=0;i<8;i++)和for(i=8;i>0;i--)了。学过c语言的人都知道,这两个句子都是实现一个8次的循环,功能一模一样。怎么会因为这个句子的区别就导致单片机控制的错误呢?神奇!

接着我试着把错误程序中的ACC改为51芯片的寄存器B,烧录进单片机,程序运行成功,跟“for(i=8;i>0;i--),ACC版”一样,lcd在很嚣张地显示着正确的时间( for(i=0;i<8;i++),ACC版lcd的时间显示为0)。附:

这样就知道原因了,使用for(i=0;i<8;i++)的运算中可能有累加器ACC参与了,导致修改了ACC的值,使写入的命令出现错误。但为什么for(i=8;i>0;i--)就没有ACC的参与呢?一个大大的问号。基于我调试了一个星期的程序,皆因为这一个神奇的错误,我实在不甘心,决定研究到底。于是,分别查看了这三个程序代码keil4 编译后得到的 汇编代码。(学过汇编就是爽啊,哈)

对比后,可以发现,出错的原因是for(i=0;i<8;i++)ACC版中,用ACC接收了实参(存储的为要写入的指令),然后在 for 循环前要给变量 “ i " 赋值时,要用到ACC清零,再把ACC中的零赋给 R7 ("i"的值存储在R7)。这样的话,原来存储在ACC中的写入指令就被清零,自然会导致控制出现错误,最终没法读取ds1302芯片的时间,故显示为零。

而在for(i=8;i>0;i--)ACC版中,也用ACC接收了实参的值,但在 for 循环前,给变量“ i ” 赋值时,赋值为8,不需要用到ACC,所以ACC一直是存储着实参中的指令,没有被清零,所以能够顺利地向ds1302发送指令,从而能够读取到时间。

总结:

因为用for(i=0;i0;i--)类的指令多了 CLR A 和 INC R7 两条指令,CJNE 指令又比较DJNZ指令多了一个字节的程序代码存储空间,在频率为12M的51单片机上体现为执行同样功能的程序,要多用2us,代码空间花多一字节。所以前者是毫无优势的,以后应养成用

for(i=n;i>0;i--)的习惯。

请不要反驳我用了这么长的时间去研究,只能使单片机执行快2us,而说我钻牛角尖,只是因为,这个错误导致我整个程序无法正常运行,这不是一件小事。

至于为什么要用到累加器ACC来接收实参,是因为后面的程序要把一个8位的实参一位一位地输出到一个io口,自定义一个变量的话,按位寻址好像比较麻烦,要经过一系列 位运算 ,或者用bit定义8个位(有好的方法请告诉我,哈),而且我写不出来。而用ACC的话,可以很轻易地操作ACC的任意一位,如ACC0,ACC7。在网上查了一下,好像还有一种方法是定义 一种叫 位域 的东东,我看的c语言的书都没介绍,所以还不是很了解。

/************************************************************/

刚刚想了一下,不用ACC 的方法,作一个位运算dat &0x01,修改如下:

想到了这个方法后,觉得自己好白痴,以后都不用ACC了。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    5999

    文章

    43963

    浏览量

    620710
  • ACC
    ACC
    +关注

    关注

    1

    文章

    54

    浏览量

    22582

原文标题:关于单片机上for循环中运用ACC的隐蔽错误

文章出处:【微信号:changxuemcu,微信公众号:畅学单片机】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    使用STM32F401的单片机移植了ucosii操作系统后,在循环中调用sprintf函数时莫名卡死的原因?

    使用STM32F401的单片机移植了ucosii操作系统后。在编写任务函数时,在循环中调用sprintf函数时莫名卡死的原因?
    发表于 04-02 06:12

    单片机中for语句的运用

    单片机中的for语句是一种常见的循环控制结构,用于重复执行一段代码块,可以简化程序的编写和减少代码量。本文将详细介绍单片机中for语句的运用。 一、for语句的基本结构和功能 for语
    的头像 发表于 01-05 14:02 584次阅读

    如何在循环中断中创建工艺对象PID控制器?

    以下步骤将介绍如何在循环中断 OB“PID [OB200]”中调用工艺对象“PID_Compact” 。
    的头像 发表于 12-29 18:10 721次阅读
    如何在<b class='flag-5'>循环中</b>断中创建工艺对象PID控制器?

    51单片机for循环结束之后还在运行

    当我们设计并编写嵌入式系统时,使用51单片机编写程序时,常常会用到循环结构来重复执行一段代码。然而,有时我们可能会遇到51单片机循环结束之后还在运行的问题,这可能会导致系统的功能异常
    的头像 发表于 12-26 14:06 327次阅读

    关于AD5940移植到其他单片机上的问题求解

    你好,我想问一下关于AD5940移植到其他单片机上的问题,我有以下问题。 1、我在调试过程中,单片机可以正常发送数据,但无法读回AD5940芯片的数据,为什么会出现这种情况?AD5940
    发表于 12-01 06:05

    for循环中i++与++i的区别

    和++i的含义。i++被称为后缀递增运算符,它的作用是先使用变量i的值,然后再将i的值加一。而++i被称为前缀递增运算符,它的作用是先将i的值加一,然后再使用i的值。尽管这两个运算符都会增加变量的值,但它们在使用变量值的时机上稍有不同。 在循环中,i++和++
    的头像 发表于 11-26 09:20 1279次阅读

    单片机上电后没有运转,首先要检查什么?

    单片机上电后没有运转,首先要检查什么? 当单片机上电后没有运转时,我们需要进行一系列的检查,以确定导致问题的根源。 导语: 在现代科技领域中,单片机扮演着重要的角色,它广泛应用于各种电子设备中。然而
    的头像 发表于 11-17 14:16 2476次阅读

    51单片机矩阵按键怎么运用

    51单片机矩阵按键怎么运用
    发表于 11-01 08:15

    请问单片机的ALU、ACC功能是什么?

    单片机的ALU、ACC功能是什么?
    发表于 10-31 06:35

    单片机上位复位电路与按键与上电复位的区别

    单片机上位复位电路与按键与上电复位的区别  单片机的复位电路常用于保证单片机在复位状态下正常工作,以便单片机能够在正确的起始状态下启动。常见的单片机
    的头像 发表于 10-17 18:17 1740次阅读

    如何在单片机上用摁键编辑信息可以在单片机上显示?

    做一个设计求指导,就是想在单片机上用摁键编辑信息可以在单片机上显示,并且能发送到电脑上,还能收到电脑的的信息。
    发表于 09-28 06:37

    西门子博途SCL: FOR:在计数循环中执行

    使用“在计数循环中执行”指令,重复执行程序循环,直至运行变量不在指定的取值范围内。
    的头像 发表于 07-18 10:07 5426次阅读

    单片机三种常见按键设计优化方案

    对于单片机初学者很容易理解和使用,但是缺点是,需要在主循环中不断检测按键是否按下,并且需要做消抖处理。若主循环中某个函数任务占用时间较长,则按键会有不同程度的“失灵”。
    发表于 07-01 11:37 1979次阅读
    <b class='flag-5'>单片机</b>三种常见按键设计优化方案

    基于89C51单片机的LED循环右移源程序

    基于89C51单片机的LED循环右移源程序
    发表于 05-16 10:02 0次下载

    基于89C51单片机的LED循环左移源程序

    基于89C51单片机的LED循环左移源程序
    发表于 05-16 10:02 0次下载