当前位置: 首页 > news >正文

解锁STM32外设:开启嵌入式开发新世界

✨✨✨这里是小韩学长yyds的BLOG(喜欢作者的点个关注吧)

✨✨✨想要了解更多内容可以访问我的主页 小韩学长yyds-CSDN博客

目录

探索 STM32 强大的外设家族

初窥门径:STM32 外设开发基础

开发方式与工具

外设配置基础步骤

深入剖析:常见外设应用实例

GPIO:最基础的数字接口

定时器:精准时间掌控者

串口通信:数据传输的桥梁

ADC:模拟世界的数字化窗口

进阶之路:外设驱动开发与优化

驱动开发步骤

优化策略

实战演练:综合项目开发

项目背景与需求分析

硬件设计与选型

软件实现与调试


探索 STM32 强大的外设家族

在嵌入式系统的广阔天地中,STM32 系列微控制器凭借其卓越的性能和丰富的外设资源,占据着举足轻重的地位。意法半导体(STMicroelectronics)精心打造的 STM32,基于 ARM Cortex-M 内核,犹如一把万能钥匙,能开启从基础日常应用到复杂嵌入式系统开发的大门。

STM32 拥有种类繁多的外设,宛如一个庞大而有序的家族,每个成员都各司其职,在不同的应用场景中发挥着关键作用。GPIO(通用输入输出口)作为其中最基础且常用的外设,如同微控制器与外部世界沟通的桥梁。它可配置为 8 种输入输出模式 ,通过简单的高低电平变化,就能轻松实现对 LED 灯的控制。比如在智能照明系统中,通过控制 GPIO 口的电平,就能让 LED 灯按照预设的模式亮起、熄灭或闪烁,为用户营造出温馨舒适的灯光环境;在按键检测方面,GPIO 口能敏锐地捕捉到按键按下或松开时产生的电平变化,将用户的操作指令准确无误地传递给微控制器,进而实现各种功能的切换。

定时器则像是一位精准的时间管家,在许多场景中都不可或缺。在工业自动化领域,电机的转速控制至关重要,定时器可以通过精确的计时,为电机提供稳定的 PWM(脉冲宽度调制)信号,从而实现对电机转速的精准调控,确保生产过程的高效与稳定;在智能家居系统中,定时开关电器的功能为用户带来了极大的便利,定时器能够按照用户设定的时间,准时开启或关闭电器设备,实现智能化的家居控制。

串口通信,作为一种经典的通信方式,在 STM32 的外设家族中也有着重要的地位。它就像一条无形的纽带,将 STM32 与各种外部设备紧密相连。在嵌入式系统中,常常需要与显示屏进行数据交互,串口通信能够将微控制器中的数据准确地传输到显示屏上,实现信息的直观展示;与传感器的通信也是串口的重要应用场景之一,传感器采集到的数据通过串口源源不断地传输到 STM32 中,经过微控制器的分析和处理,为系统的决策提供依据。

初窥门径:STM32 外设开发基础

开发方式与工具

在 STM32 外设开发的领域中,开发者宛如置身于一个充满选择的宝库,拥有多种趁手的开发方式与工具,它们各自闪耀着独特的光芒,为不同需求的开发者提供了多样化的选择。

标准外设库是意法半导体为 STM32 系列微控制器精心打造的官方开发库,犹如一座连接开发者与底层硬件的坚实桥梁。它涵盖了丰富的 API 和示例代码,全方位覆盖了 STM32 微控制器的各种外设,从基础的 GPIO 到复杂的定时器,再到 CAN、I2C、SPI、UART 和 ADC 等,一应俱全。以 GPIO 操作为例,在使用标准外设库时,开发者只需通过简单的函数调用,如GPIO_Init()函数,就可以轻松配置 GPIO 的工作模式、速度和上下拉电阻等参数 ,无需深入了解底层寄存器的复杂操作。这种方式极大地提高了开发效率,让开发者能够将更多的精力集中在应用层的逻辑设计上。而且,标准外设库的 API 设计巧妙地遵循了面向对象的编程思想,使得代码结构清晰、易于理解和维护。例如,在对定时器进行配置时,开发者可以通过一系列相关的函数和结构体,清晰地设置定时器的时钟源、分频系数、计数模式等关键参数,从而实现精确的定时控制。

HAL 库,即 Hardware Abstraction Layer(硬件抽象层),则是 ST 公司主推的一款更高级的开发库,它像是一位贴心的助手,将底层硬件操作巧妙地封装起来,以高级函数调用的形式呈现给开发者。这使得开发过程变得异常简单,即使是对硬件底层知识了解有限的开发者,也能快速上手。以串口通信为例,在 HAL 库中,初始化串口只需定义一个UART_HandleTypeDef类型的句柄,然后调用HAL_UART_Init()函数进行初始化配置即可 。在数据收发时,使用HAL_UART_Transmit()和HAL_UART_Receive()函数就能轻松实现数据的发送和接收,大大简化了开发流程。而且,HAL 库具有出色的跨平台支持能力,它允许开发者在不同型号的 STM32 微控制器上使用相同的 API 进行开发,这不仅提高了代码的可移植性和复用性,还能有效减少重复开发工作,为开发者节省大量的时间和精力。

STM32CubeMX 工具则是一款极具创新性的图形化配置工具,它为 STM32 外设开发带来了前所未有的便捷体验,仿佛是为开发者打开了一扇通往高效开发的魔法之门。通过直观的图形界面,开发者可以像搭建积木一样,轻松地配置 STM32 微控制器的引脚、时钟树、电源设置以及各种外设。在配置 GPIO 时,只需在图形界面中点击相应的引脚,即可选择其工作模式、输出类型和上下拉电阻等参数 ,操作简单直观,无需手动查阅复杂的数据手册。更令人惊喜的是,STM32CubeMX 能够根据用户的配置,自动生成高度优化的初始化 C 代码,并且这些代码能够完美兼容 IAR、Keil 以及 STM32CubeIDE 等主流编译环境,极大地加速了软件开发的前期准备阶段,让开发者能够更快地将精力投入到核心功能的开发中。

外设配置基础步骤

在 STM32 的世界里,要让各个外设正常工作,就需要按照一定的步骤进行精心配置,这就如同搭建一座高楼,每一步都至关重要。

使能外设时钟是开启外设工作的第一步,就像为机器注入动力。在 STM32 中,每个外设都有独立的时钟控制,这样的设计可以有效降低系统功耗,当某个外设暂时不需要使用时,关闭其时钟即可。以 GPIO 外设为例,假设要使用 GPIOA 端口,就需要通过 RCC(复位和时钟控制)寄存器来使能 GPIOA 的时钟。在标准外设库中,可以使用RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);函数来实现;在 HAL 库中,则可以使用__HAL_RCC_GPIOA_CLK_ENABLE();宏定义来完成这一操作 。这一步骤的原理是,时钟信号就如同外设运行的脉搏,只有在时钟信号的驱动下,外设内部的寄存器才能正常工作,从而实现各种功能。

