【STM32】综合练习——智能风扇系统

news2025/7/11 1:35:12

目录

0 前言

1 硬件准备

2 功能介绍

3 前置配置

3.1 时钟配置

3.2 文件配置

4 功能实现 

4.1 按键功能

4.2 屏幕功能

4.3 调速功能

4.4 倒计时功能

4.5 摇头功能

4.6 测距待机功能


0 前言

由于时间关系,暂停详细更新,本文章中,只会记录重要代码,关于cubmx的配置以及引脚配置,请自行下载文件配置

【免费】基于STM32的多功能风扇资源-CSDN文库


1 硬件准备

STM32F103C8T6 * 1

面包板 * 1

OLED显示屏(SSD131590) * 1

RGB三色全彩LED模块 * 1

SG90舵机 * 1

HC-SR04超声波模块 * 1

130直流电机 * 1

风扇头 * 1

L298N电机驱动模块 * 1

直插2脚微动按键 * 2

USB转TTL模块-CH340模块 * 1

ST-LINK V2 * 1

杜邦线 (公对公、公对母、母对母)

跳线


2 功能介绍

(1)完成手动调节(按键)调节风扇三档转速(档位转速分别为30%、50%、80%)
(2)实现按键定时功能(短按一次时间加5秒,长按后倒计时开始,倒计时结束后风扇停止转动)
(3)实现风速不同档位显示,一档风速亮白灯,二档风速亮蓝灯,三档风速亮红灯,并通过OLED屏幕显示当前灯的颜色和定时时间(用英文和数字)
(4)实现通过串口显示当前风速
(5)以超声波为总开关控制系统运作(在20厘米内系统才可工作)
(6)利用舵机实现风扇摇头功能,并通过按键进行控制


3 前置配置

3.1 时钟配置

 设置高速外部时钟:晶振

设置时钟频率为72Mhz 


3.2 文件配置

修改文件名称以及选择IDE:MDK-ARM 

为每一个外设单独生成一对.c/.h文件(模块化,方便管理)


4 功能实现 

4.1 按键功能

在interrupt.c中使用回调函数判断定时器2,进行按键扫描(按键具体的功能不在此文件中) 

// interrupt.c

if(htim == &htim2)	// button
	{
		keys[0].clickState = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6);	// left BUTTON
		keys[1].clickState = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);	// right BUTTON
		
		for(int i=0; i<=1; i++)
		{
			switch(keys[i].stage)
			{
				case 0:
				{
					//judge click
					if(keys[i].clickState == 0) keys[i].stage = 1; //go next stage
				}
				break;
				case 1:
				{
					if(keys[i].clickState == 0)
					{
						// is true click
						// clear time
						keys[i].pressTime = 0;
						// go next stage
						keys[i].stage = 2;
					}
				}
				break;
				case 2:
				{
					if(keys[i].clickState == 1)	// release click
					{
						//judge click which button and its type
						if(keys[i].pressTime < 30){
							// short click
							chooseButton(i, click);
						} else {
							// long click
							chooseButton(i, longClick);
						}
						// reset stage 
						keys[i].stage = 0;
					} else {	// still click
						// time ++
						keys[i].pressTime++;
					}
				}
				break;
			
			}
		
		}
	}

按键具体的功能被拆分在了buttonFunciton.c中

从上到下依次为:

按键1的单击(调速)、按键1的长按(摇头)

按键2的单击(计时器加5)、按键2的长按(倒计时开始)

#include "buttonFunction.h"

