【极光 Orbit·STC8AH】04. 深度探索 GPIO 底层逻辑

news2025/3/15 15:56:54

【极光 Orbit·STC8A&H】04. 深度探索 GPIO 底层逻辑

引言:当代码遇见硬件

上周我看着学生调试的工控产品,他们困惑地盯着自己编写的代码:“老师,这段C语言明明在PC上跑得没问题啊!” ,让我想起自己初学嵌入式时的窘迫——那时我曾用标准C的思维写代码,结果让价值数万的工业控制器冒起了青烟。

这个小插曲恰恰揭示了嵌入式开发的核心矛盾:纯软件思维与硬件物理特性的碰撞。学生们用熟悉的printf()调试习惯,将LED控制写成简单的led = 1;,却忽略了单片机GPIO需要先配置方向寄存器的底层逻辑。这种思维差异,正是本文要探讨的嵌入式编程特殊性。

故此,STC8A 这个专栏停更了一周,专门开设了【编程技巧】,写了一点嵌入式编程的感悟,全是学校里学不到的内容,希望大家喜欢。

纯C与嵌入式C的三大本质区别
  1. 硬件寄存器的直接操作
    纯C代码:int led = 1;(逻辑值)
    嵌入式C:P0 = 0xFF; P0M0 = 0xFF;(需同时配置数据寄存器和模式寄存器)
  2. 时序敏感性
    纯C:delay(1000);(依赖系统时钟)
    嵌入式C:for(volatile uint16_t i=0;i<12000;i++);(精确控制时序)
  3. 资源约束
    纯C:可自由使用动态内存、复杂数据结构
    嵌入式C:需手动管理有限的RAM(如STC8H仅8KB SRAM)

当用标准C的int led_array[8]记录LED状态时,程序在STC8A上频繁崩溃——因为数组占用了宝贵的硬件堆栈空间。这正是本文要深入剖析的GPIO底层逻辑:从寄存器直接操作的"硬件级编程",到官方库函数封装的"开发友好模式",再到结合两者优势的"优化位操作",开发者需要理解不同模式背后的硬件原理。

接下来我们将通过GPIO控制LED的典型案例,对比三种编程模式的实现差异,揭示嵌入式C语言如何通过代码与硬件的"对话",实现从算法到物理世界的精准控制。这个过程就像在数字电路与软件逻辑之间架设桥梁——而这座桥梁的建材,正是本文要展开的底层寄存器配置与优化技巧。

硬件连接

硬件电路图

  • LED连接方式
    将8只LED的阳极分别连接到单片机的GPIO引脚(如P0.0~P0.7),阴极通过限流电阻(如220Ω)接地。
    • 共阳极接法:GPIO输出低电平点亮LED。
    • 共阴极接法:GPIO输出高电平点亮LED。

单片机引脚分配

引脚名称功能说明
P0.0~P0.7GPIO输出控制8只LED的亮灭

编程模式详解

1. 寄存器直接操作模式

步骤说明
  1. 配置GPIO方向:将P0端口的所有引脚设置为推挽输出模式。
  2. 控制LED状态:通过写入P0寄存器的值直接控制LED的亮灭。
关键寄存器
  • P0M0和P0M1:控制P0端口每个引脚的模式。
    • P0M0 = 0xFFP0M1 = 0xFF:设置所有引脚为推挽输出模式。
  • P0:数据寄存器,直接控制引脚的输出电平。
代码示例
#include "stc8h.h"

void Delay(uint16_t ms) {
    while (ms--) {
        for (volatile uint16_t i = 0; i < 12000; i++);
    }
}

int main() {
    // 1. 配置P0端口为推挽输出模式
    P0M0 = 0xFF;  // 低四位控制P0.0~P0.3,高四位控制P0.4~P0.7
    P0M1 = 0xFF;  // 低四位控制P0.0~P0.3,高四位控制P0.4~P0.7

    while (1) {
        // 2. 全部点亮LED(假设共阴极)
        P0 = 0xFF;  // 输出高电平
        Delay(500);

        // 3. 熄灭所有LED
        P0 = 0x00;  // 输出低电平
        Delay(500);
    }
}
原理分析
  • 优势:直接操作硬件寄存器,执行效率最高,适合对性能要求高的场景。
  • 缺点:代码可读性低,需熟悉寄存器功能。