配置引脚功能是外设配置的关键环节,它决定了引脚的用途。STM32 的引脚具有丰富的复用功能,一个引脚可以作为普通 GPIO 使用,也可以复用为其他外设的功能引脚,如串口、SPI、定时器等。在配置引脚功能时,需要根据具体的应用需求,通过复用器来配置引脚。比如,要将 PA0 引脚配置为串口通信的 TX 引脚,在标准外设库中,需要先配置 GPIO 的模式为复用推挽输出,然后设置复用功能寄存器,使 PA0 引脚复用为串口功能;在 HAL 库中,可以通过GPIO_InitTypeDef结构体来配置引脚的模式、速度和复用功能等参数,然后调用HAL_GPIO_Init()函数进行初始化 。这一过程就像是为引脚选择了一条特定的工作路径,使其能够准确地实现相应的功能。

配置外设控制寄存器是实现外设功能的核心步骤,它就像是为外设设定工作规则。不同的外设具有不同的控制寄存器,这些寄存器用于设置外设的各种工作参数。以定时器为例,需要配置定时器的预分频器、自动重装载寄存器、计数模式等参数。在标准外设库中,通过TIM_TimeBaseInit()函数来配置定时器的基本参数;在 HAL 库中,则使用HAL_TIM_Base_Init()函数来完成这一操作 。通过合理配置这些寄存器,定时器就能够按照设定的时间间隔产生中断或输出 PWM 信号,实现精确的时间控制和信号生成。

深入剖析:常见外设应用实例

GPIO:最基础的数字接口

GPIO 作为 STM32 最基础的外设,其应用极为广泛。以控制 LED 灯为例,这是学习 GPIO 的入门级应用。在硬件连接上,将 LED 的阴极接地,阳极通过限流电阻连接到 STM32 的 GPIO 引脚 。在软件配置方面,使用 HAL 库时,首先要定义一个GPIO_InitTypeDef结构体变量,用于配置 GPIO 的参数。例如:

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

上述代码中,先使能了 GPIOA 的时钟,然后对 GPIOA 的引脚 5 进行配置,将其模式设置为推挽输出模式,无上拉下拉电阻,速度设置为低速。之后,通过HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);函数即可控制 LED 灯的点亮,使用HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);函数则可控制 LED 灯熄灭。

读取按键状态也是 GPIO 的常见应用。在硬件连接上,将按键的一端连接到 STM32 的 GPIO 引脚,另一端接地或接高电平。以按键一端接地为例,当按键未按下时,GPIO 引脚为高电平;当按键按下时,GPIO 引脚被拉低为低电平。在软件配置上,同样使用GPIO_InitTypeDef结构体进行配置,不过此时模式应设置为输入模式。例如:

GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

在上述代码中,将 GPIOA 的引脚 0 配置为输入模式,并使能上拉电阻,这样在按键未按下时,引脚处于高电平状态。在主程序中,可以通过HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)函数来读取按键状态,若返回值为GPIO_PIN_RESET,则表示按键被按下 。

定时器:精准时间掌控者

定时器在 STM32 的应用中起着至关重要的作用,其原理基于计数器对时钟信号进行计数。当计数器的值达到预设的自动重装载值时,就会产生溢出事件,进而触发中断或执行其他预设操作。

定时中断是定时器的常见应用之一。以 STM32 的通用定时器 TIM3 为例,使用 HAL 库进行配置。首先,需要使能 TIM3 的时钟,代码如下:

__HAL_RCC_TIM3_CLK_ENABLE();

然后,定义一个TIM_HandleTypeDef结构体变量,用于配置 TIM3 的参数,如预分频器、自动重装载值、计数模式等。例如:

TIM_HandleTypeDef htim3;htim3.Instance = TIM3;htim3.Init.Prescaler = 7199;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 9999;htim3.Init.ClockDivision = 0;if (HAL_TIM_Base_Init(&htim3)!= HAL_OK){Error_Handler();}

在上述代码中,将 TIM3 的预分频器设置为 7199,这样经过预分频后,定时器的时钟频率为 1kHz(假设系统时钟为 72MHz) ;计数模式设置为向上计数模式;自动重装载值设置为 9999,意味着定时器每 10000 个时钟周期产生一次溢出中断,即定时时间为 1 秒。接下来,配置中断优先级并使能中断:

HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);HAL_TIM_Base_Start_IT(&htim3);

在中断服务函数中,可以编写需要定时执行的代码,例如控制 LED 灯的闪烁:

void TIM3_IRQHandler(void){HAL_TIM_IRQHandler(&htim3);}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){if (htim->Instance == TIM3){HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);}}

上述代码中,当 TIM3 的定时时间到达时,会进入中断服务函数TIM3_IRQHandler,进而调用HAL_TIM_PeriodElapsedCallback函数,在该函数中通过HAL_GPIO_TogglePin函数实现 GPIOA 引脚 5 的电平翻转,从而控制连接在该引脚上的 LED 灯闪烁。

PWM 输出也是定时器的重要应用。在电机调速、灯光亮度调节等场景中,PWM 技术被广泛应用。同样以 TIM3 为例,配置其通道 1 输出 PWM 信号。首先,除了使能 TIM3 时钟外,还需要使能相关 GPIO 的时钟,因为 PWM 输出需要使用特定的 GPIO 引脚。假设使用 PA6 引脚作为 TIM3 通道 1 的 PWM 输出引脚:

__HAL_RCC_GPIOA_CLK_ENABLE();

然后,配置 GPIO 引脚为复用功能输出模式:

GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_6;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

接着,配置 TIM3 的 PWM 模式,包括预分频器、自动重装载值、计数模式以及 PWM 模式等:

TIM_HandleTypeDef htim3;htim3.Instance = TIM3;htim3.Init.Prescaler = 71;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 999;htim3.Init.ClockDivision = 0;if (HAL_TIM_PWM_Init(&htim3)!= HAL_OK){Error_Handler();}

在上述代码中,预分频器设置为 71,自动重装载值设置为 999,此时 PWM 信号的频率为 1kHz(假设系统时钟为 72MHz) 。最后,配置 PWM 的占空比,并启动 PWM 输出:

TIM_OC_InitTypeDef sConfigOC;sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 500;sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1)!= HAL_OK){Error_Handler();}HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

上述代码中,将 PWM 模式设置为 PWM1 模式,占空比设置为 50%(通过Pulse的值为 500,自动重装载值为 999 计算得出) ,极性设置为高电平有效,然后启动 TIM3 通道 1 的 PWM 输出。通过调整Pulse的值,就可以改变 PWM 信号的占空比,从而实现对电机转速或灯光亮度的控制。

串口通信:数据传输的桥梁

