52、U-boot2023的移植教程

uboot:https://ftp.denx.de/pub/u-boot/
nxp-uboot:https://github.com/nxp-imx/uboot-imx

1、顶层Makefile

 文件加入编译的两种方式:以xxx/xxx.c文件为例
        1、使用menuconfig:
              先编辑.c所在目录下的Kconfig,加入配置项xxx
              再编辑.c所在目录下的Makefile,添加obj-$(CONFIG_xxx) = xxx.o
        2、不使用menuconfig:
              直接编辑.c所在目录下的Makefile,添加obj-y = xxx.o
        说明:$(libs-y)依赖每个文件夹下的xxx-in.o,而每个文件夹下的xxx-in.o又依赖当前文件夹的所有.o文件。

2、Kbuild框架

<1>在scripts文件夹下,有一个Kbuild.include文件中定义了如下几个关键的变量:181: build := -f $(srctree)/scripts/Makefile.build obj187: modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj193: dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj199: clean := -f $(srctree)/scripts/Makefile.clean obj205  hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj217: echo-cmd = $(if $($(quiet)cmd_$(1)),\echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';).....<2>在顶层Makefile文件的391-393行有如下:# We need some generic definitions (do not try to remake the file).scripts/Kbuild.include: ;include scripts/Kbuild.include                   # 包含<1>中定义的变量<3>在顶层Makefile文件的1232-1234行有如下:%.imx: $(IMX_DEPS) %.bin$(Q)$(MAKE) $(build)=arch/arm/mach-imx $@    # <1>中定义的build被使用$(BOARD_SIZE_CHECK)<4>在顶层Makefile文件的1255-1259行有如下:(make dtbs命令)PHONY += dtbsdtbs: dts/dt.dtb@:dts/dt.dtb: u-boot$(Q)$(MAKE) $(build)=dts dtbs  展开得:@ make -f $(srctree)/scripts/Makefile.build obj=dts dtbs其中:obj=dts是一个传入的变量, dtbs是要构建的目标

2、u-boot.map文件

反汇编:arm-linux-gnueabihf-objdump -D -m arm u-boot > u-boot.dis

./scripts/dtc/dtc -I dtb -O dts -o ./itop.dts ./arch/arm/dts/imx6ull-14x14-itop.dtb

./scripts/dtc/dtc -I dtb -O dts -o ./evk.dts ./arch/arm/dts/imx6ull-14x14-evk.dtb

注意:如何确定哪个.c文件的哪个函数被编译?
        通过函数名在u-boot.map、u-boot.dis这两个文件中搜索。先在u-boot.dis找到函数的链接地址,以此链接地址在u-boot.map中搜索,即可确定是哪个.c文件下的函数被编译。

save_boot_params_ret:/* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode, except if in HYP mode already *//* 禁用中断(FIQ 和 IRQ),同时将处理器设置为 SVC32 模式,除非已经处于 HYP 模式。 */mrs	r0, cpsr            @ 将当前程序状态寄存器(CPSR)的值加载到寄存器r0中and	r1, r0, #0x1f		@ 使用掩码操作提取r0的低5位,即当前的处理器模式teq	r1, #0x1a		    @ 测试是否当前处理器模式为HYP模式(Hypervisor mode)bicne	r0, r0, #0x1f	@ 如果不在HYP模式,清除 CPSR 中的所有模式位orrne	r0, r0, #0x13	@ 如果不在HYP模式,设置 CPSR 的模式为SVC模式orr	r0, r0, #0xc0		@ 禁用FIQ和IRQ中断,将 CPSR 的FIQ和IRQ位设置为 1msr	cpsr,r0             @ 将修改后的 CPSR 的值写回 CPSR 寄存器,完成设置/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector *//* 将 CP15 的 SCTLR 寄存器中将 V 位设置为0,以便将 VBAR 指向向量表 */mrc	p15, 0, r0, c1, c0, 0	@ 读取 CP15 SCTLR 寄存器里面的值bic	r0, #CR_V		        @ 将 CP15 SCTLR 寄存器中的 V 位清零mcr	p15, 0, r0, c1, c0, 0	@ 写回修改后的值到 CP15 SCTLR 寄存器/* Set vector address in CP15 VBAR register *//* 在 CP15 的 VBAR 寄存器中设置向量表的地址   */ldr	r0, =_start             @ 将 _start 符号的地址加载到寄存器 r0 中mcr	p15, 0, r0, c12, c0, 0	@ 将 r0 中的地址写入 CP15 VBAR 寄存器,设置异常向量表基地址bl	cpu_init_cp15bl	cpu_init_critbl	_main注:对于CP15协处理器的操作,CP15有c0-c15共16个寄存器组,每个组里面含有多个寄存器
mcr	p15, 0, r0, c12, c0, 0  @读操作,读取c12寄存器组里面的c0,0对应的寄存器到r0中
注意:c0,0并不是偏移的意思,而是由具体的表决定的,不要以为c0,1就是组里的第1个寄存器,这是不一定的。具体的cx,x对应组里面的第几个寄存器,参考手册上有写。
/************************************************************************************** cpu_init_cp15* 设置 CP15 寄存器(缓存、MMU、TLBs)。如果定义了 CONFIG_SYS_ICACHE_OFF,则打开 I-cache。*************************************************************************************/
cpu_init_cp15:/* Invalidate L1 I/D */mov	r0, #0			        @ set up for MCR (r0 = 0)mcr	p15, 0, r0, c8, c7, 0	@ invalidate TLBs (置零)mcr	p15, 0, r0, c7, c5, 0	@ invalidate icache (置零)mcr	p15, 0, r0, c7, c5, 6	@ invalidate BP array (置零)dsbisb/* disable MMU stuff and caches */mrc	p15, 0, r0, c1, c0, 0  @ 读 SCTLR => r0 bic	r0, r0, #0x00002000	   @ clear bits 13 (--V-)bic	r0, r0, #0x00000007	   @ clear bits 2:0 (-CAM)orr	r0, r0, #0x00000002	   @ set bit 1 (--A-) Alignorr	r0, r0, #0x00000800	   @ set bit 11 (Z---) BTBorr	r0, r0, #0x00001000	   @ set bit 12 (I) I-cachemcr	p15, 0, r0, c1, c0, 0  @ 写 r0 => SCTLRmov	r5, lr			       @ Store my Caller (r5 = lr)(跳转)mrc	p15, 0, r1, c0, c0, 0  @ r1 has Read Main ID Register (r1 = MIDR)mov	r3, r1, lsr #20		   @ get variant field (r3 = r1>>20)and	r3, r3, #0xf		   @ r3 has CPU variant (r3 = r3&0xf)and	r4, r1, #0xf		   @ r4 has CPU revision (r4 = r1&0xf)mov	r2, r3, lsl #4		   @ shift variant field for combined value(r2 = r3<<4)orr	r2, r4, r2		       @ r2 has combined CPU variant + revision(r2 = r4|r2)/* Early stack for ERRATA that needs into call C code */
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)ldr	r0, =(CONFIG_SPL_STACK)
#elseldr	r0, =(SYS_INIT_SP_ADDR)
#endifbic	r0, r0, #7	 @ 8-byte alignment for ABI compliance(将r0最低的三个比特位清零)mov	sp, r0       @ SP = r0mov	pc, r5	     @ back to my caller ( pc=r5 )(返回)
cpu_init_crit:b lowlevel_init   #(注意:这是一个无返回跳转)# 下面具体分析lowlevel_init -------------------------------------------------
lowlevel_init:/*Setup a temporary stack. Global data is not available yet. */
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)ldr	sp, =CONFIG_SPL_STACK  @ 设置堆栈指针
#elseldr	sp, =SYS_INIT_SP_ADDR  @ 设置堆栈指针
#endifbic	sp, sp, #7    @ 8字节对齐 for ABI compliance(将sp最低的三个比特位清零) 
#ifdef CONFIG_SPL_DMmov	r9, #0        @ r9 = 0
#elsepush  {ip, lr}    @ 压ip入栈、压lr入栈bl	s_init        @ 调用s_init(C函数)初始化处理器的时钟pop	{ip, pc}      @ 出栈#include <asm/io.h>
#include <asm/arch/imx-regs.h>
_main:
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)ldr	r0, =(CONFIG_TPL_STACK)
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)ldr	r0, =(CONFIG_SPL_STACK)
#elseldr	r0, =(SYS_INIT_SP_ADDR)
#endifbic	r0, r0, #7	/* 8-byte alignment for ABI compliance */mov	sp, r0                       @ sp = r0 (设置栈指针)bl	board_init_f_alloc_reserve   @ 在栈中,分配早期的malloc区域和gd区域(r0为函数的参数)mov	sp, r0                       @ sp = r0 (r0为函数的返回值)/* set up gd here, outside any C code */mov	r9, r0                       @ r9 = r0bl	board_init_f_init_reserve    @ 对早期的malloc区域和gd区域进行初始化(r0为函数的参数)#if defined(CONFIG_DEBUG_UART) && CONFIG_IS_ENABLED(SERIAL)bl	debug_uart_init
#endif#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_EARLY_BSS)CLEAR_BSS
#endifmov	r0, #0bl	board_init_fldr	r0, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */mov	sp, r0ldr	r9, [r9, #GD_NEW_GD]		/* r9 <- gd->new_gd */adr	lr, here......bl relocate_code......
struct driver *drv = ll_entry_start(struct driver, driver);struct driver *drv = ({									\static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN)	\__attribute__((unused))					\__section("__u_boot_list_2_driver_1");			\struct driver * tmp = (struct driver *)&start;					\asm("":"+r"(tmp));						\tmp;								\
});//说明:返回__u_boot_list_2_driver_1段的第一个元素的起始地址

