stm32四种方式精密控制步进电机

在搭建完clion的开发环境后,我决定重写之前的项目并优化完善,争取做出完全可落地的东西,也结合要写的论文内容一同学习下去。

因此,首当其冲的就是回到步进电机控制领域,把之前使用中断溢出进行步进电机控制的方案进行进一步优化。

目前使用中断溢出控制步进电机,有如下几个问题:

1.有时电压不稳定/电压太低,电机转不起来。

2.电机频率太高有响声,频率太低有气声,需要设置一个合理的范围值,同时不会因为数值的事情用很长时间去调试电机。

3.电机转向会出问题,或是反应不过来,或是接线有问题。

4.只能通过改变psc预分频器和arr自动重装载值去改变电机速度,无法通过改变占空比的方式控制电机,且驱动器上合适的细分数需要自己调节。

因此我这次使用了四种方式控制电机

1.模拟io控制

2.中断溢出控制

3.定时器比较通道控制

4.定时器pwm控制

芯片选用的是stm32f103zet6,全程未使用编码器/PID,电机驱动器用的是最简单常见的TB6612,主打一个好复现且好上手。电机控制比较稳定,可以根据自己需要选择控制方式。本篇文章使用的硬件和这两篇文章里介绍的一致:

stm32精密控制步进电机(基础篇)_stm32 步进电机-CSDN博客

stm32精密控制步进电机(升级篇)_stm32微机控制-CSDN博客

与之前不同的是我把使能引脚也加上了(PA7控制ENA-;ENA+,PUL+和DIR+接到5v或3.3v引脚),这里可以用万用表验证一下。

四种方式的详细代码我放在了github上,都使用了freertos系统,欢迎移步下载,可以试着点个star,谢谢: 

https://github.com/Re-restart/four_ways_to_control_stepper


怎么完成电机接线

Aout1与Aout2(A+与A-)是同相,Bout1与Bout2(B+与B-)是同相。把同相的两条线拧在一起,会发现难以拧动电机;或是直接测试电阻,两个引脚之间电阻极大,那这两个电机引脚就是同相的。

如果驱动器是9v的,建议接12v电源+DCDC,这样电流会更加稳定,电机抖动现象就可以减轻很多。如果外部不是稳定的开关电源,只靠板子和12v电池供电,最好不要设置板子的脉冲和方向引脚为推挽上拉,设置推挽会抢占一些电压,可能给驱动器分配的电压就变少了。

进行电机微秒级延时

众所周知,HAL_Delay和Osdelay都是毫秒延时。这种情况下需要一个定时器去负责微秒的延时,我使用的方式是把TIM4里的预分频器psc设为71,定时器时钟源频率是72MHZ,定时器输入时钟频率就是:

72MHZ/(71+1)=1MHZ

把arr值设置为65535,这样读取出来的寄存器值就是1微秒增加一次,最后比较出的值小于要执行的微秒数就可以。

void delay_us(uint16_t us)
{__HAL_TIM_SET_COUNTER(&htim4, 0);  // 清零了 TIM4 的计数器,因此不再需要 start_time 变量来记录初始时间while (__HAL_TIM_GET_COUNTER(&htim4) < us);  // 等待计数达到 us
}

另外还有一种做法是设置一个volatile变量(代表这个变量不要被编译器优化,可能在外设或中断中改变它的值,每次访问该变量时需要从内存中读取),start_time是用来读取中断的初始值的,和清零函数__HAL_TIM_SET_COUNTER(&htim4, 0)的作用一致。

为了处理溢出问题,可以利用无符号整数的特性,即(uint16_t)(delay_time-start_time)。

volatile uint16_t start_time=0;
volatile uint16_t delay_time=0;void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/* USER CODE BEGIN Callback 0 *//* USER CODE END Callback 0 */if (htim->Instance == TIM4) {delay_time++;}/* USER CODE BEGIN Callback 1 *//* USER CODE END Callback 1 */
}void delay_us(uint16_t us)
{start_time=delay_time;while((uint16_t)(delay_time-start_time)<us);
}

按键进行外部中断控制

先新建系统任务控制函数,利用两个板子自带的按钮做外部中断,控制电机左转/右转。这个按键逻辑是默认flag=1,flag_key=1。按下按键后,防抖10s,并把flag和flag_key全置为0。

按键松开后,按键引脚恢复到之前的电平,因为也不会同时摁,就用flag,flag_key和按键引脚松开后的状态共同判断,区分电机状态并执行stepper_turn函数。

