8位单片机(51 STC8)C语言处理32位unsigned long型数据之计算出错

news2025/1/12 12:14:22

一、问题描述


入门51没多久后就主攻32了,最近又搞起51,移植一个软定时器代码到STC8上,结果出现了奇怪的问题,而这种问题在各种32位单片机上都是不曾有的。


有如下代码,实现了软定时器。使用内部IRC,22.1184MHz


定义了一个32位变量,在定时器01ms中断里面自增,作为系统时基

static __IO uint32_t xdata SystemTimer = 0;

void timer0_int (void) interrupt TIMER0_VECTOR
{
    SystemTimer++;
}

void UserTimer_Reset(uint32_t xdata *Timer)
{
	*Timer = SystemTimer;
}

uint32_t UserTimer_Read(uint32_t xdata *Timer)
{
	return (SystemTimer - *Timer);
}


然后在主循环里面定义一个变量与时基进行比较,大于等于1000ms则通过串口发送计数值

int main(void)
{
    static __IO uint32_t xdata timer_test = 0;
    static __IO uint8_t xdata run_step = 0;

    __IO uint32_t xdata val;
    
    while (1)
	{
	    if ((val = UserTimer_Read(&timer_test)) >= TIMEOUT_1S)
	    {
	    	uart_send_bytes(UART2, (uint8_t *)(&timer_test), 4);
	        UserTimer_Reset(&timer_test);
	        uart_send_bytes(UART2, (uint8_t *)(&SystemTimer), 4);
	        uart_send_bytes(UART2, (uint8_t *)(&val), 4);  
	    }
	}
}

得到如下结果,相减的结果和打印的结果不一致


在这里插入图片描述

变量指定到xdata区时,时不时会出现差值非常大但是实际只过了几百ms的情况

在这里插入图片描述

变量指定到data区时,时不时会出现差值大于1000ms但是实际只过了几百ms的情况

二、问题猜想


1、以上图一为例,当指定到xdata区时,timer_test、SystemTimer和val三者的关系为val = SystemTimer - 0x100 - timer_test,即0x800-0x100-0x7D0 = 0xFFFFFF30。
而差值很大的时候均发生在SystemTimer 的低8位变为0x00的时候。
猜测是中断中自增时,自增前为0x7FF,自增后低8位溢出变为0x00,而在退出中断后并运行到UserTimer_Read()函数进行减法时,次低8位还未获得进位,于是减法算式拿到的值是0x700,于是就发生了SystemTimer(0x700) - *Timer(0x7D0) = 0xFFFFFF30的惨案。

2、以上图二为例,当指定到data区时timer_test、SystemTimer和val三者的关系为SystemTimer = val + timer_test - 0xFF,即0x437+0x7C3C8-0xFF=0x7C700。
同样是均发生在SystemTimer 的低8位变为0x00的时候。
猜测是中断中自增时,自增前0x07C6FF,自增后低8位溢出,应该变为0x00但内存中还是0xFF,而次低8位已经获得进位变为了0xC7。于是退出中断后,减法算式拿到的值是0x07C7FF,于是有SystemTimer(0x07C7FF) - *Timer(0x07C3C8) = 0x0437。


三、试图解决


这或许跟8位单片机一个指令只能处理32位数据其中的8位有关,因对汇编不熟悉,不了解编译器具体实现,只能瞎改一下。


1、修改自增语句,令其执行周期变长,即先加上1再覆盖SystemTimer 。 实测没用,可能被编译器优化掉了

void timer0_int (void) interrupt TIMER0_VECTOR
{
    SystemTimer = SystemTimer + 1;
}
或者
void timer0_int (void) interrupt TIMER0_VECTOR
{
	__IO uint32_t t = SystemTimer + 1;
    SystemTimer = t;
}

2、再定义一个变量,进行如下操作。错误变少了,但还是有。有用但不多

static __IO uint32_t xdata SystemTimer_1 = 0;

