07 输入捕获和编码器接口

news2024/9/27 5:56:08

前言

前面介绍了定时器和输出比较,这一节主要介绍一下输入捕获测量输入频率和PWM占空比,然后介绍一下编码器接口。

一、输入捕获

1.什么是输入捕获

当输入的引脚有指定电平跳变时,会将计数器CNT中的值保存在CCR中,这个就称为输入捕获。

2.输入捕获测频率

我们可以通过获取输入的值来测量频率,这里有两个计算的方法:

2.1 测频法

在一个闸门时间T内,对上升沿进行计数,得到计数值N,频率就为=N/T。

2.2 测周法

在一个标准的频率fc下,对上升沿进行计数,得到计数值N,频率就为:fc / N。

3.输入捕获的内部结构

接下来了解一下输入捕获的内部结构,只有了解了内部结构,我们写代码才会很轻松,下图就是输入捕获的内部结构:

img

可以看到,从GPIO口输入电平,然后通过输入捕获单元,检测到触发电平,如果是设定的电平就会将CNT中的值保存到CCR中,然后通过配置从模式来将CNT中的值清0。

了解了这个结构后我们大概就知道如何配置输入捕获了。

首先配置外部输入,即GPIO口,然后配置定时器,因为输入捕获是定时器的一个工作模式,然后配置从模式,使用从模式的Reset来清空计数器CNT,这样就是配置好输入捕获了。

我们可以通过读取CCR中的值来计算频率。

4.软件实现

前面了解了硬件结构后,我们就可以使用软件来一一实现了,首先要打开时钟,时钟是stm32中最重要的一个部件,如果不打开时钟,就算配置了也没办法运行。

4.1 打开时钟

这里我们从上面的硬件分析可以得到,其实就是只用开启两个时钟,一个是GPIO的时钟,另一个就是TIM的时钟,输入捕获这个功能是在TIM中的,所以打开了TIM的时钟,输入捕获和输出比较也就打开了。

所以这里的代码就比较简单,我这里使用TIM3作为输入捕获的定时器,那么打开的代码如下:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

4.2 配置GPIO口

GPIO口做为一个外部信号的输入口,所以要为其设置输入模式,那选择什么模式最好呢?这里可以翻看一下手册:

img

可以看到GPIO配置为浮空输入,但是其实这里也可以配置为上拉输入,浮空输入就是能很好的捕捉电平的变化,但是没有上拉或者下拉导致不是很稳定,这里因为都是一个电平的跳变,就算是使用上拉,当输入的是高电平后会跳变为低电平,然后再变成高电平,所以这里可以选上拉或者下拉。

如果你不清楚这个跳变到底是什么,你可以选择浮空输入,这样获得的要好一点。

这里就是正常的配置GPIO口即可:

GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;   // 这里使用上拉输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);

这里是使用的是TIM3的通道1。

4.3 配置TIM

现在需要配置一下TIM了,在配置GPIO那配置的是TIM3的通道1,所以这要配置一下TIM3。

如果你选择的是TIM2,那上面要配置TIM2对应的引脚。

这里的配置方法和之前配置定时器那一样:

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct = {0};

TIM_InternalClockConfig(TIM3);    // 使用内部时钟
    
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;       // 不分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;     // 向上计数
TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;     // 这里需要注意
TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1;      // 频率
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;       // 重复计数器,高级定时器才有的功能
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);

这里的自动重装寄存器是填了一个最大值,是因为这里的输入捕获是用CNT对变化电平进行计数,而CNT中的值和自动重装寄存器ARR中的值一致时,就会使得计数器清0然后发送一个信号,如果这里到了ARR中的值后,还有变化的电平,是不是就会被舍弃。

所以这里为了防止这个问题,我们将ARR中的值设置成最大值,防止出现到了自动重装值时还有变化,所以用个最大的值,防止溢出。

4.4 配置输入捕获

这个也是使用一个结构体来进行配置的,结构体类型为:

