PotatoPie 4.0 实验教程(41) —— FPGA实现RISC-V 扩展 GPIO UART Timer功能

TD工程介绍

我们提供的TD工程里的RISC-V核默认就开启了GPIO UART扩展,可以看到还有SPI和I2C扩展。因此后面的实验中TD的工程我们基本不怎么修改TD的内容,只需要修改TD工具中Soc_Top.v文件中的TCM0_INITFILE为FD生成的固件名称即可,主要修我以为都是在FD工程进行修改即可。

FD工程介绍

这个工程我们主要演示了如何使用UART及UART中断,如何使用定时器中断,以及如何使用GPIO和GPIO中断。

FD工程导入

打开FD选择workspace为 demo_riscv\wkspace 就会自动导入该workspace下的所有项目。

由于你的FD的目录与我的FD目录不在同一个位置,会导致编译器工具链的找不着,我们需要在工程上右键选择Reset Project Toolchain

执行完这个操作就FD会重新修正工程的工具链配置。

FD工程源代码分析

头文件、宏定义及全局变量介绍

头文件

 

#include "core.h" // 核心头文件

//#define USE_MTIME // 不使用MTIME

#include "uart.h" // UART 头文件

#include "gpio.h" // GPIO 头文件

#include "anl_printf.h" // 打印库头文件

#include "interrupt.h" // 中断库头文件

#ifdef USE_MTIME

#include "mtime.h" // 如果使用 MTIME,则引入 MTIME 头文件

#else

#include "systick.h" // 否则引入 SysTick 头文件

#endif

  1. #include "core.h":这个头文件是系统的核心头文件,通常包含了与硬件相关的低级别配置和宏定义。它可能包含了处理器寄存器的定义、中断控制器配置等内容。

  2. #include "uart.h":这个头文件包含了 UART(通用异步收发传输)相关的函数声明和宏定义。

  3. #include "gpio.h":这个头文件包含了 GPIO(通用输入输出)相关的函数声明和宏定义。

  4. #include "anl_printf.h":这个头文件包含了打印函数的声明和定义。

  5. #include "interrupt.h":这个头文件包含了中断控制器相关的函数声明和宏定义。

  6. #ifdef USE_MTIME:这是一个条件编译指令,用于根据是否定义了 USE_MTIME 宏来选择性地包含不同的头文件内容。

  7. #include "mtime.h":如果定义了 USE_MTIME 宏,就会包含这个头文件。它可能包含了 MTIME(Machine Timer)相关的函数声明和宏定义,用于配置和操作处理器的计时器。

  8. #include "systick.h":如果没有定义 USE_MTIME 宏,就会包含这个头文件。它可能包含了 SysTick 定时器相关的函数声明和宏定义,用于配置和操作 SysTick 定时器。

  9. Systick 和 MTIME 定时器的区别主要是其资源占用和操作模式。 Systick 是一个自动重装的 30bit 定时器,用户需要使用 SetSystickCfg()函数启用定时器,并在定时器中断处理程序中使用 ClrSystickInt()函数清除掉挂起的定时器状态对于 MTIME 定时器而言,它的初始化和中断响应都是使用 SetMtimeCmp()函数将下一时钟节拍的计数值装入定时器比较值中。

全局变量sys_banner

static char sys_banner[] = {"- Anlogic eMCU buildtime [" __TIME__" " __DATE__ "] " "rev 1.0 \r\n"};

这行代码定义了一个静态字符数组 sys_banner,用于存储系统的横幅信息。该信息包含了编译时间和日期,以及版本号。

  • __TIME__:编译时的时间,格式为 HH:MM:SS。
  • __DATE__:编译时的日期,格式为 MMM DD YYYY(月份、日期、年份)。

这两个宏是编译器提供的预定义宏,在编译时会被替换为当前的编译时间和日期。在这里,它们被用于构建一个包含编译时间和日期的字符串。

宏定义

 

//THIS DEMO IS FOR SYSTICK SYSTEM

#define SYS_FREQ 80000000 // 系统频率