3.1、添加自己的单板<主>

1、添加头文件cp ./include/configs/mx6ullevk.h   ./include/configs/mx6ullitop.hvim  ./include/configs/mx6ullitop.h修改.h开头的宏定义2、添加板级文件夹cp -r ./board/freescale/mx6ullevk   ./board/freescale/mx6ullitopmv ./board/freescale/mx6ullitop/mx6ullevk.c ./board/freescale/mx6ullitop/mx6ullitop.cvim ./board/freescale/mx6ullitop/Kconfigvim ./board/freescale/mx6ullitop/Makefilevim ./board/freescale/mx6ullitop/MAINTAINERSvim ./board/freescale/mx6ullitop/imximage.cfg3、添加设备树文件1cp  ./arch/arm/dts/imx6ull-14x14-evk.dts  ./arch/arm/dts/imx6ull-14x14-itop.dtsvim ./arch/arm/dts/imx6ull-14x14-itop.dtsvim ./arch/arm/dts/Makefile在 dtb-$(CONFIG_MX6ULL) 添加一项imx6ull-14x14-itop.dtb \   (为了使能dtb的编译)4、添加设备树文件2 cp ./arch/arm/dts/imx6ull-14x14-evk-u-boot.dtsi ./arch/arm/dts/imx6ull-14x14-itop-u-boot.dtsi5、添加默认配置文件cp ./configs/mx6ull_14x14_evk_defconfig ./configs/mx6ull_14x14_itop_defconfigvim configs/mx6ull_14x14_itop_defconfig<1>找到 CONFIG_TARGET_MX6ULL_14X14_EVK=y​<1>改为 CONFIG_TARGET_MX6ULL_14X14_ITOP=y<2>找到 CONFIG_DEFAULT_DEVICE_TREE="imx6ull-14x14-evk"<2>改为 ​CONFIG_DEFAULT_DEVICE_TREE="imx6ull-14x14-itop"​​6、修改Kconfig文件vim ./arch/arm/mach-imx/mx6/Kconfig添加config TARGET_MX6ULL_14X14_ITOPbool "Support mx6ull_14x14_itop"depends on MX6ULLselect BOARD_LATE_INITselect DMselect DM_THERMALselect MX6ULLimply CMD_DM添加source "board/freescale/mx6ullitop/Kconfig"
7、修改 ./arch/arm/mach-imx/cpu.c,在reset_cpu函数中添加如下代码:方法一:注释掉此函数,此时会链接drivers/watchdog/imx_watchdog.c中的reset_cpu函数
/*
__weak void reset_cpu(void)
{return;
}
*/
方法二:修改函数如下
__weak void reset_cpu(void)
{#include <fsl_wdog.h>struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;//do not assert internal resetu16 wcr = 0x04|0x10; // WCR_WDE|WCR_SRS //Write 3 times to ensure it works, due to IMX6Q errata ERR004346 writew(wcr, &wdog->wcr);writew(wcr, &wdog->wcr);writew(wcr, &wdog->wcr);//Start while for(;;);return;
}