void StartDefaultTask(void *argument)
{/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */for(;;) {if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {osDelay(10);flag = 0;}if(flag == 0 && flag_key == 1) {if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {stepper_turn(120,360,32,CW);}flag = 1;}
/if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_RESET) {osDelay(10);flag_key = 0;}if(flag_key == 0 && flag == 1) {if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_SET) {stepper_turn(120,360,32,CCW);}}flag_key = 1;}

电机引脚初始设置

中断和模拟io控制电机都是PA5为PUL-控制引脚,PA6为DIR-控制引脚,PA7为ENA-控制引脚。输入捕获和pwm用的都是TIM3-Channel1,也就是PC6。不是不能设置推挽引脚哈,这个主要看外界的电压状态,如果外界供电稳定,引脚电压也够,那全设置推挽上拉也没什么问题。但是我需要大多数情况下都没问题的引脚配置,所以会设置开漏不上拉,只有PA7是推挽上拉。

  /*Configure GPIO pins : PA5 PA6 */GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : PA7 */GPIO_InitStruct.Pin = GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_RESET);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);//void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(timHandle->Instance==TIM3){/* USER CODE BEGIN TIM3_MspPostInit 0 *//* USER CODE END TIM3_MspPostInit 0 */__HAL_RCC_GPIOC_CLK_ENABLE();/**TIM3 GPIO ConfigurationPC6     ------> TIM3_CH1*/GPIO_InitStruct.Pin = GPIO_PIN_6;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);__HAL_AFIO_REMAP_TIM3_ENABLE();/* USER CODE BEGIN TIM3_MspPostInit 1 *//* USER CODE END TIM3_MspPostInit 1 */}}

模拟IO控制步进电机

通过编写stepper_turn函数控制模拟IO。这里面注意一下,ENA-引脚是推挽上拉状态,初始为SET,此时ENA-引脚电平为0v。

已知ENA+引脚电平是3.3v或5v,构成使能信号有效,电机pulse引脚开始翻转,电机转动。电机停止转动时,使能引脚恢复到reset状态。

电机转动的时候,使能引脚PA7其实是有电压的,2v~3v的样子。可以看作这个引脚是来激活驱动器的。如果讨厌这个使能引脚/板子引脚资源比较少,可以不接使能+和使能-引脚,PUL+和DIR+接到5v或3.3v引脚,PUL-和DIR-用于控制电机即可。

tim是周期,angle是角度,subdivide是电机驱动器的细分数,dir是电机旋转方向。

void stepper_turn(int tim,float angle,float subdivide,uint8_t dir)
{int n,i;/*根据细分数求得步距角被分成多少个方波*/n=(int)(angle/(1.8/subdivide));if(dir==CW)        //顺时针{HAL_GPIO_WritePin(MOTOR_DIR_GPIO_PORT,MOTOR_DIR_PIN,HIGH);}else if(dir==CCW)//逆时针{HAL_GPIO_WritePin(MOTOR_DIR_GPIO_PORT,MOTOR_DIR_PIN,LOW);}/*开使能*/HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,GPIO_PIN_SET);/*模拟方波*/for(i=0;i<n;i++){HAL_GPIO_WritePin(MOTOR_PUL_GPIO_PORT,MOTOR_PUL_PIN,LOW);delay_us(tim/2);HAL_GPIO_WritePin(MOTOR_PUL_GPIO_PORT,MOTOR_PUL_PIN,HIGH);delay_us(tim/2);}/*关使能*/HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,GPIO_PIN_RESET);
}

中断溢出控制步进电机

和之前文章里的类似,这里不再详细讲解。逻辑稍微改良了一下,不再通过读取引脚状态计数,而是每溢出两次,脉冲引脚翻转一次。这是因为中断需要保持实时性,需要尽量处理简单的逻辑。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/* USER CODE BEGIN Callback 0 *//* USER CODE END Callback 0 */if (htim->Instance == TIM2) {HAL_IncTick();}/* USER CODE BEGIN Callback 1 */if(htim->Instance==TIM5){pulse=pulse+1;if(pulse%2==0){Pulse_Toggle();}__HAL_TIM_CLEAR_IT(&htim5, TIM_IT_UPDATE);}/* USER CODE END Callback 1 */
}

 中断跟其他方式相比,比较容易出现失控,所以启动之前需要先关闭中断,停止电机运行,然后再打开电机驱动和使能。