#define UART_BAUD 115200 // UART 波特率

#define GPIO_INTSRC 0x04 // GPIO 中断源

#define UART1_INTSRC 0x01 // UART1 中断源

#define TIM_TRIG_FREQ 1 // 定时器触发频率,每秒1次

这段代码是一些预定义的常量和注释,用于描述程序的一些基本参数和特性:

  1. // THIS DEMO IS FOR SYSTICK SYSTEM:这是一个注释,用于说明这段代码是针对 SysTick 系统设计的演示程序。

  2. #define SYS_FREQ 80000000:这是一个宏定义,表示系统的频率为 80MHz。这个频率用于配置定时器、UART 通信等时序相关的功能。

  3. #define UART_BAUD 115200:这是一个宏定义,表示 UART 的波特率为 115200。波特率是串行通信中表示数据传输速率的参数。

  4. #define GPIO_INTSRC 0x04:这是一个宏定义,表示 GPIO 中断源的值为 0x04。在某些系统中,GPIO 的中断可以被多个源触发,此处定义了其中一个源的标识值。

  5. #define UART1_INTSRC 0x01:这是一个宏定义,表示 UART1 中断源的值为 0x01。类似于上面的 GPIO 中断源,这里定义了 UART1 中断的标识值。

  6. #define TIM_TRIG_FREQ 1:这是一个宏定义,表示定时器的触发频率为每秒 1 次。这个参数用于配置定时器中断的触发频率,可以根据需要进行调整。

函数说明

main()函数

  • 先配置UART
 

// 配置 UART 参数

Uart_Config UART1_Cfg;

UART1_Cfg.BaudDivider=(SYS_FREQ/UART_BAUD);

UART1_Cfg.IntEnable=True;

UART1_Cfg.Event_ParityCheckFail=False;

UART1_Cfg.Event_RxFifoHalfFull=False;

UART1_Cfg.Event_TxFifoHalfEmpty=False;

UART1_Cfg.Event_RxBufFull=True;

UART1_Cfg.Event_TxBufEmpty=False;

UART1_Cfg.RxFifoEnable=False;

UART1_Cfg.TxFifoEnable=True;

UART1_Cfg.Parity=NONE;

UART1_Cfg.Stop=ONE;

uart_applyConfig(UART,&UART1_Cfg);

这段代码是配置 UART 参数的过程,具体的配置包括:

  • BaudDivider:波特率分频器,根据系统时钟频率 SYS_FREQ 和波特率 UART_BAUD 计算得出。
  • IntEnable:使能 UART 中断。
  • Event_ParityCheckFail:奇偶校验失败事件的处理,设置为 False 表示不处理。
  • Event_RxFifoHalfFull:接收 FIFO 缓冲区半满事件的处理,设置为 False 表示不处理。
  • Event_TxFifoHalfEmpty:发送 FIFO 缓冲区半空事件的处理,设置为 False 表示不处理。
  • Event_RxBufFull:接收缓冲区满事件的处理,设置为 True 表示处理。
  • Event_TxBufEmpty:发送缓冲区空事件的处理,设置为 False 表示不处理。
  • RxFifoEnable:使能接收 FIFO 缓冲区,设置为 False 表示不使用 FIFO 缓冲区。
  • TxFifoEnable:使能发送 FIFO 缓冲区,设置为 True 表示使用 FIFO 缓冲区。
  • Parity:奇偶校验类型,设置为 NONE 表示不使用奇偶校验。
  • Stop:停止位数,设置为 ONE 表示一个停止位。

最后,通过 uart_applyConfig 函数将以上配置应用到 UART 上。

  • 配置完后打印系统信息
 

// 打印系统信息

anl_printf("---------------------------------------------------------------- \r\n");

anl_printf("- SoftCore Demo : RISCV(Freq 80MHz. 32kB RAM. Full Feature) \r\n");

anl_printf("- Hardware Platform : EG4S20NG88 PotatoPie V4.0 \r\n");

anl_printf("- TD Ver. : TD 5.6.4(97693) \r\n");

