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

【Let‘s do第四期】DIY液体流量检测仪

DIY液体流量检测仪

  • 开箱
    • 前言
    • 实物
    • 主控板
    • 流量传感器
    • 继电器模块
    • 抽水泵
  • 过程
    • 点亮板载LED
    • 移植OLED程序
    • 接线
    • 驱动模块
    • 流量检测
    • 裸机代码
    • 使用FreeRTOS
      • 任务说明
      • 任务函数
      • 头文件
  • 成果

开箱

前言

非常有幸参加EEPW举办的【Let’s do第四期】DIY液体流量检测仪的活动。
我参加了一次免费的DIY活动,本次DIY通过小抽水泵和继电器实现流量控制,结合霍尔效应传感器,准确测量液体的传播时间,实现瞬时流量和累计流量的监测。该技术广泛运用于咖啡机、饮水机等定量取水场景~

实物

收到东西已经非常久了,今天才来发开箱贴,首先看一下我的全部配套的东西。

首先是两张集体照:
在这里插入图片描述

在这里插入图片描述

介绍一下我购买的物料清单:

  • NUCLEO-64 STM32F103RB EVAL BRD核心板1块
  • MINI SUBMERSIBLE WATER PUMP 抽水泵一个
  • GRAVITY DIGITAL 5A RELAY MODULE 继电器模块一个
  • EVAL BOARD FOR LM1117 降压模块一个
  • SENSOR FLOW 0.3-6LPM ML G18" 流量传感器一个

主控板

主控板介绍:NUCLEO-64 STM32F103RB核心板采用的主控芯片是STM32F103RBT6,系统频率:72MHz,RAM:20KB、Flash:128KB,另外,核心板板载有ST-Link调试器,方便烧录程序开发调试。可支持Keil、IAR、STM32CubeIDE、AuduinoIDE等工具进行开发。图片如下

在这里插入图片描述

流量传感器

  • YF-S401
  • 感应范围:0.3 ~ 6 LPM
  • 描述:5~12V供电,由塑料阀体 、水流转子组件和霍尔传感器组成
  • 工作原理:当水通过水流转子组件时,磁性转子转动并且转速随着流量变化而变化,霍尔传感器输出相应脉冲信号,反馈给控制器,控制器通过触发的脉冲信号数获得水流量。

在这里插入图片描述

继电器模块

在这里插入图片描述

  • 描述:3.3~5V供电,实测高电平导通

抽水泵

  • 描述:5V供电,功率0.91W
  • 防水等级:IP68

在这里插入图片描述

本次DIY活动可以学习到

  1. IIC 通讯协议的了解
  2. OLED 显示信息
  3. 硬件接线继电器控制抽水泵
  4. 软件环境搭建与硬件测试
  5. 流量计实现对液体的测量

过程

点亮板载LED

拿到新的开发板,第一个任务就是点亮板载LED,励志成为点灯大师!

板载自带了stlink,不需要额外的烧录器了,需要一根mini-B线连接电脑和开发板烧录程序。

使用CubeMX快速配置一下工程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

然后设置工程路径和工程名称,这里我使用Keil-MDK开发

在这里插入图片描述

参照原理图

在这里插入图片描述

板载的LED是PA5引脚,配置引脚PA5为输出模式

在这里插入图片描述

点击Generate Code 生成工程。

在while(1)里写这两段代码即可成为点灯大师!

HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // LED
Hal_Delay(500);

现象就是LED以1S为间隔闪烁一次。

移植OLED程序

我移植了之前用的程序,具体的代码会放在Gitee里,链接在文章最后

在这里插入图片描述

先来个效果展示

在这里插入图片描述

汉字显示:汉字取模步骤:软件PCtoLCD2002

  1. 模式:字符模式
  2. 配置取模方式:点击选项按钮或者齿轮按钮
    点阵格式:阴码(正常色显示)阳码(反色显示)
    取模方式:列行式
    取模走向:逆向(低位在前)
    输出数制:十六进制
    自定义格式:C51格式,把行前缀的’{‘和行后缀的’}'删掉
    点击确定,然后输入想取模的汉字,复制下面的十六进制代码到程序里即可

接线

接线其实是比较简单的,用电池或者充电头12V DC输入给降压模块,降压模块输出5V和3.3V

OLED供电3.3V,PC6 - SCL、PC8 - SDA
代码的宏定义如下所示:

#define OLED_PROT GPIOC
#define OLED_PIN_SCL GPIO_PIN_6
#define OLED_PIN_SDA GPIO_PIN_8

抽水泵是5V供电,尽量不用板载USB的5V,抽水泵的两根线,一根接到降压模块的GND,另一根接到继电器的COM口,然后再拿一根线连接继电器的NO和降压模块输出的5V