void timer0_int (void) interrupt TIMER0_VECTOR
{
	SystemTimer = SystemTimer_1;
    SystemTimer_1++;
}

3、在2的基础上,将进中断的时间由1ms改为10ms,也不行

static __IO uint32_t xdata SystemTimer_1 = 0;

void timer0_int (void) interrupt TIMER0_VECTOR
{
	SystemTimer = SystemTimer_1;
    SystemTimer_1 += 10;
}




为什么在中断中自加,不是更新了RAM才出来的?确切原因有时间再深究,或者哪位大佬能给小弟指点一下。
这51单片机给我整出心理阴影了,还是避免我这个用法吧。



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/379674.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LabVIEW与Web通讯

LabVIEW与Web通讯Web客户端可通过LabVIEWWeb服务与远程LabVIEW应用程序交换数据。Web服务由运行在服务器上的VI和其他文件组成,这些VI对应于客户端发出的HTTP请求。LabVIEWWeb服务仅在LabVIEW完整版开发系统和LabVIEW专业版开发系统中可用。Web服务用于下列情况&…

服务器、存储、数据保护……又把奖拿了个遍

新一代高端存储      新一代中端存储      新一代入门级存储      新的数据保护产品线      新一代服务器和边缘服务器新品      … …      戴尔科技集团      在过去一年      继续保持强劲研发创新势头      不仅在硬件层面持续升级  …

NXP iMX8系列处理器Pin Multiplexing定义说明

By Toradex秦海1). 简介为了提高处理器的设计灵活性和可用性,NXP的所有i.MX系列处理器都配备了基于 IOMUX Controller (IOMUXC)和IOMUX来使能Pin Mux功能,使得一个特定的IO管脚可以选择不同的可能多达8种的功能定义模块(ALT0, ALT1, ALT2, ALT3...)&…

YOLOv5全面解析教程⑤:计算mAP用到的Numpy函数详解

作者 | Fengwen、BBuf 本文主要介绍在One-YOLOv5项目中计算mAP用到的一些numpy操作,这些numpy操作使用在utils/metrics.py中。本文是《YOLOv5全面解析教程④:目标检测模型精确度评估》的补充,希望能帮助到小伙伴们。 欢迎Star、试用One-YOLOv…

openpnp - configure - 主次基准点矫正

文章目录openpnp - configure - 主次基准点矫正概述备注ENDopenpnp - configure - 主次基准点矫正 概述 查找问题, 视觉里程碑只剩下4个问题了. 先看下设备上的主校准点, 我设备上的主校准点在设备前部的一个铝合金块上, 一块只带一个mark点的小PCB, 两边用螺丝拧住了.比PCB…

(五十四)大白话索引的页存储物理结构,是如何用B+树来实现的?.md

上一次我们给大家说了主键索引的目录结构,只要在一个主键索引里包含每个数据页跟他最小主键值,就可以组成一个索引目录,然后后续你查询主键值,就可以在目录里二分查找直接定位到那条数据所属的数据页,接着到数据页里二…

腾讯云轻量应用服务器配置表汇总(2核2G/2核4G/4核8G/8核16G)

轻量应用服务器(TencentCloud Lighthouse)是新一代开箱即用、面向轻量应用场景的云服务器产品,助力中小企业和开发者便捷高效的在云端构建网站、Web应用、小程序/小游戏、APP、电商应用、云盘/图床和开发测试环境,相比普通云服务器…

我的 System Verilog 学习记录(7)