anl_printf("- OS+Build+Debug : Windows, OpenOCD + Riscv-none-embed. \r\n");

anl_printf("- Test Case : UART Interrupt Demo \r\n");

anl_printf(sys_banner);

anl_printf("---------------------------------------------------------------- \r\n");

这段代码使用 anl_printf 函数打印了一段系统信息。让我们来逐行解释:

  • anl_printf("---------------------------------------------------------------- \r\n");

    打印了一条分隔线,用于美观和区分信息的开头。

  • anl_printf("- SoftCore Demo : RISCV(Freq 80MHz. 32kB RAM. Full Feature) \r\n");

    打印了系统的软核演示信息,包括软核类型(RISCV)、频率(80MHz)、RAM 大小(32kB)和功能(全功能)。

  • anl_printf("- Hardware Platform : EG4S20NG88 PotatoPie V4.0 \r\n");

    打印了硬件平台信息,包括硬件平台型号(EG4S20NG88)和版本(PotatoPie V4.0)。

  • anl_printf("- TD Ver. : TD 5.6.4(97693) \r\n");

    打印了测试开发工具的版本信息,包括版本号(TD 5.6.4)和编译号(97693)。

  • anl_printf("- OS+Build+Debug : Windows, OpenOCD + Riscv-none-embed. \r\n");

    打印了操作系统、构建环境和调试工具的信息,包括操作系统类型(Windows)和使用的调试工具(OpenOCD + Riscv-none-embed)。

  • anl_printf("- Test Case : UART & GPIO Interrupt, SPI Master Demo \r\n");

    打印了测试用例的信息,包括测试的内容(UART & GPIO 中断、SPI 主控演示)。

  • anl_printf(sys_banner);

    打印了之前定义的 sys_banner 字符串,其中包含了编译时间和日期的信息。

  • anl_printf("---------------------------------------------------------------- \r\n");

    再次打印了一条分隔线,用于美观和区分信息的结尾。

 

SetSystickCfg((SYS_FREQ/TIM_TRIG_FREQ),True);

ClrSystickInt();

这两行代码用于配置和清除 SysTick 定时器的设置:

  1. SetSystickCfg((SYS_FREQ/TIM_TRIG_FREQ),True);

    • 这行代码调用了 SetSystickCfg 函数,用于设置 SysTick 定时器的配置。
    • 第一个参数 (SYS_FREQ/TIM_TRIG_FREQ) 表示每秒钟 SysTick 定时器的时钟周期数,它是系统频率 SYS_FREQ 除以定时器触发频率 TIM_TRIG_FREQ 的结果。
    • 第二个参数 True 表示启用 SysTick 定时器。
  2. ClrSystickInt();

    • 这行代码调用了 ClrSystickInt 函数,用于清除 SysTick 中断标志位。
    • 这样做是为了确保在进入主循环之前,任何可能触发的 SysTick 中断都被处理,以免影响程序的正常执行。
 

// 设置中断掩码

SetIntMask(UART1_INTSRC | GPIO_INTSRC);

uart_ClrEvent(UART,0xFF); //清除全部UART中断

ClrIntEvent(0xFFFFFFFF); // 清除所有中断

GPIO_A->OUTPUT_ENABLE=0x0000FFFF;

GPIO_A->GPIO_INTMASK=0xFFFFFFFF; // 允许所有 GPIO 发送中断