// to judge which button is press down
void chooseButton(uint8_t key, uint8_t type){

	switch(key){
		case 0:	// button 1
		{
			if(type == 0){
				// click —— Toggle Speed Mode and Oled Update
					
				//WindSpeed
				speedLevel++;
				speedLevel %= 4;
				SetWindSpeed();
				UsartSpeed();
				HomePage();
				
			} else if (type == 1){
				// long click —— Toggle Shaking Mode
				
				isShake = !isShake;
				if(isShake){
					HAL_TIM_Base_Start_IT(&htim1);
					shakeIsBegin = 1;
				} else {
					HAL_TIM_Base_Stop_IT(&htim1);
					shakeIsBegin = 0;
				}
				
			}
		}
		break;
		case 1:	//	button 2
		{
			if(type == 0){
				// click —— Count Down Number Add and Oled Update
				
				timeCount += 5;
				HomePage();
				
				
			} else if (type == 1){
				// long click	—— Count Down Start
				
				if(timeCount > 0){
					HAL_TIM_Base_Start_IT(&htim4);
					isBegin = 1;
				}
				
			}
		}
		break;
	}
}

4.2 屏幕功能

OLED使用Keysking的模块文件,这里就不展示了,使用方法见【STM32入门教程-2024】第14集 如何在OLED屏幕上挥毫_哔哩哔哩_bilibili

// page.c
#include "page.h"


// ——————————————Init—————————————————
void PageInit(void){
	HAL_Delay(20); // 单片机启动比OLED上电快,需要延迟等待一下
  OLED_Init(); // 初始化OLED
}

// ——————————————View——————————————————
void CopyrightPage(void) {
	OLED_NewFrame();
	OLED_DrawImage(5,1, &logoImg, OLED_COLOR_NORMAL);
	OLED_PrintString(85, 4, "创客", &font16x16, OLED_COLOR_NORMAL);
	OLED_PrintString(85, 24, "中心", &font16x16, OLED_COLOR_NORMAL);
	OLED_PrintString(85, 44, "出品", &font16x16, OLED_COLOR_NORMAL);
	OLED_ShowFrame();
}

void HomePage(void){
	OLED_NewFrame();
	HomePageTitle();
	HomePageSpeedLight();
	if(timeCount > 0){
		HomePageCountDown();
	}
	OLED_ShowFrame();
}

void SleepPage(void){
		OLED_NewFrame();
		OLED_PrintString(32, 10, "待机中...", &font16x16, OLED_COLOR_NORMAL);
		OLED_PrintString(4, 35, "~(p≧ w≦ q)~", &font12x12, OLED_COLOR_NORMAL);
		OLED_ShowFrame();
}

// ————————————Component————————————————

// Home Title
void HomePageTitle(void){
	OLED_PrintString(32, 10, "智能の扇", &font16x16, OLED_COLOR_NORMAL);
}

// Home Body
void HomePageSpeedLight(void){
	StopAllLight();
	switch(speedLevel){
		case 0:
		{
			OLED_PrintString(50, 30, "STOP", &font16x16, OLED_COLOR_NORMAL);
		}
		break;
		case 1:
		{
			OLED_PrintString(46, 30, "WHITE", &font16x16, OLED_COLOR_NORMAL);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
		}
		break;
		case 2:
		{
			OLED_PrintString(50, 30, "BLUE", &font16x16, OLED_COLOR_NORMAL);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
		}
		break;
		case 3:
		{
			OLED_PrintString(54, 30, "RED", &font16x16, OLED_COLOR_NORMAL);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
		}
		break;
	}
}

// Home Bottom
void HomePageCountDown(void){
	char arr[40];
	sprintf(arr, "%d", timeCount);
	if(timeCount >= 10000){
		OLED_PrintString(46, 50, arr, &font16x16, OLED_COLOR_NORMAL);
	} else if(timeCount >= 1000){
		OLED_PrintString(50, 50, arr, &font16x16, OLED_COLOR_NORMAL);
	} else if(timeCount >= 100){
		OLED_PrintString(54, 50, arr, &font16x16, OLED_COLOR_NORMAL);
	} else if(timeCount >= 10){
		OLED_PrintString(58, 50, arr, &font16x16, OLED_COLOR_NORMAL);
	} else {
		OLED_PrintString(62, 50, arr, &font16x16, OLED_COLOR_NORMAL);
	}
}

