当前位置: 首页 > news >正文

【目录】8051汇编与C语言系列教程

8051汇编与C语言系列教程

作者将狼才鲸
创建日期2024-07-23
  • CSDN文章地址:【目录】8051汇编与C语言系列教程
  • 本Gitee仓库原始地址:才鲸嵌入式/8051_c51_单片机从汇编到C_从Boot到应用实践教程

一、本教程目录

序号教程名称简述教程链接
1点亮LCD灯通过IO输出而点亮LCD灯教程链接
2延时与函数用汇编准确延时函数,C语言近似延时函数教程链接
……………………

二、参考网址

  • 51单片机教程(简叙及目录)1~28章 51单片机教程(从原理开始基于汇编)
    • 评分:5分。51单片机汇编,可以下载源码和工程,能直接运行。教程非常入门,有单片机介绍、组成部分、引脚介绍、Keil使用、汇编介绍、IO口介绍、寄存器、汇编指令介绍、数码管等。
  • 单片机c语言教程1~17
    • 评分:5分。51单片机的C语言和32位ARM C语言有点不一样,这个教程描述了8051专有的存储关键字,Keil使用
  • 零基础学习8051单片机(一)~(十六)
    • 评分:5分。和学校里学的类似,讲解了8051单片机的结构、组成、有哪些历史厂商、常用寄存器的介绍。
  • 51单片机入门教程0~6
    • 评分:4分。介绍了Keil和Proteus,模拟器使用Proteus来运行程序,展示了传统的流水灯、数码管、按键。
  • 51单片机从零开始学习
    • 评分:4分。介绍了C语言关键字、Keil使用、流水灯、按键、数码管、模块化编程、定时器、串口、外设控制。
  • 单片机学习教程(目录)1~20章
    • 评分:4分。51单片机C语言。
  • 51单片机轻松入门—基于STC15W4K系列(C语言版)1-22章
    • 评分:4分。
  • 51单片机入门基础教程(共十节)
    • 评分:4分。介绍了原理、引脚、代码。
  • 单片机入门教程1~7
    • 评分:4分。51单片机介绍、键盘、LCD、定时器。
  • 单片机教程
    • 评分:4分。代码不全。51单片机的一些项目设计:万年历、宠物小屋、视频小车等
  • 51 单片机1~18
    • 评分:4分。代码不全。一些单片机自带模块的项目。
  • 51单片机-从零开始入门1~14
  • 51单片机教程1~6
    • 评分:3分。内容少。
  • 单片机应用1~32
  • 屠龙刀STC32保姆级教程[共9篇-13个实验代码]

三、教程介绍

1、点亮一个LED灯

  • 本源码包含C语言和汇编工程,能直接在电脑中通过Keil模拟器运行,并在Keil示波器窗口看到 IO 输出的矩形波。

  • 源码及工程链接

    • 汇编效果:img
    • C语言效果:img
  • 汇编源码:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; \brief	让LCD灯闪烁(控制IO输出)
; \details	使用Keil Simulator模拟器,和Debug时的Logic Analyzer示波器窗口查看输出
; \remark	File format: UTF-8,源文件使用UTF-8中文编码
; \note		省略了8051的初始化,使用模拟器时会自动准备好运行环境
; \author	将狼才鲸
; \date		2024-07-18
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 头文件 ;;
;$INCLUDE(at89c51xd2.inc)	; 也可以使用 #include <at89c51xd2.inc>,Keil默认隐藏包含了8051通用寄存器,不用重复包含MAIN:	; 标号或函数名; 请在Debug后通过 View--Analysis Windows--Logic Analyzer--Setup--点击右上角叉叉左边的新建图标--键入P1; --点击选中P1--在Max那里将0xFF改成0x01--在And Mask中将0xFFFFFFFF改成0x00000001--Close 来创建模拟器中示波器的采样引脚;; 把示波器的小窗口向下拉一点,露出波形的显示区域;; 再点击Zoom中的All来显示整个波形(不点击会看不到变化的波形);; 再F10单步运行,一边运行一边看输出的矩形波。CLR		P1.0	; P1_0 IO口置低;P1.0里面的.0是汇编的特殊语法,意思是前面P1寄存器的第0 bit,能位寻址的寄存器都能这样调用SETB	P1.0	; P1_0 IO口拉高LJMP	MAIN	; 跳转到标号END	; 源文件结束
  • C源码:
/******************************************************************************* \brief	让LCD灯闪烁(控制IO输出)* \details	使用Keil Simulator模拟器,和Debug时的Logic Analyzer示波器窗口查看输出* \remark	File format: UTF-8,源文件使用UTF-8中文编码* \note	省略了8051的初始化,使用模拟器时会自动准备好运行环境* \author	将狼才鲸* \date	2024-07-18******************************************************************************//** 头文件 **/
#include <Atmel/at89c51RC2.h>	/* 寄存器定义 *//** 接口函数 **/
int main(void)
{while (1){/**请在Debug后通过 View--Analysis Windows--Logic Analyzer--Setup--点击右上角叉叉左边的新建图标--键入P1_0--Close 来创建模拟器中示波器的采样引脚;把示波器的小窗口向下拉一点,露出波形的显示区域;再点击Zoom中的All来显示整个波形(不点击会看不到变化的波形);再F10单步运行,一边运行一边看输出的矩形波。*/P1_0 = 0;	/* P1_0是头文件中已经定义的寄存器Bit */P1_0 = 1;}
}
  • 参考网址:
    • 2课:单片机引脚介绍 该文章后半部分有C语言原始工程下载链接
    • 4课:第一个单片机小程序 该文章前半部分有汇编原始工程下载链接

2、延时与函数

  • ms、us级别的延时最好使用定时器,ns级别的延时就可以关闭所有中断后使用汇编,不需要精准的延时则可以使用C语言的for循环;

    • 使用C语言进行延时时,延时的时间不好算,一般通过实际测试得到,并且延时的时间长短容易受到代码优化的影响;
    • 在关闭中断的情况下,汇编函数可以做到精准控制延时,精度和指令周期一致,前提是你要知道当前主频和每条指令的执行时间(指令周期);
  • 延时可以用在IO输出的时序控制和通信端口模拟,例如用IO口模拟I2C、SPI、SDIO等协议;

  • 源码及工程链接

    • 该汇编工程里演示了汇编函数的编写、参数的调用和精准的延时;
    • 该C语言工程里演示了一般的延时,在C语言中如何调用汇编函数;
    • 汇编效果:img
    • C语言效果:img
    • C语言中调用汇编精准延时效果:img
  • 汇编精准延时函数源码:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; \brief	演示延时与函数,控制LCD灯闪烁的间隔