3.2、移植网络的驱动<主>

< 1 >设备树:imx6ull-14x14-itop.dts

一、设备树:目录
[arch/arm/dts/imx6ull-14x14-itop.dts]|-->#include "imx6ull.dtsi"|-->#include "imx6ul.dtsi"|-->#include <dt-bindings/clock/imx6ul-clock.h>|-->#include <dt-bindings/gpio/gpio.h>|-->#include <dt-bindings/input/input.h>|-->#include <dt-bindings/interrupt-controller/arm-gic.h>|-->#include "imx6ul-pinfunc.h"|-->#include "imx6ull-pinfunc.h"|-->#include "imx6ull-pinfunc-snvs.h"|-->#include "imx6ul-14x14-evk.dtsi"
[arch/arm/dts/imx6ull-14x14-evk-u-boot.dtsi]
二、设备树:网络相关
[arch/arm/dts/imx6ull-14x14-itop.dts]|-->#include "imx6ull.dtsi"|-->#include "imx6ul.dtsi"//Fast Ethernet Controller 1 (CPU内部资源)
&fec1 { pinctrl-names = "default";pinctrl-0 = <&pinctrl_enet1 &pinctrl_enet1_reset>; //zjh addphy-mode = "rmii";phy-handle = <&ethphy0>;phy-supply = <&reg_peri_3v3>;phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>; //zjh addphy-reset-duration = <200>;                   //zjh addstatus = "okay";
};
//Fast Ethernet Controller 2 (CPU内部资源)
&fec2 { pinctrl-names = "default";pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_reset>; //zjh addphy-mode = "rmii";phy-handle = <&ethphy1>;phy-supply = <&reg_peri_3v3>;phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; //zjh addphy-reset-duration = <200>;                   //zjh addstatus = "okay";mdio { //MDIO总线:用于连接 FEC 和 PHY 设备#address-cells = <1>;#size-cells = <0>;ethphy0: ethernet-phy@2 { //(网口1)compatible = "ethernet-phy-id0022.1560";reg = <2>;                //phy芯片地址(硬件电路决定)micrel,led-mode = <1>;clocks = <&clks IMX6UL_CLK_ENET_REF>;clock-names = "rmii-ref";};ethphy1: ethernet-phy@1 { //(网口2)compatible = "ethernet-phy-id0022.1560";reg = <1>;                //phy芯片地址(硬件电路决定)micrel,led-mode = <1>;clocks = <&clks IMX6UL_CLK_ENET2_REF>;clock-names = "rmii-ref";};};
};			

