U-boot(五):启动内核

news2025/2/23 3:12:41

本文主要探讨210的uboot启动内核过程。

嵌入式系统状态启动
        未上电时bootloader、kernel、rootfs以镜像形式存储在启动介质中(X210为iNand/SD卡),运行时搬运到DDR中
        未上电时u-boot.bin,zImage,rootfs在SD卡中各自对应的分区中,启动时去对应分区寻找(分区表一致)
        动态启动为从SD卡到DDR内存,并且运行启动代码进行硬/软件初始化
        uboo在第一阶段重定位时将第二阶段(整个uboot镜像)加载到DDR的0xc3e00000地址处(uboot链接地址)
        uboot启动内核时从SD卡读取内核到DDR地址是0x30008000(内核链接地址)
        uboot启动内核:将内核搬移到DDR中,校验内核格式、CRC等,准备传参,跳转执行内核
        启动内核主要函数是:do_boom,do_bootm_linux
        uboot能启动的内核格式:zImage,uImage,fdt

image_header_t

typedef struct image_header {
    uint32_t    ih_magic;    /* Image Header Magic Number    */
    uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */
    uint32_t    ih_time;    /* Image Creation Timestamp    */
    uint32_t    ih_size;    /* Image Data Size        */
    uint32_t    ih_load;    /* Data     Load  Address        */
    uint32_t    ih_ep;        /* Entry Point Address        */
    uint32_t    ih_dcrc;    /* Image Data CRC Checksum    */
    uint8_t        ih_os;        /* Operating System        */
    uint8_t        ih_arch;    /* CPU architecture        */
    uint8_t        ih_type;    /* Image Type            */
    uint8_t        ih_comp;    /* Compression Type        */
    uint8_t        ih_name[IH_NMLEN];    /* Image Name        */
} image_header_t;
image_header_t    *hdr;

        uboot启动内核使用的数据结构(镜像头部信息)


内核启动
        内核不能自主开机,uboot帮助内核重定位到链接地址(SD卡到DDR)并且给内核传递启动参数
        210的iNand版本uboot使用movi命令完成内核重定位(movi read kernel 30008000),kernel为uboot中kernel分区

do_bootm(cmd_bootm.c)

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

/* find out kernel image address */
    if (argc < 2) {
        addr = load_addr;
        debug ("*  kernel: default image load address = 0x%08lx\n",
                load_addr);
    } else {
        addr = simple_strtoul(argv[1], NULL, 16);
        debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);
    }
ulong load_addr = CFG_LOAD_ADDR;    /* Default Load Address */

#define CFG_LOAD_ADDR        MEMORY_BASE_ADDRESS    /* default load address    */

#define MEMORY_BASE_ADDRESS    0x30000000

        启动命令:bootm 0x30008000,故do_boom的argc=2,argv[0]=bootm,argv[1]=0x30008000
        启动命令:bootm,从CFG_LOAD_ADDR地址启动(x210_sd.h)


vmlinuz,zImage,uImage
        uboot编译生成u-boot(elf格式),由u-boot用arm-linux-objcopy工具加工得到u-boot.bin(镜像)用来烧录
        linux内核编译生成vmlinux或vmlinuz(几十M)(elf格式),用objcopy工具加工成烧录Image镜像(几M),对Image压缩,在image压缩后的文件前端附加解压缩代码构成zImage
        uImage是由zImage加工得到,mkimage工具由zImage加工生成uImage给uboot启动,在zImage前加64字节头信息即可得到


zImage启动

#ifdef CONFIG_ZIMAGE_BOOT
#define LINUX_ZIMAGE_MAGIC    0x016f2818
    /* find out kernel image address */
    if (argc < 2) {
        addr = load_addr;
        debug ("*  kernel: default image load address = 0x%08lx\n",
                load_addr);
    } else {
        addr = simple_strtoul(argv[1], NULL, 16);
        debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);
    }

    if (*(ulong *)(addr + 9*4) == LINUX_ZIMAGE_MAGIC) {
        printf("Boot with zImage\n");
        addr = virt_to_phys(addr);
        hdr = (image_header_t *)addr;
        hdr->ih_os = IH_OS_LINUX;
        hdr->ih_ep = ntohl(addr);

        memmove (&images.legacy_hdr_os_copy, hdr, sizeof(image_header_t));

        /* save pointer to image header */
        images.legacy_hdr_os = hdr;

        images.legacy_hdr_valid = 1;

        goto after_header_check;
    }