串口通信是 STM32 与外部设备进行数据传输的常用方式之一,其原理是通过 TX(发送)和 RX(接收)引脚,按照一定的波特率、数据位、停止位和校验位等参数,将数据一位一位地进行传输。

在 STM32 中配置串口通信,以 USART1 为例,使用 HAL 库时,首先需要使能 USART1 和相关 GPIO 的时钟。假设 USART1 的 TX 引脚为 PA9,RX 引脚为 PA10:

__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();

然后,配置 GPIO 引脚为复用功能模式,分别设置 TX 引脚为复用推挽输出,RX 引脚为浮空输入:

GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate = GPIO_AF7_USART1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

接着,配置 USART1 的参数,包括波特率、数据位、停止位、校验位等:

UART_HandleTypeDef huart1;huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1)!= HAL_OK){Error_Handler();}

在上述代码中,将波特率设置为 115200,数据位设置为 8 位,停止位设置为 1 位,无校验位,工作模式为收发模式,无硬件流控制,过采样率设置为 16 倍。配置完成后,就可以使用HAL_UART_Transmit函数发送数据,使用HAL_UART_Receive函数接收数据。例如,发送一个字符串:

uint8_t tx_data[] = "Hello, STM32!";HAL_UART_Transmit(&huart1, tx_data, sizeof(tx_data), HAL_MAX_DELAY);

接收数据时,可以定义一个接收缓冲区,然后使用HAL_UART_Receive函数进行接收:


uint8_t rx_data[10];HAL_UART_Receive(&huart1, rx_data, sizeof(rx_data), HAL_MAX_DELAY);

在实际应用中,还可以通过中断方式来处理串口数据的接收和发送,以提高系统的实时性。例如,配置 USART1 的接收中断:

HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);HAL_NVIC_EnableIRQ(USART1_IRQn);HAL_UART_Receive_IT(&huart1, rx_data, 1);

在中断服务函数USART1_IRQHandler中,处理接收到的数据:

void USART1_IRQHandler(void){HAL_UART_IRQHandler(&huart1);}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if (huart->Instance == USART1){// 处理接收到的数据HAL_UART_Receive_IT(&huart1, rx_data, 1);}}

上述代码中,当接收到一个字节的数据后,会进入中断服务函数USART1_IRQHandler,进而调用HAL_UART_RxCpltCallback函数,在该函数中可以对接收到的数据进行处理,然后再次启动接收中断,以便接收下一个字节的数据。

ADC:模拟世界的数字化窗口

ADC(Analog - to - Digital Converter)即模拟数字转换器,其工作原理是将连续变化的模拟信号转换为离散的数字信号,以便微控制器进行处理。在 STM32 中,ADC 模块通过采样保持电路对模拟输入信号进行采样,然后利用逐次逼近寄存器(SAR)将采样得到的模拟电压值转换为对应的数字值。

以电压采集为例,介绍 ADC 的配置和数据处理方法。首先,需要使能 ADC 和相关 GPIO 的时钟。假设使用 PA0 引脚作为 ADC 的输入通道:

__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();

然后,配置 GPIO 引脚为模拟输入模式:

GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

接着,配置 ADC 的参数,包括分辨率、采样时间、转换模式等:

ADC_HandleTypeDef hadc1;hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.ScanConvMode = DISABLE;hadc1.Init.ContinuousConvMode = DISABLE;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion = 1;if (HAL_ADC_Init(&hadc1)!= HAL_OK){Error_Handler();}

在上述代码中,将 ADC 的时钟预分频器设置为 4,分辨率设置为 12 位,关闭扫描模式、连续转换模式和不连续转换模式,无外部触发转换,数据对齐方式设置为右对齐,转换通道数设置为 1。接下来,配置 ADC 的通道:

ADC_ChannelConfTypeDef sConfig;sConfig.Channel = ADC_CHANNEL_0;sConfig.Rank = 1;sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig)!= HAL_OK){Error_Handler();}

在上述代码中,将 ADC 的通道 0 配置为要转换的通道,采样时间设置为 56 个周期。配置完成后,就可以启动 ADC 转换,并读取转换结果:

if (HAL_ADC_Start(&hadc1)!= HAL_OK){Error_Handler();}HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);uint16_t adc_value = HAL_ADC_GetValue(&hadc1);

在上述代码中,首先启动 ADC 转换,然后通过HAL_ADC_PollForConversion函数等待转换完成,最后使用HAL_ADC_GetValue函数读取转换结果。得到的adc_value即为转换后的数字值,该值与输入的模拟电压值成正比关系。假设参考电压为 3.3V,那么可以通过以下公式将数字值转换为实际的电压值:

float voltage = (float)adc_value * 3.3f / 4096.0f;

上述公式中,4096 是 12 位 ADC 的满量程数字值(\(2^{12}\)) ,通过该公式可以将 ADC 转换得到的数字值转换为对应的实际电压值,从而实现对模拟电压的精确测量和处理。

进阶之路:外设驱动开发与优化

驱动开发步骤

在 STM32 外设开发中,驱动程序的编写是实现硬件功能的关键环节。以 HAL 库为例,其驱动开发步骤严谨且有序,为开发者提供了清晰的思路和方法。

确定外设类型是驱动开发的首要任务。在项目开始前,开发者需要深入了解目标外设的特性和需求,这就如同探险家在出发前要明确目的地的特点一样。例如,当开发一个基于 STM32 的智能温度控制系统时,需要使用 ADC 外设来采集温度传感器的模拟信号,此时就需要仔细查阅 ADC 外设的数据手册,了解其寄存器的地址、位域描述以及各种功能特性,从而为后续的开发工作奠定坚实的基础。

创建驱动程序文件是使代码结构清晰、易于维护的重要举措。为每个外设创建独立的.c和.h文件,就像为每个工具打造一个专属的收纳盒,方便管理和使用。比如在开发 SPI 外设驱动时,在工程目录中新建spi_driver.c和spi_driver.h文件 。在spi_driver.h文件中,主要声明函数接口与宏定义,如:

#ifndef __SPI_DRIVER_H#define __SPI_DRIVER_Hvoid SPI_Init(void);void SPI_Transmit(uint8_t *data, uint16_t len);void SPI_Receive(uint8_t *data, uint16_t len);#endif

在spi_driver.c文件中,则实现具体的功能,包括包含头文件、定义相关变量以及实现函数功能等,如下所示:

#include "spi_driver.h"#include "stm32f4xx_hal.h"SPI_HandleTypeDef hspi;void SPI_Init(void){hspi.Instance = SPI1;hspi.Init.Mode = SPI_MODE_MASTER;hspi.Init.Direction = SPI_DIRECTION_2LINES;hspi.Init.DataSize = SPI_DataSize_8BIT;hspi.Init.CLKPolarity = SPI_POLARITY_LOW;hspi.Init.CLKPhase = SPI_PHASE_1EDGE;hspi.Init.NSS = SPI_NSS_SOFT;hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi.Init.TIMode = SPI_TIMODE_DISABLE;hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi)!= HAL_OK){Error_Handler();}}void SPI_Transmit(uint8_t *data, uint16_t len){HAL_SPI_Transmit(&hspi, data, len, HAL_MAX_DELAY);}void SPI_Receive(uint8_t *data, uint16_t len){HAL_SPI_Receive(&hspi, data, len, HAL_MAX_DELAY);}

配置外设时钟是确保外设正常工作的关键步骤。使用 RCC(Reset and Clock Control)库函数来配置外设的时钟源和分频系数,就像为机器调整合适的动力供应。以 GPIO 外设为例,使用__HAL_RCC_GPIOA_CLK_ENABLE()宏定义来启用 GPIOA 外设的时钟 ,确保 GPIOA 端口能够正常工作。在配置时钟时,需要根据外设的工作频率要求,合理设置分频系数,以保证外设的稳定运行。

初始化外设是让外设按照预期工作模式运行的重要操作。使用 HAL 库函数提供的初始化函数,根据外设的功能需求,配置其工作模式、输入输出模式、中断设置等参数。例如,对于 GPIO 外设,使用HAL_GPIO_Init()函数来配置 GPIO 引脚的模式和上下拉设置。假设要将 PA0 引脚配置为输出模式,无上拉下拉电阻,速度为低速,代码如下:

GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

配置外设寄存器是实现外设特定功能的核心步骤。使用 HAL 库函数提供的寄存器操作函数来读写外设寄存器,根据外设的工作模式和需求,设置相应的寄存器位。例如,对于定时器外设,使用HAL_TIM_Base_Init()函数来配置定时器的基本参数,如预分频器、自动重装载值、计数模式等 ,然后使用HAL_TIM_Base_Start()函数启动定时器。假设要配置 TIM3 定时器,使其定时时间为 1 秒,代码如下:

TIM_HandleTypeDef htim3;htim3.Instance = TIM3;htim3.Init.Prescaler = 7199;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 9999;htim3.Init.ClockDivision = 0;if (HAL_TIM_Base_Init(&htim3)!= HAL_OK){Error_Handler();}HAL_TIM_Base_Start(&htim3);

实现数据传输功能是许多外设的重要任务。对于需要进行数据传输的外设,如 SPI 和 UART 等,使用 HAL 库函数提供的数据传输函数来实现数据的发送和接收。这些函数通常包括缓冲区管理、数据传输中断处理和错误处理等功能,确保数据传输的稳定和可靠。例如,在使用 SPI 进行数据传输时,使用SPI_Transmit和SPI_Receive函数来发送和接收数据;在使用 UART 进行数据传输时,使用HAL_UART_Transmit和HAL_UART_Receive函数来实现数据的收发。

实现中断处理函数是使外设能够及时响应外部事件的关键。使用 HAL 库函数提供的中断处理函数来实现中断的配置和处理,当外设产生中断时,能够及时调用相应的回调函数进行处理。例如,对于定时器外设,使用HAL_TIM_PeriodElapsedCallback()函数作为定时器溢出中断的回调函数 ,在该函数中编写需要在中断发生时执行的代码。

提供用户接口函数是方便用户使用外设的重要手段。为了让用户能够更便捷地操作外设,提供一组简单的接口函数来封装并抽象外设驱动程序的功能,这些接口函数可以实现常见的操作,如初始化、读取、写入等。用户通过调用这些接口函数,无需了解底层的驱动程序实现细节,就能轻松操作外设。例如,在上述 SPI 驱动中,提供SPI_Init、SPI_Transmit和SPI_Receive等接口函数,用户只需调用这些函数,就能实现 SPI 外设的初始化、数据发送和接收等功能。

测试和调试是确保驱动程序正确性和稳定性的重要环节。完成外设驱动程序的编写后,通过编写测试代码和使用调试工具,如示波器、逻辑分析仪等,对驱动程序进行全面的测试和调试,确保外设在不同工作模式、各种输入条件和异常情况下都能正常工作。在测试过程中,仔细检查外设的工作状态、数据传输的准确性以及中断处理的及时性等,及时发现并解决问题。

优化策略

在 STM32 外设开发中,优化驱动程序对于提升系统性能、降低功耗以及增强稳定性至关重要。以下将深入探讨降低功耗、优化算法、合理配置中断优先级等优化策略。

降低功耗是许多嵌入式系统开发中的关键目标,尤其是在电池供电或对功耗有严格要求的应用场景中。STM32 微控制器提供了多种低功耗模式,如睡眠模式、停止模式和待机模式,开发者可以根据系统的工作状态,灵活选择合适的低功耗模式。在智能手环等可穿戴设备中,当设备处于闲置状态时,可将 STM32 微控制器切换到停止模式,此时 CPU 停止运行,大部分外设时钟被关闭,仅保留最低限度的系统功能,从而显著降低功耗。除了选择低功耗模式,还可以通过关闭不必要的外设时钟来减少功耗。在一个基于 STM32 的智能家居控制系统中,当某个时间段内不需要使用 SPI 通信时,可通过__HAL_RCC_SPIx_CLK_DISABLE()函数关闭 SPI 外设的时钟,避免不必要的功耗浪费。

优化算法是提高驱动程序效率和性能的重要手段。在数据处理过程中,选择合适的算法可以显著减少计算量和执行时间。在数字滤波算法中,采用高效的滤波算法,如卡尔曼滤波算法,相比简单的均值滤波算法,能够更有效地去除噪声干扰,同时减少计算量,提高系统的实时性。此外,还可以通过优化代码结构,减少不必要的循环和条件判断,提高代码的执行效率。在一个控制电机转速的程序中,将一些固定的计算结果提前计算并存储,避免在循环中重复计算,从而提高程序的执行速度。

合理配置中断优先级是确保系统实时性和稳定性的关键。在多中断源的系统中,不同的中断具有不同的紧急程度和重要性。通过合理分配中断优先级,可以保证重要的中断能够及时得到响应,避免因低优先级中断的干扰而导致系统响应延迟。在一个工业自动化控制系统中,将外部设备的紧急故障中断设置为高优先级,而将一些定期的数据采集中断设置为低优先级,这样当出现紧急故障时,系统能够立即响应并进行处理,保障系统的安全运行。同时,在中断处理函数中,应尽量减少处理时间,避免长时间占用 CPU 资源,影响其他中断的响应。

使用 DMA(直接内存访问)技术可以有效减轻 CPU 的负担,提高数据传输效率。在数据量较大的传输场景中,如将大量数据从内存传输到外设或从外设读取大量数据到内存时,使用 DMA 可以实现数据的直接传输,无需 CPU 频繁参与,从而使 CPU 能够专注于其他重要任务。在一个图像采集系统中,使用 DMA 将图像传感器采集到的数据直接传输到内存中,CPU 可以在 DMA 传输数据的同时,进行图像的预处理和分析等工作,大大提高了系统的整体性能。