// Stop All Light
void StopAllLight(void){
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
}
// page.h
#ifndef __PAGE_H__
#define __PAGE_H__

#include "main.h"
#include "string.h"
#include "oled.h"
#include "stdio.h"
#include "stdbool.h"

// ——————————————Internal Api————————————————
// view
void PageInit(void);
void CopyrightPage(void);
void HomePage(void);
void SleepPage(void);

// Component
void HomePageTitle(void);
void HomePageSpeedLight(void);
void HomePageCountDown(void);
void StopAllLight(void);
// ——————————————External Api————————————————
// windSpeed
extern uint8_t speedLevel;
extern uint8_t tempSpeedLevel;
// countDown
extern uint16_t timeCount;
// ——————————————————————————————————————————
#endif

4.3 调速功能

// windSpeed.c
#include "windSpeed.h"

void SetWindSpeed(void){
	switch(speedLevel){
		case 0:
		{
			__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, StopSpeed);
		}
		break;
		case 1:
		{
			__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, LowSpeed);
		}
		break;
		case 2:
		{
			__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, MidSpeed);
		}
		break;
		case 3:
		{
			__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, HighSpeed);
		}
		break;
	}
}


void UsartSpeed(void){
	
	sprintf(arr, "当前档位为:%d", speedLevel);
	HAL_UART_Transmit(&huart1, (uint8_t *)arr, sizeof(arr), HAL_MAX_DELAY);

}
// windSpeed.h
#ifndef __WINDSPEED_H__
#define __WINDSPEED_H__

#include "main.h"
#include "tim.h"
#include "usart.h"
#include <stdio.h>


// ————————————Internal Api——————————————————

#define StopSpeed 0
#define LowSpeed 300
#define MidSpeed 500
#define HighSpeed 800
uint8_t speedLevel = 0;
uint8_t tempSpeedLevel = 10;
void SetWindSpeed(void);
void UsartSpeed(void);
char arr[99];

// ————————————External Api——————————————————

// 0

// ——————————————————————————————————————————

#endif

4.4 倒计时功能

// interrupt.c
	if(htim == &htim4){	// Time Count Down
		if(timeCount > 1)
		{
			timeCount--;
		} else {
			timeCount--;
			speedLevel = 0;
			SetWindSpeed();
			HAL_TIM_Base_Stop_IT(&htim4);
			isBegin = 0;
			HAL_TIM_Base_Stop_IT(&htim1);
			shakeIsBegin = 0;
			UsartSpeed();
		}
		HomePage();
	
	}

 倒计时功能主要在interrupt中实现,此处只声明了个全局变量 

// countDown.c
#include "countDown.h"
// countDown.h
#ifndef __COUNTDOWN_H__
#define __COUNTDOWN_H__

#include "main.h"
#include "stdbool.h"
// ————————————Internal Api——————————————————

uint16_t timeCount;
bool isBegin = 0;

// ————————————External Api——————————————————

// 0

// ——————————————————————————————————————————

#endif

4.5 摇头功能

舵机教程:【STM32】动画讲解输入捕获 并实现超声波测距_哔哩哔哩_bilibili 

// shake.c
#include "shake.h"

int shakeNumber = 1500;	//500——2500 duty
bool shakeMode = 0;

void shakeApi(void){
	if(shakeMode == 0){
		// forward
		if(shakeNumber < 2500){
			shakeNumber += shakeSpeed;
		} else {
			shakeMode = 1;
		}
		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, shakeNumber);
	} else {
		// reverse
		if(shakeNumber > 500){
			shakeNumber -= shakeSpeed;
		} else {
			shakeMode = 0;
		}
		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, shakeNumber);
	}


}
// shake.h
#ifndef __SHAKE_H__
#define __SHAKE_H__

#include "main.h"
#include "tim.h"
#include "stdbool.h"

// ————————————Internal Api——————————————————