#endif

        CONFIG_ZIMAGE_BOOT(x210_sd.h)用宏控制编译支持zImage格式的内核启动
        LINUX_ZIMAGE_MAGIC是魔数(0x016f2818)来表示zImage,即zImage格式镜像在头部存放该数作为标记辨别它是否是zImage(是否等于LINUX_ZIMAGE_MAGIC),若为在Image则对头部信息改造,用头信息初始化images,完成了校验

after_header_check

#if defined(CONFIG_ZIMAGE_BOOT)
after_header_check:
    os = hdr->ih_os;
#endif

    switch (os) {
    default:            /* handled by (original) Linux case */
    case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
        fixup_silent_linux();
#endif
        do_bootm_linux (cmdtp, flag, argc, argv, &images);
        break;

    case IH_OS_NETBSD:
        do_bootm_netbsd (cmdtp, flag, argc, argv, &images);
        break;

#ifdef CONFIG_LYNXKDI
    case IH_OS_LYNXOS:
        do_bootm_lynxkdi (cmdtp, flag, argc, argv, &images);
        break;
#endif

    case IH_OS_RTEMS:
        do_bootm_rtems (cmdtp, flag, argc, argv, &images);
        break;

#if defined(CONFIG_CMD_ELF)
    case IH_OS_VXWORKS:
        do_bootm_vxworks (cmdtp, flag, argc, argv, &images);
        break;

    case IH_OS_QNX:
        do_bootm_qnxelf (cmdtp, flag, argc, argv, &images);
        break;
#endif

#ifdef CONFIG_ARTOS
    case IH_OS_ARTOS:
        do_bootm_artos (cmdtp, flag, argc, argv, &images);
        break;
#endif
    }

    show_boot_progress (-9);
#ifdef DEBUG
    puts ("\n## Control returned to monitor - resetting...\n");
    do_reset (cmdtp, flag, argc, argv);
#endif
    if (iflag)
        enable_interrupts();

    return 1;
}


        确定image类型,依据类型进行头信息校验,校验通过则准备启动内核


uImage启动和设备数启动

/* get kernel image header, start address and length */
    os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
            &images, &os_data, &os_len);
    if (os_len == 0) {
        puts ("ERROR: can't get kernel image!\n");
        return 1;
    }

    /* get image parameters */

    switch (genimg_get_format (os_hdr)) {
    case IMAGE_FORMAT_LEGACY:
        type = image_get_type (os_hdr);
        comp = image_get_comp (os_hdr);
        os = image_get_os (os_hdr);

        image_end = image_get_image_end (os_hdr);
        load_start = image_get_load (os_hdr);
        break;
#if defined(CONFIG_FIT)
    case IMAGE_FORMAT_FIT:
        if (fit_image_get_type (images.fit_hdr_os,
                    images.fit_noffset_os, &type)) {
            puts ("Can't get image type!\n");
            show_boot_progress (-109);
            return 1;
        }

        if (fit_image_get_comp (images.fit_hdr_os,
                    images.fit_noffset_os, &comp)) {
            puts ("Can't get image compression!\n");
            show_boot_progress (-110);
            return 1;
        }

        if (fit_image_get_os (images.fit_hdr_os,
                    images.fit_noffset_os, &os)) {
            puts ("Can't get image OS!\n");
            show_boot_progress (-111);
            return 1;
        }
        break;
#endif
    default:
        puts ("ERROR: unknown image format type!\n");
        return 1;
    }

    image_start = (ulong)os_hdr;
    load_end = 0;
    type_name = genimg_get_type_name (type);
static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
        bootm_headers_t *images, ulong *os_data, ulong *os_len)