< 2 >迅为开发板硬件原理图

5、DM框架

DM 是 U-Boot 中的驱动框架,全称 Driver Mode。
Linux 中 platform bus 模型的驱动有着三要素:device 、bus 、driver 
Uboot 中 Driver Mode 模型的驱动也有三要素:udevice、uclass、driver。

1、udevice 描述具体的某一个硬件设备。struct udevice {const struct driver *driver;const char *name;......};通过三种路径生成:a、dts设备节点。(大多数使用)b、U_BOOT_DEVICE(__name) 宏申明 (少部分使用)c、主动调用 device_bind_xxx 系列 API (极少部分使用)2、driver 是与这个设备匹配的驱动。通过 U_BOOT_DRIVER(__name) 宏声明。如果 driver 实现了 bind 接口,该 bind 将在 device_bind_common 中 device 和 driver 匹配上后被调用, 而且在 device_bind_common 中会完成 udevice 和 driver 的绑定。driver 一般都有对应的 probe 接口,通过 device_probe(struct udevice *dev) 调用,要注意的是driver 的 bind 接口调用的比 probe 接口早, 大部分在 dm_init_and_scan 中就被调用了driver 一般会提供 ops 操作接口,供上一层调用。需要说明的是,driver 一般都不需要把自己注册到 uclass 中,而是在 device_bind_common 阶段实现 driver 、uclass、device 三者的对接,然后 uclass 层通过 udevice->driver->ops 获取对应 driver 的操作接口。3、uclass 是同一类设备的抽象,提供管理同一类设备的抽象接口主要包括两个类型的结构体:struct uclass_driver 和 struct uclass其中struct uclass_driver 为 struct uclass 的驱动struct uclass_driver {  //由UCLASS_DRIVER(__name)定义const char *name; enum uclass_id id;int (*post_bind)(struct udevice *dev);......};struct uclass {void *priv_;                  //类本身私有数据struct uclass_driver *uc_drv; //类本身的驱动程序struct list_head dev_head;    //该类中的设备列表struct list_head sibling_node;//类链表中的下一个类};

uclass和udevice都是动态生成的

1、在解析设备树中的设备或直接定义的平台设备的时候,会动态生成udevice。
2、然后找到udevice对应的driver,通过driver中的uclass id得到uclass_driver id。
3、从uclass链表中查找对应的uclass是否已经生成,没有生成的话则动态生成uclass。
注:uclass链表的起点是gd的一个成员:gd->uclass_root        (*全局变量gd的很重要*)

设备驱动的使用(应用层使用驱动)

1、首先需要通过 uclass_get_device_xxx 系列 API 拿到该设备的 udevice。
2、然后通过该设备的 uclass 提供的 API 操作该设备。
<+>uclass_get_device_xxx 拿到该设备的 udevice 后会调用该设备的 probe 接口。
以驱动[ pwm backlight ]为例:

/*** drivers/video/simple_panel.c*/
struct udevice *bldev;
uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, "backlight", &bldev);
backlight_enable(bldev);
backlight_set_brightness(bldev, percent);