这段代码用于配置中断掩码和清除所有中断:

  1. SetIntMask(UART1_INTSRC | GPIO_INTSRC);

    • 这行代码调用了 SetIntMask 函数,用于设置中断掩码。通过将 UART1_INTSRC 和 GPIO_INTSRC 按位或运算,将 UART1 和 GPIO 的中断源加入到中断掩码中。
    • 这样做的目的是指定哪些中断将被允许触发。
  2. uart_ClrEvent(UART, 0xFF);

    • 这行代码调用了 uart_ClrEvent 函数,清除了 UART 的所有中断事件。
    • 第一个参数 UART 指定了要清除中断事件的 UART 模块。
    • 第二个参数 0xFF 表示清除所有类型的 UART 中断事件。
  3. ClrIntEvent(0xFFFFFFFF);

    • 这行代码调用了 ClrIntEvent 函数,清除了所有的中断事件。
    • 传递的参数 0xFFFFFFFF 表示清除所有中断事件。
  4. GPIO_A->OUTPUT_ENABLE = 0x0000FFFF;

    • 这行代码设置了 GPIO_A 模块的输出使能寄存器,使得 GPIO_A 的低 16 位引脚成为输出引脚。
  5. GPIO_A->GPIO_INTMASK = 0xFFFFFFFF;

    • 这行代码设置了 GPIO_A 模块的中断掩码寄存器,允许所有 GPIO_A 引脚产生中断。
 

while (1)

{

GPIO_A->OUTPUT=i;

i=i+1;

Delay(5000000);

anl_printf("Hello Main!\r\n");

}

这个 while 循环是程序的主循环,它会不断地执行以下操作:

  1. GPIO_A->OUTPUT=i;

    • 将变量 i 的值写入 GPIO_A 模块的输出寄存器中,控制 GPIO_A 的输出状态。每次循环迭代,i 的值会递增。
    • 这个操作会改变 GPIO_A 引脚的输出状态,具体的改变依赖于 i 的值。
  2. i=i+1;

    • 递增变量 i 的值,用于改变 GPIO_A 输出状态的控制值。
  3. Delay(5000000);

    • 调用 Delay 函数,使程序停顿一段时间。在这里,函数的参数 5000000 表示延时的周期数,具体延时时长由系统时钟频率决定。
  4. anl_printf("Hello Main!\r\n");

    • 打印字符串 “Hello Main!\r\n” 到串行终端,向用户输出一条消息。

这样,循环将一直重复执行上述步骤,不断改变 GPIO_A 的输出状态,延时一段时间,然后打印一条消息,形成一个周期性的操作。

其它函数

 

void Delay(int cycle)

{

int i;

for (i=0;i<cycle;i++)

asm volatile(

"add x0, x0, x0"

);

}

这个Delay函数是一个简单的延时循环,它通过重复执行一个无操作的操作add x0, x0, x0来等待指定数量的周期。asm volatile语句用于将汇编语言直接嵌入到C代码中,提供一种执行可能无法直接用C表达的机器指令的方法。

它的功能说明:

  • for循环执行cycle次。
  • 在循环内部,它执行一个汇编指令,将寄存器x0的内容加到自身,并将结果存回x0
  • 由于这是一个无操作指令(它将一个值加到自身,实际上什么都没做),它实际上是一个消耗CPU周期的循环,没有执行任何有意义的计算。

这个函数可用于在时间敏感的应用程序中创建延时,例如控制某些操作的时序。然而,需要注意的是,延迟的持续时间取决于各种因素,包括处理器速度和优化设置,因此它可能不太精确,也不适用于不同平台。

 

// 定时器中断服务函数

void TimerISP()

{

#ifdef USE_MTIME

uint64_t mtime_calc;

mtime_calc=GetMTimeCnt()+(SYS_FREQ/TIM_TRIG_FREQ);

SetMTimeCmp(mtime_calc);

#else

ClrSystickInt();

#endif

GPIO_A->OUTPUT = ~(GPIO_A->OUTPUT);

anl_printf("Hello Tick!\r\n");

return;

}

这是定时器中断服务函数 TimerISP。根据编译时是否定义了 USE_MTIME 宏,函数会有不同的行为:

  1. 如果定义了 USE_MTIME

    • 函数首先声明了一个 uint64_t 类型的变量 mtime_calc,用于计算下一次定时器中断的触发时间。
    • 调用 GetMTimeCnt() 函数获取当前的 MTIME 计数值,即当前时间。
    • 根据系统频率 SYS_FREQ 和定时器触发频率 TIM_TRIG_FREQ 计算下一次定时器中断触发的时间点,并将结果存储在 mtime_calc 中。
    • 调用 SetMTimeCmp 函数设置 MTIME 比较寄存器,使得下一次定时器中断在计算得到的时间点触发。
    • 最后,将 GPIO_A 的输出取反,即翻转输出状态,并打印 “Hello Tick!\r\n” 消息。
  2. 如果未定义 USE_MTIME

    • 则调用 ClrSystickInt() 函数清除 SysTick 定时器中断标志。
    • 接着,将 GPIO_A 的输出取反,即翻转输出状态,并打印 “Hello Tick!\r\n” 消息。