#define shakeSpeed 10	// 5(slow) 10(normal) 20(fast) 100(very fast)
void shakeApi(void);
bool shakeIsBegin = 0;

// ————————————External Api——————————————————

// 0

// ——————————————————————————————————————————


#endif

启用中断:

// interrupt.c
if(htim == &htim1){ // Shake
	shakeApi();
}

4.6 测距待机功能

为了使系统正常工作时(20cm以内) ,能继续进行上一次的数据(如倒计时从上一次离开开始,继续倒计时),这里并没有直接修改存储该数据的变量,而是直接将所有功能暂停(具体实现见StopAll函数),恢复时再读取存储数据的变量

// ultrasound.c
#include "ultrasound.h"

void TriggerUltrasound(void){

	// Send trigger signal
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_SET);
//	HAL_Delay(1);
	for(uint32_t i=0; i<11; i++);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
	// Reset counter
	__HAL_TIM_SET_COUNTER(&htim3, 0);
	// Wait
	HAL_Delay(50);
}


void MeasurementDistance(void){
	timeCountBefore = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1);
	timeCountAfter = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_2);
	distance = (timeCountAfter - timeCountBefore) * 0.034 / 2;
}

void StopAll(void){
	// stop all light
	StopAllLight();
	// stop wideSpeed
	__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 0);
	// stop count down
	HAL_TIM_Base_Stop_IT(&htim4);
	// stop shake
	HAL_TIM_Base_Stop_IT(&htim1);
	// sleep page
	SleepPage();
}

void StartAll(void){
	// start count down
	if(timeCount > 0 && isBegin){
		HAL_TIM_Base_Start_IT(&htim4);
	}
	// start shake
	if(shakeIsBegin){
		HAL_TIM_Base_Start_IT(&htim1);
	}
	// start wideSpeed
	SetWindSpeed();
	// home page - start all light
	HomePage();
}
 
// ultrasound.h
#ifndef __ULTRASOUND_H__
#define __ULTRASOUND_H__

#include "main.h"
#include "tim.h"
#include "stdbool.h"

// ————————————Internal Api——————————————————

uint16_t timeCountBefore;
uint16_t timeCountAfter;
float distance;
void TriggerUltrasound(void);
void MeasurementDistance(void);
void StopAll(void);
void StartAll(void);

// ————————————External Api——————————————————

// page - light
extern void HomePage(void);
extern void SleepPage(void);
extern void StopAllLight(void);
// windSpeed
extern uint8_t speedLevel;
extern void SetWindSpeed(void);
// count down
extern uint16_t timeCount;
extern bool isBegin;
// shake
extern bool shakeIsBegin;
// ——————————————————————————————————————————

#endif

输入捕获中断:

测距思想:一个通道读上升沿,一组的另一个通道读下降沿,并且在读到下降沿的时候进行中断

教程:【STM32】动画讲解输入捕获 并实现超声波测距_哔哩哔哩_bilibili 

// interrupt.c
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){

	if(htim == &htim3 && htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_2){	// ultrasound
		// Measurement Ultrasound Distance
		MeasurementDistance();
//		sprintf(aeee, "%f", distance);
//		HAL_UART_Transmit(&huart1, (uint8_t *)aeee, sizeof(aeee), HAL_MAX_DELAY);
		if(distance > 22){
			// sleep
			StopAll();
		} else if(distance >= 0 && distance <= 22){
			// normal
			StartAll();
		}
	}

}

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

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

相关文章

【重装系统】大白菜自制U盘装机,备份C盘数据,解决电脑启动黑屏/蓝屏

1. 准备 U 盘 U 盘容量至少 8G&#xff0c;备份 U 盘的数据&#xff08;后期会格式化&#xff09; 2. 从微软官网下载操作系统镜像 https://www.microsoft.com/zh-cn/software-download/windows11 3. 下载安装大白菜 https://www.alipan.com/s/33RVnKayUfY 4. 插入 U 盘&#…