typedef struct
{

  uint16_t TIM_Channel;      /*!< 指定 TIM 通道。
  此参数的值可以是 @ref TIM_Channel */

  uint16_t TIM_ICPolarity;   /*!< 指定输入信号的有效边沿。
  此参数的值可以是 @ref TIM_Input_Capture_Polarity */

  uint16_t TIM_ICSelection;  /*!< 指定输入。
  此参数的值可以是 @ref TIM_Input_Capture_Selection */

  uint16_t TIM_ICPrescaler;  /*!< 指定输入捕获预分频器。
  此参数的值可以是 @ref TIM_Input_Capture_Prescaler */

  uint16_t TIM_ICFilter;     /*!< 指定输入捕获筛选器。
  此参数可以是介于 0x0 和 0xF 之间的数字 */
} TIM_ICInitTypeDef;

第一个参数TIM_Channel是选择通道,这个是通过之前说的引脚来进行设定的:

img

img

img

前面比如是设置了TIM3_CH1,那这里就填写TIM_Channel_1

第二个参数TIM_ICPolarity,这个参数是选择有效信号的,可以选择TIM_ICPolarity_Rising高电平触发,TIM_ICPolarity_Falling低电平触发。

第三个参数TIM_ICSelection,指定输入,有信号直连TIM_ICSelection_DirectTI和交叉TIM_ICSelection_IndirectTI。这个需要拿个图来看看:

img

从这可以看到,我们通过选择TI1FP1它可以连到两个输入通道,一个是连到输入通道1,另一个连到通道2,直接配置到输入通道1的就叫做直连模式,如果连到输入通道2就叫做交叉模式。

第四个参数TIM_ICPrescaler就是分配器。

第五个参数TIM_ICFilter这个参数是选择过滤器的分辨率。

了解了结构体后我们就可以配置一下结构体中的内容了,这里我直接使用定时器通道1和输入通道1,所以模式就是直连:

TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;      // 有效电平高电平
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;     // 直连
TIM_ICInit(TIM3, &TIM_ICInitStruct);

这里再举一个例子,我这还是定时器通道1,输入通道变成了通道2,那这就选择交叉模式,代码如下:

TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;      // 有效电平高电平
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_IndirectTI;     // 交叉
TIM_ICInit(TIM3, &TIM_ICInitStruct);

这样就可以通过读取输入通道2中的CCR值来获取有效电平的次数了。

我们可以通过这个来计算PWM的频率和PWM的占空比,一个输入通道来获取PWM频率,另一个通道获取PWM的占空比。

一个通道两个设置的方法如下:

TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;      // 有效电平高电平
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;     // 直连
TIM_ICInit(TIM3, &TIM_ICInitStruct);

TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling;      // 有效电平低电平
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_IndirectTI;     // 交叉
TIM_ICInit(TIM3, &TIM_ICInitStruct);

一个通道分别有直连和交叉,然后一个是高电平有效,一个是低电平有效。

4.5 配置从模式

我们在前面知道,需要配置个从模式让从模式去执行Reset操作来讲CNT中的值清0,这里只需要使用俩个函数就可以实现,首先是第一个TIM_SelectInputTrigger,这个函数是选择触发器源,在这个图中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以看到在边缘检测电路后有四个信号,分别是是TI1FP1TI2FP2TI3FP3TI4FP4,这几个信号可以触发从模式,我们先用这个定时器的输入通道后,然后通过TIM_SelectSlaveMode函数来设置从模式。

比如说我们上面设置的是TIM3定时器,而且是使用的是TIM3_CH1,那这的设置函数就为:

TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

再比如说,这里是TIM2的CH2,那设置函数为:

TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);

这里的信号TIxFPx和定时器是什么无关,只和通道有关。stm32f103c8t6只能配置4个输入捕获,所以这里的x是从1到4。

4.6 使能定时器

这个就不详细说了,就是使用TIM_Cmd()函数就可以使能了,代码如下:

TIM_Cmd(TIMx, ENABLE);

5.输入捕获测频率和占空比

上面介绍了代码的实现,这里来介绍一下,如果使用输入捕获来获取PWM频率和PWM占空比。

这个的代码实现比较简单,就是设置为输入捕获模式,然后写两个转换函数即可:

#include "ic.h"

void IC_Init()
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct = {0};
    TIM_ICInitTypeDef TIM_ICInitStruct = {0};
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;  // 这里使用的是TIM3_CH2
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    TIM_InternalClockConfig(TIM3);
    
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;
    TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
    
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;       // 直连模式要选择通道2
    TIM_ICInitStruct.TIM_ICFilter = 0xF;
    TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;        // 直连模式
    TIM_ICInit(TIM3, &TIM_ICInitStruct);
    
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;          // 交叉模式要选择通道1
    TIM_ICInitStruct.TIM_ICFilter = 0xF;
    TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling;   // 这里需要和上面设置的有效电平分割开,要不然会出现运行不了的问题,我试过,必须要分开,要不然测试不了。
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_IndirectTI;      // 交叉模式
    TIM_ICInit(TIM3, &TIM_ICInitStruct);
    
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
    
    TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_Get_Freq()
{
    // 转换为频率
    return 1000000 / (TIM_GetCapture2(TIM3) + 1);      // 用输入捕获设置的频率除以标准时钟72MHz后得到1000000,然后用这个频率除以获取的N即可得到频率。
}

uint32_t IC_Get_Pulse()
{
    // 转换为占空比
    return ((TIM_GetCapture1(TIM3) + 1) * 100) / IC_Get_Freq();      // 这个算法是在PWM占空比那说过的。这里不重复
}

这样就可以获取得到PWM的频率和占空比了。

二、编码器接口

1.什么是编码器接口

编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减。

下图是一个正交编码器的图:

img

可以看到,编码器的这个波形,A项和B项的波形是相差90度的,所以这两个波形在一起就可以分正和反了。

2.编码器接口的硬件结构

我们可以用前面学过的输入捕获或者是中断来实现编码器的实现,但是,在stm32f103c8t6中设置了一个编码器接口,我们可以直接使用硬件来实现编码器的测试。

硬件结构如下:

img

可以看到非常的简单,只需要在前面的基础上增加个编译器接口的配置即可。

使用的函数是:

void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);

这个函数就可以设置编码器接口了,首先设置GPIO口,因为我们的这个编码器是需要两个输入的,所以需要设置两个引脚作为输入引脚,然后配置定时器,配置为定时器后需要配置输入捕获,之后就使用上面的函数进行配置编码器接口。

第一个参数TIMx是定时器的编号。

第二个参数TIM_EncoderMode是使用模式,可以选下面这几个模式:

模式解释
TIM_EncoderMode_TI1使用TI1FP1作为编码器设置
TIM_EncoderMode_TI2使用TI2FP2作为编码器设置
TIM_EncoderMode_TI12使用TI1FP1和TI2FP2作为编码器设置

第三个参数TIM_IC1Polarity是选择TI1FP1是正项还是反向,第四个参数TIM_IC2Polarity和第三个参数一样,是选择TI2FP2。

当两个都选择正向或者是反向时,就如下图的时许一样:

img

当TI1有上升电平,TI2还是低电平时,计数器就会自增,当TI2有上升电平,TI1是高电平时,计数器也会自增。

当TI1FP1或者TI2FP2有一个是反项时就会变成下面的时许:

img

在正向时TI1有上升电平,TI2还是低电平时,计数器就会自增,但反向后就是变成自减了。

也就是说当正向的自增转到反向后就会变成自减。

3.软件实现

硬件结构讲完成后,就可以用代码来对其中的功能进行一个实现了。

3.1 时钟开启

这里的开启时钟也就只需要开启GPIO的时钟和定时器的时钟,因为编码器接口也是定时器的一个附加功能,所以只用开启GPIO和定时器的时钟即可,不需要额外的时钟开启。

