网站首页 > 技术文章 正文
运算符%
说完位运算,再说说其他的运算符。+ - * / 不用多说,应该都比较清楚,但是还是要注意的就是使用 / 进行整型变量的计算时,它不像平常一样可以得到小数的,而只有整数部分,并没有小数。还有就是各个运算符的顺序,如果不确定哪个先运算,不如加上括号()吧,不用担心效率的问题,因为加了括号只是告诉编译器该如何处理这条语句而已。另外使用#define定义一些表达式的时候也最好加上括号,因为你不能确定你这个宏定义会在什么地方使用,为了安全起见还是加上比较好,这些内容在宏定义小节将进行更详细的说明。
现在来重点说说 % 取余运算。这个运算就很有意思了。如果从51单片机过来的,看到这个运算符最多的地方就是在为定时器赋值时将高低字节进行分离了,还有在数码管实验中将一个数分离成十进制的。这些都是很常见的应用。但是其实更广泛的应用不在此。
编程的时候,很多时候都会要求一个数在某一个范围内进行反复循环,0~100循环,0~5循环等等。一般的方法是使用if语句,当判断达到最大值的时候回到开始处。实际上使用这种方法也是可以的,但是如果有更简单更高效的方法你是否还会使用if语句呢。
先说说使用 & 的方法吧。比如说我想让一个数在0~7内循环,该如何做呢?temp = (temp++)&0x07,如此就简单的实现了0~7循环。因为要实现0~7的循环,其实只要提取一个变量递增的低三位即可。不管这个变量如何变化,它的低三位始终都是在0~7循环变化的。同理,它也可以实现0~15、0~31变化。但是这个方法有局限,它只能按照连续bit位的最大值进行循环。
现在再说 %,这个就厉害了,它不存在这个限制。可以在0~任意数循环。比如0~5循环,只要temp = (temp++)%6(注意是6而不是5),那么temp就会在0~5之间循环了(这是我在看循环队列的时候看到的方法,当时很是震惊,关于循环队列更多的东西将在循环队列中讲解)。
很神奇吧,更神奇的是使用它还可以计算两个变量之间的距离(因为距离时没有负数的,这里我称之为距离可能不是很好理解,慢慢来)我们知道不管是8bit数据,16bit、32bit、64bit,它始终有一个位数的限制,如何在有限的位数里面获得两个数据之间准确距离信息呢。以8bit为例,最大数为255,第一次读取为0x4,第二次读取是0x9,那么从0x04变化到0x09,变化了几次(递增数为1)? 9 – 4 = 5,如果变化后的数小于255当然好办,但是超过了255,又从0开始递增呢?这个时候又该如何。
比如说一开始读取的是251,之后再读一次,变成了1,怎么算,251-1=250?肯定不对,1-250=-250,更不是?那到底变化了几次?252、253、254、255、0、1,这里可以看出是6,但是该怎么计算,又是否有一个公式可以在不改变原来数据变化的情况下将超过限制和没超过限制这两种情况的计算包含呢。有的。就是length = (num2 – num1 + max)%max。关于这个公式更详细内容请看循环队列小节。
确实,使用%可以在任意数之间循环,但是她也有限制,就是目前来看只能实现递增1的情况,我想递减呢?就是说我想从9减为0,然后从9开始继续,又该如何。我的一个项目就需要这样的变化,怎么办,如果用if确实能够解决问题,但是直觉告诉我,肯定有简单方法实现,所以我就上网搜,但是可能我搜索的方法不对,始终没有搜到,所以我暂时搁置了。直到一天夜里,回想递增循环的情况,慢慢的思考其中的本质,再结合距离计算的公式,突然明悟了。就是num--; num = (num+max)%max;这样两条语句去实现。比如9~0,就是num--; num = (num+10)%10;
那么怎么理解呢,按理说0再自减就是0xff,即255,再加10就是265,265%10 =5,怎么就变成了9呢?这和存储有关。255从有符号的角度来看,就是-1,-1+10等于9,9%10=9,没错,就是如此。但是我的变量声明不是有符号的,而是无符号的,怎么也没有出问题呢?这是因为溢出了,因为265在8bit情况下溢出就变成了9,所以计算也不会出现问题。所以这些计算机基础方面的东西一定要理解透彻清晰,才能更好的驾驭一门语言,你也会发现其中的东西真的很神奇……
查看原文:https://www.dianyuan.com/eestar/article-8147.html
i.MXRT四位数系列Boot之编程利器Flashloader
在上一篇文章 Serial Downloader模式(sdphost, mfgtool) 里痞子衡为大家介绍了i.MXRTyyyy Boot的Serial Downloader模式,这种模式主要是用来引导启动Flashloader,那么Flashloader到底具有哪些功能?这是本篇文章痞子衡要为大家解惑的主题。
痞子衡在前面提过Flashloader程序主要是用来将你的Application下载进i.MXRTyyyy支持的所有外部非易失性存储器中,为后续从外部存储器启动做准备。BootROM只有启动Application功能,没有下载更新Application功能,而Flashloader最核心的就是下载更新Application功能,所以Flashloader是BootROM的完美补充。你可能会疑问,为什么不把Flashloader的下载更新Application的功能也放进BootROM里?痞子衡个人觉得应该是芯片成本问题,ROM的空间是96KB(RT102x/RT105x)/128KB(RT106x),如果把Flashloader功能也放进BootROM里,势必要扩大ROM空间,从而导致芯片成本上升,做成二级Flashloader既不占ROM空间,也方便Flashloader程序自身的维护升级(目前RT1050的Flashloader版本是1.1,你看,这不显然升级过嘛)。
一、进入Flashloader程序
1.1 官方程序包
恩智浦提供了 Flashloader程序包,你首先需要下载这个Flashloader包,Flashloader所有相关资源全在包里面。注:每个i.MXRTyyyy子系列均有一个以子系列名字命名的Flashloader包,即Flashloader程序并不是通用的(偷偷告诉你,其实RT105x与RT106x是通用的),此处以RT1050系列为例:
Flashloader程序是\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Flashloader\flashloader.elf Flashloader工具在\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools目录下
1.2 三种引导方式
其实引导启动Flashloader的方式并不唯一,Flashloader就是一段运行在SRAM中的应用程序而已,只要能有工具将Flashloader下载进SRAM,并将CPU的PC指针指向Flashloader的程序入口便可启动Flashloader。下面痞子衡分别介绍3种引导方式:
1.2.1 标准方式:通过sdphost
第一种引导方式是通过BootROM的Serial Downloader模式和sdphost.exe工具,这是恩智浦官方推荐的方式,这种方式在上一篇文章里已经详细介绍过了,这里不再赘述。 这种方式的优点是不需要外接调试器,缺点是涉及到BootROM启动以及IVT的知识,需要有BootROM相关知识储备。
1.2.2 简便方式:通过J-Link Commander
第二种引导方式是通过外接J-Link调试器和J-Link Commander工具(JLink.exe)。i.MXRTyyyy芯片JTAG口连接上J-Link调试器后,安装好Jlink驱动(痞子衡安装的是v6.30e版本),打开J-Link Commander(即\SEGGER\JLink_V630e\JLink.exe),连接上i.MXRTyyyy的Core,按顺序执行如下JLink命令:
到这里Flashloader就已经被成功启动了,有朋友看不懂上面的一串JLink命令,痞子衡为大家解释一下:
- loadfile命令用于将Flashloader程序数据(.srec格式,含地址信息)下载进SRAM(0x20002000)中;
- mem32命令用于从起始下载地址(0x20002000)读回部分数据(8字节)确认上一步的下载操作是否成功,并且获取Flashloader的起始SP和PC值。
- wreg命令用于设置R13(MSP/PSP)寄存器的值,使其等于Flashloader的初始SP值。
- SetPC命令用于设置R15(PC)寄存器的值,使其指向Flashloader的初始PC。
- g命令用于让Core开始执行代码(Flashloader程序)。
这种方式的优点是不需要借助BootROM(你可以不用了解BootROM相关工具用法),缺点是需要额外准备一个J-Link调试器。
Note:关于JLink命令的详细解释请查阅JLink驱动软件安装目录下\SEGGER\JLink_V630e\Doc\UM08001_JLink.pdf文档里的3.2 J-Link Commander (Command line tool)一节。
1.2.3 高级方式:通过Ozone
前两种引导方式都是把Flashloader程序当做黑盒子,只需要将其启动运行即可,接下来痞子衡介绍的引导方式可以让你看到Flashloader源代码并且可以让你调试Flashloader。这第三种引导方式还是通过外接J-Link调试器,但还需要一个特殊的软件,即SEGGER公司提供的Ozone软件,去SEGGER先下载Ozone软件(痞子衡下载的版本是v2.56c),下载安装后打开Ozone软件,第一步选择CM7,第二步选择SWD,第三步选择elf文件时要选择Flashloader下载包里的flashloader.elf……
查看原文:https://www.dianyuan.com/eestar/article-8167.html
告别拷贝烦恼:为何版本管理工具是更好的选择?
前言
在没有专门版本管理工具之前,一些人可能会选择的简单版本管理方法:文件拷贝备份。虽然这是一种简单的方式,但它也存在一些不足之处。通过下面可以了解到为什么需要专业的版本管理工具,如Git。
如果你是一个从未使用过软件版本管理的新手(指的是连文件拷贝备份都没有操作过),或许会对专业的版本管理工具感到陌生,但相信我,一旦你了解并开始使用它,你将会发现它是一个极为强大而又实用的工具。
什么是版本管理
版本管理是一种记录文件变更历史的系统,用于跟踪、管理和控制项目中文件的变化。它使得开发者能够追溯到项目的任意历史状态,方便协同开发、Bug追踪和项目维护。
通俗来说,在实际的软件开发过程中,通常会遇到实现某一个功能后或者想优化软件代码时,都会将整个工程复制副本备份起来,避免软件修改后出现问题,但是因为不知道改动了哪些地方而无法还原之前的软件代码。因此在软件开发过程中,常常会有很多工程副本存在,但是副本一多,自己也不知道每个副本对应的状态是什么,也许有的人考虑到了,所以重命名副本的时候都会有一些简单描述用来记录当前工程副本的状态。
为什么要使用版本控制工具
文件拷贝备份存在的问题有:
不可追溯性:通过手动拷贝,我们能够保存项目在某一时刻的状态,但无法准确追踪到每个文件的具体变更历史。这在项目变得复杂时会变得非常困难。
大量冗余数据:每次拷贝都复制整个项目,导致大量冗余数据,不仅占用磁盘空间,还增加了备份和恢复的时间成本。
容易出错:手动操作容易引发错误,例如忘记拷贝某个文件或者错误地覆盖了之前的备份,可能导致数据丢失或者项目状态混乱。
不适用于多人协作:在团队协作的情境中,手动拷贝的方式容易引发混乱,需要额外的规则来同步项目状态。
通过专业的版本管理工具,可以做到:
追踪变更:版本管理系统能够准确记录每一次代码变更,包括新增、修改和删除的操作,从而清晰地了解项目的发展历程。
团队协作:在多人协作的环境中,版本管理系统可以协助开发者独立工作、合并各自的改动,并最终将这些改动整合成一个统一的版本。
Bug追踪:版本管理系统可以帮助快速定位Bug的引入点,因为你可以准确地追溯到哪一次变更导致了问题。
回滚和恢复:遇到问题或者需要回到之前的某个版本?版本管理系统可以轻松地帮助你回滚到任意历史状态,确保项目的稳定性。
提高代码质量:因为代码中有些改动没有任何注释时,通过版本记录能查到当时因为什么原因改动的,也可删除无用代码
节省存储空间:采用差异存储方式,有效节省磁盘空间,提高存储效率。
查看原文:https://www.dianyuan.com/eestar/article-8133.html
嵌入式中,日志调试法的一些规则!
在我们嵌入式开发中,打印日志是最常用的一种调试手段。合理地打印日志,可以帮助我们快速地分析问题。
本篇文章我们来汇总一些嵌入式打log的一些规则。
1、什么操作下加日志?
(1)错误处理
对于不能恢复的严重错误,日志内容应详细到足以帮助定位问题,但同时不应该包含敏感信息。比如申请内存失败时使用错误(Error)级别加上日志信息。
(2)一些关键性的操作
一些很关键地处理,无论是正常情况或者异常情况都要打印日志。比如wifi打开时要有对应的日志信息。
(3)系统的打开、关闭
记录系统启动和关闭过程中的关键步骤有助于分析系统初始化是否正确,或者系统是否正常关闭。
(4)性能监控
日志可以记录系统运行的关键性能指标,如CPU和内存使用率、IO操作等,以便进行系统性能分析和优化。
(5)关键数据
一些关键数据需要打印,很多功能上的问题大多直接与数据进行挂钩。
(6)通信日志
对于需要与外部设备或网络通信的嵌入式系统,记录通信日志可以帮助分析和调试通信协议或数据交换的问题。
(7)记录用户行为
在需要分析用户如何与嵌入式设备交互的情况下,记录用户行为的日志会非常有帮助。
(8)if、switch
分支判断中,各执行分支需要加上对应的日志信息,可以帮助我们准确地知道程序执行的走向。
(9)程序崩溃时的信息
比如,Linxu下应用进程崩溃时的调用堆栈信息。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <execinfo.h>
void func0(void)
{
printf("This is func0\n");
int *p = NULL;
*p = 1234;
}
void func1(void)
{
printf("This is func1\n");
func0();
}
void func2(void)
{
printf("This is func2\n");
func1();
}
void dump(int signo)
{
void *array[100];
size_t size;
char **strings;
size = backtrace(array, 100);
strings = backtrace_symbols(array, size);
printf("Obtained %zd stacks.\n", size);
for(int i = 0; i < size; i++)
{
printf("%s\n", strings[i]);
}
free(strings);
exit(0);
}
int main(int argc, char **argv)
{
printf("==================segmentation fault test5==================\n");
signal(SIGSEGV, &dump);
func2();
return 0;
}
2、功能模块标签
项目中肯定会划分有多个模块,可以给各个模块标记一个模块标签字符串,包含在日志条目里。这样我们就可以在日志文件里通过模块标签来筛选某个模块的日志,提高我们定位问题的效率……
查看原文:https://www.dianyuan.com/eestar/article-8124.html
XECC为串行NOR Flash和SDRAM保驾护航
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是i.MXRT1170 XECC功能特点及其保护串行NOR Flash和SDRAM之道。
ECC 是 “Error Correcting Code” 的简写,ECC 能够实现错误检查和纠正,含有 ECC 功能的内存一般称为 ECC 内存,使用了 ECC 内存的系统在稳定性和可靠性上得到很大提升。相比前几代不带 ECC 的 i.MXRT10xx 型号,新一代 i.MXRT1170 在 ECC 上做了全面武装,从 eFuse到 FlexRAM,从 OCRAM 到外部存储空间全都加上了 ECC 功能。如下表所示,不同类型的存储由不同的 ECC 控制器来守护:
今天痞子衡给大家简单介绍一下 i.MXRT1170 上用于保护挂载在 FlexSPI 和 SEMC 接口上的外部存储器的 XECC 功能:
一、XECC功能简介
1.1 XECC特点
从用户角度来说,其实 XECC 的设计特别简单,当 XECC 使能后,任何对 ECC 保护区域的 AHB 访问(注意仅 AHB 方式才能激活 XECC,IPG 方式是不受 XECC 影响的)都会被 XECC 模块接管,WECC 组件负责根据用户写入的数据值产生 ECC 校验值一并存入目标地址,RECC 组件负责根据用户读取的地址获取相应 ECC 检验值并做检验处理后再返回数据值。WECC 和 RECC 组件可独立开关控制。
XECC 模块一共有三个,分别是 XECC_FLEXSPI1、XECC_FLEXSPI2、XECC_SEMC,每个模块均支持 4 个 ECC 区域的设置(区域最小单位 4KB,即 ECC_BASE/EDD_ADDRx 寄存器的低 12bits 总是 0)。
1.2 关于ECC设计细节
关于 ECC 基本概念,参看《简析i.MXRT1170 Cortex-M7 FlexRAM ECC功能特点、开启步骤、性能影响》 的 1.2节,这里不予赘述。
1.2.1 ECC检验能力
XECC 中每 4bits 数据就会计算出一个 ECC 校验值(4bits),不同于 FlexRAM ECC 会有专门的独立存储空间用于存放 ECC 校验值,XECC 校验值是紧跟着放在源数据后面的,这意味着 XECC 校验值会占据目标存储器(Flash 或 SDRAM)里受 ECC 保护区域的一半空间。
存储类型ECC校验数据块大小ECC校验值长度ECC校验能力Raw NAND512 bytes4 bytes5-bit检错,4-bit纠错XECC4bits4bits2-bit检错,1-bit纠错
为便于 master 通过 AHB 总线访问,实际 XECC 检验值是拓展到 32bits 来存储的,即 32bits 原始数据后面会紧跟着 32bits XECC 检验值,如此往复如下图所示。
比如 XECC 保护挂在 FlexSPI1 上的 Flash,设置的 Flash ECC 保护区域为 0x30000000 - 0x30000FFF,共 4KB 空间。那么从实际物理空间角度(IPG 方式去读)来说 0x30000000 处保存的是原始 4bytes 用户数据(D0),0x30000004 处保存的是 4bytes XECC 校验值(E0),0x30000008 处保存的又是原始 4bytes 用户数据(D1),0x3000000c 处保存的又是 4bytes XECC 校验值(E1)...
注意上述地址均表述的是实际物理地址,但 master 通过 AHB 总线直接读写 Flash 时,仅需访问 0x30000000 - 0x300007FF 空间里的 2KB 实际用户数据即可,完全不需在意另外 2KB 的 XECC 检验值的处理,SoC 系统里直接做了自动处理与地址转换,即 0x30000000 处对应校验后的 4bytes 用户数据(D0),0x30000004 处对应校验后的 4bytes 用户数据(D1)...
1.2.2 ECC错误触发处理
ECC 错误分两种,分别是 1-bit 错误和 2-bit 错误(针对 4bits 数据而言)。从软件层面来看,1-bit 错误可以不用管,XECC 模块会自动纠错。我们主要处理 2-bit 错误,由于 2-bit 错误仅能检错,无法纠错,所以发生了这个错误,就意味着读取的数据不可靠了。对于 1/2 bit错误,XECC 均提供了中断响应(XECC_xxModule_INT_IRQn / XECC_xxModule_FATAL_INT_IRQn)。
对于 32bits 数据而言,XECC 是可以纠正其中发生的 8bits 错误的,但前提是按序分割开的每 4bits 数据位仅能有 1bit 错误,如果这 4bits 数据位里有多 bit 错误,我们依然想校正的话,需要借助 Data Swap 功能,这里不再单独展开,可查看 RM 了解细节。
二、开启XECC的步骤
2.1 激活XECC特性
芯片出厂,默认是没有激活 XECC 特性的,如果需要开启 XECC,需要烧写 efuse,fusemap 中 0x840[3] 对应的是 XECC_ENABLE bit,我们需要将这个 bit 烧写成 1,才能激活 XECC 特性。
2.2 初始化存储器接口外设
在初始化 XECC 模块之前一般先初始化存储器接口外设,这里我们先初始化 FlexSPI1,因为测试板卡 MIMXRT1170-EVK 上默认是 FlexSPI1 连接的串行 NOR Flash。
void init_flexspi_flash(void)
{
flexspi_nor_flash_init(FLEXSPI1);
// 尽量等待 FlexSPI 总线空闲再退出
if ((FLEXSPI1->MCR0 & FLEXSPI_MCR0_MDIS_MASK) != FLEXSPI_MCR0_MDIS_MASK)
{
while (!FLEXSPI_GetBusIdleStatus(FLEXSPI1));
}
FLEXSPI_SoftwareReset(FLEXSPI1);
}
2.3 SDK驱动初始化XECC
然后可以直接利用 SDK 里的 fsl_xecc 驱动对 XECC 模块进行初始化,代码非常简单,如下示例代码就是初始化 XECC_FLEXSPI1,使能 0x30000000 - 0x30000FFF 区域的读写 ECC 功能……
查看原文:https://www.dianyuan.com/eestar/article-8164.html
更多精彩内容,尽在电子星球 APP(https://www.eestar.com/)
- 上一篇: 自动控制原理-滞后校正设计方法以及编程实现
- 下一篇: 有没有通俗易懂的动态代理示例可供参考学习?
猜你喜欢
- 2024-12-31 发那科机器人2DV码垛功能
- 2024-12-31 如何使用python进行正确的四舍五入?这个坑有点大
- 2024-12-31 有没有通俗易懂的动态代理示例可供参考学习?
- 2024-12-31 第十九天:EXCEL万能字符串转换函数TEXT那些普拉斯的神操作
- 2024-12-31 自动控制原理-滞后校正设计方法以及编程实现
- 2024-12-31 C语言 | 由小到大输出两个数
- 2024-12-31 C++笔记:函数
- 2024-12-31 十万个怎么办-不清楚机器人TEST指令怎么办?
- 2024-12-31 一个 print 函数,挺会玩啊?
- 2024-12-31 Excel公式计算
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)