{
    image_header_t    *hdr;
    ulong        img_addr;
#if defined(CONFIG_FIT)
    void        *fit_hdr;
    const char    *fit_uname_config = NULL;
    const char    *fit_uname_kernel = NULL;
    const void    *data;
    size_t        len;
    int        cfg_noffset;
    int        os_noffset;
#endif

    /* find out kernel image address */
    if (argc < 2) {
        img_addr = load_addr;
        debug ("*  kernel: default image load address = 0x%08lx\n",
                load_addr);
#if defined(CONFIG_FIT)
    } else if (fit_parse_conf (argv[1], load_addr, &img_addr,
                            &fit_uname_config)) {
        debug ("*  kernel: config '%s' from image at 0x%08lx\n",
                fit_uname_config, img_addr);
    } else if (fit_parse_subimage (argv[1], load_addr, &img_addr,
                            &fit_uname_kernel)) {
        debug ("*  kernel: subimage '%s' from image at 0x%08lx\n",
                fit_uname_kernel, img_addr);
#endif
    } else {
        img_addr = simple_strtoul(argv[1], NULL, 16);
        debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);
    }

    show_boot_progress (1);

    /* copy from dataflash if needed */
    img_addr = genimg_get_image (img_addr);

    /* check image type, for FIT images get FIT kernel node */
    *os_data = *os_len = 0;
    switch (genimg_get_format ((void *)img_addr)) {
    case IMAGE_FORMAT_LEGACY:
        printf ("## Booting kernel from Legacy Image at %08lx ...\n",
                img_addr);
        hdr = image_get_kernel (img_addr, images->verify);
        if (!hdr)
            return NULL;
        show_boot_progress (5);

        /* get os_data and os_len */
        switch (image_get_type (hdr)) {
        case IH_TYPE_KERNEL:
            *os_data = image_get_data (hdr);
            *os_len = image_get_data_size (hdr);
            break;
        case IH_TYPE_MULTI:
            image_multi_getimg (hdr, 0, os_data, os_len);
            break;
        default:
            printf ("Wrong Image Type for %s command\n", cmdtp->name);
            show_boot_progress (-5);
            return NULL;
        }

        /*
         * copy image header to allow for image overwrites during kernel
         * decompression.
         */
        memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));

        /* save pointer to image header */
        images->legacy_hdr_os = hdr;

        images->legacy_hdr_valid = 1;
        show_boot_progress (6);
        break;
#if defined(CONFIG_FIT)
    case IMAGE_FORMAT_FIT:
        fit_hdr = (void *)img_addr;
        printf ("## Booting kernel from FIT Image at %08lx ...\n",
                img_addr);

        if (!fit_check_format (fit_hdr)) {
            puts ("Bad FIT kernel image format!\n");
            show_boot_progress (-100);
            return NULL;
        }
        show_boot_progress (100);

        if (!fit_uname_kernel) {
            /*
             * no kernel image node unit name, try to get config
             * node first. If config unit node name is NULL
             * fit_conf_get_node() will try to find default config node
             */
            show_boot_progress (101);
            cfg_noffset = fit_conf_get_node (fit_hdr, fit_uname_config);
            if (cfg_noffset < 0) {
                show_boot_progress (-101);
                return NULL;
            }
            /* save configuration uname provided in the first
             * bootm argument
             */
            images->fit_uname_cfg = fdt_get_name (fit_hdr, cfg_noffset, NULL);
            printf ("   Using '%s' configuration\n", images->fit_uname_cfg);
            show_boot_progress (103);

            os_noffset = fit_conf_get_kernel_node (fit_hdr, cfg_noffset);
            fit_uname_kernel = fit_get_name (fit_hdr, os_noffset, NULL);
        } else {
            /* get kernel component image node offset */
            show_boot_progress (102);
            os_noffset = fit_image_get_node (fit_hdr, fit_uname_kernel);
        }
        if (os_noffset < 0) {
            show_boot_progress (-103);
            return NULL;
        }

        printf ("   Trying '%s' kernel subimage\n", fit_uname_kernel);

        show_boot_progress (104);
        if (!fit_check_kernel (fit_hdr, os_noffset, images->verify))
            return NULL;

        /* get kernel image data address and length */
        if (fit_image_get_data (fit_hdr, os_noffset, &data, &len)) {
            puts ("Could not find kernel subimage data!\n");
            show_boot_progress (-107);
            return NULL;
        }
        show_boot_progress (108);

        *os_len = len;
        *os_data = (ulong)data;
        images->fit_hdr_os = fit_hdr;
        images->fit_uname_os = fit_uname_kernel;
        images->fit_noffset_os = os_noffset;
        break;
#endif
    default:
        printf ("Wrong Image Format for %s command\n", cmdtp->name);
        show_boot_progress (-108);
        return NULL;
    }

    debug ("   kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",
            *os_data, *os_len, *os_len);

    return (void *)img_addr;
}

        IMAGE_FORMAT_LEGACY为uImage启动方式,启动校验在boot_get_kernel函数:校验uImage头信息,得kernel起始位置去启动
        CONFIG_FIT:设备树方式启动

do_bootm_linux(zImage)

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
             bootm_headers_t *images)