3.2 GPIO口配置

这里还是需要配置GPIO口,因为需要外部的编码器的输入,这里选择的引脚和定时器的输入捕获和输出比较一样,需要查看引脚的复用功能是不是在TIM定时器的通道上,如果不在那就不能使用。

这里选择的是定时器3的通道1和通道2,对应的引脚是PA6和PA7。

配置代码如下:

GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);

3.3 配置定时器

配置的方法也是和上面一样,打开TIM3定时器,然后配置一系列操作,但这里需要改变一下,预分频器PSC这里就不需要分频,只需要填写1-1即可,1就是不分频,这里是又编码器接口硬件来进行操作即可,然后自动重装寄存器ARR只需要配置最大即可,也不需要TIM指定使用内部时钟,这个时钟也是由编码器接口来提供的。

TIM_TimeBaseTypeDef TIM_TimeBaseStruct = {0};
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_Period = 65536 - 1;
TIM_TimeBaseStruct.TIM_Prescaler = 1 - 1;
TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);

3.4 配置输入捕获

这里需要注意一下,有些东西在这配置时不需要配置,只需要配置两个参数即可,需要配置的有通道TIM_Channel和过滤器的分辨率TIM_ICFilter然后其他的不需要配置。

所以这里需要使用一个函数来为结构体赋一个默认值:

TIM_ICInitTypeDef TIM_ICInitStruct = {0};
TIM_ICStructInit(&TIM_ICInitStruct);

TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0x0F;
TIM_Init(TIM3, &TIM_ICInitStruct);

TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInitStruct.TIM_ICFilter = 0x0F;
TIM_Init(TIM3, &TIM_ICInitStruct);

这里可能会比较好奇为什么那些都不配置,比如说预分频器和有效电平和反向,这是因为在配置编码器接口那就已经配置好了的,不需要我们再进行配置,编码器接口会为这个输入捕获一个时钟,所以就不需要分频了,然后反向也是,也是那一个函数就可以配置好了的。

3.5配置编码器接口

这里就使用上面介绍的那个函数即可配置:

TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

这里我都设置的是不反向,是为了方便。

3.6 使能定时器

最后使能一下定时器就可以了,使能方法之前介绍了很多遍,这里就不再拉出代码了,下面完整代码中有。

3.7 完整代码

这里为了方便,我把完整代码贴出来:

void Encoder_Init()
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct = {0};
    TIM_ICInitTypeDef TIM_ICInitStruct = {0};
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStruct.TIM_Period = 65536 - 1;
    TIM_TimeBaseStruct.TIM_Prescaler = 1 - 1;
    TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
    
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStruct.TIM_ICFilter = 0x0F;
    TIM_ICInit(TIM3, &TIM_ICInitStruct);
    
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
    TIM_ICInitStruct.TIM_ICFilter = 0x0F;
    TIM_ICInit(TIM3, &TIM_ICInitStruct);
    
    TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    
    TIM_Cmd(TIM3, ENABLE);
}

总结

通用定时器的相关操作就介绍完成了,后面有机会的话给大家介绍一下高级定时器,高级定时器可以操作三项无刷电机,等后面有时间我做一个无人机会使用到高级定时器。

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

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

相关文章

JDK 1.8从下载、安装、配置、以及检查是否安装成功,最详细教学教程

参考&#xff1a; JDK1.8下载、安装和环境配置教程(2024年6月5日)-CSDN博客 以下所有步骤&#xff0c;jjycheng作者亲测,所以截图是我自己截取的&#xff0c;和原文略有不同。这也是为什么我可耻的选择“原创”的原因。。。哈哈。。。 一、下载安装包 链接&#xff1a;https:/…

pycharm安装与配置Pyqt5

pycharm安装与配置Pyqt5 1、创建项目、虚拟环境 打开pycharm&#xff0c;File->New Project 2、安装pyqt5库 在pycharm下方Terminal终端窗口输入&#xff1a; pip install PyQt5 -i https://pypi.douban.com/simple pip install PyQt5-tools -i https://pypi.douban.c…