x、启动分析(基于IMX6ULL)

u-boot2023:启动详细的代码调用流程
u-boot.lds:  [arch/arm/cpu/u-boot.lds]
-->_start:  [arch/arm/lib/vectors.S]-->reset:  [arch/arm/cpu/armv7/start.S]    -->save_boot_params:  [arch/arm/cpu/armv7/start.S] /*将引导参数保存到内存中*/-->save_boot_params_ret:   [arch/arm/cpu/armv7/start.S]|-->cpu_init_cp15:      [arch/arm/cpu/armv7/start.S]|-->cpu_init_crit:      [arch/arm/cpu/armv7/start.S]|-->lowlevel_init:  [arch/arm/cpu/armv7/lowlevel_init.S]|-->ENTRY(_main)              [arch/arm/lib/crt0.S]|-->board_init_f_alloc_reserve [common/init/board_init.c) /*为u-boot的gd结构体分配空间*/|-->board_init_f_init_reserve  [common/init/board_init.c) /*将gd结构体清零*/|-->board_init_f               [common/board_f.c]|-->initcall_run_list      [include/initcall.h]       /*初始化序列函数*/|-->init_sequence_f[]  [common/board_f.c]         /*初始化序列函数数组 */|-->setup_mon_len|-->fdtdec_setup|-->initf_malloc|-->log_init|-->...|-->arch_cpu_init|-->mach_cpu_init|-->initf_dm|-->board_early_init_f|-->...|-->env_init|-->init_baud_rate|-->serial_init|-->console_init_f|-->...|-->dram_init|-->...---------------------------------------------------------------------------分界线							|-->relocate_code       [arch/arm/lib/relocate.S]    /*主要完成镜像拷贝和重定位*/---------------------------------------------------------------------------分界线|-->relocate_vectors                        [arch/arm/lib/relocate.S]  /*重定位向量表*/|-->board_init_r                            [common/board_r.c]         /*重定向后板级初始化*/|-->initcall_run_list(init_sequence_r)  [include/initcall.h]       /*初始化序列函数*/|-->init_sequence_r[]               [common/board_r.c]         /*初始化序列函数数组*/|-->...|-->initr_dm					/*DM初始化*/ |-->board_init                  |-->...|-->initr_dm_devices            /*DM设备初始化*/|-->stdio_init_tables|-->serial_initialize           /*串口初始化*/|-->initr_announce					      |-->dm_announce                 |-->...	|-->initr_mmc                   /*MMC初始化*/|-->initr_env                   /*环境初始化*/|-->...	|-->interrupt_init|-->board_late_init|-->initr_net                   /*网络初始化*/|-->...|-->run_main_loop     [common/board_r.c] /* It does not return */								

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

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