2. 官方库函数模式

GPIO.C

#### 步骤说明
1. **包含头文件**:引入STC标准库头文件。
2. **初始化GPIO**:通过结构体配置GPIO方向和初始值。
3. **控制LED**:使用库函数切换GPIO电平。
/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */
/*---------------------------------------------------------------------*/

/***************	功能说明	****************

本文件为STC8系列的端口初始化程序,用户几乎可以不修改这个程序.

******************************************/

#include	"GPIO.h"

//========================================================================
// 函数: u8	GPIO_Inilize(u8 GPIO, GPIO_InitTypeDef *GPIOx)
// 描述: 初始化IO口.
// 参数: GPIOx: 结构参数,请参考timer.h里的定义.
// 返回: 成功返回0, 空操作返回1,错误返回2.
// 版本: V1.0, 2012-10-22
//========================================================================
u8	GPIO_Inilize(u8 GPIO, GPIO_InitTypeDef *GPIOx)
{
	if(GPIO > GPIO_P7)				return 1;	//空操作
	if(GPIOx->Mode > GPIO_OUT_PP)	return 2;	//错误
	if(GPIO == GPIO_P0)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P0M1 &= ~GPIOx->Pin,	P0M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P0M1 |=  GPIOx->Pin,	P0M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P0M1 |=  GPIOx->Pin,	P0M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P0M1 &= ~GPIOx->Pin,	P0M0 |=  GPIOx->Pin;	 //推挽输出
	}
	if(GPIO == GPIO_P1)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P1M1 &= ~GPIOx->Pin,	P1M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P1M1 |=  GPIOx->Pin,	P1M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P1M1 |=  GPIOx->Pin,	P1M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P1M1 &= ~GPIOx->Pin,	P1M0 |=  GPIOx->Pin;	 //推挽输出
	}
	if(GPIO == GPIO_P2)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P2M1 &= ~GPIOx->Pin,	P2M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P2M1 |=  GPIOx->Pin,	P2M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P2M1 |=  GPIOx->Pin,	P2M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P2M1 &= ~GPIOx->Pin,	P2M0 |=  GPIOx->Pin;	 //推挽输出
	}
	if(GPIO == GPIO_P3)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P3M1 &= ~GPIOx->Pin,	P3M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P3M1 |=  GPIOx->Pin,	P3M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P3M1 |=  GPIOx->Pin,	P3M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P3M1 &= ~GPIOx->Pin,	P3M0 |=  GPIOx->Pin;	 //推挽输出
	}
	if(GPIO == GPIO_P4)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P4M1 &= ~GPIOx->Pin,	P4M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P4M1 |=  GPIOx->Pin,	P4M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P4M1 |=  GPIOx->Pin,	P4M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P4M1 &= ~GPIOx->Pin,	P4M0 |=  GPIOx->Pin;	 //推挽输出
	}
	if(GPIO == GPIO_P5)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P5M1 &= ~GPIOx->Pin,	P5M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P5M1 |=  GPIOx->Pin,	P5M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P5M1 |=  GPIOx->Pin,	P5M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P5M1 &= ~GPIOx->Pin,	P5M0 |=  GPIOx->Pin;	 //推挽输出
	}
	if(GPIO == GPIO_P6)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P6M1 &= ~GPIOx->Pin,	P6M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P6M1 |=  GPIOx->Pin,	P6M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P6M1 |=  GPIOx->Pin,	P6M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P6M1 &= ~GPIOx->Pin,	P6M0 |=  GPIOx->Pin;	 //推挽输出
	}
	if(GPIO == GPIO_P7)
	{
		if(GPIOx->Mode == GPIO_PullUp)		P7M1 &= ~GPIOx->Pin,	P7M0 &= ~GPIOx->Pin;	 //上拉准双向口
		if(GPIOx->Mode == GPIO_HighZ)		P7M1 |=  GPIOx->Pin,	P7M0 &= ~GPIOx->Pin;	 //浮空输入
		if(GPIOx->Mode == GPIO_OUT_OD)		P7M1 |=  GPIOx->Pin,	P7M0 |=  GPIOx->Pin;	 //开漏输出
		if(GPIOx->Mode == GPIO_OUT_PP)		P7M1 &= ~GPIOx->Pin,	P7M0 |=  GPIOx->Pin;	 //推挽输出
	}
	return 0;	//成功
}