继电器的另一端有三根线,供电接3.3~5V,实测高电平导通,第三根是信号线,我接了PC10

  • 继电器在不通电或者没导通情况下COM端默认打到NC即相通,继电器开关导通后COM和NO打通,COM和NC断开。

流量传感器接5V供电,信号线接PC2,使用外部中断检测脉冲

PC13是板载的按键,输入模式

对应的CubeMX引脚配置
在这里插入图片描述

驱动模块

接线成功后,先测试是否能驱动继电器

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_10); //继电器
Hal_Delay(1000);	//延时时间尽量长,不要频繁开关继电器

在while(1)里测试这段代码,如果继电器1S吸合,1S断开,那就是驱动成功了!

检测外部中断的脉冲信号 - 检测流量传感器的数据

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_2)
    {
        flow_cnt ++;
    }
}

流量检测

流量检测的思路

累积流量:用按键控制继电器的开关,在OLED上显示脉冲计数,实际测试时候,打开继电器,抽水1000ml,得到一个计数值x1,多次测量x2,x3,取x1,x2,x3的平均值x,x/1000 = 每毫升水的计数值,这个数值可以定义成一个宏,供电电压不同,这个数值不同,数值需要自己实测!!!

#define CNT_Flow_1ML 355.357f

瞬时流量:我取的20ms的计数值,计数值*50 = 1S的计数值,然后用这个值除以CNT_Flow_1ML,得到1S的流量,单位是ml/S

裸机代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "OLED.h"
#include "myoldkey.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

uint32_t OLED_Tick;
uint32_t Func_Tick;
uint32_t flow_cnt;
uint32_t key_tick;
float Moment_Flow = 1.2f;		// 瞬间流量
float Cumulative_Flow = 0.0f;	// 累计流量

int8_t textnum;

uint16_t TargetFlow = 0;    //目标水量 - 100ML
uint32_t Target_CNT = 0;

void OLED_Show_Func(void);
void JDQ_Func(void);
void key_proc(void);

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

// CNT:164157 --- 650ML


#define CNT_Flow_1ML 355.357f
//#define CNT_Flow_1ML 533.295f
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  
    OLED_Init();
    OLED_Clear();
    OLED_ShowChinese(8*6, 0, "得捷");

    OLED_Printf(0, 16, OLED_8X16, "   Waiting... ");
    OLED_Update();
    HAL_Delay(1800);
    OLED_Clear();
    
    HAL_TIM_Base_Start_IT(&htim3);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // 继电器 off
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    OLED_Show_Func();
//    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);    // 继电器 on
//    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);    // 继电器 off
    JDQ_Func();
    key_proc();
      
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

void OLED_Show_Func(void)
{
    if (uwTick - OLED_Tick <= 200)
        return;
    OLED_Tick = uwTick;
    
    OLED_Clear();
    
    char tempStr[20];
    
    OLED_ShowChinese(8 * 2, 16 * 0, "瞬间流量");
    OLED_ShowChar(8 * 10, 16 * 0 + 8, ':', OLED_6X8);	// :

//    sprintf(tempStr, "%d  %d ", flow_cnt, TargetFlow);
    sprintf(tempStr, " %.1f mL/s %d ", Moment_Flow, TargetFlow);
    OLED_Printf(8 * 4, 16 * 1 + 5, OLED_6X8, tempStr);

    OLED_ShowChinese(8 * 2, 16 * 2, "累计流量");
    OLED_ShowChar(8 * 10, 16 * 2 + 8, ':', OLED_6X8);	// 显示:
    
    Cumulative_Flow = (float)flow_cnt / CNT_Flow_1ML;
    
    sprintf(tempStr, " %.2f mL", Cumulative_Flow);
    OLED_Printf(8 * 4, 16 * 3 + 5, OLED_6X8, tempStr);

    OLED_Update();
}

void JDQ_Func(void)
{
    static uint32_t Last_CNT;   //上次计数
    static uint32_t error_Flow;  //前后两次的流量差
    
    if (uwTick - Func_Tick <= 20)   //如果要修改这个20ms,就需要重新计算瞬间流量
        return;
    Func_Tick = uwTick;

    Target_CNT = TargetFlow*CNT_Flow_1ML;
    
    if (flow_cnt <= TargetFlow*CNT_Flow_1ML)    // 当前小于目标,未到,开继电器
    {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // 继电器 on
    }
    else if (flow_cnt >= TargetFlow*CNT_Flow_1ML)    //如果当前计数值 >= 目标计数值,关闭继电器
    {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // 继电器 off
    }
    
    error_Flow = flow_cnt - Last_CNT;   //前后两次的流量差 20ms
    Moment_Flow = (float)(error_Flow * (1000/20)) / CNT_Flow_1ML;  //计算瞬间流量  // error_Flow * (1000/20) === 20ms的流量*50, 等于1S的流量
    
    Last_CNT = flow_cnt;
}