; \details	使用Keil Simulator模拟器,和Debug时的Logic Analyzer示波器窗口查看输出
; \remark	File format: UTF-8,源文件使用UTF-8中文编码
; \note		省略了8051的初始化,使用模拟器时会自动准备好运行环境
; \author	将狼才鲸
; \date		2024-07-21
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8051汇编指令及每条指令所消耗的时钟数详见:
; https://gitee.com/langcai1943/8051-from-boot-to-application/blob/develop/02_doc/01_8051寄存器、指令集、伪指令和关键字介绍.md; 当前工程中配置的晶振是Keil默认的24MHz,时钟周期41.67ns,状态周期是2倍时钟周期即83.3333ns,
; 机器周期是6倍状态周期即500ns,一个机器周期记为1T,一条指令周期为1~4T,具体哪条指令占多少T需要查阅上面文档;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 声明 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$NOMOD51	; 不使用Keil默认隐含的8051通用寄存器定义,而是显式的包含寄存器定义头文件;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 头文件 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$INCLUDE(at89c51xd2.inc)	; 也可以使用 #include <at89c51xd2.inc>,实际文件在C:\Keil_v5\C51\ASM\at89c51xd2.inc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 宏定义 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INS_SET_10US_NUM	EQU 20	; 10us占20个机器周期;当前工程中配置的晶振是Keil默认的24MHz,时钟周期41.67ns,机器周期500ns;;; 宏定义函数
DELAY_1US  MACRONOP	; 1T,500nsNOP
ENDMDELAY_2US  MACRODELAY_1USDELAY_1US
ENDMDELAY_4US  MACRODELAY_2USDELAY_2US
ENDMDELAY_8US  MACRODELAY_4USDELAY_4US
ENDMDELAY_16US  MACRODELAY_8USDELAY_8US
ENDM;;
; \brief	汇编主函数,演示延时与函数,控制LCD灯闪烁的间隔
;			其实不算真正的函数,只是标号 + 死循环
; \param	无
; \return	无
;;
MAIN:	; 标号或函数名; 请在Debug后通过 View--Analysis Windows--Logic Analyzer--Setup--点击右上角叉叉左边的新建图标--键入P1; --点击选中P1--在Max那里将0xFF改成0x01--在And Mask中将0xFFFFFFFF改成0x00000001--Close 来创建模拟器中示波器的采样引脚;; 把示波器的小窗口向下拉一点,露出波形的显示区域;; 再点击Zoom中的All来显示整个波形(不点击会看不到变化的波形);; 再F10单步运行,一边运行一边看输出的矩形波。CLR		P1.0			; 1T(耗时1个机器周期),P1_0 IO口置低;P1.0里面的.0是汇编的特殊语法,意思是前面P1寄存器的第0 bit,能位寻址的寄存器都能这样调用;; 和CLR一起延时10us,再补齐9.5usNOP						; 1T,0.5usDELAY_8US				; 宏定义函数DELAY_1US;; 延时990usMOV		R7, #99			; 1T;延时99 x 10 = 990us;0xR7 = 十进制99;调用函数时,第一个参数是0xR7LCALL	_delay_us_10x	; 2T,传入的参数是R7;; 延时4msMOV		R6, #HIGH(4)	; HIGH和LOW是Keil C51的伪指令,用于获取16位立即数中的高字节和低字节MOV		R7, #LOW(4)		; 传入的参数0xR6R7 = 4msLCALL	_delay_ms		; 调用函数;和C语言不一样,汇编函数的定义即使在本调用下方的话,不用先声明也能使用SETB	P1.0			; 1T,P1_0 IO口拉高;; 和SETB、LJMP MAIN一起延时10us,再补齐8.5usNOP						; 1T,0.5usDELAY_8US				; 宏定义函数;; 延时1000usMOV		R7, #99			; 0xR7 = 99LCALL	_delay_us_10x	; 传入的参数是99,延时990us;; 延时9msMOV		R6, #HIGH(9)MOV		R7, #LOW(9)		; 传入的参数0xR6R7 = 9msLCALL	_delay_msLJMP	MAIN			; 2T,跳转到标号;;
; \brief	以10us为单位的延时函数(必须延时20us及以上,否则请直接使用NOP进行延时!)
; \details	1. 使用小写标号(函数名),在C语言中调用该函数时让函数名与C语言标准更统一;
;			2. 传入的参数需要 >= 2,否则会有异常的长时间延时,也就是说至少延时2个10us;
; \note		注意:要使用汇编实现精准延时的话,需要在调用延时前关闭所有中断,调用后再恢复中断!
; \remark	C语言调用此汇编函数时使用 delay_us_10x(100); // 延时1000us
; \param	0xR7	uint8,延时多少个10us,取值为 2 ~ 255
; \return	无
;;
_delay_us_10x:; 外部调用此函数时如果有给R7赋值则会额外消耗1T(已优化); 外部调用此函数的LCALL或ACALL会额外占2T(已优化)DEC		R7					; 1T,将10us的次数直接减1;用于补齐10us,抵消额外的消耗;; 抵消额外消耗的6T,再补14T凑成10us;;  \note	如果晶振有变化,则这里的补时也要调整,或者修改得和 INS_SET_10US_NUM 相关DELAY_4US					; 这里是宏定义函数DELAY_2USDELAY_1US;; 延时10us
DELAY_US_LOOP2:MOV		R6, #((INS_SET_10US_NUM - 4) / 2)	; 1TNOP											; 1T,空指令,什么也不做;为了补齐MOV指令的1T时间到2T
DELAY_US_LOOP1:DJNZ	R6, DELAY_US_LOOP1	; 2TDJNZ	R7, DELAY_US_LOOP2	; 2T,延时多少个10usRET	; 从函数中返回;返回额外占2T(已优化);;
; \brief	ms延时函数
; \details	1. 传入的参数必须 >= 1,即至少延时1ms,如果为0则会导致超长时间延时
;			2. 当低字节为0x01时,本延时函数少了2T也就是1us;
;			3. 当低字节为0x00时,本延时函数多了4T也就是2us;
; \note		注意:要使用汇编实现精准延时的话,需要在调用延时前关闭所有中断,调用后再恢复中断!
; \remark	C语言调用此汇编函数时使用 delay_ms(1000); // 延时1000ms
; \param	0xR6R7-->0xR4R5	uint16,延时多少ms;取值范围为0x0002~0xFEFF(注意不是0xFFFF!; \return	无
;;
_delay_ms:; 外部调用此函数时如果有给R6R7赋值则会额外消耗2T(已优化); 外部调用此函数的LCALL或ACALL会额外占2T(已优化); 0xR4R5 = 0xR6R7MOV		A, R7	; 1T,因为之后R7还需作为子函数的参数,所以将0xR6R7先移动到0xR4R5MOV		R5, A	; 1T,不能直接MOV R5, R7; 没有这种指令,两个内部寄存器之间不能直接赋值MOV		A, R6	; 1T,下面调用us延时函数时没有进行压栈弹栈操作,us延时里面用了R6作为临时变量,所以这里也要避开MOV		R4, A	; 1TINC		R4		; 1T,R4自增1;如果R4本来为0,则本函数最后的R4减1不为0跳转会有bug;因此高位的取值只能是0x00~0xFE,不能取到0xFF;; 函数进入和函数返回时的额外消耗是24T(其中有2T是R4自增一导致的),12us,此处将其补齐到1ms,;  还需额外补980us + 8us;并后续将0xR4R5减1,也就是减去这补齐的1msDELAY_8USMOV		R7, #98			; 1T已抵消,_delay_us_10x函数的参数,980usLCALL	_delay_us_10x	; 2T已抵消;; 将0xR4R5减1,用于时间凑整补齐;  执行所有INC或DEC自增自减、所有ADD加法指令时都不会产生PSW寄存器的CY借位;;  只有ADDC和SUBB指令才带进位或借位,进位和借位都是PSW寄存器的CY位;;  SUBB不能用R0~R7去减别的数,只能用累加器A去减;; 低字节减1MOV		A, R5	; 1TCLR		C		; 1T,CLR C和CLR CY是一样的效果,C是指令集里面特定的用法,CY是头文件中BIT伪指令定义的位SUBB	A, #1	; 1TMOV		R5, A	; 1T,减完后放回R5JNC		DELAY_MS_HIGH_BYTE_IGNORE_DEC	; 2T,如果CY进位为0则跳转;; 类似跳转指令还有:JNZ累加器为1跳转,JZ累加器为0跳转,JNC进位为0跳转,JC进位为1跳转,;  JNB比特为0跳转,JB比特为1跳转,JBC比特为1跳转并清零(前面其他指令都不会自动清零);; 如果有借位则高字节减1(因为有减1的步骤,所以传入的参数不能为0x0001);  当低字节为0x00时,此处会执行,则会多了4T也就是2us;                               ;=====================;CLR		C		; 1T,CLR C和CLR CY是一样的效果,C是指令集里面特定的用法,CY是头文件中BIT伪指令定义的位MOV		A, R4	; 1TSUBB	A, #1	; 1T,SUBB使用前要清零进位CY,否则借位存在的话会多减去1MOV		R4, A	; 1T,减完后放回R4DELAY_MS_HIGH_BYTE_IGNORE_DEC:;; 处理传入的参数低字节为0的情况MOV		A, R5					; 1TJZ		DELAY_MS_HIGH_BYTE_JMP	; 2T,累加器A为0则跳转LJMP	DELAY_MS_BYTE_LOOP_LOW	; 2T,当低字节减完1后为0时,此处会少了2T也就是1us,少的这1us没有进行优化;                                                          ;=====================;
DELAY_MS_BYTE_LOOP_HIGH:; 每次高字节循环256ms时的额外消耗是4T,2us;此处将其补齐到10us,后面再调用990usDELAY_8US;; 延时1ms;高字节减1,低字节从256变成255时,将少的那一次补上MOV		R7, #99			; 1T已抵消,_delay_us_10x函数的参数LCALL	_delay_us_10x	; 2T已抵消MOV		R5, #0FFH		; 2T,R5 = 255;; 延时1 ~ 255ms
DELAY_MS_BYTE_LOOP_LOW:; 每次低字节循环1ms时的额外消耗是2T,1us,此处将其补齐到10us,后面再调用990usDELAY_8USDELAY_1US;; 延时1msMOV		R7, #99			; 1T已抵消,_delay_us_10x函数的参数LCALL	_delay_us_10x	; 2T已抵消DJNZ	R5, DELAY_MS_BYTE_LOOP_LOW	; 2T,R5寄存器内的数据减1,不为0则跳转;延时多少个msDELAY_MS_HIGH_BYTE_JMP:DJNZ	R4, DELAY_MS_BYTE_LOOP_HIGH	; 2T,处理高字节,延时多少个256ms;之前有加1,函数调用时这里额外多了2T(已优化)RET	; 2T,返回额外占2T(已优化)END	; 源文件结束
  • C语言不精准的延时函数源码
/******************************************************************************* \brief	演示延时与函数,控制LCD灯闪烁的间隔* \details	使用Keil Simulator模拟器,和Debug时的Logic Analyzer示波器窗口查看输出* \remark	File format: UTF-8,源文件使用UTF-8中文编码* \note	省略了8051的初始化,使用模拟器时会自动准备好运行环境* \author	将狼才鲸* \date	2024-07-23******************************************************************************//* 一个文件中将一些全局的东西分门别类,模块性更好,不容易错漏,方便查找bug *//********************************* 头文件 *************************************/
#include <Atmel/at89c51RC2.h>	/* 寄存器定义 *//******************************** 类型定义 ************************************/
/** 下面的类型定义让程序的可移植性更好,例如无负担的移植到32位或64位MCU上;typedef是C语言进行类型定义的关键字,很常用 */
typedef unsigned char		uint8;		/* 使用uint8代替8051一个字节的unsigned char */
typedef unsigned int		uint16;		/* 使用uint16代替8051两个字节的unsigned int,8051的int是2字节,而32位CPU是4字节 */
typedef unsigned long int	uint32;		/* 8051的long是4字节,而32位CPU是8字节,4字节的float和8字节的double与32位CPU一致 */
typedef char				int8;
typedef int					int16;
typedef long int			int32;/********************************* 宏定义 *************************************/
/** 定义错误码,正式工程建议所有的返回值都用错误码,不要直接返回 -1,这样模块化更好 */
#define	OK			0
#define ERR			(-1)	/* 宏定义如果是表达式,建议用括号括起来,防止优先级错误导致难定位的bug出现 */
#define ERR_PARAM	(-2)	/* 传入的参数错误 *//****************************** 结构体定义*************************************/
typedef enum _BOOL {	/* enum是C语言的关键词,联合体,很常用 */FALSE = 0,TRUE		/* enum的项目如果是缺省值,则值默认是上一个值 + 1 */
} BOOL;	/* C语言标准库没有定义布尔类型,所以自己定义,当然,Linux和Windows的一些库文件中会有 *//******************************* 函数声明 *************************************/
static int16 sleep_us_10x(int16 cnt);	/* 函数声明,如果有函数在定义前就被调用,则需要在调用前进行声明 */
static int16 sleep_ms(int16 cnt);	/* static是C语言关键字,表示静态变量或静态函数,这里是静态函数 *//******************************* 接口函数 *************************************/
/*** \brief	主函数* \details	当整个工程文件中没有汇编文件时,Debug后默认进入到main函数第一行,*			但当有汇编文件时,默认会先进入到汇编,此时则需要写好boot*/
int main(void)
{/* 进入函数时先拉低拉高做标记,作为延时的起始零点,因为main执行前会有耗时 */P1_0 = 0;	/* IO口输出低;P1_0是头文件中已经定义的寄存器Bit */P1_0 = 1;	/* IO口输出高 */while (1){/**请在Debug后通过 View--Analysis Windows--Logic Analyzer--Setup--点击右上角叉叉左边的新建图标--键入P1_0--Close 来创建模拟器中示波器的采样引脚;把示波器的小窗口向下拉一点,露出波形的显示区域;再点击Zoom中的All来显示整个波形(不点击会看不到变化的波形);再F10单步运行,一边运行一边看输出的矩形波。*/P1_0 = 0;			/* IO口输出低;P1_0是头文件中已经定义的寄存器Bit */sleep_us_10x(500);	/* 延时5ms */P1_0 = 1;			/* IO口输出高 */sleep_ms(15);		/* 延时15ms */}
}/******************************* 私有函数 *************************************/
/*** \brief	us级别延时,延时时间 = cnt x 10 us* \details	没使用定时器,只使用了死循环,当前延时只是大体上准,而且会受中断的影响;*			只延时10us时,误差+13.5us;*			延时20us及以上时,误差 + 0.25% x 想要的延时 + 13.5us,例如想要延时1ms,实际会延时1016us;* \param	cnt	延时多少个10us,有效取值范围为 1 ~ 32768* \return	返回值无实际含义*/
static int16 sleep_us_10x(int16 cnt)	/* 不是供其它模块调用的接口函数,都建议定义成静态函数,模块化更好 */
{int16 i;	/* 8051的所有局部变量必须在函数的前面定义,不能像32位CPU那样随用随定义 */int8 ret = 0;/* cnt为0时延时12us,cnt为1时延时19.5us,通过实测得到 *//* 循环1001次耗时8021us,每次循环消耗8.0015us,通过实测得到 */for (i = 0; i < cnt; i++)	/* 8051不能使用 for (int i = 0; i < cnt; i++); 这种使用时定义的做法 */{/** 每次空循环耗时8us,此处再补2us,补成10us *//* 也可以使用 __asm NOP; 插入汇编,但是这样会导致.c文件打不了断点,所以不用 *//* 指令集参见:https://gitee.com/langcai1943/8051-from-boot-to-application/blob/develop/02_doc/01_8051寄存器、指令集、伪指令和关键字介绍.md */ret++;	/* 字节自增在汇编中消耗1个机器周期,当前24MHz晶振,一个机器周期0.5us */ret++;ret++;ret++;}return ret;	/* 使用ret,防止此变量的所有操作被编译器优化掉;该返回值没有含义 */
}/*** \brief	ms级别延时* \details	没使用定时器,只使用了死循环,当前延时只是大体上准,而且会受中断的影响;*			延时误差约 + 0.1%,例如延时1000ms,实际耗时约1001ms;* \param	cnt	延时多少个ms,有效取值范围为 1 ~ 32768* \return	返回值无实际含义*/
static int16 sleep_ms(int16 cnt)
{int16 i, j;
#	define MS_SLEEP_CNT	356	/* 延时1ms所需要的循环次数,实测所得 */for (i = 0; i < cnt; i++){for (j = 0; j < MS_SLEEP_CNT; j++){}}return 0;	/* 返回0代表一切执行正常,处理错误则返回负数的错误码;建议所有函数都弄成有返回值的结构,中断处理除外 */
}/********************************* 文件尾 *************************************/
  • C语言中调用精准汇编延时函数的源码
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; \brief	汇编延时函数,供C语言调用
; \remark	File format: UTF-8,源文件使用UTF-8中文编码
; \author	将狼才鲸
; \date		2024-07-22
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$NOMOD51	; 不使用Keil默认隐含的8051通用寄存器定义,而是显式的包含寄存器定义头文件;; 定义本汇编文件的代码段,不定义的话放到位置不固定,有可能上电RESET后直接就跑到这里来了 ;
;  如果该汇编文件会被别的汇编文件直接包含,则不用定义,同时文件尾也不用加END
NAME	DELAY_ASM
DELAY_ASM  SEGMENT  CODE	; SEGMENT CODE是定义代码段
RSEG  DELAY_ASM; 8051汇编指令及每条指令所消耗的时钟数详见:
; https://gitee.com/langcai1943/8051-from-boot-to-application/blob/develop/02_doc/01_8051寄存器、指令集、伪指令和关键字介绍.md; 当前工程中配置的晶振是Keil默认的24MHz,时钟周期41.67ns,状态周期是2倍时钟周期即83.3333ns,
; 机器周期是6倍状态周期即500ns,一个机器周期记为1T,一条指令周期为1~4T,具体哪条指令占多少T需要查阅上面文档;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 函数声明 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PUBLIC _delay_us_10x	; 类似于C语言头文件中的 extern void delay_us_10x(uint8 cnt); 让别的文件中能调用此函数
PUBLIC _delay_ms;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 宏定义 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INS_SET_10US_NUM	EQU 20	; 10us占20个机器周期;当前工程中配置的晶振是Keil默认的24MHz,时钟周期41.67ns,机器周期500ns;;; 宏定义函数
DELAY_1US  MACRONOP	; 1T,500nsNOP
ENDMDELAY_2US  MACRODELAY_1USDELAY_1US
ENDMDELAY_4US  MACRODELAY_2USDELAY_2US
ENDMDELAY_8US  MACRODELAY_4USDELAY_4US
ENDMDELAY_16US  MACRODELAY_8USDELAY_8US
ENDM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 接口函数 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
; \brief	以10us为单位的延时函数(必须延时20us及以上,否则请直接使用NOP进行延时!)
; \details	1. 使用小写标号(函数名),在C语言中调用该函数时让函数名与C语言标准更统一;
;			2. 传入的参数需要 >= 2,否则会有异常的长时间延时,也就是说至少延时2个10us;
; \note		注意:要使用汇编实现精准延时的话,需要在调用延时前关闭所有中断,调用后再恢复中断!
; \remark	C语言调用此汇编函数时使用 delay_us_10x(100); // 延时1000us
; \param	0xR7	uint8,延时多少个10us,取值为 2 ~ 255
; \return	无
;;
_delay_us_10x:; 外部调用此函数时如果有给R7赋值则会额外消耗1T(已优化); 外部调用此函数的LCALL或ACALL会额外占2T(已优化)DEC		R7					; 1T,将10us的次数直接减1;用于补齐10us,抵消额外的消耗;; 抵消额外消耗的6T,再补14T凑成10us;;  \note	如果晶振有变化,则这里的补时也要调整,或者修改得和 INS_SET_10US_NUM 相关DELAY_4US					; 这里是宏定义函数DELAY_2USDELAY_1US;; 延时10us
DELAY_US_LOOP2:MOV		R6, #((INS_SET_10US_NUM - 4) / 2)	; 1TNOP											; 1T,空指令,什么也不做;为了补齐MOV指令的1T时间到2T
DELAY_US_LOOP1:DJNZ	R6, DELAY_US_LOOP1	; 2TDJNZ	R7, DELAY_US_LOOP2	; 2T,延时多少个10usRET	; 从函数中返回;返回额外占2T(已优化);;
; \brief	ms延时函数
; \details	1. 传入的参数必须 >= 1,即至少延时1ms,如果为0则会导致超长时间延时
;			2. 当低字节为0x01时,本延时函数少了2T也就是1us;
;			3. 当低字节为0x00时,本延时函数多了4T也就是2us;
; \note		注意:要使用汇编实现精准延时的话,需要在调用延时前关闭所有中断,调用后再恢复中断!
; \remark	C语言调用此汇编函数时使用 delay_ms(1000); // 延时1000ms
; \param	0xR6R7-->0xR4R5	uint16,延时多少ms;取值范围为0x0002~0xFEFF(注意不是0xFFFF!; \return	无
;;
_delay_ms:; 外部调用此函数时如果有给R6R7赋值则会额外消耗2T(已优化); 外部调用此函数的LCALL或ACALL会额外占2T(已优化); 0xR4R5 = 0xR6R7MOV		A, R7	; 1T,因为之后R7还需作为子函数的参数,所以将0xR6R7先移动到0xR4R5MOV		R5, A	; 1T,不能直接MOV R5, R7; 没有这种指令,两个内部寄存器之间不能直接赋值MOV		A, R6	; 1T,下面调用us延时函数时没有进行压栈弹栈操作,us延时里面用了R6作为临时变量,所以这里也要避开MOV		R4, A	; 1TINC		R4		; 1T,R4自增1;如果R4本来为0,则本函数最后的R4减1不为0跳转会有bug;因此高位的取值只能是0x00~0xFE,不能取到0xFF;; 函数进入和函数返回时的额外消耗是24T(其中有2T是R4自增一导致的),12us,此处将其补齐到1ms,;  还需额外补980us + 8us;并后续将0xR4R5减1,也就是减去这补齐的1msDELAY_8USMOV		R7, #98			; 1T已抵消,_delay_us_10x函数的参数,980usLCALL	_delay_us_10x	; 2T已抵消;; 将0xR4R5减1,用于时间凑整补齐;  执行所有INC或DEC自增自减、所有ADD加法指令时都不会产生PSW寄存器的CY借位;;  只有ADDC和SUBB指令才带进位或借位,进位和借位都是PSW寄存器的CY位;;  SUBB不能用R0~R7去减别的数,只能用累加器A去减;; 低字节减1MOV		A, R5	; 1TCLR		C		; 1T,CLR C和CLR CY是一样的效果,C是指令集里面特定的用法,CY是头文件中BIT伪指令定义的位SUBB	A, #1	; 1TMOV		R5, A	; 1T,减完后放回R5JNC		DELAY_MS_HIGH_BYTE_IGNORE_DEC	; 2T,如果CY进位为0则跳转;; 类似跳转指令还有:JNZ累加器为1跳转,JZ累加器为0跳转,JNC进位为0跳转,JC进位为1跳转,;  JNB比特为0跳转,JB比特为1跳转,JBC比特为1跳转并清零(前面其他指令都不会自动清零);; 如果有借位则高字节减1(因为有减1的步骤,所以传入的参数不能为0x0001);  当低字节为0x00时,此处会执行,则会多了4T也就是2us;                               ;=====================;CLR		C		; 1T,CLR C和CLR CY是一样的效果,C是指令集里面特定的用法,CY是头文件中BIT伪指令定义的位MOV		A, R4	; 1TSUBB	A, #1	; 1T,SUBB使用前要清零进位CY,否则借位存在的话会多减去1MOV		R4, A	; 1T,减完后放回R4DELAY_MS_HIGH_BYTE_IGNORE_DEC:;; 处理传入的参数低字节为0的情况MOV		A, R5					; 1TJZ		DELAY_MS_HIGH_BYTE_JMP	; 2T,累加器A为0则跳转LJMP	DELAY_MS_BYTE_LOOP_LOW	; 2T,当低字节减完1后为0时,此处会少了2T也就是1us,少的这1us没有进行优化;                                                          ;=====================;
DELAY_MS_BYTE_LOOP_HIGH:; 每次高字节循环256ms时的额外消耗是4T,2us;此处将其补齐到10us,后面再调用990usDELAY_8US;; 延时1ms;高字节减1,低字节从256变成255时,将少的那一次补上MOV		R7, #99			; 1T已抵消,_delay_us_10x函数的参数LCALL	_delay_us_10x	; 2T已抵消MOV		R5, #0FFH		; 2T,R5 = 255;; 延时1 ~ 255ms
DELAY_MS_BYTE_LOOP_LOW:; 每次低字节循环1ms时的额外消耗是2T,1us,此处将其补齐到10us,后面再调用990usDELAY_8USDELAY_1US;; 延时1msMOV		R7, #99			; 1T已抵消,_delay_us_10x函数的参数LCALL	_delay_us_10x	; 2T已抵消DJNZ	R5, DELAY_MS_BYTE_LOOP_LOW	; 2T,R5寄存器内的数据减1,不为0则跳转;延时多少个msDELAY_MS_HIGH_BYTE_JMP:DJNZ	R4, DELAY_MS_BYTE_LOOP_HIGH	; 2T,处理高字节,延时多少个256ms;之前有加1,函数调用时这里额外多了2T(已优化)RET	; 2T,返回额外占2T(已优化)END	; 源文件结束;如果该汇编文件会被别的汇编文件直接包含,则不用加END
/******************************************************************************* \brief	演示在C语言中调用汇编函数和汇编宏定义函数* \details	使用Keil Simulator模拟器,和Debug时的Logic Analyzer示波器窗口查看输出* \remark	File format: UTF-8,源文件使用UTF-8中文编码* \note	工程里包含了汇编文件的话,还需要自己手写Boot代码,或者创建工程时添加Keil默认的Boot代码* \author	将狼才鲸* \date	2024-07-23******************************************************************************//********************************* 头文件 *************************************/
#include <Atmel/at89c51RC2.h>/******************************** 类型定义 ************************************/
typedef unsigned char		uint8;
typedef unsigned int		uint16;
typedef unsigned long int	uint32;
typedef char				int8;
typedef int					int16;
typedef long int			int32;/********************************* 宏定义 *************************************/
/** 错误码 */
#define	OK			0
#define ERR			(-1)	/* 通用的错误码 */
#define ERR_PARAM	(-2)	/* 传入的参数错误 *//****************************** 结构体定义*************************************/
typedef enum _BOOL {FALSE = 0,TRUE		/* TRUE = 1 */
} BOOL;/******************************* 函数声明 *************************************/
extern void delay_us_10x(uint8 cnt);
extern void delay_ms(uint16 cnt);/* 如果是在一个汇编文件中调用另一个汇编文件里的函数,采用 EXTRN CODE (YOUR_FUNCTION_NAME) 的方式进行声明 *//******************************* 接口函数 *************************************/
/*** \brief	主函数* \details	当整个工程文件中没有汇编文件时,Debug后默认进入到main函数第一行,*			但当有汇编文件时,默认会先进入到汇编,此时则需要写好boot*/
int main(void)
{P1_0 = 0;P1_0 = 1;while (1){/**请在Debug后通过 View--Analysis Windows--Logic Analyzer--Setup--点击右上角叉叉左边的新建图标--键入P1_0--Close 来创建模拟器中示波器的采样引脚;把示波器的小窗口向下拉一点,露出波形的显示区域;再点击Zoom中的All来显示整个波形(不点击会看不到变化的波形);再F10单步运行,一边运行一边看输出的矩形波。*/P1_0 = 0;			/* IO口输出低;P1_0是头文件中已经定义的寄存器Bit */delay_us_10x(200);	/* 调用汇编函数延时2000us */P1_0 = 1;			/* IO口输出高 */delay_ms(8);		/* 调用汇编函数延时8ms */}
}/********************************* 文件尾 *************************************/
  • 参考网址:

    • 4课:第一个单片机小程序 该文章前半部分有汇编原始工程下载链接
    • C51中汇编的使用及参数传递与数据返回
    • 试把如下c函数改写成汇编语言函数,用51汇编完整写一个函数
    • 当AT89C51单片机外接晶振为6MHz时,其震荡周期、状态时钟周期、机器周期、指令周期的值各是多少?
    • Keil官方8051 Instruction Set Manual指令集在线查看
    • MicroChip Atmel官方指令集文档8051 Microcontroller Instruction Set下载
    • MicroChip Atmel官方芯片手册Atmell 8051 Microcontrollers Hardware Manual下载
    • [Keil官方MCS-51 INSTRUCTION SET指令集文档下载]((https://www.keil.com/dd/docs/datashts/intel/ism51.pdf)
  • Keil C51 C语言中调用汇编函数时,最多使用三个参数,默认第一个参数从R7开始放,第二个参数从R5开始放,第三个参数从R3开始放,如果是2字节的int,那么遵循8051的大端模式,高字节放在R2、R4、R6,低字节放在R3、R5、R7;如果是指针参数,无论是第一第二第三个参数,都放在R1~R3,存储类型是R3,指针值是0xR2R1(注意此时是小端模式存储);超过三个的参数请用外部RAM来实现;

  • 汇编函数将返回值返回给C语言时,返回值需要放在R7开始的位置,char就放在R7,int是0xR6R7,long和float是0xR4R5R6R7,指针是类型在R3,指针值0xR2R1;

  • 汇编里的函数如果要给C语言用,那么函数名(标号)前要叫下划线,例如 _LOOP: NOP; RET;,C语言调用时去掉下划线,如:LOOP();

    • 其实加下划线是代表有参数调用,但是无参数的汇编函数你也这么加并没有问题;
  • 想找原文的,在Keil安装目录的C:\Keil_v5\C51\Hlp\c51.chm,在里面搜索Parameter Passing或者Passing in Registers,原文摘抄如下:

Passing in Registers

C functions may pass parameters in registers and fixed memory locations. A maximum of 3 parameters may be passed in registers. All other parameters are passed using fixed memory locations. The following tables define which registers are used for passing parameters.

Arg Numberchar, 1-byte ptrint, 2-byte ptrlong, floatgeneric ptr
1R7R6 & R7 (MSB in R6,LSB in R7)R4—R7R1—R3 (Mem type in R3, MSB in R2, LSB in R1)
2R5R4 & R5 (MSB in R4,LSB in R5)R4—R7R1—R3 (Mem type in R3, MSB in R2, LSB in R1)
3R3R2 & R3 (MSB in R2,LSB in R3)R1—R3 (Mem type in R3, MSB in R2, LSB in R1)

The following examples clarify how registers are selected for parameter passing.

DeclarationDescription
func1 ( int a)The first and only argument, a, is passed in registers R6 and R7.
func2 ( int b, int c, int *d)The first argument, b, is passed in registers R6 and R7. The second argument, c, is passed in registers R4 and R5. The third argument, d, is passed in registers R1, R2, and R3.
func3 ( long e, long f)The first argument, e, is passed in registers R4, R5, R6, and R7. The second argument, f, cannot be located in registers since those available for a second parameter with a type of long are already used by the first argument. This parameter is passed using fixed memory locations.
func4 ( float g, char h)The first argument, g, passed in registers R4, R5, R6, and R7. The second parameter, h, cannot be passed in registers and is passed in fixed memory locations.

Copyright © Keil, An ARM Company. All rights reserved.

* 4、中断
* 参考网址:
  * 19课:单片机定时器、中断试验

  • 5、定时器计数器
  • 参考网址:
    • 20课:单片机定时/计数器实验
  • 串口收发 22课:单片机串行口通信程序设计
  • IO波形模拟数码管 3课:LED数码管静态显示接口与编程
  • 按钮,IO输入

相关文章:

【目录】8051汇编与C语言系列教程

8051汇编与C语言系列教程 作者将狼才鲸创建日期2024-07-23 CSDN文章地址&#xff1a;【目录】8051汇编与C语言系列教程本Gitee仓库原始地址&#xff1a;才鲸嵌入式/8051_c51_单片机从汇编到C_从Boot到应用实践教程 一、本教程目录 序号教程名称简述教程链接1点亮LCD灯通过IO…...

群管机器人官网源码

一款非常好看的群管机器人html官网源码 搭建教程&#xff1a; 域名解析绑定 源码文件上传解压 访问域名即可 演示图片&#xff1a; 群管机器人官网源码下载&#xff1a;客户端下载 - 红客网络编程与渗透技术 原文链接&#xff1a; 群管机器人官网源码...

整合EasyExcel实现灵活的导入导出java

引入pom依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId></dependency>实现功能 结合Vue前端&#xff0c;实现浏览器页面直接导出日志文件实现文件的灵活导入文件导出 3. 实体类 实体类里有自定义转…...

springSecurity学习之springSecurity web如何取得用户信息

web如何取得用户信息 之前说过SecurityContextHolder默认使用的是ThreadLocal来进行存储的&#xff0c;而且每次都会清除&#xff0c;但是web每次请求都会验证用户权限&#xff0c;这是如何做到的呢&#xff1f; 这是通过SecurityContextPersistenceFilter来实现的&#xff0…...

eclipse中的classbean导入外部class文件,clean项目后删除问题

最近被eclipse搞得头疼&#xff0c;下午终于解决 eclipse创建的java项目中&#xff0c;类的输出目录是classbean。由于项目需要&#xff0c;classbean目录下已经导入了外部的类&#xff0c;但每次clean项目时&#xff0c;会把class删掉。 广泛查询&#xff0c;eclipse不清空c…...

OBD诊断(ISO15031) 0A服务

文章目录 功能简介ISO 15765-4的诊断服务定义1、请求具有永久状态的排放相关故障诊断码2、请求具有永久状态的排放相关故障诊断码3、示例报文 功能简介 0A服务&#xff0c;即 Request emission-related diagnostic trouble code with permanent status&#xff08;请求排放相关…...

ForCloud全栈安全体验,一站式云安全托管试用 开启全能高效攻防

对于正处于业务快速发展阶段的企业&#xff0c;特别是大型央国企而言&#xff0c;日常的安全部署和运营管理往往横跨多家子公司&#xff0c;所面临的挑战不言而喻。尤其是在面对当前常态化的大型攻防演练任务时&#xff0c;难度更是呈“几何级数”上升&#xff1a; 合规难 众…...

Java——————接口(interface) <详解>

1.1 接口的概念 在现实生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&#xff1a;笔记本电脑上的USB接口&#xff0c;电源插座等。 电脑的USB口上&#xff0c;可以插&#xff1a;U盘、鼠标、键盘...所有符合USB协议的设备 电源插座插孔上&#xff0c;可以插&#xff…...

【C++】【继承】【子对象】【构造函数】含子对象的派生类的构造函数写法

&#xff08;1&#xff09;子对象的概念&#xff1a;若派生类A1的数据成员中包含基类A的对象a&#xff0c;则a为派生类A1的子对象 &#xff08;2&#xff09;含子对象的派生类的构造函数的执行顺序是&#xff1a; ①调用基类构造函数&#xff0c;对基类数据成员初始化 ②调用子…...

golang语言 .go文件版本条件编译,xxx.go文件指定go的编译版本必须大于等于xxx才生效的方法, 同一个项目多个go版本文件共存方法

在go语言中&#xff0c;我们不关是可以在编译时指定版本&#xff0c; 在我们的xxx.go文件中也可以指定go的运行版本&#xff0c;即 忽略go.mod中的版本&#xff0c;而是当当前的go运行版本达到指定条件后才生效的xxx.go文件。 方法如下&#xff1a; 我们通过在xxx.go文件的头部…...

深入浅出mediasoup—通信框架

libuv 是一个跨平台的异步事件驱动库&#xff0c;用于构建高性能和可扩展的网络应用程序。mediasoup 基于 libuv 构建了包括管道、信号和 socket 在内的一整套通信框架&#xff0c;具有单线程、事件驱动和异步的典型特征&#xff0c;是构建高性能 WebRTC 流媒体服务器的重要基础…...

每日一题 LeetCode03 无重复字符的最长字串

1.题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长字串的长度。 2 思路 可以用两个指针, 滑动窗口的思想来做这道题,即定义两个指针.一个left和一个right 并且用一个set容器,一个length , 一个maxlength来记录, 让right往右走,并且用一个set容器来…...

栈和队列(C语言)

栈的定义 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xff1a;…...

swagger-ui.html报错404

问题1&#xff1a;权限受限无法访问 由于采用的Shiro安全框架&#xff0c;需要在配置类ShiroConfig下的Shiro 的过滤器链放行该页面&#xff1a;【添加&#xff1a;filterChainDefinitionMap.put("/swagger-ui.html", "anon");】 public ShiroFilterFact…...

Milvus 核心组件(3)--- MinIO详解

目录 背景 MinIO 安装 docker desktop 安装 Ubuntu UI 在 docker 中的安装 Minio 下载及安装 启动minio docker image 保存 启动 minio web 网页 下一次启动 MinIO基本概念 基本概述 主要特性 应用场景 MinIO 使用 连接server 创建bucket 查询bucket 上传文件…...

[数据集][目标检测]婴儿车检测数据集VOC+YOLO格式1073张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1073 标注数量(xml文件个数)&#xff1a;1073 标注数量(txt文件个数)&#xff1a;1073 标注…...

JAVASE进阶day14(网络编程续TCP,日志)

TCP 三次握手 四次挥手 package com.lu.day14.tcp;import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket;public class Client {public static void main(String[] args) {try(Socket socket new Socket("192.…...

机器学习(五) -- 无监督学习(1) --聚类1

系列文章目录及链接 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 监督学习&#xff08;7&#xff09; --SVM2 下篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;1&#xff09; --聚类2 前言 tips&#xff1a;标题前有“***”的内容…...

leetcode 116. 填充每个节点的下一个右侧节点指针

leetcode 116. 填充每个节点的下一个右侧节点指针 题目 给定一个 完美二叉树 &#xff0c;其所有叶子节点都在同一层&#xff0c;每个父节点都有两个子节点。二叉树定义如下&#xff1a; struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next …...

[C++]优先级队列

1 .了解优先级队列 优先级队列是一种容器适配器&#xff0c;根据一些严格的弱排序标准&#xff0c;专门设计使其第一个元素始终是它所包含的元素中最大的元素。 此上下文类似于堆&#xff0c;其中可以随时插入元素&#xff0c;并且只能检索最大堆元素&#xff08;优先级队列中顶…...

学习大数据DAY22 Linux 基 本 指 令 3与 在 Linux 系 统 中 配 置MySQL 和 Oracle

目录 网络配置类 ps 显示系统执行的进程 kill systemctl 服务管理 配置静态 ip 常见错误---虚拟机重启网卡失败或者网卡丢失 mysql 操作 上机练习 6---安装 mysql---参考《mysql 安装》文档 解锁 scott 重启后的步骤 上机练习 7---安装 oracle---参考《oracle 安装》…...

scp 服务器复制命令

步骤如下&#xff1a; 终端执行如下命令 #ssh-keygen -t rsa 2. 密钥生成后会在 /root/.ssh/ 文件夹下产生两个文件 id_rsa id_rsa.pub 将 id_rsa.pub 文件复制到 152.136.121.24 执行如下命令 scp /root/.ssh/id_rsa.pub root152.136.121.24:/root/.ssh/authorized_keys…...

PyQt5学习路线

后续会根据该文章的路线逐步发布对应的教程&#xff0c;订阅专栏不迷路&#x1f970; 本专栏纯干货&#x1f929; 学习Python的PyQt5库&#xff0c;可以遵循以下的学习路线&#xff1a; 1. Python基础 掌握Python语法&#xff1a;确保你熟悉Python的基本语法&#xff0c;包括…...

2024论文精读:利用大语言模型(GPT)增强上下文学习去做关系抽取任务

文章目录 1. 前置知识2. 文章通过什么来引出他要解决的问题3. 作者通过什么提出RE任务存在上面所提出的那几个问题3.1 问题一&#xff1a;ICL检索到的**示范**中实体个关系的相关性很低。3.2 问题二&#xff1a;示范中缺乏解释输入-标签映射导致ICL效果不佳。 4. 作者为了解决上…...

WEB 手柄 http通信,mcu端解析代码 2024/7/23 日志

WEB 手柄 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>WEB遥控器</title> </head> &l…...

cmake中的正则表达式

以下字符或者字符组合在cmake的正则表达式中的特殊含义&#xff1a; ^ 匹配输入的开始 $ 匹配输入的结束 . 匹配任意一个字符 \<char> 匹配一个字符&#xff0c;如.匹配字符.&#xff0c;\匹配字符\&#xff0c;\a匹配字符a [ ] 匹配在括号里面的任意字符&#xff0…...

05. Java 三大范式

1. 前言 在面向对象语言中涉及到诸多的设计模式&#xff0c;例如单例模式、适配器模式&#xff0c;设计模式的存在是为了让系统中的代码逻辑更加清晰&#xff0c;帮助开发者建立更加健壮的系统&#xff0c;同时满足易修改特性和易扩展特性。数据库设计时也存在类似设计模式的通…...

opencv 按键开启连续截图,并加载提示图片

背景图小图 键盘监听使用的是pynput 库 保存图片时使用了年月日时分秒命名 原图&#xff1a; from pynput import keyboard import cv2 import time# 键盘监听 def on_press(key):global jieglobal guanif key.char a:jie Trueelif key.char d:jie Falseelif key.char…...

Android-- 集成谷歌地图

引言 项目需求需要在谷歌地图&#xff1a; 地图展示&#xff0c;设备点聚合&#xff0c;设备站点&#xff0c;绘制点和区域等功能。 我只针对我涉及到的技术做一下总结&#xff0c;希望能帮到开始接触谷歌地图的伙伴们。 集成步骤 1、在项目的modle的build.gradle中添加依赖如…...

Jvm是如何处理异常的

异常抛出 当Java程序运行时遇到无法处理的情况时,会抛出一个异常(比如在一个方法中如果发生异常),这时会创建一个异常对象,并转交给JVM,该异常对象包含异常名称,异常描述以及异常发生时应用程序的状态。创建异常对象并转交给JVM的过程称为抛出异常。 异常捕捉 当JVM检测…...

recursion depth exceeded” error

有些时候不可以用jax.jit装饰器 参考资料&#xff1a;使用 JAX 后端在 Keras 3 中训练 GAN |由 Khawaja Abaid |中等 (medium.com)...

虚拟现实和增强现实技术系列—Expressive Talking Avatars

文章目录 1. 概述2. 背景介绍3. 数据集3.1 设计标准3.2 数据采集 4. 方法4.1 概述4.2 架构4.3 目标函数 5. 实验评测5.1 用户研究5.2 我们方法的结果5.3 比较与消融研究 1. 概述 支持远程协作者之间的交互和沟通。然而&#xff0c;明确的表达是出了名的难以创建&#xff0c;主…...

网站验证:确保网络安全与信任的重要步骤

网站验证&#xff1a;确保网络安全与信任的重要步骤 引言 在数字时代&#xff0c;网站验证是确保网络安全和建立用户信任的关键措施。随着网络诈骗和恶意软件的日益增多&#xff0c;验证网站的真实性和安全性变得尤为重要。本文将探讨网站验证的重要性、常见的验证方法以及如…...

C语言——字符串比较函数strcmp和strncmp

目录 strcmp 函数原型如下&#xff1a; 示例 注意事项 strcmp自实现代码&#xff1a; strncmp 函数 函数原型&#xff1a; 参数&#xff1a; 返回值&#xff1a; 特点&#xff1a; 两者之间的区别和联系 strcmp strcmp 是 C 语言标准库中的一个函数&#xff0c;用于…...

redis的集群模式

目录 1. 为什么使用redis集群 2. 主从模式 2.1修改配置文件 2.2 开启三台redis服务 2.3配置主从关系 3. 哨兵模式 3.1 监控功能 3.2 选举的机制 3.3 准备条件 4. 去中心化模式 4.1 准备三主三从 4.2 启动redis 4.3 分配槽以及主从关系 4.4 命令行的客户端 redis提供…...

基于微信小程序+SpringBoot+Vue的青少年科普教学系统平台(带1w+文档)

基于微信小程序SpringBootVue的青少年科普教学系统平台(带1w文档) 基于微信小程序SpringBootVue的青少年科普教学系统平台(带1w文档) 这个工具就是解决上述问题的最好的解决方案。它不仅可以实时完成信息处理&#xff0c;还缩短高校教师成果信息管理流程&#xff0c;使其系统化…...

智能听觉:从任务特定的机器学习到基础模型

关键词&#xff1a;计算机听觉、音频基础模型、多模态学习、声音事件检测 声音无处不在&#xff0c;弥漫于我们生活的每一个角落。鸟儿向伴侣倾诉心意的歌声&#xff0c;浓缩咖啡机中蒸汽的嘶嘶作响&#xff0c;午后阳光下昆虫振翅的嗡嗡声&#xff0c;金属屋顶上雨滴跳跃的滴答…...

14、如何⽤DDD设计微服务代码模型

在完成领域模型设计后&#xff0c;接下来我们就可以开始微服务的设计和 落地了。在微服务落地前&#xff0c;⾸先要确定微服务的代码结构&#xff0c;也就是我 下⾯要讲的微服务代码模型。 只有建⽴了标准的微服务代码模型和代码规范后&#xff0c;我们才可以将 领域对象映射到…...

ArcGIS Pro SDK (九)几何 12 多面体

ArcGIS Pro SDK &#xff08;九&#xff09;几何 12 多面体 文章目录 ArcGIS Pro SDK &#xff08;九&#xff09;几何 12 多面体1 通过拉伸多边形或折线构建多面体2 多面体属性3 构建多面体4 通过MultipatchBuilderEx构建多面体5 从另一个多面体构建多面体6 从 3D 模型文件构建…...

二次元手游《交错战线》游戏拆解

交错战线游戏拆解案 游戏亮点即核心趣味 一、关键词&#xff1a; 回合制游戏、二次元、机甲、横板、剧情、养成、异星探索。 二、游戏亮点&#xff1a; 符合目标群体审美的原画。 三、核心趣味&#xff1a; 抽卡、肝或者氪金解锁新皮肤。 核心玩法及系统规则 核心玩法&…...

【BUG】已解决:Downgrade the protobuf package to 3.20.x or lower.

Downgrade the protobuf package to 3.20.x or lower. 目录 Downgrade the protobuf package to 3.20.x or lower. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身…...

Java开发之Redis

1、非关系型数据库、快、高并发、功能强大 2、为什么快&#xff1f;内存单线程 非阻塞的IO多路复用有效的数据类型/结构 3、应用&#xff1a;支持缓存、支持事务、持久化、发布订阅模型、Lua脚本 4、数据类型&#xff1a; 5 种基础数据类型&#xff1a;String&#xff08;字…...

Java面试八股之 Spring Bean的生命周期

Spring Bean的生命周期 实例化&#xff08;Instantiation&#xff09;&#xff1a;Spring容器根据Bean定义信息创建Bean的实例&#xff0c;通常通过无参构造函数进行。 依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;&#xff1a;Spring容器按照Bean定…...

SQL中的函数

目录 前言 一、系统内置函数 1、数学函数 2、日期和时间函数 3、聚合函数 4、字符串函数 二、自定义函数 1、标量函数的创建与调用 2、内嵌表值函数的创建与调用 3、多语句表值函数的创建与调用 前言 函数是由一个或多个 T-SQL 语句组成的子程序&#xff0c;可用于封…...

VSCode | 修改编辑器注释的颜色

1 打开VsCode的设置进入settings.json 2 添加如下代码 "editor.tokenColorCustomizations": {"comments": "#17e917"},3 保存即可生效...

媒体邀约专访与群访的区别?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体邀约中的专访与群访在多个方面存在显著差异&#xff0c;以下是对这两种采访方式的详细比较&#xff1a; 一、定义与形式 专访&#xff1a; 定义&#xff1a;专访是指由媒体记者对单…...

Pycharm2024最新版community社区版下载安装配置,快速上手

第一步&#xff1a;下载 方法1&#xff1a;官网链接 https://www.jetbrains.com/pycharm/download/?sectionwindows .方法2&#xff1a;百度网盘 链接&#xff1a;https://pan.baidu.com/s/1ic2N5hUQ2m1Kmyr5nK9Jxw?pwd76dt 提取码&#xff1a;76dt --来自百度网盘超级…...

服务器选择租用还是托管?托管和租用哪个比较划算

在构建或扩展IT基础设施时&#xff0c;服务器作为关键组件&#xff0c;其选择方式——租用或托管&#xff0c;直接关系到企业的运营成本、灵活性、安全性及长期发展战略。本文将从技术、经济、安全等多个维度&#xff0c;深入解析这两种方案的优缺点&#xff0c;并探讨在何种情…...

智能制造·数字化工厂建设规划方案(65P)

获取完整PPT见下图 更多有关华为研发管理/IPD、MBSE、PLM、ERP、MES、数据治理、数字样机等方面免费解决方案、资料获取&#xff0c;请见下图...

ACM中国图灵大会专题 | 图灵奖得主Manuel Blum教授与仓颉团队交流 | 华为论坛:面向全场景应用编程语言精彩回顾

ACM 中国图灵大会&#xff08;ACM Turing Award Celebration Conference TURC 2024&#xff09;于2024年7月5日至7日在长沙举行。本届大会由ACM主办&#xff0c;in cooperation with CCF&#xff0c;互联网之父Vinton Cerf、中国计算机学会前理事长梅宏院士和廖湘科院士担任学术…...