GPIO.H

/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */
/*---------------------------------------------------------------------*/

#ifndef	__GPIO_H
#define	__GPIO_H

#include	"config.h"

#define	GPIO_PullUp		0	//上拉准双向口
#define	GPIO_HighZ		1	//浮空输入
#define	GPIO_OUT_OD		2	//开漏输出
#define	GPIO_OUT_PP		3	//推挽输出

#define	GPIO_Pin_0		0x01	//IO引脚 Px.0
#define	GPIO_Pin_1		0x02	//IO引脚 Px.1
#define	GPIO_Pin_2		0x04	//IO引脚 Px.2
#define	GPIO_Pin_3		0x08	//IO引脚 Px.3
#define	GPIO_Pin_4		0x10	//IO引脚 Px.4
#define	GPIO_Pin_5		0x20	//IO引脚 Px.5
#define	GPIO_Pin_6		0x40	//IO引脚 Px.6
#define	GPIO_Pin_7		0x80	//IO引脚 Px.7
#define	GPIO_Pin_All	0xFF	//IO所有引脚
	
#define	GPIO_P0			0		//
#define	GPIO_P1			1
#define	GPIO_P2			2
#define	GPIO_P3			3
#define	GPIO_P4			4
#define	GPIO_P5			5
#define	GPIO_P6			6
#define	GPIO_P7			7


typedef struct
{
	u8	Mode;		//IO模式,  		GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
	u8	Pin;		//要设置的端口	
} GPIO_InitTypeDef;

u8	GPIO_Inilize(u8 GPIO, GPIO_InitTypeDef *GPIOx);

#endif
关键库函数
  • GPIO_Inilize(u8 GPIO, GPIO_InitTypeDef *GPIOx):初始化GPIO引脚方向和模式。
代码示例
#include "stc8h.h"

void Delay(uint16_t ms) {
    while (ms--) {
        for (volatile uint16_t i = 0; i < 12000; i++);
    }
}

void	GPIO_config(void)
{
	GPIO_InitTypeDef	GPIO_InitStructure;				//结构定义
	GPIO_InitStructure.Pin  = GPIO_Pin_All;				//指定要初始化的IO,
	GPIO_InitStructure.Mode = GPIO_PullUp;				//指定IO的输入或输出方式,
    GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
	GPIO_Inilize(GPIO_P0,&GPIO_InitStructure);			//初始化
}

int main() {
    // 1. 配置P0端口为推挽输出模式
    GPIO_config(); 

    while (1) {
        // 2. 全部点亮LED(假设共阴极)
        P0 = 0xFF;  // 输出高电平
        Delay(500);

        // 3. 全部熄灭LED
        P0 = 0;      // 输出低电平
        Delay(500);
    }
}
原理分析
  • 优势:代码简洁易读,封装了寄存器操作细节。
  • 缺点:函数调用开销较大,执行速度略低于直接寄存器操作。

3. 优化库函数模式(位操作)

步骤说明
  1. 配置GPIO模式:通过寄存器设置为推挽输出。
  2. 位操作:利用STC的位(Bit-Band)功能快速操作单个引脚。
优化技巧:
(1)使用宏定义GPIO端口和引脚
/* GPIO组号,是GPIO宏操作函数的第一个参数,支持对这个宏进行再封装 */
#define	GPIO_P0  0 /*!< IO P0. */
#define	GPIO_P1  1 /*!< IO P1. */
#define	GPIO_P2  2 /*!< IO P2. */
#define	GPIO_P3  3 /*!< IO P3. */
#define	GPIO_P4  4 /*!< IO P4. */
#define	GPIO_P5  5 /*!< IO P5. */
#define	GPIO_P6  6 /*!< IO P6. */
#define	GPIO_P7  7 /*!< IO P7. */