void key_proc(void)
{
    if (uwTick - key_tick <= 10)
        return;
    key_tick = uwTick;
    
    if (Key[1].short_flag == 1)
    {
        Key[1].short_flag = 0;
        TargetFlow += 100;                      //目标值+=100
//        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_10); //继电器
//        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // 继电器 on
    }
}


void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_2)
    {
        flow_cnt ++;
    }
}


/* 定时器回调函数 1ms */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static uint32_t tim3_cnt;
    static uint8_t keyscan_cnt;
    
    if (htim->Instance == TIM3)
    {
        if (tim3_cnt ++ >= 500)
        {
            // LED T
            HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // LED
            tim3_cnt = 0;
        }
        
        if (keyscan_cnt ++ >= 20)
        {
            key_serv_long();
            keyscan_cnt = 0;
        }
    }
}


/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

使用FreeRTOS

任务说明

一共创建了四个任务,CubeMX创建的默认任务,用来当做LED指示灯,代表系统正在运行中,系统卡死则LED不再闪烁。

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // LED
    vTaskDelay(500);
  }
  /* USER CODE END StartDefaultTask */
}

手动创建按键任务,继电器任务,OLED任务

TaskHandle_t xTaskOLED_Handle;  // OLED显示任务句柄
TaskHandle_t xTaskKey_Handle;   // 按键任务句柄
TaskHandle_t xTaskRelay_Handle;   // 继电器任务句柄
 
BaseType_t xRelay_Handle  = xTaskCreate(Relay_Task, "Relay_Task", 128, NULL, (UBaseType_t)osPriorityNormal, &xTaskRelay_Handle);
BaseType_t xKey_Handle  = xTaskCreate(KEY_Task, "KEY_Task", 128, NULL, (UBaseType_t)osPriorityNormal + 1, &xTaskKey_Handle);
BaseType_t xOLED_Handle = xTaskCreate(OLED_Show_Func, "OLED_Task", 256, NULL, (UBaseType_t)osPriorityNormal + 2, &xTaskOLED_Handle); 

创建一个软件定时器,10ms扫描一次按键,刷新按键任务的键值

  xTimerKey = xTimerCreate(
      "KeyScanTimer",                           // 定时器名称
      (10),                                     // 定时器周期,10 ms
      pdTRUE,                                   // 自动重装
      (void *)0,                                // 定时器 ID,这里没有特殊用途
      (TimerCallbackFunction_t)vScanKeyCallback // 定时器到期时调用的函数
  );

任务函数

完整代码可以见最下方的Gitee链接

#include "TaskFunction.h"

TimerHandle_t xTimerKey;

uint32_t flow_cnt = 0;
uint8_t OLED_View_Flag = 0; //OLED界面切换FLAG

float Moment_Flow = 0.0f;		// 瞬间流量
float Cumulative_Flow = 0.0f;	// 累计流量

uint16_t TargetFlow = 0;    //目标水量 - 100ML
uint32_t Target_CNT = 0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_2)
    {
        flow_cnt ++;
    }
}

// 软件定时器-扫描按键-回调函数
void vScanKeyCallback(TimerHandle_t xTimer)
{
// 定时 10ms获取一次按键键值
//    static unsigned char led;
    key_serv_double();

    // 测试软件定时器是否正常工作

//    if (++led >= 100)   // 1S
//    {
//        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // LED
//        led = 0;
//    }
}

void OLED_Show_Func(void *params)
{
    OLED_Init();
    OLED_Clear();
    OLED_ShowChinese(8*6, 0, "得捷");

    OLED_Printf(0, 16, OLED_8X16, "   Waiting... ");
    OLED_Update();
    vTaskDelay(1800);
    OLED_Clear();

    for(;;)
    {
        char tempStr[20];
        
        if (OLED_View_Flag == 0)
        {
            OLED_ShowChinese(8 * 2, 16 * 0, "瞬间流量");
            OLED_ShowChar(8 * 10, 16 * 0 + 8, ':', OLED_6X8);	// 显示:

        //    sprintf(tempStr, "%d  %d ", flow_cnt, TargetFlow);
            sprintf(tempStr, " %.1f mL/s %d ", Moment_Flow, TargetFlow);
            OLED_Printf(8 * 4, 16 * 1 + 5, OLED_6X8, tempStr);

            OLED_ShowChinese(8 * 2, 16 * 2, "累计流量");
            OLED_ShowChar(8 * 10, 16 * 2 + 8, ':', OLED_6X8);	// 显示:
            
            Cumulative_Flow = (float)flow_cnt / CNT_Flow_1ML;
            
            sprintf(tempStr, " %.2f mL", Cumulative_Flow);
            OLED_Printf(8 * 4, 16 * 3 + 5, OLED_6X8, tempStr);
        }
        else
        {
            OLED_ShowChinese(8*6, 16*1, "得捷");
            
            sprintf(tempStr, "Target:%d ", TargetFlow);
            OLED_Printf(8 * 4, 16 * 2 + 5, OLED_6X8, tempStr);
        }

        OLED_Update();
        vTaskDelay(100);
    }
}