【C++】简约与清晰的编程艺术

C编程的艺术&#xff1a;简约与清晰的实践之道 一、基础之美&#xff1a;基本类型与数据结构的力量二、函数与库类的艺术三、简约与清晰的实践之道 在C这一既古老又充满活力的编程语言世界里&#xff0c;程序员们常常面临着一个重要的选择&#xff1a;是追求代码的极致抽象与封…

【Elasticsearch】Elasticsearch的分片和副本机制

文章目录 &#x1f4d1;前言一、分片&#xff08;Shard&#xff09;1.1 分片的定义1.2 分片的重要性1.3 分片的类型1.4 分片的分配 二、副本&#xff08;Replica&#xff09;2.1 副本的定义2.2 副本的重要性2.3 副本的分配 三、分片和副本的机制3.1 分片的创建和分配3.2 数据写…

发送邮件API接口的安全性保障措施有哪些?

发送邮件API接口的性能如何评估&#xff1f;API接口的使用方法&#xff1f; 发送邮件API接口已经成为了许多应用和服务的核心功能之一。确保发送邮件API接口的安全性对于保护用户隐私和数据完整性至关重要。AokSend将详细探讨发送邮件API接口的安全性保障措施。 发送邮件API接…

查找算法:线性查找,golang实现

目录 前言 线性查找 代码示例 1. 算法包 2. 线性查找代码 3. 模拟程序 4. 运行程序 循环次数 假如目标值正好在数组中的第一位 假如目标值正好在数组中的第五位 假如目标值正好在数组中的最后一位 假如目标值不在数组中 线性查找的思想 1. 顺序遍历 2. 比较 3.…

使用GPT-4插件增强LLM的功能

文章目录 GPT-4插件概述插件清单OpenAPI规范描述GPT-4插件 尽管包括GPT-4在内的LLM在各种任务上都现出色,但它们仍然存在面有的局限性。比如,这些模型只能从训练数据中学习,这些数据往往过时或不造用于特定的应用。此外,它们的能力仅限于文本生成。我们还发现,LLM不适应于…

人工智能深度学习系列—深度学习中的边界框回归新贵:GHM(Generalized Histogram Loss)全解析

文章目录 1. 背景介绍2. Loss计算公式3. 使用场景4. 代码样例5. 总结 1. 背景介绍 目标检测作为计算机视觉领域的核心技术之一&#xff0c;其精确度的提升一直是研究者们追求的目标。边界框回归作为目标检测中的关键步骤&#xff0c;其性能直接影响到检测的准确性。本文将详细…

“火炬科企对接”先进计算产业推进会 | 麒麟信安受邀参加,并签署开源生态合作协议

7月30日&#xff0c;“火炬科企对接”先进计算产业推进会在长沙隆重召开。大会由工业和信息化部火炬高技术产业开发中心、湖南省科学技术厅、湖南省工业和信息化厅、湖南湘江新区管理委员会、中国邮政储蓄银行联合举办。麒麟信安与来自国内先进计算领域的专家学者&#xff0c;2…

25考研数据结构复习·7.3树形查找

目录 二叉排序树 平衡二叉树 平衡二叉树的删除 红黑树 红黑树的插入 红黑树的删除 二叉排序树 二叉排序树的定义 &#x1f469;‍&#x1f4bb; 左子树结点值 < 根节点值 < 右子树结点值默认不允许两个结点的关键字相同查找操作 从根节点开始&#xff0c;目标值更…

用 VS Code 开发 uni-app 项目

文章目录 1.为什么选择 VS Code &#xff1f;2.安装相关插件2.1 安装uni-app插件2.2 安装ts类型检验 3.在微信小程序中运行 1.为什么选择 VS Code &#xff1f; ⚫ HbuilderX 对 TS 类型支持暂不完善 ⚫ VS Code 对 TS 类型支持友好&#xff0c;同时VS Code 也是我们熟悉的编辑…