{
    ulong    initrd_start, initrd_end;
    ulong    ep = 0;
    bd_t    *bd = gd->bd;
    char    *s;
    int    machid = bd->bi_arch_number;
    void    (*theKernel)(int zero, int arch, uint params);
    int    ret;

#ifdef CONFIG_CMDLINE_TAG
    char *commandline = getenv ("bootargs");
#endif

    /* find kernel entry point */
    if (images->legacy_hdr_valid) {
        ep = image_get_ep (&images->legacy_hdr_os_copy);
#if defined(CONFIG_FIT)
    } else if (images->fit_uname_os) {
        ret = fit_image_get_entry (images->fit_hdr_os,
                    images->fit_noffset_os, &ep);
        if (ret) {
            puts ("Can't get entry point property!\n");
            goto error;
        }
#endif
    } else {
        puts ("Could not find kernel entry point!\n");
        goto error;
    }
    theKernel = (void (*)(int, int, uint))ep;

    s = getenv ("machid");
    if (s) {
        machid = simple_strtoul (s, NULL, 16);
        printf ("Using machid 0x%x from environment\n", machid);
    }

    ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_ARM,
            &initrd_start, &initrd_end);
    if (ret)
        goto error;

    show_boot_progress (15);

    debug ("## Transferring control to Linux (at address %08lx) ...\n",
           (ulong) theKernel);

#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
    defined (CONFIG_CMDLINE_TAG) || \
    defined (CONFIG_INITRD_TAG) || \
    defined (CONFIG_SERIAL_TAG) || \
    defined (CONFIG_REVISION_TAG) || \
    defined (CONFIG_LCD) || \
    defined (CONFIG_VFD) || \
    defined (CONFIG_MTDPARTITION)
    setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
    setup_serial_tag (&params);
#endif
#ifdef CONFIG_REVISION_TAG
    setup_revision_tag (&params);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
    setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
    setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
    if (initrd_start && initrd_end)
        setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
    setup_videolfb_tag ((gd_t *) gd);
#endif

#ifdef CONFIG_MTDPARTITION
    setup_mtdpartition_tag();
#endif

    setup_end_tag (bd);
#endif

    /* we assume that the kernel is in place */
    printf ("\nStarting kernel ...\n\n");

#ifdef CONFIG_USB_DEVICE
    {
        extern void udc_disconnect (void);
        udc_disconnect ();
    }
#endif

    cleanup_before_linux ();

    theKernel (0, machid, bd->bi_boot_params);
    /* does not return */
    return;

error:
    do_reset (cmdtp, flag, argc, argv);
    return;
}

        ulong    ep = 0;ep(entrypoint)是程序入口,镜像文件起始执行部分不在镜像开头,在镜像开头某个字节处(有偏移量)
        运行镜像过程:读取头信息MAGIC_NUM来确定镜像种类,镜像校验,读取头信息获取镜像信息(镜像长度,种类,入口地址),去entrypoint处运行镜像
        theKernel = (void (*)(int, int, uint))ep;将ep赋值给theKernel,函数指向OS镜像真正入口地址(操作系统运行首代码)。
        int    machid = bd->bi_arch_number;uboot启动内核时,机器码传给内核,uboot通过全局变量gd->bd->bi_arch_num将x210_sd.h定义的机器码传给uboot
        函数(110-144)是uboot给linux内核传递参数处理
        Starting kernel标志uboot加载内核镜像,校验通过,获得内核入口地址


tag传参

struct tag {
        struct tag_header hdr;
        union { 
                struct tag_core         core;
                struct tag_mem32        mem;
                struct tag_videotext    videotext;
                struct tag_ramdisk      ramdisk;
                struct tag_initrd       initrd;
                struct tag_serialnr     serialnr;
                struct tag_revision     revision;
                struct tag_videolfb     videolfb;
                struct tag_cmdline      cmdline;
                
                /*
                * Acorn specific
                */
                struct tag_acorn        acorn;
                
                /*
                 * DC21285 specific
                 */
                struct tag_memclk       memclk;
                
                struct tag_mtdpart      mtdpart_info;
        } u;
};
struct tag_header {
    u32 size;
    u32 tag;
};
static struct tag *params;

        tag_header中有tag的size和类型编码


        tag函数参宏