无论哪种情况,这个函数都用于定时器中断服务,每当定时器中断触发时,GPIO_A 的输出状态都会取反,并输出一条消息。

 

// UART1 中断服务函数

void UART1_ISP()

{

char recv_value;

while(uart_GetEvent(UART,UartRxVld))

{

uart_write(UART,uart_read(UART));

}

uart_ClrEvent(UART,UartRxBufFull | UartRxBufHfFull);

ClrIntEvent(UART1_INTSRC);

}

这是 UART1 的中断服务函数 UART1_ISP。当 UART1 接收到数据时,该函数会执行以下操作:

  1. 声明一个 char 类型的变量 recv_value,用于存储接收到的数据。

  2. 使用 while 循环结构,调用 uart_GetEvent 函数检查 UART 接收缓冲区是否有数据可用(即接收到有效数据)。如果接收到数据,则进入循环体。

  3. 在循环体内,调用 uart_read 函数读取 UART 接收缓冲区中的数据,并立即将其通过 uart_write 函数写回 UART 发送缓冲区。这实现了一种称为回显(echo)的功能,即将接收到的数据原样发送回去。

  4. 循环继续,直到 UART 接收缓冲区中没有数据可用。

  5. 调用 uart_ClrEvent 函数清除 UART 接收缓冲区满和半满的标志位,以及清除 UART1 中断标志位。

总的来说,该函数实现了 UART1 接收数据并回显的功能,同时清除相关的中断标志位。

 

void GPIO_ISP()

{

anl_printf("Hello Click!\r\n");

ClrIntEvent(GPIO_INTSRC);

}

这是 GPIO 的中断服务函数 GPIO_ISP。当 GPIO 触发中断时,该函数会执行以下操作:

  1. 使用 anl_printf 函数打印字符串 “Hello Click!\r\n”,提示发生了 GPIO 中断。

  2. 调用 ClrIntEvent 函数清除 GPIO 中断源(即 GPIO_INTSRC 对应的中断标志位),以确认已处理完中断事件。

 

void ExternalISP()

{

uint32_t temp;

temp=GetIntEvent();

if(temp&UART1_INTSRC)

UART1_ISP();

if(temp&GPIO_INTSRC)

GPIO_ISP();

else

{

anl_printf("UNKNOWN INT SRC! SRC= 0x%x",temp);

while(1);

}

}

这是外部中断服务函数 ExternalISP。当发生外部中断时,该函数会执行以下操作:

  1. 声明一个 uint32_t 类型的变量 temp,用于存储当前发生的中断事件。

  2. 调用 GetIntEvent 函数获取当前的中断事件。

  3. 使用条件语句检查中断事件的类型:

    • 如果 temp 中包含 UART1_INTSRC 标志位,则执行 UART1 的中断服务函数 UART1_ISP
    • 如果 temp 中包含 GPIO_INTSRC 标志位,则执行 GPIO 的中断服务函数 GPIO_ISP
    • 如果 temp 中不包含以上任何一种中断源的标志位,则打印消息 “UNKNOWN INT SRC! SRC= 0x%x”,其中 %x 是 temp 的十六进制表示,表示未知的中断来源,并进入无限循环。

工程源码在这个路径:

实验结果:

在 《PotatoPie 4.0 实验教程(40) —— FPGA实现RISC-V工程创建和调试》教程里我们知道如何创建,编译下载和调试RISCV工程,我们这里先只编译FD工程,而不用FD进行下载。

在TD中我们需要修改TD Soc_Top.v文件中的TCM0_INITFILE为,并重新编译TD工程。