相关文章

实验六:三维图形修改器的综合应用

如果文章有写的不准确或需要改进的地方&#xff0c;还请各位大佬不吝赐教&#x1f49e;&#x1f49e;&#x1f49e;。朱七在此先感谢大家了。&#x1f618;&#x1f618;&#x1f618; &#x1f3e0;个人主页&#xff1a;语雀个人知识库 &#x1f9d1;个人简介&#xff1a;大家…

20240623 每日AI必读资讯

&#x1f916;原生鸿蒙AI浓度要爆表了&#xff01; - 一年一度华为开发者大会上&#xff0c;余承东首次揭秘“鸿蒙原生智能”Harmony Intelligence&#xff01; - 华为小艺进化成系统级智能体。 - 一句话实现跨多个应用的规划和任务执行&#xff1b;在第三方APP上随意处理文…

啥移动硬盘格式能更好兼容Windows和Mac系统 NTFS格式苹果电脑不能修改 paragon ntfs for mac激活码

对于同时使用Windows和Mac操作系统的用户而言&#xff0c;选择一个既能确保数据互通又能满足大容量存储需求的移动硬盘格式尤为重要。下面我们来看看啥移动硬盘格式能更好兼容Windows和Mac系统&#xff0c;NTFS格式苹果电脑不能修改的相关内容。 一、啥移动硬盘格式能更好兼容…

简单了解html常用的标签

HTML 一、基础认知 1、注释 1.1、注释的作用和写法 1.1.1、作用 为代码添加解释性&#xff0c;描述性的信息&#xff0c;主要用来帮助开发人员理解代码&#xff0c;浏览器执行代码时回忽略所有注释。 1.1.2、注释的快捷键 在VS Code中&#xff1a;Ctrl / 2、HTML标签的…

Android-系统开发_四大组件篇----探讨-Activity-的生命周期

当一个活动不再处于栈顶位置&#xff0c;但仍然可见时&#xff0c;这时活动就进入了暂停状态。你可能会觉得既然活动已经不在栈顶了&#xff0c;还怎么会可见呢&#xff1f; 这是因为并不是每一个活动都会占满整个屏幕&#xff0c;比如对话框形式的活动只会占用屏幕中间的部分…

基于SpringBoot+Vue二手交易平台设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝1W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;还…

《Windows API每日一练》5.4 键盘消息和字符集

本节我们将通过实例来说明不同国家的语言、字符集和字体之间的差异&#xff0c;以及Windows系统是如何处理的。 本节必须掌握的知识点&#xff1a; 第31练&#xff1a;显示键盘消息 非英语键盘问题 字符集和字体 第32练&#xff1a;显示默认字体信息 第33练&#xff1a;创建逻…

爬虫笔记15——爬取网页数据并使用redis数据库set类型去重存入,以爬取芒果踢V为例

下载redis数据库 首先需要下载redis数据库&#xff0c;可以直接去Redis官网下载。或者可以看这里下载过程。 pycharm项目文件下载redis库 > pip install redis 然后在程序中连接redis服务&#xff1a; from redis import RedisredisObj Redis(host127.0.0.1, port6379)…

2024青海三支一扶报名流程图解❗