ATAG_NONE	                tag_header        tag结束
ATAG_CORE	                tag_core
ATAG_MEM	                tag_mem32         内存配置信息
ATAG_VIDEOTEXT	            tag_videotext
ATAG_RAMDISK	            tag_ramdisk
ATAG_INITRD	                tag_initrd
ATAG_SERIAL	                tag_serialnr
ATAG_REVISION	            tag_revision
ATAG_VIDEOLFB	            tag_videolfb
ATAG_CMDLINE	            tag_cmdline      启动命令参数(的bootargs)
ATAG_ACORN	                tag_acorn        tag起始
ATAG_MEMCLK	                tag_memclk
ATAG_MTDPART                tag_mtdpart      iNand/SD卡分区表
/* The list must start with an ATAG_CORE node */
#define ATAG_CORE	0x54410001

struct tag_core {
	u32 flags;		/* bit 0 = read-only */
	u32 pagesize;
	u32 rootdev;
};

theKernel (0, machid, bd->bi_boot_params);
	/* does not return */

        uboot调用theKernel函数来运行linux内核,uboot调用时传递3个参数:(0,机器码,tag首地址)

demo:

        编译uImage

ubuntu:

root@kaxi-virtual-machine:~/qt_x210v3s/kernel# cat mk
#!/bin/sh

#QT_KERNEL_CONFIG=x210_jffs_defconfig
QT_KERNEL_CONFIG=x210ii_qt_defconfig

CPU_NUM=$(cat /proc/cpuinfo |grep processor|wc -l)
CPU_NUM=$((CPU_NUM+1))

make distclean
make clean

make ${QT_KERNEL_CONFIG} 
make -j${CPU_NUM} 
cd qt_x210v3s/kernel


vim Makefile

CROSS_COMPILE   ?= /root/arm-2009q3/bin/arm-none-linux-gnueabi-


make clean &> /dev/null && make distclean &> /dev/null

cp ../uboot/tools/mkimage /usr/local/bin/


vim mk

QT_KERNEL_CONFIG=x210ii_qt_defconfig

生成zImage

./mk &>/dev/null

make uImage &>/dev/null

cp arch/arm/boot/uImage /root/tftp

uboot: 

tftp 30008000 uImage

movi read kernel 30008000

bootm 30008000

结果示例: 

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

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

相关文章

PWM(PulseWidthModulation)控制

PWM&#xff08;Pulse Width Modulation&#xff09;控制就是对脉冲的宽度进行调制的技术&#xff0c;即通过对一系列脉冲的宽度进行调制&#xff0c;来等效的获得所需要的波形&#xff08;含形状和幅值&#xff09;&#xff1b;面积等效原理是PWM技术的重要基础理论&#xff1…

HTTP协议发展

HTTP 1.0 -> HTTP 1.1 -> HTTP 2.0 -> HTTP 3.0 (QUIC) 每一代HTTP解决了什么问题&#xff1f; 下图说明了主要功能。 HTTP 1.0 于 1996 年最终确定并完整记录。对同一服务器的每个请求都需要单独的 TCP 连接。 HTTP 1.1 于 1997 年发布。TCP 连接可以保持打开状态…

漏电流直流互感器正负1-50ua

1/ 互感线圈 01 双绕组800t / 200t 互感线圈 02 单绕组 1120t

PTA-7-53 身份证排序

题目&#xff1a; 输入n&#xff0c;然后连续输入n个身份证号。 将每个身份证的年月日抽取出来&#xff0c;按年-月-日格式组装&#xff0c;然后对组装后的年-月-日升序输出。 根据题目要求&#xff0c;代码实现如下&#xff1a; import java.util.Scanner; import java.uti…

【源码解析】聊聊SpringBoot自动装配如何实现的

Springboot的习惯优于配置&#xff0c;其实就是默认装配一些配置&#xff0c;。对于整体的开发、部署提升了效率。我们直接写一个main类就可以快速开发了。 比如我们引入web的starter-web&#xff0c;那么就引入了web的框架。 <dependency><groupId>org.springfra…

设计模式之十二:复合模式

模式通常被一起使用&#xff0c;并被组合在同一个解决方案中。 复合模式在一个解决方案中结合两个或多个模式&#xff0c;以解决一般或重复发生的问题。 首先重新构建鸭子模拟器&#xff1a; package headfirst.designpatterns.combining.ducks;public interface Quackable …

关于微服务的思考

目录 什么是微服务 定义 特点 利弊 引入时机 需要哪些治理环节 从单体架构到微服务架构的演进 单体架构 集群和垂直化 SOA 微服务架构 如何实现微服务架构 服务拆分 主流微服务解决方案 基础设施 下一代微服务架构Service Mesh 什么是Service Mesh&#xff1f…

模拟电子技术Ⅲ-场效应管的分析