parameter TCM0_INITFILE="../../../../../wkspace/hello_world/Debug/hello_world.bin.mif";

然后打开看串口助手之类的工具,设置串口波特率为115200,8N1模式。

最后后用TD工具的JTAG下载功能下载到FPGA之中,在串口工具中我们将看到如下输出:

同时可以看到板上蓝灯一秒一闪烁。

如果你的FPGA中已下载过之前的RISCV软核位流,那么可以也可以直接在FD中点击这个进行代码运行,而不用重新编译和下载FPGA程序。

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

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

相关文章

Apache Seata基于改良版雪花算法的分布式UUID生成器分析2

title: 关于新版雪花算法的答疑 author: selfishlover keywords: [Seata, snowflake, UUID, page split] date: 2021/06/21 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 关于新版雪花算法的答疑 在上一篇关于新版雪花算法的解析中…

Hive优化以及相关参数设置

1.表层面设计优化 1.1 表分区 分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹&#xff0c;该文件夹下是该分区所有的数据文件。Hive 中的分区就是分目录&#xff0c;把一个大的数据集根据业务需要分割成小的数据集。在查询时通过 WHERE 子句中的表达式选择查询所需要…

Apache Seata基于改良版雪花算法的分布式UUID生成器分析1

title: Seata基于改良版雪花算法的分布式UUID生成器分析 author: selfishlover keywords: [Seata, snowflake, UUID] date: 2021/05/08 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 Seata基于改良版雪花算法的分布式UUID生成器分析…

10.JAVAEE之网络编程

1.网络编程 通过网络,让两个主机之间能够进行通信 >基于这样的通信来完成一定的功能进行网络编程的时候,需要操作系统给咱们提供一组 AP1, 通过这些 API才能完成编程&#xff08;API 可以认为是 应用层 和 传输层 之间交互的路径&#xff09;&#xff08;API:Socket API相当…

NDK 基础(一)—— C 语言知识汇总

本系列文章主要是介绍一些 NDK 开发所需的基础知识&#xff0c;目录如下&#xff1a; NDK 基础&#xff08;一&#xff09;—— C 语言知识汇总 NDK 基础&#xff08;二&#xff09;—— C 语言基础与特性1 NDK 基础&#xff08;三&#xff09;—— C 语言基础与特性2 NDK 基础…

比较美观即将跳转html源码

源码介绍 比较美观即将跳转html源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 源码截图 比较美观的一个跳转界面&#xff0c;修改方法如上&…

FreeRTOS-系统时钟节拍和时间管理

一、前言 任何操作系统都需要提供一个时钟节拍&#xff0c;以供系统处理诸如延时&#xff0c;超时等与时间相关的事件。时钟节拍是特定的周期性中断&#xff0c; 这个中断可以看做是系统心跳。 中断之间的时间间隔取决于不同的应用&#xff0c;一般是 1ms – 100ms。时钟的节拍…

【C++ —— 多态】

C —— 多态 多态的概念多态的定义和实现多态的构成条件虚函数虚函数的重写虚函数重写的两个例外协变&#xff1a;析构函数的重写 C11 override和final重载、覆盖(重写)、隐藏(重定义)的对比 抽象类概念接口继承和实现继承 多态的继承虚函数表多态的原理动态绑定和静态绑定 单继…

BERT一个蛋白质-季军-英特尔创新大师杯冷冻电镜蛋白质结构建模大赛-paipai

关联比赛: “创新大师杯”冷冻电镜蛋白质结构建模大赛 解决方案 团队介绍 paipai队、取自 PAIN AI&#xff0c;核心成员如我本人IvanaXu(IvanaXu GitHub)&#xff0c;从事于金融科技业&#xff0c;面向银行信用贷款的风控、运营场景。但我们团队先后打过很多比赛&#xf…

算法系列--BFS解决拓扑排序