void KEY_Task(void *argument)
{
    xTimerStart(xTimerKey, 0);
    KEY_GPIO_Init(); // 按键引脚的初始化

    for(;;)
    {
        if (Key[1].short_flag == 1)
        {
            TargetFlow += 100;      //目标值+=100
            Key[1].short_flag = 0;
        }

         if (Key[1].long_flag == 1)
         {
             TargetFlow += 10;

//             Key[1].long_flag = 0;
         }
         if (Key[1].double_flag == 1)
         {
            OLED_Clear();
            OLED_View_Flag++;          // 界面的切换
            if (OLED_View_Flag >= 2)    // 2个界面
                OLED_View_Flag = 0;
             Key[1].double_flag = 0;
         }

        vTaskDelay(100);
    }
}

void Relay_Task(void *argument)
{
    static uint32_t Last_CNT;   //上次计数
    static uint32_t error_Flow;  //前后两次的流量差

    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // 默认 继电器 off
//    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);    // 继电器 on
    
    for(;;)
    {
        Target_CNT = TargetFlow*CNT_Flow_1ML;
        
        if (flow_cnt <= TargetFlow*CNT_Flow_1ML)    // 当前小于目标,未到,开继电器
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // 继电器 on
        }
        else if (flow_cnt >= TargetFlow*CNT_Flow_1ML)    //如果当前计数值 >= 目标计数值,关闭继电器
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // 继电器 off
        }
        
        error_Flow = flow_cnt - Last_CNT;   //前后两次的流量差 20ms
        Moment_Flow = (float)(error_Flow * (1000/20)) / CNT_Flow_1ML;  //计算瞬间流量  // error_Flow * (1000/20) === 20ms的流量*50, 等于1S的流量
        
        Last_CNT = flow_cnt;
        vTaskDelay(20); // 不能修改这个20ms,需要和计算公式同步修改    
    }
}

头文件

#ifndef __TASKFUNCTION_H
#define __TASKFUNCTION_H

#include "stm32f1xx_hal.h"
#include "OLED.h"
#include "myoldkey.h"

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

#define CNT_Flow_1ML 355.357f

extern TimerHandle_t xTimerKey;
void vScanKeyCallback(TimerHandle_t xTimer); // 软件定时器-扫描按键-回调函数

void OLED_Show_Func(void *params);  // OLED显示任务
void KEY_Task(void *params);        // 按键任务
void Relay_Task(void *argument);    // 继电器任务
#endif

成果

  • 演示视频:
  • 代码:

在这里插入图片描述


http://www.kler.cn/a/515083.html

相关文章:

  • 实战经验:使用 Python 的 PyPDF 进行 PDF 操作
  • 高并发压力测试
  • 一文大白话讲清楚webpack基本使用——11——chunkIds和runtimeChunk
  • 基于微信小程序的健身管理系统设计与实现(LW+源码+讲解)
  • Saas Paas Iaas服务区别
  • U3D的.Net学习
  • Apache Hive3定位表并更改其位置
  • 【计算机网络】NAT应用
  • 如何保护 Flask API 的安全性?
  • javaSE.浮点类型
  • 生成对抗网络(GAN)入门与编程实现
  • LeetCode:53. 最大子序和
  • 初始Transformer
  • C++ STL(8)map
  • 正则表达式的艺术:轻松驾驭 Python 的 re 库
  • 智能鞋利用机器学习和深度学习技术进行患者监测和步态分析的演变与挑战
  • Roland 键盘合成器接声卡(福克斯特/雅马哈)声音小/音质异常的问题
  • insight在线需求分析系统概要介绍
  • redis离线安装部署详解(包括一键启动)
  • 为什么要申请专利
  • LiveBench:AI 模型基准测试与评估工具解析与实战指南
  • 复位信号的同步与释放(同步复位、异步复位、异步复位同步释放)
  • 【网络协议】【http】【https】TLS解决了HTTP存在的问题-加密通信+摘要,数字签名+CA证书
  • HTTP post请求工具类
  • 博客之星2024年度总评选——我的年度创作回顾与总结
  • Django项目的创建及运行——Django学习日志(一)