STM32 HAL库函数入门指南:从原理到实践
1 STM32 HAL库概述
STM32 HAL(Hardware Abstraction Layer)库是ST公司专门为STM32系列微控制器开发的一套硬件抽象层函数库。它的核心设计理念是在应用层与硬件层之间建立一个抽象层,这个抽象层屏蔽了底层硬件的具体实现细节,为开发者提供了一套统一的、标准化的应用程序接口(API)。这种设计极大地提高了代码的可移植性和重用性,使得开发者能够更加专注于应用功能的实现,而不必过多关注硬件细节。
1.1 HAL库架构设计
HAL库的架构设计采用了模块化的思想,将整个库函数分为多个功能模块。每个模块都对应着STM32微控器的一个或多个外设,如GPIO、UART、SPI、I2C等。这种模块化的设计使得代码结构清晰,便于管理和维护。在每个模块中,又将功能细分为初始化配置、控制操作、状态查询等不同类别的函数,形成了一个层次分明的函数调用体系。
1.2 错误处理
在错误处理方面,HAL库实现了完善的错误检测和处理机制。每个HAL函数都会返回执行状态,通过HAL_StatusTypeDef枚举类型来表示函数执行的结果,包括HAL_OK、HAL_ERROR、HAL_BUSY和HAL_TIMEOUT等状态。这种机制使得开发者能够及时发现和处理程序运行中的异常情况,提高了程序的可靠性和稳定性。
1.3 驱动模板
HAL库还提供了丰富的外设驱动模板和示例程序。这些模板和示例涵盖了绝大多数常用的应用场景,开发者可以基于这些模板快速开发自己的应用程序。每个外设驱动都包含了完整的初始化代码、中断处理函数和基本的操作函数,为开发者提供了可靠的参考。
1.4 中断处理
在中断处理方面,HAL库采用了统一的中断处理框架。它定义了标准的中断回调函数接口,开发者只需要实现相应的回调函数,就可以处理各种中断事件。这种设计大大简化了中断处理的编程工作,同时也保证了中断处理代码的规范性和可维护性。
1.5 HAL库优势
为了提高程序的执行效率,HAL库在设计时充分考虑了性能优化问题。它提供了多种操作模式,如轮询模式、中断模式和DMA模式,开发者可以根据实际需求选择合适的操作模式。同时,HAL库也支持低功耗模式的配置和管理,有助于开发低功耗应用。
在使用HAL库时,需要注意的是,所有的外设操作都需要通过相应的句柄(Handle)来进行。句柄是一个包含外设配置信息和状态信息的数据结构,它在外设初始化时创建,在后续的操作中用于标识和控制特定的外设实例。这种基于句柄的设计方式,既保证了代码的可重入性,也便于多外设的并行操作。
HAL库还提供了强大的调试支持。通过设置适当的调试级别,开发者可以获取详细的运行时信息,这对于问题定位和性能优化非常有帮助。HAL库还集成了断言机制,可以在开发阶段及时发现和定位程序中的逻辑错误。
2 HAL库使用步骤
使用HAL库开发程序通常遵循以下步骤:需要配置时钟系统。这包括设置系统时钟源、配置PLL倍频系统以及设置各个总线的分频系数。这些配置通常在SystemClock_Config()函数中完成。初始化外设使用的GPIO引脚。每个外设都需要特定的GPIO引脚配置,包括引脚的工作模式、上下拉状态等。配置并初始化具体的外设模块。这包括设置外设的工作模式、中断优先级等参数。
2.1 工程初始化阶段
在使用HAL库开发STM32项目时,第一步是建立基础工程框架。这需要包含必要的HAL库头文件,其中最基本的是"stm32f4xx_hal.h"(以STM32F4系列为例)。同时,需要在项目中添加相应的HAL库源文件,这些文件通常位于ST官方提供的固件包中。
2.2 系统初始化
在main函数的开始,必须首先调用HAL_Init()函数来初始化HAL库。这个函数会完成以下几个重要任务:设置系统滴答定时器(SysTick)、初始化默认的HAL库状态、配置NVIC中断分组等。紧接着需要配置系统时钟,这通常通过调用SystemClock_Config()函数实现。该函数负责设置PLL、AHB、APB1、APB2等时钟参数,确保系统以正确的频率运行。典型的初始化代码结构如下:
int main(void)
{HAL_Init(); //HAL库初始化SystemClock_Config(); //系统时钟配置/* 用户代码开始 */while (1){}
}
2.3 外设时钟使能
外设时钟使能是使用任何外设前的必要步骤。在STM32中,所有外设都需要先使能其时钟才能正常工作。HAL库提供了统一的宏定义来完成这个任务,例如:
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟
__HAL_RCC_DMA1_CLK_ENABLE(); //使能DMA1时钟
2.4 外设初始化配置
HAL库采用句柄(Handle)的方式管理每个外设,因此需要先定义相应的句柄结构体,然后进行参数配置。以GPIO为例,配置过程包括:定义GPIO初始化结构体、设置引脚参数(模式、上下拉、速度等)、调用初始化函数。示例代码如下:
GPIO_InitTypeDef GPIO_InitStruct = {0};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);
2.5 中断配置
如果外设需要使用中断,则需要配置NVIC并编写中断处理函数。HAL库提供了统一的中断回调函数机制,用户只需要实现相应的回调函数即可。例如:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_0){//中断处理代码}
}
2.6 错误处理
几乎所有的HAL库函数都会返回执行状态(HAL_OK、HAL_ERROR等),建议在关键操作后都进行状态检查:
if(HAL_UART_Init(&huart1) != HAL_OK)
{Error_Handler();
}
2.7 外设功能使用
HAL库为每个外设提供了完整的操作函数集,包括数据收发、状态查询、参数修改等。这些函数都遵循统一的命名规范:HAL_PPP_Function(),其中PPP代表具体的外设名称。例如:
//UART发送数据
HAL_UART_Transmit(&huart1, TxData, sizeof(TxData), HAL_MAX_DELAY);//ADC开始转换
HAL_ADC_Start(&hadc1);//定时器启动
HAL_TIM_Base_Start_IT(&htim2);
2.8 使用总结
初始化完成后,就可以在主循环中实现具体的应用功能。值得注意的是,HAL库的大多数函数都提供了阻塞和非阻塞两种版本,可以根据应用需求选择合适的方式。UART传输既可以使用阻塞式的HAL_UART_Transmit(),也可以使用非阻塞的HAL_UART_Transmit_IT()或HAL_UART_Transmit_DMA()。
在开发过程中,建议充分利用HAL库提供的DEBUG功能。可以通过配置assert_param宏来启用参数检查,这对于调试程序非常有帮助。同时,建议养成良好的错误处理习惯,合理使用HAL_Delay()函数进行延时,避免使用空循环延时。
3 GPIO的HAL库函数
GPIO(通用输入输出接口)是STM32微控制器最基础也是最常用的外设之一。HAL库为GPIO操作提供了一套完整的函数库,这些函数不仅简化了GPIO的配置和控制过程,还提供了多种工作模式的灵活配置选项。
3.1 了解GPIO结构
在使用GPIO之前,首先需要了解GPIO的基本结构。STM32的每个GPIO引脚都可以配置为不同的工作模式,包括输入模式、输出模式、复用功能模式和模拟模式。每个引脚还可以配置上拉、下拉或者浮空状态,并且可以设置不同的输出速度等级。HAL库通过GPIO_InitTypeDef结构体来管理这些配置参数。
GPIO的配置过程主要包含以下几个关键步骤:
- 使能GPIO时钟
- 定义GPIO初始化结构体
- 配置GPIO参数
- 调用初始化函数
3.2 使能GPIO时钟
必须使能对应GPIO端口的时钟。这是因为STM32采用了时钟门控技术来降低功耗,只有使能了时钟的外设才能正常工作。时钟使能可以通过__HAL_RCC_GPIOx_CLK_ENABLE()宏函数来实现,其中x表示具体的GPIO端口(A、B、C等)。
3.3 定义GPIO初始化结构体
接下来是GPIO初始化结构体的配置。GPIO_InitTypeDef结构体包含了以下重要参数:
- Pin:指定要配置的引脚,可以同时配置多个引脚
- Mode:设置引脚的工作模式,如输入、输出、中断等
- Pull:配置引脚的上拉/下拉状态
- Speed:设置引脚的输出速度
- Alternate:当使用复用功能时,指定具体的复用功能编号
在实际的GPIO操作中,HAL库提供了一系列函数来实现不同的控制需求。HAL_GPIO_Init()函数用于初始化GPIO引脚,它会根据初始化结构体中的配置参数来设置相应的寄存器。对于输出操作,HAL_GPIO_WritePin()函数可以设置引脚的输出状态,HAL_GPIO_TogglePin()函数可以翻转引脚的状态。而对于输入操作,HAL_GPIO_ReadPin()函数可以读取引脚的当前电平状态。
3.4 中断应用
GPIO可以配置为外部中断源。通过将Mode参数设置为GPIO_MODE_IT_RISING(上升沿触发)、GPIO_MODE_IT_FALLING(下降沿触发)或GPIO_MODE_IT_RISING_FALLING(双边沿触发),可以实现对引脚电平变化的中断检测。当配置为中断模式时,还需要配置中断优先级并使能中断。HAL库提供了HAL_GPIO_EXTI_IRQHandler()函数来处理GPIO外部中断,并通过HAL_GPIO_EXTI_Callback()回调函数来实现用户的具体中断服务程序。
对于需要快速响应的应用,HAL库还提供了一些直接操作GPIO寄存器的宏。比如__HAL_GPIO_SET_PIN()和__HAL_GPIO_RESET_PIN()可以直接设置或清除引脚状态,这些操作比调用标准的HAL函数更快。但使用这些宏时需要格外小心,因为它们会直接操作硬件寄存器。
在实际应用中,一个典型的GPIO配置示例如下:
void GPIO_LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};// 使能GPIOA时钟__HAL_RCC_GPIOA_CLK_ENABLE();// LED引脚配置GPIO_InitStruct.Pin = GPIO_PIN_5; // 选择PA5引脚GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速模式// 初始化GPIOHAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
在进行GPIO配置时,还需要注意一些特殊情况的处理。例如,当GPIO引脚被配置为复用功能时,除了常规的GPIO配置外,还需要正确设置复用功能编号。同时,某些引脚可能有默认的复用功能(如调试端口),在使用这些引脚时需要特别注意是否会影响系统的其他功能。
3.5 GPIO锁定功能
HAL库还提供了GPIO锁定功能,通过HAL_GPIO_LockPin()函数可以锁定引脚的配置,防止配置被意外修改。这在一些需要高可靠性的应用中特别有用。但需要注意的是,一旦引脚被锁定,在系统复位之前将无法修改其配置。
4 HAL库中断配置与处理
中断系统是STM32单片机的核心功能之一,它允许微控制器及时响应外部事件和内部状态变化。在HAL库中,中断的配置和处理采用了统一的框架,使得中断处理变得更加规范和简洁。
中断源可以分为外部中断和内部中断两大类。外部中断主要来自GPIO引脚的电平变化,而内部中断则包括定时器中断、ADC转换完成中断、UART接收发送中断等。无论是哪种中断,其配置过程都遵循相似的步骤。
使用中断时需要:
- 配置NVIC中断控制器
- 设置中断优先级
- 编写中断服务函数
4.1 外部中断配置
在STM32中,任何GPIO引脚都可以配置为外部中断源。配置过程主要包括以下步骤:
// 第一步:GPIO初始化结构体配置
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIO时钟GPIO_InitStruct.Pin = GPIO_PIN_0; //选择PA0引脚
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; //上升沿触发中断
GPIO_InitStruct.Pull = GPIO_PULLDOWN; //下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速模式HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 第二步:配置NVIC
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0); //设置中断优先级
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线
对于中断处理,HAL库采用了分层的方式。首先是中断服务函数(ISR),这是在启动文件中定义的一级中断处理函数。然后是HAL库的中断处理函数,它会进行必要的状态检查和清除中断标志。最后是用户的回调函数,这是实际进行业务处理的地方。以外部中断为例:
// 中断服务函数(在启动文件中)
void EXTI0_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}// 用户回调函数(在用户代码中实现)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_0){// 在这里添加中断处理代码HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); //翻转LED}
}
4.2 内部中断配置
内部中断的配置也遵循类似的模式。以定时器中断为例,配置过程如下:
// 定时器初始化配置
TIM_HandleTypeDef htim2;htim2.Instance = TIM2;
htim2.Init.Prescaler = 7199; //预分频值
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数模式
htim2.Init.Period = 9999; //周期值
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{Error_Handler();
}// 启动定时器中断
HAL_TIM_Base_Start_IT(&htim2);// 配置NVIC
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
对应的中断处理函数:
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim2);
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){// 定时器中断处理代码}
}
4.3 中断优先级配置
在使用中断时,需要特别注意中断优先级的配置。STM32使用抢占优先级和子优先级的组合来管理中断优先级。HAL库在初始化时会设置默认的优先级分组(通常是4位抢占优先级,0位子优先级)。可以通过HAL_NVIC_SetPriorityGrouping()函数修改分组方式:
// 配置中断优先级分组
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); //4位抢占优先级,0位子优先级
在中断处理中,还需要注意以下几点:
- 中断处理函数应该尽量简短,避免在中断中执行耗时操作。如果需要处理复杂任务,建议设置标志位,在主循环中处理。
- 避免在中断中使用printf等耗时的函数,这可能会导致其他中断得不到及时响应。
- 合理使用中断标志位和状态检查,确保中断处理的可靠性:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){if(__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE)){// 接收到新数据__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_RXNE);}}
}
- 在使用DMA时,要注意配置相应的DMA中断:
// DMA中断配置
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);// DMA中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){HAL_UART_Receive_DMA(huart, RxBuffer, RXBUFFERSIZE);}
}
5 定时器的HAL库函数
STM32微控制器的定时器系统是一个功能强大的模块,它包含了多种类型的定时器,可以满足不同应用场景的需求。根据功能复杂度,STM32的定时器可以分为三类:基本定时器(Basic Timer)、通用定时器(General-Purpose Timer)和高级定时器(Advanced Timer)。HAL库为这些定时器提供了统一的操作接口,使得开发者能够方便地实现各种定时功能。
5.1 基本结构
基本定时器是最简单的定时器类型,主要用于基本的定时功能和触发DAC转换。它只包含一个16位或32位向上计数器、预分频器和重装载寄存器。通用定时器在基本定时器的基础上增加了捕获/比较通道,可以用于PWM生成、输入捕获等功能。而高级定时器则具有最完整的功能,除了包含通用定时器的所有特性外,还支持互补输出、死区控制、断路控制等高级功能,特别适合于电机控制等应用。
5.2 工作原理
在使用定时器之前,首先需要了解定时器的基本工作原理。定时器的时基单元包含了预分频器(Prescaler)和计数器(Counter)。预分频器用于对输入时钟进行分频,从而降低计数频率;计数器则根据配置的方向(向上、向下或双向)进行计数,当计数值达到设定的自动重装载值(ARR)时,会产生更新事件,计数器重新开始计数。定时器的时间计算公式如下:
定时时间 = (预分频值 + 1) * (重装载值 + 1) / 定时器时钟频率
5.3 配置步骤
HAL库通过TIM_HandleTypeDef结构体来管理定时器的配置和状态。定时器的基本配置过程包括以下步骤:首先使能定时器时钟,然后配置定时器的基本参数,包括预分频值、计数模式、重装载值等。如果需要使用中断功能,还需要配置NVIC并使能相应的中断。
定时器配置步骤:
- 使能定时器时钟
- 配置定时器基本参数
- 配置中断(如需要)
- 启动定时器
关键函数:
- HAL_TIM_Base_Init():基本定时器初始化
- HAL_TIM_PWM_Init():PWM模式初始化
- HAL_TIM_Base_Start_IT():启动定时器中断
以下是一个基本定时器配置的示例:
void Timer_Init(void)
{TIM_HandleTypeDef htim2;// 使能TIM2时钟__HAL_RCC_TIM2_CLK_ENABLE();// 基本配置htim2.Instance = TIM2;htim2.Init.Prescaler = 7199; // 预分频值htim2.Init.CounterMode = TIM_COUNTERMODE_UP;// 向上计数模式htim2.Init.Period = 9999; // 重装载值htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 初始化定时器HAL_TIM_Base_Init(&htim2);// 启动定时器HAL_TIM_Base_Start_IT(&htim2);// 配置NVICHAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);HAL_NVIC_EnableIRQ(TIM2_IRQn);
}// 定时器中断服务函数
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim2);
}// 定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){// 在这里添加定时器中断处理代码}
}
5.5 PWM应用
对于PWM应用,HAL库提供了专门的PWM配置和控制函数。PWM配置需要设置定时器的基本参数,并配置输出通道的参数,包括PWM模式、极性、输出状态等。以下是PWM配置的示例:
void PWM_Init(void)
{TIM_HandleTypeDef htim3;TIM_OC_InitTypeDef sConfigOC = {0};// 配置定时器基本参数htim3.Instance = TIM3;htim3.Init.Prescaler = 71;htim3.Init.Period = 999;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_PWM_Init(&htim3);// 配置PWM通道sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 500; // 设置占空比为50%sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);// 启动PWM输出HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
}
定时器的输入捕获功能用于测量外部信号的周期、脉宽等参数。配置输入捕获时,需要设置捕获通道的触发边沿、滤波器、预分频等参数。HAL库提供了完整的输入捕获函数集,包括配置函数和捕获回调函数。
5.6 精确时序控制
对于需要精确时序控制的应用,定时器还可以配置为主从模式,实现多个定时器的同步运行。通过设置触发源和从模式,可以实现定时器之间的级联控制,这在复杂的定时控制场景中特别有用。
在使用定时器时,需要特别注意以下几点:
- 时钟配置要准确,确保定时器的时钟源和频率符合要求
- 中断优先级的合理设置,避免中断优先级冲突
- 在中断服务程序中避免执行耗时操作
- PWM应用中注意死区时间的设置(使用高级定时器时)
- 定时器溢出时间的计算要考虑时钟频率的实际值
6 UART通信的HAL库函数
UART(Universal Asynchronous Receiver/Transmitter)是STM32中最常用的串行通信接口之一,它实现了异步串行通信,广泛应用于设备间的数据传输和调试。在HAL库中,UART的配置和使用都有统一的接口函数。
6.1 配置步骤
首先,我们来看UART的基本初始化配置。在使用UART前,需要先使能相关的时钟并配置对应的GPIO引脚。
- 配置GPIO引脚
- 配置UART参数
- 使能UART
- 配置中断(如需要)
典型的初始化代码如下:
// 定义UART句柄
UART_HandleTypeDef huart1;void UART1_Init(void)
{// 第一步:使能时钟__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();// 第二步:配置GPIOGPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; // TX:PA9, RX:PA10GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速GPIO_InitStruct.Alternate = GPIO_AF7_USART1; // 复用为USART1HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 第三步:配置UART参数huart1.Instance = USART1;huart1.Init.BaudRate = 115200; // 波特率huart1.Init.WordLength = UART_WORDLENGTH_8B; // 8位数据位huart1.Init.StopBits = UART_STOPBITS_1; // 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();}
}
UART通信支持多种数据传输模式,包括轮询模式、中断模式和DMA模式。让我们分别来看这些模式的使用方法。
6.2 轮询模式
轮询模式是最简单的传输方式,适用于数据量小、实时性要求不高的场合:
// 发送数据(阻塞式)
uint8_t TxData[] = "Hello World\r\n";
HAL_UART_Transmit(&huart1, TxData, sizeof(TxData), HAL_MAX_DELAY);// 接收数据(阻塞式)
uint8_t RxData[20];
HAL_UART_Receive(&huart1, RxData, sizeof(RxData), HAL_MAX_DELAY);
6.3 中断模式
中断模式适用于需要及时响应但数据量不大的场合。使用中断模式需要配置NVIC并实现相应的回调函数:
// 配置UART中断
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);// 启动中断接收
HAL_UART_Receive_IT(&huart1, RxData, 1); // 每次接收1个字节// 中断服务函数
void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&huart1);
}// 接收完成回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){// 处理接收到的数据// 重新启动接收HAL_UART_Receive_IT(&huart1, RxData, 1);}
}
6.4 DMA模式
DMA模式最适合大量数据的传输,它可以在不占用CPU的情况下完成数据传输:
// DMA配置
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;void UART_DMA_Init(void)
{// 使能DMA时钟__HAL_RCC_DMA2_CLK_ENABLE();// 配置DMA参数(以发送DMA为例)hdma_usart1_tx.Instance = DMA2_Stream7;hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart1_tx.Init.Mode = DMA_NORMAL;hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;HAL_DMA_Init(&hdma_usart1_tx);// 关联DMA与UART__HAL_LINKDMA(&huart1, hdmatx, hdma_usart1_tx);// 配置DMA中断HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}// 使用DMA发送数据
uint8_t TxBuffer[] = "DMA Test\r\n";
HAL_UART_Transmit_DMA(&huart1, TxBuffer, sizeof(TxBuffer));// DMA传输完成回调
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){// 发送完成处理}
}
6.5 串口调试
为了实现更好的串口调试功能,我们通常会重定向printf函数到串口:
// 重定向printf到串口
int fputc(int ch, FILE *f)
{uint8_t temp[1] = {ch};HAL_UART_Transmit(&huart1, temp, 1, HAL_MAX_DELAY);return ch;
}
在实际应用中,还需要考虑数据的封装和解析。这里给出一个简单的数据帧处理示例:
// 定义数据帧结构
typedef struct
{uint8_t header; // 帧头 0xAAuint8_t length; // 数据长度uint8_t data[32]; // 数据uint8_t checksum; // 校验和
} UART_Frame_TypeDef;// 数据帧处理
void UART_Frame_Process(uint8_t data)
{static UART_Frame_TypeDef frame;static uint8_t rxState = 0;static uint8_t rxCount = 0;switch(rxState){case 0: // 等待帧头if(data == 0xAA){frame.header = data;rxState = 1;}break;case 1: // 接收长度frame.length = data;rxCount = 0;rxState = 2;break;case 2: // 接收数据frame.data[rxCount++] = data;if(rxCount >= frame.length)rxState = 3;break;case 3: // 接收校验和frame.checksum = data;// 验证校验和if(Check_Sum(&frame) == HAL_OK){// 数据帧处理}rxState = 0;break;}
}
6.6 注意事项
在使用UART时,还需要注意以下几点:
- 波特率计算:实际波特率可能与设定值有偏差,需要考虑时钟频率的影响。
- 数据缓冲:在中断或DMA接收时,要注意缓冲区大小的设置,避免溢出。
- 错误处理:要处理好帧错误、噪声错误、溢出错误等异常情况:
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1){if(__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE)){__HAL_UART_CLEAR_OREFLAG(huart);}// 重新启动接收HAL_UART_Receive_IT(huart, RxData, 1);}
}
7 ADC转换器的HAL库函数
ADC(模数转换器)是STM32中重要的模拟外设,它能将模拟信号转换为数字信号。STM32的ADC具有多通道、高精度、可配置采样时间等特点。HAL库提供了完整的ADC操作接口,使得ADC的配置和使用变得简单直观。
ADC配置步骤:
- 配置ADC时钟
- 配置ADC通道
- 配置采样时间
- 启动ADC转换
7.1 ADC基本配置
使用ADC前需要完成时钟使能和GPIO配置:
// 定义ADC句柄
ADC_HandleTypeDef hadc1;void ADC1_Init(void)
{// 使能时钟__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();// 配置ADC引脚GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_0; // PA0作为ADC通道0GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; // 模拟输入模式GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 配置ADC参数hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // ADC时钟4分频hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 12位分辨率hadc1.Init.ScanConvMode = DISABLE; // 禁用扫描模式hadc1.Init.ContinuousConvMode = ENABLE; // 连续转换模式hadc1.Init.DiscontinuousConvMode = DISABLE; // 禁用不连续模式hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 禁用外部触发hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐hadc1.Init.NbrOfConversion = 1; // 转换通道数量hadc1.Init.DMAContinuousRequests = DISABLE; // 禁用DMA连续请求hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 单次转换结束选择if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}
}
7.2 配置ADC通道
STM32的ADC支持多个通道,每个通道都可以单独配置采样时间:
void ADC_Channel_Config(void)
{ADC_ChannelConfTypeDef sConfig = {0};// 配置通道0sConfig.Channel = ADC_CHANNEL_0; // 选择通道0sConfig.Rank = 1; // 转换序列顺序sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 采样时间if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}
}
7.3 ADC的采集方式
包括单次采集、连续采集、DMA采集等。下面分别介绍这些模式:
- 单次采集模式:
// 启动单次转换
HAL_ADC_Start(&hadc1);
// 等待转换完成
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
// 获取转换结果
uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
// 停止ADC转换
HAL_ADC_Stop(&hadc1);
- 连续采集模式:
// 启动连续转换
HAL_ADC_Start(&hadc1);// 在主循环中读取数据
while(1)
{if(HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK){uint32_t value = HAL_ADC_GetValue(&hadc1);// 处理ADC数据}
}
- 中断模式:
// 配置ADC中断
HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);// 启动中断模式转换
HAL_ADC_Start_IT(&hadc1);// ADC转换完成回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if(hadc->Instance == ADC1){uint32_t value = HAL_ADC_GetValue(hadc);// 处理ADC数据}
}
- DMA模式(适合多通道采集):
// DMA配置
DMA_HandleTypeDef hdma_adc1;
uint16_t ADC_DMA_Buffer[8]; // DMA缓冲区void ADC_DMA_Init(void)
{__HAL_RCC_DMA2_CLK_ENABLE();hdma_adc1.Instance = DMA2_Stream0;hdma_adc1.Init.Channel = DMA_CHANNEL_0;hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;hdma_adc1.Init.Mode = DMA_CIRCULAR;hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&hdma_adc1);__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);// 启动ADC DMA传输HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_DMA_Buffer, 8);
}
7.4 实际应用
我们经常需要对ADC数据进行处理,例如滤波、校准等:
// 移动平均滤波
#define FILTER_LENGTH 16
uint16_t filter_buffer[FILTER_LENGTH];
uint8_t filter_index = 0;uint16_t ADC_Filter(uint16_t new_value)
{uint32_t sum = 0;filter_buffer[filter_index] = new_value;filter_index = (filter_index + 1) % FILTER_LENGTH;for(uint8_t i = 0; i < FILTER_LENGTH; i++){sum += filter_buffer[i];}return sum / FILTER_LENGTH;
}// ADC值转换为实际电压
float ADC_To_Voltage(uint16_t adc_value)
{return (float)adc_value * 3.3f / 4096.0f; // 12位ADC, 参考电压3.3V
}
7.5 多通道扫描
ADC还支持多通道扫描模式,适合需要采集多个通道的应用:
// 多通道配置
void ADC_MultiChannel_Config(void)
{ADC_ChannelConfTypeDef sConfig = {0};// 配置通道0sConfig.Channel = ADC_CHANNEL_0;sConfig.Rank = 1;sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;HAL_ADC_ConfigChannel(&hadc1, &sConfig);// 配置通道1sConfig.Channel = ADC_CHANNEL_1;sConfig.Rank = 2;HAL_ADC_ConfigChannel(&hadc1, &sConfig);// 启动DMA传输HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_DMA_Buffer, 2);
}
在使用ADC时,需要注意以下几点:
- 采样时间的选择:采样时间越长,转换结果越准确,但会降低采样速率。
- 参考电压的影响:ADC转换结果与参考电压有关,需要保证参考电压的稳定性。
- 输入信号范围:确保输入信号不超过ADC的量程范围(0~VREF)。
- 抗干扰措施:在ADC输入端加入RC滤波电路;PCB布局时注意模拟地和数字地的分离;使用独立的模拟电源供电
8 DMA的HAL库函数
STM32的HAL库提供了一系列用于配置和控制DMA传输的函数。DMA初始化的核心函数是HAL_DMA_Init(),该函数需要传入一个DMA_HandleTypeDef结构体指针,该结构体包含了DMA的配置信息。在使用DMA之前,我们首先需要配置DMA的基本参数,包括传输方向、源地址和目标地址的数据宽度、地址是否自增、传输优先级等。
DMA配置步骤:
- 使能DMA时钟
- 配置DMA传输参数
- 配置DMA中断
- 启动DMA传输
8.1 DMA初始化
以下是DMA初始化的核心代码示例:
void DMA_Init(void) {hdma_usart1_rx.Instance = DMA1_Stream5;hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;hdma_usart1_rx.Init.Priority = DMA_PRIORITY_HIGH;hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;HAL_DMA_Init(&hdma_usart1_rx);
}
8.2 启动普通传输
除了初始化函数,HAL库还提供了启动传输、停止传输、查询状态等功能函数。HAL_DMA_Start()用于启动普通传输,HAL_DMA_Start_IT()用于启动带中断的传输。这些函数的原型分别如下:
HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
8.3 DMA使用实例
ADC连续采样
在这个例子中,我们使用DMA将ADC采样数据直接传输到内存数组中,无需CPU干预:
#define ADC_BUFFER_SIZE 1000uint16_t adc_buffer[ADC_BUFFER_SIZE];void ADC_DMA_Config(void) {// ADC配置部分hadc1.Instance = ADC1;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.ContinuousConvMode = ENABLE;hadc1.Init.ScanConvMode = DISABLE;HAL_ADC_Init(&hadc1);// DMA配置部分hdma_adc1.Instance = DMA2_Stream0;hdma_adc1.Init.Channel = DMA_CHANNEL_0;hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;hdma_adc1.Init.Mode = DMA_CIRCULAR;hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&hdma_adc1);// 关联ADC和DMA__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);// 启动ADC和DMA传输HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_BUFFER_SIZE);
}
在实际开发中,建议参考ST官方提供的示例代码和文档,深入理解每个模块的具体使用方法。同时,建议在使用HAL库时养成良好的错误处理习惯,确保程序的稳定性和可靠性。
相关文章:
STM32 HAL库函数入门指南:从原理到实践
1 STM32 HAL库概述 STM32 HAL(Hardware Abstraction Layer)库是ST公司专门为STM32系列微控制器开发的一套硬件抽象层函数库。它的核心设计理念是在应用层与硬件层之间建立一个抽象层,这个抽象层屏蔽了底层硬件的具体实现细节,为开发者提供了一套统一的、…...
React封装倒计时按钮
背景 在开发过程中,经常需要使用到倒计时的场景,当用户点击后,按钮进行倒计时,然后等待邮件或者短信发送,每次都写重复代码,会让代码显得臃肿,所以封装一个组件来减少耦合 创建一个倒计时组件…...
深入探究Linux树状目录结构
Linux 作为一款广泛使用的开源操作系统,其目录结构采用了树状设计,这种结构清晰、有条理,便于用户和系统进行文件管理与操作。 一、根目录(/) 根目录是整个 Linux 文件系统的起始点,就像一棵大树的根部&…...
Realsense相机驱动安装及其ROS通讯配置——机器人抓取系统基础系列(四)
文章目录 概要1 Realsense相机驱动安装Method1: 使用Intel服务器预编译包Method2: 使用ROS服务器预编译包Method3: 使用SDK源代码方法对比总结 2 Realsense-ROS通讯配置与使用2.1 Realsense-ROS包安装2.2 ROS节点启动 小结Reference 概要 本文首先阐述了Realsense相机驱动安装…...
linux安装nvm
下载命令 wget https://github.com/nvm-sh/nvm/archive/refs/tags/v0.39.1.tar.gz当前盘打开终端后的nvm文件夹中 mkdir -p /nvm/.nvm如果树根不够就用加sudo 解压文件 tar xvf v0.39.1.tar.gz输入pwd 确定当前文件完成路径 在当前文件中写入。bashrc文件及代码回车进入编辑…...
图论1-问题 C: 算法7-6:图的遍历——广度优先搜索
题目描述 广度优先搜索遍历类似于树的按层次遍历的过程。其过程为:假设从图中的某顶点v出发,在访问了v之后依次访问v的各个未曾被访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先…...
基于 STM32 的多功能时间管理器项目
引言 在快节奏的生活中,时间管理显得尤为重要。本项目旨在通过 STM32 开发一个多功能时间管理器,功能包括计时器、闹钟和日历。用户可以方便地设置不同的提醒和计时任务,以更好地管理日常生活和工作。 项目名称 多功能时间管理器 环境准备 …...
Java工程结构:二方库依赖规约
文章目录 I jar 包分类一方库:二方库:三方库:II 专有名词GAV(GroupId、ArtifactId、Version):Maven 坐标III GAV 规则GroupId 格式ArtifactId 格式二方库版本号命名方式:主版本号.次版本号.修订号I jar 包分类 一方库: 本工程内部子项目模块依赖的库(jar 包)。 二…...
Django自带admin管理系统使用
1、admin路径地址 localhost:8000/admin 2、使用命令行创建超级管理员 python manage.py createsuperuser 之后按照提示一步一步往下走就好了。 3、修改管理员密码 python manage.py changepassword admin admin是超级管理员的账号 4、后台管理系统注册模型,…...
Jmeter 简单使用、生成测试报告(一)
一、下载Jmter 去官网下载,我下载的是apache-jmeter-5.6.3.zip,解压后就能用。 二、安装java环境 JMeter是基于Java开发的,运行JMeter需要Java环境。 1.下载JDK、安装Jdk 2.配置java环境变量 3.验证安装是否成功(java -versio…...
手摸手实战前端项目CI CD
由于图片和格式解析问题,为了更好阅读体验可前往 阅读原文 CI/CD 是 持续集成(Continuous Integration) 和 持续交付/部署(Continuous Delivery/Continuous Deployment) 的缩写,是现代软件开发中的一种自动…...
【Elasticsearch】搜索类型介绍,以及使用SpringBoot实现,并展现给前端
Elasticsearch 提供了多种查询类型,每种查询类型适用于不同的搜索场景。以下是八种常见的 Elasticsearch 查询类型及其详细说明和示例。 1. Match Query 用途:用于全文搜索,会对输入的文本进行分词,并在索引中的字段中查找这些分…...
K8S中的Pod调度之亲和性调度
亲和性调度 亲和性调度是一种比硬性指定节点(使用 nodeName 或 nodeSelector)更灵活的调度策略,它允许定义一组规则,根据这些规则,调度器会尝试将 Pod 调度到最合适的节点上,但如果找不到完全匹配的节点&a…...
高等数学学习笔记 ☞ 不定积分的积分法
1. 第一换元积分法 1. 基础概念:形如的过程,称为第一换元积分法。 2. 核心思想:通过对被积函数的观察(把被积函数的形式与积分表的积分公式进行比较),把外部的部分项拿到的内部(求原函数), 然后进行拼凑,…...
【HTTP】详解
目录 HTTP 基本概念啥是HTTP,有什么用?一次HTTP请求的过程当你在浏览器中输入一个浏览器地址,它会发送什么 ?---(底层流程)HTTP的协议头请求头(对应客户端)一些请求头请求方法 响应头…...
cursor重构谷粒商城01——为何要重构谷粒商城
前言:这个系列将使用最前沿的cursor作为辅助编程工具,来快速开发一些基础的编程项目。目的是为了在真实项目中,帮助初级程序员快速进阶,以最快的速度,效率,快速进阶到中高阶程序员。 本项目将基于谷粒商城…...
如何在 ASP.NET Core 中实现速率限制?
在 ASP.NET Core 中实现速率限制(Rate Limiting)中间件可以帮助你控制客户端对 API 的请求频率,防止滥用和过载。速率限制通常用于保护服务器资源,确保服务的稳定性和可用性。 ASP.NET Core 本身并没有内置的速率限制中间件&…...
STM32-笔记43-低功耗
一、什么是低功耗? 低功耗是指通过优化设计和采用特定的技术手段,降低电子设备在运行过程中消耗的能量,从而延长电池寿命、提高性能和减少发热。低功耗设计主要从芯片设计和系统设计两个方面进行,旨在减少所有器件的功率损耗&am…...
Facebook 隐私风波:互联网时代数据安全警钟
在社交媒体飞速发展的今天,个人数据的隐私保护已成为全球关注的焦点。作为全球最大的社交平台之一,Facebook面临的隐私问题,尤其是数据泄露事件,频繁引发公众的广泛讨论。从用户信息被滥用到数据泄漏,Facebook的隐私挑…...
Java 中的 ZoneOffset
介绍 在我们的这个世界上因为地球是圆的,所以每个国家都会有自己特定的时区。 时区在我们对时间的使用上扮演了非常重要的角色。但又因为时区的存在,又给我们带来了很多的麻烦,比如北美地区使用的夏令时和中国统一使用东 8 区的时间等。 当…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
如何把工业通信协议转换成http websocket
1.现状 工业通信协议多数工作在边缘设备上,比如:PLC、IOT盒子等。上层业务系统需要根据不同的工业协议做对应开发,当设备上用的是modbus从站时,采集设备数据需要开发modbus主站;当设备上用的是西门子PN协议时…...
高抗扰度汽车光耦合器的特性
晶台光电推出的125℃光耦合器系列产品(包括KL357NU、KL3H7U和KL817U),专为高温环境下的汽车应用设计,具备以下核心优势和技术特点: 一、技术特性分析 高温稳定性 采用先进的LED技术和优化的IC设计,确保在…...