移远通信LTE-A模组EM060K-GL成为ChromeOS准入供应商

近日&#xff0c;全球领先的物联网整体解决方案移远通信宣布&#xff0c;其先进的LTE-A模组EM060K-GL已进入谷歌Chrome OS准入供应商名录&#xff0c;后续将作为候选模组用于搭载Chrome OS系统的笔记本电脑中&#xff0c;为其提供“始终在线”的网络连接体验。这一重要里程碑彰…

禾川Q1系列PLC通过ModbusRtu控制E600变频器

一、新建CodeSys工程项目 新建工程可以选择【File】→【New Project】,也可以直接选择【New Project】两种方式 用户可以选择需要的项目类型,命名项目工程以及存储路径,完成后选择【OK】 选择连接设备【HCQ1-1300-D】(在此之前PC已经安装Q1安装包),选择编程语言,教程示例…

Node.js(4)——模块化

什么是模块化&#xff1f; ComminJS模块是为Node.js打包JavaScript代码的原始方式。Node.js还支持浏览器和其他JavaScript运行时使用的ECMAScript标准。在Node.js中&#xff0c;每个文件都被视为一个单独的模块。 CommonJS标准 使用&#xff1a; 导出&#xff1a;moudule.exp…

一六零、云服务器开发机配置zsh

切换shell 在Linux中默认使用/bin/bash&#xff0c;在用户创建时&#xff0c;会自动给用户创建用户默认的shell。默认的shell就是/bin/bash。要修改shell将其设置为/bin/ksh&#xff0c;有两种方法方法 # 方法一: chsh -s /bin/ksh chsh -s /bin/zsh # 方法二: usermod -s /b…

基于CIFAR10的图片识别

前言 这个算是重拾一个古早项目了&#xff0c;当时搭建神经网络对CIFAR10数据集进行训练以后&#xff0c;对训练好的网络进行了验证&#xff0c;可以参考这笔者的两篇博客&#xff1a; pytorch 模型训练&#xff08;以CIFAR10数据集为例&#xff09;_pytorch cifar10-CSDN博客…

CAPL使用结构体的方式组装一条DoIP车辆声明消息(方法2)

在文章CAPL使用结构体的方式组装一条DoIP车辆声明消息(方法1)中,我们声明一个结构体DoIPMessage表示完整的DoIP车辆声明消息: 上半部分是DoIP报头通用部分(也就是所有类型的DoIP消息都有的),而payload是每个类型的DoIP消息独有的部分,对于车辆声明消息来说,用另一个结…

Golang | Leetcode Golang题解之第309题买卖股票的最佳时机含冷冻期

题目&#xff1a; 题解&#xff1a; func maxProfit(prices []int) int {if len(prices) 0 {return 0}n : len(prices)f0, f1, f2 : -prices[0], 0, 0for i : 1; i < n; i {newf0 : max(f0, f2 - prices[i])newf1 : f0 prices[i]newf2 : max(f1, f2)f0, f1, f2 newf0, n…

【划分字母区间】python刷题记录

R3-贪心篇. 思路&#xff1a; 1.使用dict记录S中每个字符出现的最后位置 2.从s[0]开始&#xff0c;j该元素的dict值&#xff0c;遍历s&#xff0c;如果出现s[i]>j&#xff0c;就需要更新j的值 3.i到j了&#xff0c;那就下一段 class Solution:def partitionLabels(self,…

「Unity3D」自动布局LayoutElement、ContentSizeFitter、AspectRatioFitter、GridLayoutGroup

布局元素与布局控制器 布局元素实现ILayoutElement接口&#xff0c;布局控制器实现ILayoutController接口&#xff0c;后者根据前者的属性控制具体布局——有些布局控制器也是布局元素&#xff0c;即同时实现这两个接口&#xff0c;如LayoutGroup。 public interface ILayout…