for(;;) {if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {osDelay(10);flag = 0;}if(flag == 0 && flag_key == 1) {if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {StopMotor();Dir_CW();StartMotor();HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,GPIO_PIN_SET);}flag = 1;}if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_RESET) {osDelay(10);flag_key = 0;}if(flag_key == 0 && flag == 1) {if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_SET) {StopMotor();Dir_CC();StartMotor();HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,GPIO_PIN_SET);//打开使能}flag_key = 1;}if(pulse > 3200) {pulse = 0;StopMotor();BlinkLEDs();}}

然后我把比较重要的操作都封装成函数,这样便于调用。HAL_TIM_Base_MspDeInit用于关闭定时器中断,HAL_TIM_Base_MspInit打开定时器中断。

void StopMotor(void) {HAL_TIM_Base_MspDeInit(&htim5);HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,GPIO_PIN_RESET);
}void StartMotor(void) {HAL_TIM_Base_MspInit(&htim5);
}

定时器比较通道控制步进电机

在这里通过PC6引脚控制步进电机,不需要考虑什么引脚推挽还是开漏的问题,直接设置通道就可以了。如果这里不加延时,电机会一直转。我设置过像HAL_TIM_OC_DelayElapsedCallback一样的回调函数去按照比较通道执行顺序计数,但是并不好用,会发现初始的库文件并没有弱定义这个函数,遂放弃这种方式。

void stepper_turn(uint8_t dir)
{if(dir==CW)        //顺时针{HAL_GPIO_WritePin(MOTOR_DIR_GPIO_PORT,MOTOR_DIR_PIN,HIGH);}else if(dir==CCW)//逆时针{HAL_GPIO_WritePin(MOTOR_DIR_GPIO_PORT,MOTOR_DIR_PIN,LOW);}/*开使能*/HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,GPIO_PIN_SET);/* 启动比较输出并使能中断 */HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);for(uint16_t i=0;i<2000;i++) {delay_us(1000);}stepper_stop();
}void stepper_stop(void) {HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_1);HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,GPIO_PIN_RESET);
}

在定时器内设置速度,使能比较通道后关闭中断,需要中断时再去调用并打开中断。这里面电机速度计算过程如下,可算得电机速度周期是1.375ms。

72MHZ/(1+899)=0.08 \\ (109+1)/0.08=1.375ms

void MX_TIM3_Init(void)
{/* USER CODE BEGIN TIM3_Init 0 *//* USER CODE END TIM3_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* USER CODE BEGIN TIM3_Init 1 *//* USER CODE END TIM3_Init 1 */htim3.Instance = TIM3;htim3.Init.Prescaler = 899;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 109;htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim3) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_OC_Init(&htim3) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigOC.OCMode = TIM_OCMODE_TOGGLE;sConfigOC.Pulse = 0;sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM3_Init 2 *//*使能比较通道*/TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_1,TIM_CCx_ENABLE);HAL_TIM_OC_Stop_IT(&htim3,TIM_CHANNEL_1);/* USER CODE END TIM3_Init 2 */HAL_TIM_MspPostInit(&htim3);}

定时器PWM方式控制步进电机

其实就是把使能比较通道方式换成pwm通道。 sConfigOC.Pulse/(arr+1)这个值是占空比,可以把它设置在tim周期的50%到80% 之间。

但其实这种方式个人认为并不利于电机控制,因为如果想旋转需要的角度,需要设置主从定时器和输入触发源,而且cubeide会初始化很多配置,其中就包括psc,arr和pulse占空比,不利于程序本身的赋值。而且开启PWM时,必须同时开启AFIO时钟!!必须配置对应引脚为复用输出!HAL_TIM_MspPostInit(&htim3);就是这个定时器引脚定义函数,所以下面的定时器配置里是HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);,假如设置HAL_TIM_PWM_Stop,在freertos里再打开,是驱动不了步进电机的。。。。。这件事情卡了我很久。

好处是它和输出比较方式都随时转换方向,而且不需要考虑推挽还是开漏引脚,控制是真的很稳。

void MX_TIM3_Init(void)
{/* USER CODE BEGIN TIM3_Init 0 *//* USER CODE END TIM3_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* USER CODE BEGIN TIM3_Init 1 *//* USER CODE END TIM3_Init 1 */htim3.Instance = TIM3;htim3.Init.Prescaler = 719;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = tim_per-1;htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim3) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_Init(&htim3) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = tim_per/2;sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM3_Init 2 */HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);/* USER CODE END TIM3_Init 2 */HAL_TIM_MspPostInit(&htim3);}