&#x1f495;"请努力活下去"&#x1f495; 作者&#xff1a;Lvzi 文章主要内容&#xff1a;算法系列–算法系列–BFS解决拓扑排序 大家好,今天为大家带来的是算法系列--BFS解决拓扑排序 前言:什么是拓扑排序 拓扑排序–解决有顺序的排序问题(要做事情的先后顺序) …

docker各目录含义

目录含义builder构建docker镜像的工具或过程buildkit用于构建和打包容器镜像&#xff0c;官方构建引擎&#xff0c;支持多阶段构建、缓存管理、并行化构建和多平台构建等功能containerd负责容器生命周期管理&#xff0c;能起、停、重启&#xff0c;确保容器运行。负责镜管理&am…

Java设计模式 _结构型模式_组合模式

一、组合模式 1、组合模式 组合模式&#xff08;Composite Pattern&#xff09;是这一种结构型设计模式。又叫部分整体模式。组合模式依据树形结构来组合对象&#xff0c;用来表示部分以及整体层次关系。即&#xff1a;创建了一个包含自己对象组的类&#xff0c;该类提供了修改…

Idea报错:无法访问org.springframework.boot.SpringApplication

在开发项目时&#xff0c;常常会遇到这种问题&#xff0c;报错信息如下图所示 版本号与jdk版本号存在对应关系&#xff0c;61.0对应jdk17&#xff0c;52.0对应jdk8 所以是某个依赖的版本太高&#xff0c;降低该依赖的版本即可 具体步骤&#xff1a; ①修改pom.xml中spring b…

ASP.NET实验室预约系统的设计

摘 要 实验室预约系统的设计主要是基于B/S模型&#xff0c;在Windows系统下&#xff0c;运用ASP.NET平台和SQLServer2000数据库实现实验室预约功能。该设计主要实现了实验室的预约和管理功能。预约功能包括老师对实验室信息、实验项目和实验预约情况的查询以及对实验室的预约…

ubuntu系统搭建pytorch环境详细步骤【笔记】

实践设备&#xff1a;华硕FX-PRO&#xff08;NVIDIA GeForce GTX 960M&#xff09; 搭建PyTorch环境的详细步骤如下&#xff1a; 1.安装Ubuntu系统&#xff1a; 下载Ubuntu的镜像文件并制作启动盘。将启动盘插入计算机&#xff0c;启动计算机并按照提示安装Ubuntu系统。 2.…

Linux内核之原子操作:atomic_long_dec用法实例(六十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

一起Talk Android吧(第五百五十八回:lombok用法)

文章目录 1. 概述2. 使用方法3. 内容总结 各位看官们大家好&#xff0c;上一回中介绍了如何获取文件读写权限的知识,本章回中将介绍lombok相关的知识。闲话休提&#xff0c;言归正转&#xff0c;让我们一起Talk Android吧&#xff01; 1. 概述 这是一个java库&#xff0c;用来…

ES全文检索支持拼音和繁简检索

ES全文检索支持拼音和繁简检索 1. 实现目标2. 引入pinyin插件2.1 编译 elasticsearch-analysis-pinyin 插件2.2 安装拼音插件 3. 引入ik分词器插件3.1 已有作者编译后的包文件3.2 只有源代码的版本3.3 安装ik分词插件 4. 建立es索引5.测试检索6. 繁简转换 1. 实现目标 ES检索时…

flutter开发实战-build apk名称及指令abiFilters常用gradle设置

flutter开发实战-build apk名称及指令abiFilters常用gradle设置 最近通过打包flutter build apk lib/main.dart --release&#xff0c;发现apk命名规则需要在build.gradle设置。这里记录一下。 一、apk命名规则 在android/app/build.gradle中需要设置 android.applicationVa…

Pandas入门篇(二)-------Dataframe篇4(进阶)(Dataframe的进阶用法)(机器学习前置技术栈)

目录 概述一、复合索引&#xff08;一&#xff09;创建具有复合索引的 DataFrame1. 使用 set_index 方法&#xff1a;2.在创建 DataFrame 时直接指定索引&#xff1a; &#xff08;二&#xff09;使用复合索引进行数据选择和切片&#xff08;三&#xff09;重置索引&#xff08…