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


【极光 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.7P0M1 = 0xFF;  // 低四位控制P0.0~P0.3,高四位控制P0.4~P0.7while (1) {// 2. 全部点亮LED(假设共阴极)P0 = 0xFF;  // 输出高电平Delay(500);// 3. 熄灭所有LEDP0 = 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			7typedef struct
{u8	Mode;		//IO模式,  		GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPu8	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_PPGPIO_Inilize(GPIO_P0,&GPIO_InitStructure);			//初始化
}int main() {// 1. 配置P0端口为推挽输出模式GPIO_config(); while (1) {// 2. 全部点亮LED(假设共阴极)P0 = 0xFF;  // 输出高电平Delay(500);// 3. 全部熄灭LEDP0 = 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.rhkb.cn/news/35987.html

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

相关文章

【算法】力扣 713题:乘积小于 K 的子数组之深入思考

文章目录 前言题目&#xff1a;乘积小于 K 的子数组参考思路方法一&#xff1a;滑动窗口方法二&#xff1a;二分查找 参考题解方法一&#xff1a;滑动窗口解法方法二&#xff1a;二分查找解法 深入思考浮点精度&#xff1f;right - left 1&#xff1f;二分法&#xff1f;哈希优…

超声重建,3D重建 超声三维重建,三维可视化平台 UR 3D Reconstruction

1. 超声波3D重建技术的实现方法与算法 技术概述 3D超声重建是一种基于2D超声图像生成3D体积数据的技术&#xff0c;广泛应用于医学影像领域。通过重建和可视化三维结构&#xff0c;3D超声能够显著提高诊断精度和效率&#xff0c;同时减少医生的脑力负担。本技术文档将详细阐述…

Docker 部署 Graylog 日志管理系统

Docker 部署 Graylog 日志管理系统 前言一、准备工作二、Docker Compose 配置三、启动 Graylog 服务四、访问 Graylog Web 界面总结 前言 Graylog 是一个开源的日志管理平台&#xff0c;专为实时日志收集、分析和可视化设计。它支持强大的搜索功能&#xff0c;并且与 Elastics…

【图论】并查集的学习和使用

目录 并查集是什么&#xff1f; 举个例子 组成 父亲数组&#xff1a; find函数&#xff1a; union函数&#xff1a; 代码实现&#xff1a; fa[] 初始化code: find code&#xff1a; 递归实现: 非递归实现: union code : 画图模拟&#xff1a; 路径压缩&#xff1a…

FPGA-流水灯

Quartus中使用Verilog实现 根据之前所学内容&#xff0c;打开Quartus 软件&#xff0c;新建FPGA项目文件&#xff0c;建立好空项目过后&#xff0c;选择Verilog HDL File&#xff0c;因为我们要使用Verilog代码实现仿真。 详细操作可参考往期博客&#xff1a; FPGA 实验报告&a…

React19源码系列之createRoot的执行流程是怎么的?

2024年12月5日&#xff0c;react发布了react19版本。后面一段时间都将学习它的源码&#xff0c;并着手记录。 react官网&#xff1a;react19新特性 https://react.dev/blog/2024/12/05/react-19 在用vite创建react项目的使用&#xff0c;main.tsx主文件都会有以下代码。 //i…

全网首创/纯Qt/C++实现国标GB28181服务/实时视频/云台控制/预置位/录像回放和下载/事件订阅/语音对讲

一、前言说明 用纯Qt来实现这个GB28181的想法很久了&#xff0c;具体可以追溯到2014年&#xff0c;一晃十年都过去了&#xff0c;总算是整体的框架和逻辑都打通了&#xff0c;总归还是杂七杂八的事情多&#xff0c;无法静下心来研究具体的协议&#xff0c;最开始初步了解协议后…

Qt 实操记录:打造自己的“ QQ 音乐播放器”

目录 一.界面设计1.成品界面分析2.head界面实现3.body界面实现4.主界面设置(1).设置无标题栏与阴影效果(2).重写鼠标事件实现拖拽 二.自定义控件1.BtFrom界面设计2.推荐页面设计3.recBox页面设计4.recBoxItem页面设计(1).eventFilter介绍和使用(2).QJsonObject介绍和使用(3).向…

如何打造安全稳定的亚马逊采购测评自养号下单系统?

在当今的电商领域&#xff0c;亚马逊作为全球领先的在线购物平台&#xff0c;其商品种类繁多&#xff0c;用户基数庞大&#xff0c;成为了众多商家和消费者的首选。而对于一些需要进行商品测评或市场调研的用户来说&#xff0c;拥有一个稳定、安全的亚马逊账号体系显得尤为重要…

Python文字识别OCR

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…

如何在 Github 上获得 1000 star?

作为程序员&#xff0c;Github 是第一个绕不开的网站。我们每天都在上面享受着开源带来的便利&#xff0c;我相信很多同学也想自己做一个开源项目&#xff0c;从而获得大家的关注。然而&#xff0c;理想很丰满&#xff0c;现实却是开发了很久的项目仍然无人问津。 最近&#x…

汽车机械钥匙升级一键启动的优点

汽车机械钥匙升级一键启动的优点主要包括&#xff1a; 便捷性&#xff1a;一键启动功能的引入极大地提升了用车便捷性。车主无需翻找钥匙&#xff0c;只需在车辆感应范围内轻触启动键&#xff0c;即可轻松发动汽车。 安全性&#xff1a;移动管家专车专用一键启动系统配备了防…

[QT]深入理解Qt中的信号与槽机制

文章目录 信号与槽1. 信号和槽概述信号的本质槽的本质说明 2. 信号和槽的使用2.1 连接信号和槽2.2 查看内置信号和槽2.3 通过 Qt Creator 生成信号槽代码 3. 自定义信号和槽3.1 基本语法3.2 带参数的信号和槽**示例1&#xff1a;重载信号槽****示例2&#xff1a;信号槽参数列表…

Axure设计之下拉多选框制作教程C(中继器)

利用Axure制作下拉多选器组件可以极大地提升原型制作的效率和效果。以下是基于你提供的详细步骤的详细指导&#xff0c;帮助你在Axure中实现一个功能完善、高保真且可复用的下拉多选器组件。 一、案例预览 预览地址&#xff1a;https://pghy0i.axshare.com 实现效果包括&#…

STC89C52单片机学习——第25节: [11-1]蜂鸣器

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.03.18 51单片机学习——第25节: [11-1]蜂鸣器 前言开发板说明引用解答和科普一、蜂鸣器…

Linux上的`i2c-tools`工具集的详细介绍;并利用它操作IMX6ULL的I2C控制器进而控制芯片AP3216C读取光照值和距离值

IC-Tools 工具集介绍 i2c-tools 是 Linux 下用于 IC 设备调试 的用户空间工具集(你也可以把它看成是一个库&#xff0c;类似于之前自己用过的触摸屏库tslib库、FreeType矢量字符库)&#xff0c;它提供了一系列命令行工具&#xff0c;可以扫描、读取、写入 IC 设备&#xff0c;…

《CircleCI:CircleCI:解锁软件开发持续集成(CI)和持续部署(CD)高效密码》:此文为AI自动生成

《CircleCI&#xff1a;CircleCI&#xff1a;解锁软件开发持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;高效密码》&#xff1a;此文为AI自动生成 一、CircleCI 初印象 在当今软件开发的快节奏赛道上&#xff0c;持续集成&#xff08;CI&#xff0…

LinuX---Shell脚本创建和执行

概述&#xff1a; 它是一个命令行解释器&#xff0c;接收应用程序/用户命令&#xff0c;然后调用操作系统内核。 Shell还是一个功能强大的编程语言&#xff0c;易编写、易调试、灵活性强。 Linux提供的Shell解析器有 atguiguubuntu:~$ cat /etc/shells # /etc/shells: valid …

再学:Solidity数据类型

目录 1.uint&#xff1a;无符号整型 2.引用类型 3.数组 4.注意gas的消耗 ​编辑 5.映射 1.uint&#xff1a;无符号整型 注意能容纳的最大值和最小值 2.引用类型 值类型赋值 相当于 拷贝 若拷贝开销过大&#xff0c;可以考虑引用类型。 memory&#xff1a;只存在于函数内部…

Docker Desktop配置国内镜像源教程

在使用 Docker 时&#xff0c;由于默认镜像源在国外&#xff0c;经常会遇到下载速度慢、连接超时等问题。本文将详细介绍如何在 Windows 系统中为 Docker 配置国内镜像源&#xff0c;以提升镜像拉取速度。 常用国内镜像源 https://docker.1ms.run清华镜像源 https://docker.m…