几种方式的优缺点总结

个人认为这里面设置最简单,相对来说最可控,占用单片机内部资源最少的还是模拟io方式,延时的问题通过定时器TIM4解决后,大大增加了可控的精度。而且实际测试时,12v供电它的引脚电压基本能稳到10v,且电机发热时一样可运行,也不需要特定的gpio驱动,是和模拟i2c一样的,比较好的方式,之后做项目可能会多用这种电机控制方式。

如果特定项目需要快速切换电机方向,建议选择定时器比较通道控制,或以PWM方式控制电机。

另外,发现TIM1是没有办法设置TIM_OCMODE_TOGGLE方式的,只能设置TIM_OCMODE_TIMING,也查了相关手册,并没介绍这个地方,之后可能会继续完善看看这是怎么回事。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML——前端基础1

目录 前端概述 前端能做的事情​编辑 两步完成一个网页程序 前端工具的选择与安装 HTML HTML5介绍 HTML5的DOCTYPE声明 HTML基本骨架 文字标签 标题之标签 标签之段落、换行、水平线 标签之图片 标签之超文本链接 标签之文本 列表标签之有序列表 列表标签之无序…

【QT问题】Ubantu环境下解决已经下载好的qt怎么添加或卸载其他组件

1、找到自己qt的安装目录->双击打开MaintenanceTool.exe 2、点击next进去&#xff0c;此时需要登录qt账户&#xff08;如果没有去官网注册一个&#xff0c;很快且免费&#xff09; 我这里随便填的账号&#xff0c;如果是正确的下面next就能够点击。 这里随便提一下&#xf…

TaskBuilder设置排序条件

在整个向导的最后一步&#xff0c;可以设置是否按指定字段的值对查询结果进行排序&#xff0c;支持正序和倒序两种排序方式。如果没有设置任何排序字段&#xff0c;则默认按数据库里现有数据记录的实际存储的先后顺序排序。如果设置了多个排序条件&#xff0c;则按这些条件从上…

Taylor龙哥库塔。各种稳定性

——Taylor 龙额库塔 需要利用&#xff1a; 1.k1f 2.b21a1 3.k1fuffu | | 稳定区域 | | | | | | BDFq 方法是 A(φq)-稳定的&#xff0c;其中 φ1 φ2 90◦, φ3 ≈86.03◦, φ4 ≈73.35◦, φ5 ≈51.84◦, 和 φ6 ≈17.84◦; 参见 2 3. | | | WSBDFq 方法是 A( ˜ φ…

AI如何通过大数据分析提升制造效率和决策智能化

人工智能&#xff08;AI&#xff09;与大数据技术的融合&#xff0c;不仅重新定义了生产流程&#xff0c;更让企业实现了从“经验驱动”到“数据智能驱动”的跨越式升级。 从“模糊经验”到“精准洞察”​​ 传统制造业依赖人工经验制定生产计划&#xff0c;但面对复杂多变的市…

Windows docker下载minio出现“Using default tag: latestError response from daemon”

Windows docker下载minio出现 Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded 此类情况&#xff0c;一般为镜像地址问题。 {"registry-mirrors": ["https://docker.re…

【前端基础】Day 4 CSS盒子模型

目录 1. 盒子模型 1.1 盒子模型布局 1.2 盒子模型组成 1.3 边框 1.4 表格细线边框 1.5 边框会影响盒子实际大小 1.6 内边距 1.7 外边距 1.8 外边距合并 1.9 清除内外边距 2. PS基本操作 3. 综合案例 3.1 案例1 3.2 案例2-快报模块 4. 圆角边框 5. 盒子阴影 6…

DeepSeek R1 + 飞书机器人实现AI智能助手

效果 TFChat项目地址 https://github.com/fish2018/TFChat 腾讯大模型知识引擎用的是DeepSeek R1&#xff0c;项目为sanic和redis实现&#xff0c;利用httpx异步处理流式响应&#xff0c;同时使用buffer来避免频繁调用飞书接口更新卡片的网络耗时。为了进一步减少网络IO消耗&…

Go红队开发—并发编程

文章目录 并发编程go协程chan通道无缓冲通道有缓冲通道创建⽆缓冲和缓冲通道 等协程sync.WaitGroup同步Runtime包Gosched()Goexit() 区别 同步变量sync.Mutex互斥锁atomic原子变量 SelectTicker定时器控制并发数量核心机制 并发编程阶段练习重要的细节端口扫描股票监控 并发编程…