vue实现目录锚点且滚动到指定区域时锚点自动回显——双向锚点

最近在用vue写官网&#xff0c;别问我为什么用vue写官网&#xff0c;问就是不会jq。。。。vue都出现11年了。。。 左侧目录&#xff1a;点击时&#xff0c;右侧区域可以自动滚动到指定的位置。 右侧区域手动滚动时&#xff0c;左侧锚点可以自动切换到对应的目录上 从而实现…

Flutter Invalid constant value.

0x00 问题 参数传入变量&#xff0c;报错&#xff01; 代码 const Padding(padding: EdgeInsets.all(20),child: GradientProgressIndicator(value: _progress), ),_progress 参数报错&#xff1a;Invalid constant value. 0x01 原因 这种情况&#xff0c;多发生于&#xff…

【精品PPT】2025固态电池知识体系及最佳实践PPT合集(36份).zip

精品推荐&#xff0c;2025固态电池知识体系及最佳实践PPT合集&#xff0c;共36份。供大家学习参考。 1、中科院化学所郭玉国研究员&#xff1a;固态金属锂电池及其关键材料.pdf 2、中科院物理所-李泓固态电池.pdf 3、全固态电池技术研究进展.pdf 4、全固态电池生产工艺.pdf 5、…

如何计算设备电池工作时长?

目录 【mAh&#xff08;毫安时&#xff09;计算方法】 【Wh&#xff08;瓦时&#xff09;计算方法】 【为什么仅用电流&#xff08;mA&#xff09;和时间&#xff08;h&#xff09;就能计算电池使用时长&#xff08;mAh&#xff09;&#xff1f;】 1. mAh 的本质是“电荷量…

抽象类及其特性

目录 1、概念2、语法3、特性4、作用 1、概念 在面向对象中&#xff0c;所有对象都是通过类来描述的&#xff0c;但是并不是所有的类都可以用来描述对象。比如下述例子中的 Animal 类&#xff0c;Dog 类和 Cat 类是 Animal 类的子类&#xff0c;可以分别描述小狗和小猫&#xf…

【教程】xrdp修改远程桌面环境为xfce4

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 xfce4 vs GNOME对比 配置教程 1. 安装 xfce4 桌面环境 2. 安装 xrdp 3. 配置 xrdp 使用 xfce4 4. 重启 xrdp 服务 5. 配置防火墙&#xff…

利用python从零实现Byte Pair Encoding(BPE):NLP 中的“变形金刚”

BPE&#xff1a;NLP 界的“变形金刚”&#xff0c;从零开始的奇幻之旅 在自然语言处理&#xff08;NLP&#xff09;的世界里&#xff0c;有一个古老而神秘的传说&#xff0c;讲述着一种强大的魔法——Byte Pair Encoding&#xff08;BPE&#xff09;。它能够将普通的文本“变形…

部署redis cluster

一。在所有的主机里面设置密码和文件地址 vi /etc/redis/6379.conf 注释&#xff1a;登陆则要使用auth 123456才可以进入redis 配置文件地址和超时时间 二。创建集群&#xff1a;上面主机为master&#xff0c;下面为slave&#xff0c;master和slave会随机分配 先写主节点&…

基于springboot钻孔数据管理系统的设计与实现(源码+lw+部署文档+讲解),源码可白嫖!

摘要 本钻孔数据管理系统采用B/S架构&#xff0c;数据库是MySQL&#xff0c;网站的搭建与开发采用了先进的Java语言、Hadoop、数据可视化技术进行编写&#xff0c;使用了Spring Boot框架。该系统从两个对象&#xff1a;由管理员和用户来对系统进行设计构建。用户主要功能包括&…

动态科技感html导航网站源码

源码介绍 动态科技感html导航网站源码&#xff0c;这个设计完美呈现了科幻电影中的未来科技界面效果&#xff0c;适合展示技术类项目或作为个人作品集的入口页面&#xff0c;自适应手机。 修改卡片中的链接指向你实际的HTML文件可以根据需要调整卡片内容、图标和颜色要添加更…