/* GPIO端口号,是GPIO宏操作函数的第二个参数,支持多个宏进行或运算,同时配置多个IO */
#define	Pin_0    0x01  /*!< IO Pin Px.0 . */
#define	Pin_1    0x02  /*!< IO Pin Px.1 . */
#define	Pin_2    0x04  /*!< IO Pin Px.2 . */
#define	Pin_3    0x08  /*!< IO Pin Px.3 . */
#define	Pin_4    0x10  /*!< IO Pin Px.4 . */
#define	Pin_5    0x20  /*!< IO Pin Px.5 . */
#define	Pin_6    0x40  /*!< IO Pin Px.6 . */
#define	Pin_7    0x80  /*!< IO Pin Px.7 . */
#define	Pin_Low  0x0F  /*!< IO Pin Px.0~3 . */
#define	Pin_High 0xF0  /*!< IO Pin Px.4~7 . */
#define	Pin_All  0xFF  /*!< IO Pin All . */
(2)用枚举定义输入输出模式和IO端口电平
typedef enum
{
    GPIO_MODE_WEAK_PULL 	= 0x00,
    GPIO_MODE_IN_FLOATING = 0x01,
    GPIO_MODE_OUT_OD 			= 0x10,
    GPIO_MODE_OUT_PP 			= 0x11,
} eGPIO_Mode;

/* GPIO Bit SET和Bit RESET枚举 */
typedef enum
{
    GPIO_PIN_RESET = 0,
    GPIO_PIN_SET = 1
} eGPIO_PinState;
(3)使用 ## 字符连接宏定义
/* ## 字符连接宏定义 A(x) (T_##X) == A(1) --> T_1 	*/
#define GPIO_Px(x)  (P##x)		// GPIO_Px(1) --> P1
#define Px_M1(x) 	(P##x##M1)  // Px_M1(0) --> P0M1	//GPIO_P0M1 GPIO_P0M0
#define Px_M0(x) 	(P##x##M0)  // P0M1 P0M0
(4)写模式配置宏函数
/* GPIO设置为准双向口(弱上拉)模式宏函数。*/
#define GPIO_MODE_WEAK_PULL(gpio_x,pin)   	\
    do{Px_M1(gpio_x) &= ~(pin); Px_M0(gpio_x) &= ~(pin);}while(0)

/* GPIO设置为浮空输入模式宏函数。*/
#define GPIO_MODE_IN_FLOATING(gpio_x,pin) 	\
    do{ Px_M1(gpio_x) |=  (pin); Px_M0(gpio_x) &= ~(pin);}while(0)

/* GPIO设置为开漏输出模式宏函数。*/
#define GPIO_MODE_OUT_OD(gpio_x,pin) 		\
    do{Px_M1(gpio_x) |=  (pin); Px_M0(gpio_x) |=  (pin);}while(0)

/* GPIO设置为推挽输出模式宏函数。*/
#define	GPIO_MODE_OUT_PP(gpio_x,pin) 		\
    do{Px_M1(gpio_x) &= ~(pin); Px_M0(gpio_x) |=  (pin);}while(0)
(5)使用 if 优化模式配置宏函数
#define GPIO_Init(gpio_x, pin, mode)					\
    do{ if(mode & 0x01)	Px_M0(gpio_x) |= (pin);			\
        else	Px_M0(gpio_x) &= ~(pin);				\
        if((mode & 0x02))	Px_M1(gpio_x) |= (pin);		\
        else	Px_M1(gpio_x) &= ~(pin);				\
    }while(0)
(6)使用三目运算符优化模式配置宏函数
#define GPIO_MODE_CFG(gpio_x, pin, mode)							  					  		\	
			do{ Px_M0(gpio_x) = ((mode & 0x01)? Px_M0(gpio_x)|(pin) : Px_M0(gpio_x)&(~pin));	\
				Px_M1(gpio_x) = ((mode & 0x02)? Px_M1(gpio_x)|(pin) : Px_M1(gpio_x)&(~pin));  	\	
			}while(0)
						

看到这里,是不是有一种代码好美的感觉。


三种模式对比

模式代码复杂度执行效率可读性适用场景
寄存器直接操作最高需极致性能的实时控制
标准库函数快速开发与调试
优化库函数高效且可读的代码

总结

通过三种编程模式的对比与示例,开发者可根据项目需求灵活选择实现方式:

  • 寄存器直接操作:适合对性能要求极高的场景(如实时控制)。
  • 官方库函数:适合快速开发与调试,代码可读性高。
  • 优化库函数:在保证高效性的同时,提供对单个引脚的精准控制。