一键导出数据库表到Excel

工作中&#xff0c;我们经常需要将数据库表导出到Excel&#xff0c;通常我们会用数据库编辑器之类的工具提供的导出功能来导出&#xff0c;但是它们的导出功能通常都比较简单。 这篇文章将介绍一种简单易用并且功能强大的导出方法。 新增导出 打开的卢导表工具&#xff0c;新…

《深度学习实战》第4集:Transformer 架构与自然语言处理(NLP)

《深度学习实战》第4集&#xff1a;Transformer 架构与自然语言处理&#xff08;NLP&#xff09; 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Transformer 架构的出现彻底改变了传统的序列建模方法。它不仅成为现代 NLP 的核心&#xff0c;还推动了诸如 BERT、…

jeecgboot项目idea启动项目(二)

文章目录 一、IntelliJ IDEA1.安装2.配置maven3.配置jdk 二、IDEA启动项目三、IDEA2024.1.4破解 一、IntelliJ IDEA ‌IntelliJ IDEA是一款由JetBrains开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要用于Java和Kotlin编程&#xff0c;但也支持多种其他编程语…

fody引用c++的dll合并后提示找不到

fody引用c的dll合并后提示找不到 解决方案&#xff1a; 在 FodyWeavers.xml 文件中添加配置 CreateTemporaryAssemblies‘true’ 官方文档&#xff1a;https://github.com/Fody/Costura <Weavers xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:noN…

DeepSeek R1满血+火山引擎详细教程

DeepSeek R1满血火山引擎详细教程 一、安装Cherry Studio。 Cherry Studio AI 是一款强大的多模型 AI 助手,支持 iOS、macOS 和 Windows 平台。可以快速切换多个先进的 LLM 模型,提升工作学习效率。下载地址 https://cherry-ai.com/ 认准官网&#xff0c;无强制注册。 这…

TP-LINK路由器如何设置网段、网关和DHCP服务

目标 ①将路由器的网段由192.168.1.XXX改为192.168.5.XXX ②确认DHCP是启用的&#xff0c;并将DHCP的IP池的范围设置为排除自己要手动指定的IP地址&#xff0c;避免IP冲突。 01-复位路由器 路由器按住复位键10秒以上进行重置操作 02-进入路由器管理界面 电脑连接到路由器&…

【C/C++】如何求出类对象的大小----类结构中的内存对齐

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 通过本章你能具体的了解到&#xff0c;如何计算出一个类的大小&#xff0c;并且了解其中到底是如何算的以及了解到为什么需要内存对齐这种算&#xff0…

鸿蒙开发第4篇__关于在鸿蒙应用中使用Java语言进行设计

本博文很重要 HarmonyOS从 API8 开始不再支持使用Java作为开发语言&#xff0c;未来的新功能将在ArkTS中实现. API 8对应的是HarmonyOS 3.0.0版本。请看下图&#xff1a; 因此&#xff0c; 读者如果看到类似《鸿蒙应用程序开发》(2021年版本 清华大学出版计)书 还使用Java语言…

【图文详解】论文《Attention Is All You Need》中位置嵌入(Positional Encoding)的流程和作用

文章目录 前言一、位置嵌入&#xff08;Positional Encoding&#xff09;的流程二、位置嵌入的作用三、为什么采用正弦和余弦函数四、位置嵌入示例五、结论 前言 亲爱的家人们&#xff0c;创作很不容易&#xff0c;若对您有帮助的话&#xff0c;请点赞收藏加关注哦&#xff0c…

SpringBoot 使用 spring.profiles.active 来区分不同环境配置

很多时候&#xff0c;我们项目在开发环境和生产环境的配置是不一样的&#xff0c;例如&#xff0c;数据库配置&#xff0c;在开发的时候&#xff0c;我们一般用测试数据库&#xff0c;而在生产环境&#xff0c;我们要用生产数据库&#xff0c;这时候&#xff0c;我们可以利用 p…

Android 常用命令和工具解析之存储相关

1 基本概念 2 命令解读 2.1 adb shell df df 命令主要用于需要检查文件系统上已使用和可用的磁盘空间的数量。如果没有指定文件名&#xff0c;则显示在当前所有挂载的文件系统上可用的空间。其原理是从proc/mounts 或 /etc/mtab 中检索磁盘信息。 注意&#xff1a;df命令并…