实战演练:综合项目开发

项目背景与需求分析

在当今科技飞速发展的时代,人们对生活和工作环境的质量要求越来越高,智能环境监测系统应运而生。本项目旨在开发一款基于 STM32 的智能环境监测系统,以满足对环境参数实时监测和智能控制的需求。

该系统需要具备实时采集多种环境参数的功能,包括温度、湿度、空气质量(如有害气体浓度)、光照强度等。通过高精度的传感器,将这些环境参数转化为电信号,再由 STM32 微控制器进行处理。当监测到某些环境参数超出预设的正常范围时,系统要能够及时发出警报,提醒用户采取相应措施。例如,当室内温度过高或过低、湿度过大或过小、有害气体浓度超标时,系统可以通过蜂鸣器、指示灯或手机短信等方式通知用户,保障用户的健康和安全。

为了实现数据的远程监控和管理,系统还需具备数据传输功能。通过 Wi-Fi 模块或其他无线通信方式,将采集到的环境数据上传至云端服务器或用户的手机 APP,用户可以随时随地通过手机或电脑查看实时环境数据和历史数据,方便对环境状况进行分析和决策。同时,系统要能够对采集到的大量环境数据进行存储,以便后续查询和分析。可以使用外部存储器,如 SD 卡,来存储数据,确保数据的安全性和完整性。

硬件设计与选型

在硬件设计方面,STM32 微控制器作为整个系统的核心,犹如大脑一般,负责数据的处理和各个外设的控制。它需要与多种传感器和其他外部设备进行连接,以实现环境参数的采集和数据的传输。

DHT11 温湿度传感器是采集温度和湿度的理想选择,它具有成本低、精度较高、响应速度快等优点。其工作原理是通过内部的电容式感湿元件和热敏电阻,将环境中的湿度和温度变化转化为数字信号输出。在硬件连接上,将 DHT11 的 VCC 引脚连接到 STM32 的 3.3V 电源引脚,GND 引脚连接到 STM32 的接地引脚,数据引脚连接到 STM32 的一个 GPIO 引脚,如 PA0,用于数据的传输。

MQ-135 气体传感器可用于检测空气中的有害气体浓度,如氨气、硫化物、苯系蒸汽等。它的工作原理基于气敏材料二氧化锡(SnO2),当环境中存在有害气体时,气敏材料的电导率会发生变化,从而通过检测电路将其转化为电信号输出。在硬件连接上,将 MQ-135 的 VCC 引脚连接到 STM32 的 5V 电源引脚(因为其工作电压通常为 5V),GND 引脚连接到 STM32 的接地引脚,信号输出引脚连接到 STM32 的 ADC 引脚,如 PA1,以便 STM32 能够采集模拟信号并进行 A/D 转换。

BH1750 光强度传感器能够精确检测环境光强度,它采用 I2C 通信接口,具有低功耗、高精度的特点。在硬件连接上,将 BH1750 的 VCC 引脚连接到 STM32 的 3.3V 电源引脚,GND 引脚连接到 STM32 的接地引脚,SCL(时钟线)引脚连接到 STM32 的 I2C 接口的时钟引脚,如 PB6,SDA(数据线)引脚连接到 STM32 的 I2C 接口的数据引脚,如 PB7,通过 I2C 通信协议与 STM32 进行数据传输。

OLED 显示屏用于实时显示环境参数,它具有自发光、对比度高、视角广、功耗低等优点。同样采用 I2C 通信接口,在硬件连接上,与 BH1750 类似,将 OLED 的 VCC 引脚连接到 STM32 的 3.3V 电源引脚,GND 引脚连接到 STM32 的接地引脚,SCL 和 SDA 引脚分别连接到 STM32 的 I2C 接口的相应引脚,如 PB6 和 PB7,方便 STM32 将处理后的环境数据显示在 OLED 屏幕上,供用户直观查看。

ESP8266 Wi-Fi 模块则负责实现数据的无线传输功能,它可以将 STM32 采集到的环境数据通过 Wi-Fi 网络上传至云端服务器或用户的手机 APP。在硬件连接上,将 ESP8266 的 TX 引脚连接到 STM32 的 USART 串口的 RX 引脚,如 PA10,RX 引脚连接到 STM32 的 USART 串口的 TX 引脚,如 PA9,VCC 引脚连接到 STM32 的 3.3V 电源引脚,GND 引脚连接到 STM32 的接地引脚,通过串口通信实现数据的传输。

软件实现与调试

软件架构设计采用模块化的思想,将整个系统的软件功能划分为多个独立的模块,每个模块负责特定的功能,如传感器驱动模块、数据处理模块、通信模块和显示模块等。这种设计方式使得代码结构清晰,易于维护和扩展。

在传感器驱动模块中,针对不同的传感器,编写相应的驱动代码。以 DHT11 温湿度传感器为例,使用 HAL 库实现其驱动。首先,初始化与 DHT11 连接的 GPIO 引脚为输入输出模式:

GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

然后,编写读取 DHT11 数据的函数。DHT11 的数据传输采用单总线协议,需要严格按照时序进行操作。以下是读取一个字节数据的函数示例:

uint8_t DHT11_ReadByte(void){uint8_t i, byte = 0;for (i = 0; i < 8; i++){while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);HAL_Delay(30);if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET){byte |= (1 << (7 - i));while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET);}}return byte;}

在数据处理模块中,对传感器采集到的数据进行滤波、校准等处理,以提高数据的准确性。例如,对于温度数据,可以采用滑动平均滤波算法,去除噪声干扰。假设有一个长度为 5 的温度数据缓冲区temperature_buf,当前采集到的温度数据为new_temperature,滑动平均滤波的代码实现如下:

static uint8_t index = 0;static float temperature_buf[5];temperature_buf[index] = new_temperature;index = (index + 1) % 5;float sum = 0;for (uint8_t i = 0; i < 5; i++){sum += temperature_buf[i];}float filtered_temperature = sum / 5;

通信模块负责实现与 Wi-Fi 模块的数据传输以及与云端服务器或手机 APP 的通信。使用 ESP8266 Wi-Fi 模块时,通过串口发送 AT 指令来配置其工作模式、连接 Wi-Fi 网络以及上传数据。以下是配置 ESP8266 连接 Wi-Fi 网络的代码示例:

void ESP8266_ConnectWiFi(const char *ssid, const char *password){char command[50];sprintf(command, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, password);HAL_UART_Transmit(&huart1, (uint8_t *)command, strlen(command), HAL_MAX_DELAY);// 等待连接成功的响应uint8_t response[100];HAL_UART_Receive(&huart1, response, sizeof(response), HAL_MAX_DELAY);// 处理响应数据,判断是否连接成功}

显示模块负责将处理后的数据显示在 OLED 显示屏上。使用 OLED 的驱动库,编写显示函数。例如,显示温度数据的函数如下:

void OLED_ShowTemperature(float temperature){char temp_str[10];sprintf(temp_str, "Temp: %.1f C", temperature);OLED_ShowString(0, 0, temp_str);}

在调试过程中,使用示波器、逻辑分析仪等工具来检测硬件信号的正确性,通过串口调试助手查看传感器数据和通信数据,及时发现并解决问题。例如,在调试 DHT11 传感器时,使用示波器观察其数据引脚的时序,确保数据传输的正确性;在调试 Wi-Fi 模块时,通过串口调试助手查看 AT 指令的响应,判断模块是否正常工作以及网络连接是否成功。

相关文章:

解锁STM32外设:开启嵌入式开发新世界

✨✨✨这里是小韩学长yyds的BLOG(喜欢作者的点个关注吧) ✨✨✨想要了解更多内容可以访问我的主页 小韩学长yyds-CSDN博客 目录 探索 STM32 强大的外设家族 初窥门径&#xff1a;STM32 外设开发基础 开发方式与工具 外设配置基础步骤 深入剖析&#xff1a;常见外设应用实例…...

C++的内存管理

1. C/C内存分布 我们先来看下面的一段代码和相关问题 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int…...

P8685 [蓝桥杯 2019 省 A] 外卖店优先级--优先队列“数组”!!!!!

P8685 [蓝桥杯 2019 省 A] 外卖店优先级 题目 解析优先队列如何判断是否使用优先队列&#xff1f;省略规则优先队列常用操作大顶堆 vs 小顶堆定义队列h队列数组 代码 题目 解析 每个外卖店会在不同的时间点收到订单&#xff0c;我们可以看见测试用例的时间顺序是不同的&#x…...

nuxt2 打包优化使用“compression-webpack-plugin”插件

在使用 Nuxt.js 构建项目时&#xff0c;为了提高性能&#xff0c;通常会考虑对静态资源进行压缩。compression-webpack-plugin 是一个常用的 Webpack 插件&#xff0c;用于在生产环境中对文件进行 Gzip 压缩。这对于减少网络传输时间和提高页面加载速度非常有帮助。下面是如何在…...

RabbitMQ知识点

1.为什么需要消息队列&#xff1f; RabbitMQ体系结构 操作001&#xff1a;RabbitMQ安装 二、安装 # 拉取镜像 docker pull rabbitmq:3.13-management ​ # -d 参数&#xff1a;后台运行 Docker 容器 # --name 参数&#xff1a;设置容器名称 # -p 参数&#xff1a;映射端口号&…...

Windsuf 连接失败问题:[unavailable] unavailable: dial tcp...

问题描述 3月6日&#xff0c;在使用Windsuf 时&#xff0c;遇到以下网络连接错误&#xff1a; [unavailable] unavailable: dial tcp 35.223.238.178:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of…...

Spark 3.0核心新特性解析与行业应用展望

Spark 3.0核心新特性解析与行业应用展望 一、自适应查询执行(Adaptive Query Execution, AQE) 作为Spark 3.0最具突破性的优化,AQE通过运行时动态调整执行计划,解决了传统静态优化的局限性。其核心技术突破体现在三方面: 1. 动态分区合并(Dynamically Coalescing Shuf…...

基于 harbor 构建docker私有仓库

仓库&#xff08;Repository&#xff09;是集中存放镜像的地方&#xff0c;又分公共仓库和私有仓库。 有时候容易把仓库与注册服务器&#xff08;Registry&#xff09;混淆。 实际上注册服务器是存放仓库的具体服务器&#xff0c; 一个注册服务器上可以有多个仓库&#xff0c;…...

MySQL基本建表操作

目录 1&#xff0c;创建数据库db_ck 1.1创建表 1.2 查看创建好的表 2,创建表t_hero 2.1 先进入数据库Db_Ck 2.1.1 这里可以看是否进入数据库: 2.2 创建表t_Hero 2.2.1 我们可以先在文本文档里面写好然后粘贴进去&#xff0c;因为直接写的话&#xff0c;错了要重新开始 …...

低空经济快速发展,无人机人才培养及校企实验室共建技术详解

随着低空经济的快速发展&#xff0c;无人机作为该领域的关键技术载体&#xff0c;其应用范围和市场需求正在迅速扩大。为了满足这一趋势&#xff0c;无人机人才的培养以及校企实验室的共建成为了推动技术进步和产业升级的重要途径。以下是对无人机人才培养及校企实验室共建技术…...

电脑网络出现问题!简单的几种方法解除电脑飞行模式

在某些情况下&#xff0c;您可能需要关闭电脑上的飞行模式以便重新连接到 Wi-Fi、蓝牙或其他无线网络。本教程中简鹿办公将指导您如何在 Windows 和 macO S操作系统上解除飞行模式。 一、Windows 系统下解除飞行模式 通过快捷操作中心 步骤一&#xff1a;点击屏幕右下角的通知…...

Docker入门篇1:搜索镜像、拉取镜像、查看本地镜像列表、删除本地镜像

大家好我是木木&#xff0c;在当今快速发展的云计算与云原生时代&#xff0c;容器化技术蓬勃兴起&#xff0c;Docker 作为实现容器化的主流工具之一&#xff0c;为开发者和运维人员带来了极大的便捷 。下面我们一起开始入门第一篇&#xff1a;搜索镜像、拉取镜像、查看本地镜像…...

网络初级复习作业

作业要求&#xff1a; 1,学校内部的HTTP客户端可以正常通过域名www.baidu.com访问到白度网络中的HTTP服务器 2&#xff0c;学校网络内部网段基于192.168.1.0/24划分&#xff1a;PC1可以正常访问3.3.3.0/24网段&#xff0c;但是PC2不允许 3,学校内部路由使用静态路由&#xf…...

Spring Boot 调用DeepSeek API的详细教程

目录 前置准备步骤1&#xff1a;创建Spring Boot项目步骤2&#xff1a;配置API参数步骤3&#xff1a;创建请求/响应DTO步骤4&#xff1a;实现API客户端步骤5&#xff1a;创建控制器步骤6&#xff1a;异常处理步骤7&#xff1a;测试验证单元测试示例Postman测试请求 常见问题排查…...

rpc和proto

rpc全称远程过程控制&#xff0c;说白了是一种对信息发送和接收的规则编写方法&#xff0c;来自google&#xff0c;这些规则会以protobuf代码存到proto文件里。我以autoGen中agent_worker.proto为例&#xff0c;大概长这样 syntax "proto3";package agents;option …...

我的两个医学数据分析技术思路

我的两个医学数据分析技术思路 从临床上获得的或者公共数据库数据这种属于观察性研究&#xff0c;是对临床诊疗过程中自然产生的数据进行分析而获得疾病发生发展的规律等研究成果。再细分&#xff0c;可以分为独立危险因素鉴定和预测模型构建两种。 独立危险因素鉴定是一直以…...

GitHub上传项目

总结&#xff08;有基础的话直接执行这几步&#xff0c;就不需要再往下看了&#xff09;&#xff1a; git init 修改git的config文件&#xff1a;添加:[user]:name你的github用户名 email你注册github的用户名 git branch -m master main git remote add origin 你的URL gi…...

汇编点亮LED

目录 一、ARM常用汇编指令 二、汇编点亮LED 2.1 GPIO简述 2.2 GPIO相关寄存器 2.3 LED原理图 2.4 汇编点亮LED 一、ARM常用汇编指令 常用汇编格式: label : instruction @ comment label:标号 instruction:具体汇编指令 comment:注释内容 常…...

VS Code C++ 开发环境配置

VS Code 是当前非常流行的开发工具. 本文讲述如何配置 VS Code 作为 C开发环境. 本文将按照如下步骤来介绍如何配置 VS Code 作为 C开发环境. 安装编译器安装插件配置工作区 第一个步骤的具体操作会因为系统不同或者方案不同而有不同的选择. 环境要求 首先需要立即 VS Code…...

Python深度学习算法介绍

一、引言 深度学习是机器学习的一个重要分支&#xff0c;它通过构建多层神经网络结构&#xff0c;自动从数据中学习特征表示&#xff0c;从而实现对复杂模式的识别和预测。Python作为一门强大的编程语言&#xff0c;凭借其简洁易读的语法和丰富的库支持&#xff0c;成为深度学…...

hadoop集群HDFS读写性能测试

一、写测试命令 hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.4-tests.jar TestDFSIO -write -nrFiles 10 -size 10MB二、读测试命令 hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.1.4-t…...

HTTPS加密原理详解

目录 HTTPS是什么 加密是什么 HTTPS的工作流程 1.使用对称加密 2.引入非对称加密 3.引入证书机制 客户端验证证书真伪的过程 签名的加密流程 整体工作流程 总结 HTTPS是什么 HTTPS协议也是一个应用程协议&#xff0c;是在HTTP的基础上加入了一个加密层&#xff0c;由…...

react基本功

useLayoutEffect useLayoutEffect 用于在浏览器重新绘制屏幕之前同步执行代码。它与 useEffect 相同,但执行时机不同。 主要特点 执行时机:useLayoutEffect 在 DOM 更新完成后同步执行,但在浏览器绘制之前。这使得它可以在浏览器渲染之前读取和修改 DOM,避免视觉上的闪烁…...

计算机视觉|3D 点云处理黑科技:PointNet++ 原理剖析与实战指南

一、引言 在当今数字化与智能化快速发展的时代&#xff0c;3D 点云处理技术在多个前沿领域中发挥着重要作用。特别是在自动驾驶和机器人视觉等领域&#xff0c;这项技术已成为实现智能化的关键支撑。 以自动驾驶为例&#xff0c;车辆需要实时感知周围复杂的环境信息&#xff…...

【VUE2】第三期——样式冲突、组件通信、异步更新、自定义指令、插槽

目录 1 scoped解决样式冲突 2 data写法 3 组件通信 3.1 父子关系 3.1.1 父向子传值 props 3.1.2 子向父传值 $emit 3.2 非父子关系 3.2.1 event bus 事件总线 3.2.2 跨层级共享数据 provide&inject 4 props 4.1 介绍 4.2 props校验完整写法 5 v-model原理 …...

WebAssembly技术及应用了解

WebAssembly&#xff08;Wasm&#xff09;是一种为Web设计的高效、低级的二进制指令格式&#xff0c;旨在提升Web应用的性能并支持多种编程语言。以下是对其核心概念、优势、应用场景及开发流程的系统介绍&#xff1a; 1. 核心概念 二进制格式&#xff1a;Wasm采用紧凑的二进制…...

工程化与框架系列(26)--前端可视化开发

前端可视化开发 &#x1f4ca; 引言 前端可视化是现代Web应用中不可或缺的一部分&#xff0c;它能够以直观的方式展示复杂的数据和信息。本文将深入探讨前端可视化开发的关键技术和最佳实践&#xff0c;包括图表绘制、数据处理、动画效果等方面。 可视化技术概述 前端可视化…...

ESP32的IDF开发学习-WiFi的开启、配置与连接

前言 本章节将实现如何使用ESP32的WiFi功能&#xff0c;尽可能的详细地介绍 简介 ESP32中的wifi支持双工作模式 Station&#xff08;STA&#xff09;模式&#xff1a;连接到路由器或其他AP设备&#xff0c;可通过esp_wifi_set_mode(WIFI_MODE_STA)设置。SoftAP模式&#xf…...

2025-3-9 一周总结

目前来看本学期上半程汇编语言,编译原理,数字电路和离散数学是相对重点的课程. 在汇编语言和编译原理这块,个人感觉黑书内知识点更多,细节更到位,体系更完整,可以在老师讲解之前进行预习 应当及时复习每天的内容.第一是看书,然后听课,在一天结束后保证自己的知识梳理完整,没有…...

【网络编程】事件选择模型

十、基于I/O模型的网络开发 10.9 事件选择模型 10.0.1 基本概念 事件选择(WSAEventSelect) 模型是另一个有用的异步 I/O 模型。和 WSAAsyncSelect 模 型类似的是&#xff0c;它也允许应用程序在一个或多个套接字上接收以事件为基础的网络事件通知&#xff0c;最 主要的差别在…...

Java核心语法:从变量到控制流

一、变量与数据类型&#xff08;对比Python/C特性&#xff09; 1. 变量声明三要素 // Java&#xff08;强类型语言&#xff0c;需显式声明类型&#xff09; int age 25; String name "CSDN"; // Python&#xff08;动态类型&#xff09; age 25 name …...

信息安全与网络安全的区别_信息安全与网络安全之差异探析

在当今数字化时代&#xff0c;信息安全与网络安全成为了人们关注的热点话题。尽管这两个概念经常被提及&#xff0c;但它们之间存在着明显的区别。本文旨在探讨信息安全与网络安全的定义、范畴及应对策略&#xff0c;以帮助读者更好地理解和应对相关挑战。 一、定义与范畴的差…...

http协议的三次握手机制

HTTP协议是基于TCP协议的&#xff0c;因此HTTP的三次握手机制实际上就是TCP的三次握手机制。TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议。为了确保通信的可靠性&#xff0c;TCP在建立连接时需要进行三次握手。下面我们详细…...

探秘沃尔什-哈达玛变换(WHT)原理

沃尔什-哈达玛变换&#xff08;WHT&#xff09;起源 起源与命名&#xff08;20世纪早期&#xff09; 数学基础&#xff1a;该变换的理论基础由法国数学家雅克哈达玛&#xff08;Jacques Hadamard&#xff09;在1893年提出&#xff0c;其核心是哈达玛矩阵的构造。扩展与命名&…...

C++ Windows下屏幕截图

屏幕截图核心代码&#xff08;如果要求高帧率&#xff0c;请使用DxGI&#xff09;&#xff1a; // RGB到YUV的转换公式 #define RGB_TO_Y(r, g, b) ((int)((0.299 * (r)) (0.587 * (g)) (0.114 * (b)))) #define RGB_TO_U(r, g, b) ((int)((-0.169 * (r)) - (0.331 * (g)) …...

【python爬虫】酷狗音乐爬取练习

注意&#xff1a;本次爬取的音乐仅有1分钟试听&#xff0c;仅作学习爬虫的原理&#xff0c;完整音乐需要自行下载客户端。 一、 初步分析 登陆酷狗音乐后随机选取一首歌&#xff0c;在请求里发现一段mp3文件&#xff0c;复制网址&#xff0c;确实是我们需要的url。 复制音频的…...

电路的一些设计经验

这个C37在这里位于AMS1117-3.3稳压器的输入端。这个是作为输入滤波电容&#xff0c;有助于平滑输入电压&#xff0c;减少输入电压的纹波和噪声&#xff0c;从而提高稳压器LDO的稳定性。 电容器储存电荷&#xff0c;当输入电压出现小的拨动或者纹波时&#xff0c;电容器可以释放…...

Windows编译环境搭建(MSYS2\MinGW\cmake)

我的音视频/流媒体开源项目(github) 一、基础环境搭建 1.1 MSYS2\MinGW 参考&#xff1a;1. 基于MSYS2的Mingw-w64 GCC搭建Windows下C开发环境_msys2使用mingw64编译 在Widndows系统上&#xff0c;使用gcc工具链&#xff08;g&#xff09;进行C程序开发&#xff1f;可以的&a…...

Vue 框架深度解析:源码分析与实现原理详解

文章目录 一、Vue 核心架构设计1.1 整体架构流程图1.2 模块职责划分 二、响应式系统源码解析2.1 核心类关系图2.2 核心源码分析2.2.1 数据劫持实现2.2.2 依赖收集过程 三、虚拟DOM与Diff算法实现3.1 Diff算法流程图3.2 核心Diff源码 四、模板编译全流程剖析4.1 编译流程图4.2 编…...

前端 | CORS 跨域问题解决

问题&#xff1a;Access to fetch at http://localhost:3000/save from origin http://localhost:5174 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the request…...

《白帽子讲 Web 安全》之文件操作安全

目录 引言 &#xff08;一&#xff09;文件上传与下载漏洞概述 1.文件上传的常见安全隐患 1.1前端校验的脆弱性与服务端脚本执行危机在文件上传流程中&#xff0c;部分开发者可能会在前端使用 JavaScript 代码对文件后缀名进行简单校验&#xff0c;试图以此阻止非法文件上传…...

【AI】AI开源IDE:CLine源码分析报告

1. 源码位置&#xff1a; CLine 是一个开源的 VSCode 插件&#xff0c;其完整源码托管在 GitHub 的 cline/cline 仓库中。这个仓库包含 CLine 的核心逻辑&#xff08;TypeScript 编写&#xff09;&#xff0c;包括与 LLM 的对话控制、工具调用接口&#xff0c;以及 VSCode 插件…...

使用数据库和缓存的时候,是如何解决数据不一致的问题的?

1.缓存更新策略 1.1. 缓存旁路模式&#xff08;Cache Aside&#xff09; 在应用里负责管理缓存&#xff0c;读取时先查缓存&#xff0c;如果命中了则返回缓存&#xff0c;如果未命中就查询数据库&#xff0c;然后返回缓存&#xff0c;返回缓存的同时把数据给写入缓存中。更新…...

docker compose 以redis为例

常见docker compose 命令 》》注意这个是旧版本的&#xff0c;新版本 docker 与compose 之间没有 - 新版本的 docker compose 把 version 取消了 &#xff0c;redis 默认是没有配置文件的 &#xff0c;nginx&#xff0c;mysql 默认是有的 services:redis:image: redis:lat…...

基于Kubernetes部署MySQL主从集群

以下是一个基于Kubernetes部署MySQL主从集群的详细YAML示例&#xff0c;包含StatefulSet、Service、ConfigMap和Secret等关键配置。MySQL主从集群需要至少1个主节点和多个从节点&#xff0c;这里使用 StatefulSet 初始化脚本 实现主从自动配置。 1. 创建 Namespace (可选) ap…...

VMware中安装配置Ubuntu(2024最新版 超详细)

目录 一、安装虚拟机软件 二、VMware虚拟机 三、 Ubuntu 下载 &#xff08;1&#xff09;官网下载 &#xff08;2&#xff09;清华镜像网站下载 四、创建虚拟机 五、Ubuntu 系统安装过程的配置 六、更换国内镜像源 七、环境搭建完毕 全篇较长&#xff0c;请慢慢观看 一…...

【Linux】信号处理以及补充知识

目录 一、信号被处理的时机&#xff1a; 1、理解&#xff1a; 2、内核态与用户态&#xff1a; 1、概念&#xff1a; 2、重谈地址空间&#xff1a; 3、处理时机&#xff1a; 补充知识&#xff1a; 1、sigaction&#xff1a; 2、函数重入&#xff1a; 3、volatile&…...

如何在rust中解析 windows 的 lnk文件(快捷方式)

一、从标题二开始看&#x1f601; 这些天在使用rust写一个pc端应用程序&#xff0c;需要解析lnk文件获取lnk的图标以及原程序地址&#xff0c;之前并没有过pc端应用程序开发的经验&#xff0c; 所以在广大的互联网上游荡了两天。额&#x1f97a; 今天找到了这个库 lnk_parse很…...

大模型系列课程学习-基于Vllm/Ollama/Ktransformers完成Deepseek推理服务部署

1.机器配置及实验说明 基于前期搭建的双卡机器装机教程&#xff0c;配置如下&#xff1a; 硬件名称参数备注CPUE5-2680V42 *2&#xff08;线程28个&#xff09;无GPU2080TI-22G 双卡魔改卡系统WSL Unbuntu 22.04.5 LTS虚拟机 本轮实验目的&#xff1a;基于VLLM/Ollama/ktran…...

Unity Shader学习总结

1.帧缓冲区和颜色缓冲区区别 用于存储每帧每个像素颜色信息的缓冲区 帧缓冲区包括&#xff1a;颜色缓冲区 深度缓冲区 模板缓冲区 自定义缓冲区 2.ImageEffectShader是什么 后处理用的shader模版 3.computerShader 独立于渲染管线之外&#xff0c;在显卡上运行&#xff0c;大量…...