通过合理选择模式,可兼顾开发效率与硬件性能,满足不同场景需求。顾性能与开发效率。

终极奥义
“通过重构库函数,深入单片机寄存器操作,悟出最佳逻辑,掌控单片机!”

希望本教程对您有所帮助,祝您在嵌入式开发的道路上取得更大的成功!

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

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

相关文章

67.Harmonyos NEXT 图片预览组件之性能优化策略

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; Harmonyos NEXT 图片预览组件之性能优化策略 文章目录 Harmonyos NEXT 图片预览组件之性能优化策略效果预览一、性能优化概述1. 性能优化的关键指标…

Windows下安装Git客户端

① 官网地址&#xff1a;https://git-scm.com/。 ② Git的优势 大部分操作在本地完成&#xff0c;不需要联网&#xff1b;完整性保证&#xff1b;尽可能添加数据而不是删除或修改数据&#xff1b;分支操作非常快捷流畅&#xff1b;与Linux 命令全面兼容。 ③ Git的安装 从官网…

SAP IBP for Supply Chain Certification Guide (Parag Bakde, Rishabh Gupta)

SAP IBP for Supply Chain Certification Guide (Parag Bakde, Rishabh Gupta)

如何处理PHP中的日期和时间问题

如何处理PHP中的日期和时间问题 在PHP开发中&#xff0c;日期和时间的处理是一个常见且重要的任务。无论是记录用户操作时间、生成时间戳&#xff0c;还是进行日期计算&#xff0c;PHP提供了丰富的函数和类来帮助开发者高效处理这些需求。本文将详细介绍如何在PHP中处理日期和…

TDengine 使用最佳实践

简介 阅读本文档需要具备的基础知识&#xff1a; Linux系统的基础知识&#xff0c;及基本命令网络基础知识&#xff1a;TCP/UDP、http、RESTful、域名解析、FQDN/hostname、hosts、防火墙、四层/七层负载均衡 本文档的阅读对象有&#xff1a;架构师、研发工程师&#xff0c;…

Spring、Spring Boot、Spring Cloud 的区别与联系

1. Spring 框架 定位&#xff1a;轻量级的企业级应用开发框架&#xff0c;核心是 IoC&#xff08;控制反转&#xff09; 和 AOP&#xff08;面向切面编程&#xff09;。 核心功能&#xff1a; 依赖注入&#xff08;DI&#xff09;&#xff1a;通过 Autowired、Component 等注解…

AutoGen-构建问答智能体

概述 如https://github.com/microsoft/autogen所述&#xff0c;autogen是一多智能体的框架&#xff0c;属于微软旗下的产品。 依靠AutoGen我们可以快速构建出一个多智能体应用&#xff0c;以满足我们各种业务场景。 环境说明 python&#xff0c;3.10AutoGen&#xff0c;0.4.2…

C语言实现括号匹配检查及栈的应用详解

目录 栈数据结构简介 C语言实现栈 栈的初始化 栈的销毁 栈的插入 栈的删除 栈的判空 获取栈顶数据 利用栈实现括号匹配检查 总结 在编程中&#xff0c;经常会遇到需要检查括号是否匹配的问题&#xff0c;比如在编译器中检查代码的语法正确性&#xff0c;或者在…

阿里云魔笔低代码应用开发平台快速搭建教程

AI低代码&#xff0c;大模型时代应用开发新范式 什么是魔笔 介绍什么是魔笔低代码应用开发平台。 魔笔是一款面向全端&#xff08;Web、H5、全平台小程序、App&#xff09;场景的模型驱动低代码开发平台&#xff0c;提供一站式的应用全生命周期管理&#xff0c;包括可视化开发…

A Survey on Mixture of Experts 混合专家模型综述(第二部分:混合专家系统设计)