报考公告 1、招考人数&#xff1a; 1910 人 2、报名时间&#xff1a;6月20-6月25 3、笔试时间&#xff1a;7月6日 4、笔试内容&#xff1a;综合知识和能力素质测验 &#x1f534;线上报名流程图解 一、本次报名采用线上报名方式&#xff0c;考生需登录《青海省人事考试信息网》…

OpenGL:中点直线算法

理论部分 中点直线算法是通过在像素中确定与理想直线最靠近的像素来进行扫描转换的。 在上图中,假设直线的斜率 0 ≤ m ≤ 1 0\le m \le 1 0≤m≤1。假设当前最近的像素已经确认为 P ( x k , y k ) P(x_k, y_k) P(xk​,yk​),由于 x x x位最大的位移方向,因此直线在 x x x方…

【因果推断python】51_去偏/正交机器学习3

目录 What is Non-Parametric About? What is Non-Parametric About? 在我们继续之前&#xff0c;我只想强调一个常见的误解。当我们考虑使用非参数 Double-ML 模型来估计 CATE 时&#xff0c;我们似乎会得到一个非线性治疗效果。例如&#xff0c;让我们假设一个非常简单的数…

【干货】Android中高级开发进阶必备资料(附:PDF+视频+源码笔记)

4、数据传输与序列化 5、Java虚拟机原理 6、高效IO 设计思想解读开源框架 随着互联网企业的不断发展&#xff0c;产品项目中的模块越来越多&#xff0c;用户体验要求也越来越高&#xff0c;想实现小步快跑、快速迭代的目的越来越难&#xff0c;插件化技术应用而生。如果没有…

大模型微调和RAG的应用场景

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

Android高工面试:分享两道阿里P6究极难度算法题,面试完我直接怀疑人生---

10亿数据内筛选最大的100个&#xff0c;要求速度要快。 最近阿里的一道面试题&#xff0c;其实基于多层博弈论&#xff0c;我想我刷过这题&#xff0c;我知道如何偷鸡的。我以为我在第二层&#xff0c;没想到我只在第一层。 第一层 于大顶堆的方式的方式筛选出数组内最​ 大的…

帆软使用总结-新建填报报表

1.界面设计 选择菜单[文件>新建普通报表] 2.分别把B3、C3设置为文本控件 3.选中D3&#xff0c;并设置为下拉控件 4.选择菜单[模板>报表填报属性] 5.选择菜单[模板>模板web属性] 2.效果演示

Vue-表格

需求 代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTE-8"> <meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width…

Git客户端安装步骤详解

git windows7 百度经验:jingyan.baidu.com 方法/步骤 1 从git官网下一个git安装包。 步骤阅读 2 点击git.exe安装程序&#xff0c;点击【next】 ![git的安装和配置](https://imgsa.baidu.com/exp/w500/sign7565f44ba58b87d65042ab1f37092860/21a4462309f790525e5b0144…

软件测试----用例篇(设计测试用例保姆级教程✅)

文章目录 前言一、测试用例概念 二、如何设计测试用例三、设计测试用例的方法3.1基于需求的设计方法3.2具体的设计方法等价类边界值正交法判定表法场景法错误猜测法 前言 在软件开发过程中&#xff0c;测试用例是至关重要的一环。它们帮助软件开发人员和测试人员确定软件是否按…

如何识别商业电子邮件诈骗

复制此链接到微信打开阅读全部已发布文章 不要关闭它标签&#xff01;我知道很少有词组比商业、电子邮件和妥协更无趣。 但这不是一篇无聊的文章&#xff1a;这是一篇关于电子邮件骗子的文章&#xff0c;根据联邦调查局的说法&#xff0c;他们每年通过诈骗人们赚取 260 亿美元…

AU音频重新混合音频,在 Adobe Audition 中无缝延长背景音乐,无缝缩短BGM

导入音频&#xff0c;选中音频&#xff0c;并且点 New Multitrack Session 的图标 设计文件名和存储路径&#xff0c;然后点 OK 点 Essential Sound 面板点 Music &#xff08;如果没有这个面板 点菜单栏 Windows > Essential Sound 调出来&#xff09; 点 Duration 展…