YOLOv11训练中精准率召回率与mAP@0.5的动态变化分析

目标检测模型的训练过程涉及多个关键性能指标和损失函数的变化&#xff0c;这些数据能够直观反映模型的收敛速度、最终精度以及改进效果。本文旨在通过绘制YOLOv11模型在训练过程中的精准率&#xff08;Precision&#xff09;、召回率&#xff08;Recall&#xff09;、mAP0.5 、…

Java常用工具算法-6--秘钥托管云服务AWS KMS

前言&#xff1a; 之前我们介绍了一些常用的加密算法&#xff08;如&#xff1a;对称加密AES&#xff0c;非对称加密RSA&#xff0c;ECC等&#xff09;&#xff0c;不论是哪一种都需要涉及到秘钥的管理。通常的做法都是把秘钥放到配置文件中进行配置&#xff0c;但是对于一些高…

11. Langchain输出解析(Output Parsers):从自由文本到结构化数据

引言&#xff1a;从"自由发挥"到"规整输出" 2025年某金融机构的合同分析系统升级前&#xff0c;AI生成的合同摘要需人工二次处理达47分钟/份。引入LangChain结构化解析后&#xff0c;处理时间缩短至3分钟。本文将详解如何用LangChain的解析器&#xff0c;…

python reportlab模块----操作PDF文件

reportlab模块----操作PDF文件 一. 安装模块二. reportlab相关介绍三. 扩展canvas类四. 水平写入完整代码五. 垂直写入完整代码 一. 安装模块 pip install reportlab二. reportlab相关介绍 # 1. letter 生成A4纸张尺寸 from reportlab.lib.pagesizes import letter print(let…

解锁基因密码之重测序(从测序到分析)

在生命科学的奇妙世界中&#xff0c;基因恰似一本记录着生命奥秘的“天书”&#xff0c;它承载着生物体生长、发育、衰老乃至疾病等一切生命现象的关键信息。而重测序技术&#xff0c;则是开启基因“天书”奥秘的一把神奇钥匙。 试想&#xff0c;你手中有一本经典书籍的通用版…

TQTT_KU5P开发板教程---QSFP25G光口回环测试

文档实现功能介绍 本文档通过一个叫做ibert的IP&#xff0c;实现25G光口回环测试例子。工程新建方法请参考文档《流水灯》&#xff0c;其中只是将文件名进行修改。 Vivado 起始页&#xff08;或 file-->Project-->New 创建新工程(Create New Project) 向导起始页面 点…

JVM虚拟机篇(七):JVM垃圾回收器全面解析与G1深度探秘及四种引用详解

JVM垃圾回收器全面解析与G1深度探秘及四种引用详解 JVM虚拟机&#xff08;七&#xff09;&#xff1a;JVM垃圾回收器全面解析与G1深度探秘及四种引用详解一、JVM有哪些垃圾回收器1. Serial回收器2. ParNew回收器3. Parallel Scavenge回收器4. Serial Old回收器5. Parallel Old回…

柑橘病虫害图像分类数据集OrangeFruitDaatset-8600

文章目录 1. 前言2. 数据类别介绍3. 数据集地址 1. 前言 柑橘&#xff0c;作为水果界的 “宠儿”&#xff0c;不仅以其酸甜可口的味道深受大众喜爱&#xff0c;更是在全球水果产业中占据着举足轻重的地位。无论是早餐中的一杯橙汁&#xff0c;还是下午茶里的柑橘甜点&#xff…

深度学习总结(4)

张量积 张量积&#xff08;tensor product&#xff09;或点积&#xff08;dot product&#xff09;是最常见且最有用的张量运算之一。注意&#xff0c;不要将其与逐元素乘积&#xff08;*运算符&#xff09;弄混。在NumPy中&#xff0c;使用np.dot函数来实现张量积&#xff0c…