A Survey on Mixture of Experts 混合专家模型综述 (第一部分&#xff1a;混合专家算法设计) A Survey on Mixture of Experts arxiv github&#xff1a;A-Survey-on-Mixture-of-Experts-in-LLMs ​ ​ ​ 5 System Design of Mixture of Experts While ​Mixture of Exper…

docker python:latest镜像 允许ssh远程

跳转到家目录 cd创建pythonsshdockerfile mkdir pythonsshdockerfile跳转pythonsshdockerfile cd pythonsshdockerfile创建Dockerfile文件 vim Dockerfile将Dockerfile的指令复制到文件中 # 使用 python:latest 作为基础镜像 # 如果我的镜像列表中没有python:latest镜像&…

Aim Robotics电动胶枪:机器人涂胶点胶的高效解决方案

在自动化和智能制造领域&#xff0c;机器人技术的应用越来越广泛&#xff0c;而涂胶和点胶作为生产过程中的重要环节&#xff0c;也逐渐实现了自动化和智能化。Aim Robotics作为一家专注于机器人技术的公司&#xff0c;其推出的电动胶枪为这一领域带来了高效、灵活且易于操作的…

【HDLbits--分支预测器简单实现】

HDLbits--分支预测器简单实现 1 timer2.branche predicitors3.Branch history shift4.Branch direction predictor 以下是分支预测器的简单其实现&#xff1b; 1 timer 实现一个计时器&#xff0c;当load1’b1时&#xff0c;加载data进去&#xff0c;当load1’b0时进行倒计时&…

Linux--操作系统/进程

ok&#xff0c;我们今天学习linux中的操作系统和进程 1. 冯诺依曼体系 我们常⻅的计算机&#xff0c;如笔记本。我们不常⻅的计算机&#xff0c;如服务器&#xff0c;⼤部分都遵守冯诺依曼体系。 内存是CPU和外设之间的一个巨大的缓存&#xff01; 截⾄⽬前&#xff0c;我们…

Java面试八股—Redis篇

一、Redis的使用场景 &#xff08;一&#xff09;缓存 1.Redis使用场景缓存 场景&#xff1a;缓存热点数据&#xff08;如用户信息、商品详情&#xff09;&#xff0c;减少数据库访问压力&#xff0c;提升响应速度。 2.缓存穿透 正常的访问是&#xff1a;根据ID查询文章&…

Web后端开发之Maven

Maven Mven是apache旗下的一个开源项目&#xff0c;用来管理和构建java项目的工具。 通过一小段描述信息来管理项目。 Maven的作用 1.依赖管理&#xff1a;方便快捷的管理项目依赖的资源&#xff08;jar包&#xff09;&#xff0c;避免版本冲突问题 以前用某个jar包需要下载…

there are no enabled repos

我做了两个操作 第一个操作&#xff1a; 1.先在本地电脑&#xff0c;也就是在我们电脑的桌面上下载 https://repo.huaweicloud.com/repository/conf/CentOS-7-reg.repo 2.在CentOS 创建etc文件夹 3在etc文件夹内创建yum.repos.d文件夹 4.将下载好的repo 黏贴到yum.repos.d…

OpenEuler-22.03-LTS上利用Ansible轻松部署MySQL 5.7

一、需求 使用ansible自动化部署mysql二进制部署mysql部署mysql并创建JDBC用户 二、环境信息 本文涉及的代码&#xff0c;配置文件地址&#xff1a; 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;1g6y 软件名称版本备注Ansible2.9.27All modules — Ansible Doc…

前端无限滚动内容自动回收技术详解:原理、实现与优化

文章目录 一、核心需求与技术挑战1.1 无限滚动的问题症结1.2 自动回收的三大目标 二、技术实现原理2.1 虚拟滚动核心机制2.2 关键技术指标 三、完整实现方案3.1 基础HTML结构3.2 CSS关键样式3.3 JavaScript核心逻辑3.3.1 滚动控制器3.3.2 动态尺寸处理 四、性能优化策略4.1 内存…

如何在Ubuntu上构建编译LLVM和ISPC,以及Ubuntu上ISPC的使用方法

之前一直在 Mac 上使用 ISPC&#xff0c;奈何核心/线程太少了。最近想在 Ubuntu 上搞搞&#xff0c;但是 snap 安装的 ISPC不知道为什么只能单核&#xff0c;很奇怪&#xff0c;就想着编译一下&#xff0c;需要 Clang 和 LLVM。但是 Ubuntu 很搞&#xff0c;他的很多软件版本是…