STC32G FreeRTOS入门(3):STC32G PK STC8--完胜
一、STC8H系列单片机的试验结果(1)在上篇文章“STC8位单片机前后台任务编程中的问题”中给出了结论:对于STC8H单片机,使用Keil的C51编译器,“printf”这个库函数不能在前后台任务中同时使用。并指出出错的原因不是单片机,也不是程序员,出错的原因是“printf”这个库函数。(2)为了证明这个结论,还可以明显地在前后台任务中分别使用输入输出缓冲区数组,用“gets+sscanf”库函数来代替“scanf”,用“sprintf+puts”库函数来代替“printf”,进一步分析原因所在。下图是完整的使用输入输出缓冲区的程序:(3)在后台任务中,使用“RX_Buf”数组作为缓冲区,用第60行和第61行代替注释掉的第59行“scanf”程序,用第65行和第66行代替注释掉的第64行“printf”程序。在前台任务中,使用“TX_Buf”数组作为缓冲区,用第80行和第81行代替原来的“printf”程序。
对于STC8H8K64U单片机,运行的效果见下面视频:(4)从视频中可以看到,前台任务的输出是正确,后台任务的输出仍然是不正确的,见下面截屏:
从图中可以看出,对于输入字符串“987654321,123456789”,库函数“gets”的输入正确的,由于第63行的赋值程序“Z=X+Y”肯定是正确的,所以结果输出的错误一定出在“sprintf”库函数上。(5)结论:对于STC8H单片机,使用Keil的C51编译器,“sprintf”这个库函数同样不能在前后台任务中同时使用。(6)知识点:“sprintf”的输出中的“NaN”(Not a Number)是“非数字值”的意思,尤其会出现在浮点数转换中,比如要转换的数值是“无穷大”或者“无穷小”。
(7)知识点:在使用上位机键盘输入时,应该像截屏中那样,用一个回车(\r)作为输入结束符,如果像视频中那样用回车换行(\r\n)作为结束符,库函数“gets”会把它作为两个输入,其中第二个是空串。 二、STC32G系列单片机的试验结果(8)STC32G12K128是STC最新推出的一款32位单片机,它与8位的STC8H8K64U有高度的兼容性,一般的STC8H程序,只要换一个头文件就行了。
为了观察32位的单片机与8位单片机的差别,我将上面的程序中的第13行STC8H包含头文件换为STC32G的头文件进行了试验,将STC8H单片机与STC32G单片机进行PK。下面是同样的前面程序在STC32G12K128单片机上运行的结果:
(9)从视频上可以看到运行结果是无论前台任务或者后台任务的运行结果都是正确的。下图是截屏:
其中:X+Y=1111111000,这个结果是正确的。(10)知识点:明明小学生都知道“987654321+123456789=1111111110”,为什么上图的结果“987654321+123456789=1111111000”会是正确的呢?这是因为X、Y和Z都是单精度浮点数变量,它们的精度只有7位有效数字,所以在其精度范围内,它是正确的。(11)结论:对于STC32G单片机,使用Keil的C251编译器,在前后台任务中使用“sprintf”和“puts”库函数都是正确的。STC32G+Keil C251与STC8H+KeilC51 PK的结果:完胜 三、STC32G胜之必然
(12)众所周知STC8H内核是8051CPU,只有A、B和R0~R7共10个8位通用寄存器做常规程序处理用,而STC32G不同,它的内核是扩展的80251CPU,其通用的寄存器如下表:
(13)STC32G单片机有8个32位的通用寄存器DR0、DR4、DR8、DR12、DR16、DR20、DR24和DR28,这些32位通用寄存器都可进行32位的运算:整数加(ADD)、整数减(SUB)、比较(CMP)和逻辑运算,其中DR0和DR4还可以进行32位的整数乘法(MUL32)、32位的无符号整数除法(DIVU32)和32位的有符号整数除法(DIVI32)。也正是由于STC32G单片机能够完整地实现了所有32位的整数运算,它是一款名副其实的“32位单片机”,而传统的80251CPU不包括32位的乘除运算,一般只称为“准32位内核”。(14)STC32G单片机的8个32位的通用寄存器每个都可以拆为高低两个16位的通用寄存器,比如DR20拆为WR20高16位和WR22低16位两个16位寄存器,再比如DR4拆为WR4高16位和WR6低16位两个16位寄存器,共计16个16位通用寄存器。STC32G的16个16位通用寄存器,全部都可以进行16位的整数加、减、乘、除、比较和逻辑运算,其中乘除运算的结果是32位的。由于每个32位寄存器与对应的两个16位寄存器不是独立的,对其中一个的运算都可能会影响到其他两个。(15)STC32G单片机的低4个32位的通用寄存器DR0、DR4、DR8和DR12每个都可以再拆分为4个8位通用寄存器,共计16个。STC32G的16个8位通用寄存器,全部都可以进行8位的整数加、减、乘、除、比较和逻辑运算,其中乘除运算的结果是16位的。由于这4个低32位寄存器与对应的两个16位寄存器以及对应的4个8位寄存器不是独立的,对其中一个的运算都可能会影响到其他的寄存器。(16)STC32G单片机的扩展80251CPU包含一个8051CPU的全子集,其中通用寄存器R0~R7与8051的R0~R7寄存器对应,R11与A寄存器对应,R10与B寄存器对应。(17)结论:由于STC32G的通用寄存器数量是STC8H的4倍,因此它使用的Keil的C251编译器的库函数“sprintf”可以把这些通用寄存器作为局部临时变量使用,使得该函数是可重入的函数,因此在前台和后台任务中可以同时使用。
而STC8H没有那么多通用寄存器可用,它使用的Keil的C51编译器的库函数“sprintf”只能把局部临时变量放到RAM中,造成该函数是不可重入的函数,所以不能同时在前台和后台任务中使用。下面是本文使用的范例程序:
版主的意思是STC32系列是不是比STC8系列更适合使用实时操作系统?? lzzasd 发表于 2023-11-16 21:11
版主的意思是STC32系列是不是比STC8系列更适合使用实时操作系统??
是的 本帖最后由 13918210822 于 2024-1-7 13:07 编辑
最近为了使用STC32F上使用多任务RTOS, 再梳理一遍指令表
发现STC32栈指针是16位SPX(DR60), 加上一个24位DPTR(DR56)
所以,合适的讲STC32其实是一个指令在编译器支持下兼容8051的增强的8/16位机,32位乘除是通过MDU32协处理模组支持,可通过总线通过DMA反馈结果。
从历史上将,80251的指令集出现在ARM之前,属于8位到32位过渡阶段的一个产品。
如果真的要完整支持32位指令,应该从底层开始扩展一个80351的指令集出来。
当然,这需要时间也需要STC以及爱好者的共同热诚。毕竟无论是FPGA验证还是底层工具链都是一条长路。
实事求是,
附上总结的指令表(STC32F参考规格书附录A) 13918210822 发表于 2024-1-7 13:03
最近为了使用STC32F上使用多任务RTOS, 再梳理一遍指令表
发现STC32栈指针是16位SPX(DR60), 加上一个24位DPT ...
你将 24位寻址/16M空间,和 32位数据总线混为一谈,还是典型的没认真思考
本帖最后由 13918210822 于 2024-1-7 15:23 编辑
神农鼎 发表于 2024-1-7 14:25
你将 24位寻址/16M空间,和 32位数据总线混为一谈,还是典型的没认真思考
举个例子,说明32位指令不全,比如立即数装载就要2条指令
; line 48: volatile long c1 = 0x7EFDFF02, c2 =0x80000003;
MOV WR6,#0FF02H
MOV WR4,#07EFDH
MOV c1?140,DR4
MOV WR6,#03H
MOV WR4,#08000H
MOV c2?141,DR4
; line 49: c1 += c2;
MOV DR0,c2?141
MOV DR4,c1?140
ADD DR4,DR0
MOV c1?140,DR4
究其根源,251没有 MOV DRj, #32
这不影响 STC32 是 32位数据总线
你去看看 M0, 没除法,成本的考量
另外我请教下,如果指令长度限定是 32位及以下长,
如何编写一条指令:将32位立即数送到某个地址的寄存器 !
寄存器地址放哪,如何执行某个指定动作
===要考虑成本,如何设计这条指令/请32位长度搞定 !
13918210822 发表于 2024-1-7 15:16
举个例子,说明32位指令不全,比如立即数装载就要2条指令
; line 48: volatile long c1 = 0x7EFDF ...
ARM和RISC-V都没有一条指令装载32位立即数 13918210822 发表于 2024-1-7 15:16
举个例子,说明32位指令不全,比如立即数装载就要2条指令
; line 48: volatile long c1 = 0x7EFDF ...
有MOV DRj, #16位立即数 13918210822 发表于 2024-1-7 15:16
举个例子,说明32位指令不全,比如立即数装载就要2条指令
; line 48: volatile long c1 = 0x7EFDF ...
ARM和RISC-V还都没有直接寻找指令,比如算C1=C2+C3,用ARM的话要这样:
LDR R0,=C2
LDR R1,
LDR R0,=C3
LDR R2,
ADD R1,R2
LDR R0,=C1
ST R1,
而STC32的话是这样
MOV DR0,C2
MOV DR4,C3
ADD DR0,DR4
MOV C1,DR0
页:
[1]
2