引言 本文简单介绍 SystemVerilog 语言的 testbench 组件间通信和数据交互。 前文链接: 我的 System Verilog 学习记录(1) 我的 System Verilog 学习记录(2) 我的 System Verilog 学习记录(3&#xff…

使用msvc命令行或msbuild编译dx3程序

从这里下载:https://github.com/microsoft/DirectX-Graphics-Samples cl.exe /D "UNICODE" /D "_UNICODE" *.cpp /EHsc -I C:\Users\54930\Downloads\DirectX-Graphics-Samples-master\Samples\Desktop\D3D12nBodyGravity\src\WinPixEventRun…

为什么DNS安全很重要

几乎所有web流量都需要标准DNS查询,这为DNS攻击创造了机会,比如DNS劫持和中间人攻击。这些攻击可以将网站的入站流量重定向到网站的伪造副本,收集敏感用户信息,并使企业承担重大责任。目前防范DNS威胁的最普遍方法之一是采用DNSSE…

为什么地图可视化炙手可热?

我们在谈到数据可视化的时候,可能第一反应就是中间有一个地图样式的大屏图。但有没有想过,为什么大多数的可视化大屏中间都是一张地图的样子?这张地图样式的模块究竟是什么呢?它又是怎么做出来的? 其实这张地图样式的…

Linux基本命令复习-面试急救版本

1、file 通过探测文件内容判断文件类型,使用权是所有用户, file[options]文件名2、mkdir/rmdir 创建文件目录(文件夹)/删除文件目录 3、grep 指定文件中搜索的特定内容 4、find 通过文件名搜索文件 find name 文件名 5、ps 查…

电子科技大学 高级计算机系统结构 考试回忆

首先题量不算小,因此没有太多时间把题都记出来,但是叙述一下题的类型希望能帮到以后选了这门课大家,在网上确实没有搜到这门课有关考试的任何资料,所以我也没啥参考全凭记忆和老师的PPT结合。复习的时候老师给了大纲,就…

mysql字符串等值查询中条件字段值末尾有空格也能查到数据问题

一、事故还原 我们仍然使用学生信息表,但是我们只需要保留两个字段即可: CREATE TABLE student_info (id int(11) NOT NULL AUTO_INCREMENT COMMENT 学号,name varchar(20) CHARACTER SET utf8 DEFAULT NULL COMMENT 姓名, PRIMARY KEY (id) ) ENGINEIn…

挑战图像处理100问(26)——双线性插值

双线性插值是一种常用的图像插值方法,用于将低分辨率的图像放大到高分辨率。它基于一个假设:在两个相邻像素之间的值是线性的。 双线性插值考察444邻域的像素点,并根据距离设置权值。虽然计算量增大使得处理时间变长,但是可以有效…

电脑开机后进不了系统?原因以及解决方法

在日常使用电脑的过程中,我们有时候会遇到电脑开机后进不了系统的情况,这是令人十分烦恼的事情。那么,这种情况的出现可能是由于什么原因呢?接下来,本文将为您介绍电脑开机后无法进入系统的原因以及解决方法。 演示机型…

【Java】String类

1. String内部声明 jdk8以前: private final char value[]; final:指明数组一旦初始化,其地址就不能改变 jdk9以后: private final byte[] value;,为节省内存空间而优化 final:指明数组一旦初始化&…

这些让人变笨的食物你是不是天天吃?

我们关注食物的营养,关注它对身材、健康的影响。现在,我们发现有些食物,还会影响人的神经系统、认知能力。简而言之,就是有些食物可能会让人变笨。《美国医学会神经病学杂志》上的一项研究,分析了超加工食物与认知能力…

【蓝桥杯入门到入土】最基础的数组你真的掌握了吗?

文章目录一:数组理论基础二:数组知识点总结三:数组这种数据结构的优点和缺点是什么?四:实战解题1. 移除元素暴力解法双指针法2.有序数组的平方暴力解法双指针法最后说一句一:数组理论基础 首先要知道数组在…

【数据结构】堆的详解

本章的知识需要有树等相关的概念,如果你还不了解请先看这篇文章:初识二叉树 堆的详解一、二叉树的顺序结构及实现1、二叉树的顺序结构2、堆的概念及结构二、堆的简单实现 (以大堆为例)1、堆的定义2、堆的初始化3、堆的销毁4、堆的打印5、堆的插入6、堆顶元素的获取7…