场效应管的定义 场效应管是单极性管&#xff1a;参与导电的是多数载流子&#xff0c;要么是自由电子&#xff0c;要么是空穴&#xff0c; 场效应管有三个极&#xff1a;源极&#xff08;s&#xff09;、栅极&#xff08;g&#xff09;、漏极&#xff08;d&#xff09;&#xf…

如何在gitlab上使用hooks

参考链接&#xff1a;gitlab git hooks 1. Git Hook 介绍 与许多其他版本控制系统一样&#xff0c;Git 有一种方法可以在发生某些重要操作时&#xff0c;触发自定义脚本&#xff0c;即 Git Hook&#xff08;Git 钩子&#xff09;。 当我们初始化一个项目之后&#xff0c;.git…

机器学习库:numpy

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 文章目录 写在开头 基本数据格式 array 数据定位 argmax 数据生成 random.rand random.randn random.randint 维度拓展 expand_dim 结语 写在…

MutationObserver 监视 DOM 树改变的api

1、介绍 MutationObserver是一个构造函数&#xff0c;可以用来监听某个节点的变化&#xff0c;当节点发生变化时&#xff0c;可以执行一些回调函数。 它不会立即执行&#xff0c;需要调用MutationObserver的observe方法&#xff0c;传入你想要监听的节点&#xff0c;以及一些配…

Proteus仿真--基于ADC0832的可调频率波形输出

本文介绍基于ADC0832的可调频率波形输出&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 本设计中80C51单片机作为主控&#xff0c;用数码管作为显示模块&#xff0c;频率采集选用ADC0832芯片 仿真运行视频 Proteus仿真--基于ADC0832的可调频率波形输出…

专业级音乐制作软件Studio One 6.5详细功能介绍

Studio One 6.5是一款专业级音乐制作软件&#xff0c;由PreSonus公司开发。它提供了强大的音频录制、编辑、混音和制作工具&#xff0c;被广泛应用于音乐制作、录音棚和现场演出等领域。 Studio One-6.5 下载地址&#xff1a;https://souurl.cn/fMjY4Q 下面是关于Studio One 6…

【刷题笔记】接雨水||暴力通过||符合思维方式

接雨水 文章目录 接雨水1 题目描述2 分析2.1 左到右2.2 右到左2.3 计算面积 3 代码3.1 Java3.2 Python 附录1 1 题目描述 https://leetcode.cn/problems/trapping-rain-water/ 面试的时候关键不是你的手法多么精妙&#xff0c;首先要做出来。 给定 n 个非负整数表示每个宽度为…

Redis之C语言底层数据结构笔记

目录 动态字符串SDS Dict ZipList QuickList ​ SkipList 动态字符串SDS Dict ZipList QuickList SkipList

汇编实验2-2 查找匹配字符串笔记

一、数据段 1.字符串结尾&#xff1a;13,10&#xff0c;$ 2.设置格式控制字符串(这样就不用再写clrf函数了) 3.设置存关键字和句子的地址标签&#xff0c;以关键字为例 二、代码段 1.输入字符串 2.字符串比较 2.1 每次的比较长度&#xff0c;KLEN->CL 2.2 设置目标串起始…

代码随想录算法训练营第五十九天|503. 下一个更大元素 II、42. 接雨水

第十章 单调栈part02 503. 下一个更大元素 II 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#xff0c;这个数字之…

应用程序安装异常(-113)

应用程序安装异常(-113) 报错如下&#xff1a;    应用未安装:应用与您的手机不兼容。    应用程序安装异常(-113)    这种情况是说我们的是x86架构&#xff0c;但是你运行的项目支持的是arm架构&#xff0c;所以你需要让自己的项目也支持arm的架构。 方案一 在项目的…

【Seata源码学习 】篇五 注册分支事务

【Seata源码学习 】篇五 分支事务注册 1.远程服务调用绑定XID 回到事务模版方法类TransactionalTemplate中 beginTransaction(txInfo, tx);Object rs;try {// Do Your Business// 执行执行拦截器链路rs business.execute();} catch (Throwable ex) {// 3. The needed busine…

人力资源管理后台 === 上传+权限数据

目录 1.员工详情-封装员工头像组件 2.员工详情-上传图片-创建腾讯云存储桶 3.员工详情-使用cos-sdk完成上传 4. 权限管理-搭建权限页面 5.权限管理-获取数据转化树形 6.权限管理-作业 7.权限应用-权限概念 8.权限应用-员工分配角色-弹出层 9.权限应用-员工分配角色-回…