HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据
HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据
- 📚MT6816相关资料(来自商家的相关资料):
资料:https://pan.baidu.com/s/1CAbdLBRi2dmL4D7cFve1XA?pwd=8888
提取码:8888
- 📍驱动代码编写,可信源参考:
https://github.com/simplefoc/Arduino-FOC-drivers/blob/master/src/encoders/mt6816/MT6816.cpp
https://github.com/unlir/XDrive/blob/master/Firmware_APP/Base_Drivers/mt6816.c
📗MT6816所有型号和功能描述差异表
- 从上图型号描述上看,差异在于ABZ模式下,径向磁铁旋转一圈,正交编码(A、B线)输出的脉冲数( ABZ输出分辨率)差异,对于Z线来讲,径向磁铁旋转一圈,都只产生一个脉冲信号,该脉冲信号的脉宽有所不同,读取角度的精度还是一样的。
- 如果选择SPI作为通讯,选择基础款:
MT6816CT-STD-R
就可以了。- 如果ABZ模式下使用,推荐
MT6816CT-ACD/ACE
相比于AKD/AKH
,一圈内,分辨率多了24个脉冲信号,正交编码信号相对变窄了一些。- 具体的其他型号的用途和场景使用,没有研究不做讨论。
🛠输出模式配置说明
MT6816可以输出ABZ、UVW和PWM信号,另外还可以通过4线或3线SPI接口读取14位的绝对角度寄存器。其中ABZ、UVW和SPI接口是互相复用I/O引脚的。SPI接口和ABZ/UVW之间是通过HVPP引脚进行配置的,当HVPP接高电平VDD时,相关I/O管脚切换至SPI模式;当HVPP接地时,芯片相关I/O切换至ABZ或UVW模式。ABZ和UVW模式的切换,由芯片内部相关寄存器控制。4线SPI和3线SPI也是通过芯片内部寄存器进行切换控制的,MT6816出厂默认配置为4线SPI.
- 👉ABZ、UVW和PWM信号读取数据和SPI方式读取数据区别在于芯片的第2引脚,如果接VCC就是SPI方式,如果接GND就是ABZ、UVW和PWM方式读取。
- 🔧ABZ, UVW 和PWM模式参考电路:
🍁MT6816 SPI参考电路
- 🌿SPI方式参考电路:
- ⚡在手册中,没有提到
mosi
上拉,在实际测试过程中,如果外部没有配置上拉或者mcu驱动引脚(mosi)内部没有开启上拉,则读取不到数据,这一点需要注意,这个坑,排查了很久才发现。✨推荐在硬件电路设计时,在mosi引脚(芯片第5引脚)外部添加一个4.7K的上拉电阻。
- 👉对于较老的STM32F103系列,在配置软件上没有该配置选项,需要使用外部上拉电阻。
🧬MT6816 SPI时序
MT6816的SPI使用模式3(CPOL=1, CPHA=1)传输数据。如图-16所示,数据传输开始于CSN的下降沿,结束于CSN的上升沿,MT6816在时钟上升沿采样数据。
- 时序图:
📄4线SPI协议
- 🌿4线SPI协议时序
MT6816的CSN下降沿激活SPI通信,CSN的上升沿结束SPI通信。SCK时钟信号由上位机发送给MT6816,在非通信状态下,请保持SCK为高电平;MOSI (上位机输出、MT6816输入) 和MISO (上位机输入、MT6816输出) 是SPI接口的两路数据信号, 数据都是在时钟信号SCK的下降沿发生改变,所以推荐使用SCK时钟信号的上升沿对数据进行采样.
- 比特 0: 读写标志位,。低电平为写操作,此时数据DI7~DI0写入芯片;高电平为读操作,此时从芯
片读出数据DO7~DO0 。- 比特 1-7: 地址A6~A0。 寄存器操作地址。
- 比特 8-15: 数据 DI7~DI0 (写模式)。会被写入芯片的数据 (MSB优先)。
- 比特 8-15: 数据DO7~DO0 (读模式)。 从芯片读出的数据(MSB优先)。
📑3线SPI协议
- 3线SPI时序
CSN的下降沿激活SPI通信,CSN的上升沿结束SPI通信。SCK时钟信号由上位机发送给MT6816,在非通信状态下,请保持SCK为高电平。SDA是数据输入输出信号数据,是在时钟信号SCK的下降沿发生改变,所以推荐使用SCK时钟信号的上升沿对数据进行采样 。
- Bit 0: 读写标志位,。低电平为写操作,此时数据DI7~DI0写入芯片;高电平为读操作,此时从芯
片读出数据DO7~DO0 。- Bit 1-7: 地址A6~A0。 寄存器操作地址。
- Bit 8-15: 数据 D7~D0 (写模式)。会被写入芯片的数据 (MSB优先)。
- Bit 8-15: 数据D7~D0 (读模式)。 从芯片读出的数据(MSB优先)。
📗SPI读取角度数据(4线SPI)
- 🌿4线SPI读取角度数据
- 📐角度数据寄存器
- 🌿3线SPI读角度时序:
📝SPI/ABZ/PWM驱动代码
- ✨本驱动代码从
https://github.com/unlir/XDrive
项目中,移植有关MT6816内容,作为单独驱动读取MT6816磁编码器数据使用。
- 🌿mt6816.c
/************************************************************************************** @project : XDrive_Step** @brief : Stepper motor with multi-function interface and closed loop function.** @brief : 具有多功能接口和闭环功能的步进电机** @author : unlir (知不知啊)** @contacts: QQ.1354077136******** @address : https://github.com/unlir/XDrive************************************************************************************** {Stepper motor with multi-function interface and closed loop function.}** Copyright (c) {2020} {unlir(知不知啊)}**** This program is free software: you can redistribute it and/or modify** it under the terms of the GNU General Public License as published by** the Free Software Foundation, either version 3 of the License, or** (at your option) any later version.**** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.**** You should have received a copy of the GNU General Public License** along with this program. If not, see <http://www.gnu.org/licenses/>.******************************************************************************
******/#include "mt6816.h"//GPIO输出
#define MT6816_SPI_CS_H() (MT6816_SPI_CS_GPIO_Port -> BSRR = MT6816_SPI_CS_Pin)
#define MT6816_SPI_CS_L() (MT6816_SPI_CS_GPIO_Port -> BRR = MT6816_SPI_CS_Pin)#if (MT6816_Mode == MT6816_Mode_PWM)
/****************************** MT6816_PWM ******************************/
/****************************** MT6816_PWM ******************************/
/****************************** MT6816_PWM ******************************/
MT6816_PWM_Signal_Typedef mt6816_pwm;/*** @brief TIM_MT6816_PWM初始化* @param NULL* @retval NULL
**/
void REIN_TIM_MT6816_PWM_Init(void)
{/* GPIO初始化 */GPIO_InitTypeDef GPIO_InitStruct = {0};/*GPIO Ports Clock Enable*/MT6816_PWM_GPIO_CLK_ENABLE(); //启用PWM端口时钟/*Configure GPIO pin*/GPIO_InitStruct.Pin = MT6816_PWM_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //输入模式GPIO_InitStruct.Pull = GPIO_PULLUP; //禁用上下拉HAL_GPIO_Init(MT6816_PWM_GPIO_Port, &GPIO_InitStruct);/* 定时器初始化 */TIM_SlaveConfigTypeDef sSlaveConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_IC_InitTypeDef sConfigIC = {0};MT6816_PWM_TIM_CLK_ENABLE(); //启用TIM时钟MT6816_PWM_Get_HTIM.Instance = MT6816_PWM_Get_TIM;MT6816_PWM_Get_HTIM.Init.Prescaler = (9 - 1); //预分频:9 采样频率 72M/9 = 8M 分辨精度125nsMT6816_PWM_Get_HTIM.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数MT6816_PWM_Get_HTIM.Init.Period = (65536 - 1); //采样宽度 65536 * 125ns = 8.192ms 频率122.07Hz (满足MT6816两种PWM频率输出)MT6816_PWM_Get_HTIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //不分频MT6816_PWM_Get_HTIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //禁用自动重新加载if (HAL_TIM_Base_Init(&MT6816_PWM_Get_HTIM) != HAL_OK) {Error_Handler();}if (HAL_TIM_IC_Init(&MT6816_PWM_Get_HTIM) != HAL_OK) {Error_Handler();}sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET; //从模式:复位模式sSlaveConfig.InputTrigger = TIM_TS_TI1FP1; //从模式触发信号:TI1FP1sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING; //从模式触发极性:上升沿触发sSlaveConfig.TriggerFilter = 0; //禁用滤波器if (HAL_TIM_SlaveConfigSynchro(&MT6816_PWM_Get_HTIM, &sSlaveConfig) != HAL_OK) {Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; //主模式:复位sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; //禁用主机模式if (HAL_TIMEx_MasterConfigSynchronization(&MT6816_PWM_Get_HTIM, &sMasterConfig) != HAL_OK) {Error_Handler();}sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; //上升沿捕获sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; //TI1FP1sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; //不分频sConfigIC.ICFilter = 0;if (HAL_TIM_IC_ConfigChannel(&MT6816_PWM_Get_HTIM, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) {Error_Handler();}sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING; //下降沿捕获sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI; //TI1FP2if (HAL_TIM_IC_ConfigChannel(&MT6816_PWM_Get_HTIM, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) {Error_Handler();}/*interrupt init*/HAL_NVIC_EnableIRQ(MT6816_PWM_Get_IRQn); //使能定时中断/*begin work*/HAL_TIM_Base_Stop(&MT6816_PWM_Get_HTIM); //停用TIMHAL_TIM_OC_Start_IT(&MT6816_PWM_Get_HTIM, TIM_CHANNEL_1); //启动CH捕获比较中断HAL_TIM_OC_Start_IT(&MT6816_PWM_Get_HTIM, TIM_CHANNEL_2); //启动CH捕获比较中断HAL_TIM_Base_Start_IT(&MT6816_PWM_Get_HTIM); //启动TIM中断模式
}
/*** @brief MT6816_PWM采集初始化* @param NULL* @retval NULL
**/
void REIN_MT6816_PWM_Signal_Init(void)
{//采集数据mt6816_pwm.h_width = 0;mt6816_pwm.period = 0;mt6816_pwm.count_rising = 0;mt6816_pwm.count_falling = 0;mt6816_pwm.count_update = 0;mt6816_pwm.whole_h_flag = false;mt6816_pwm.whole_l_flag = false;mt6816_pwm.ready_once = false;mt6816_pwm.ready_again = false;//输出数据mt6816_pwm.valid_width = 0;//配置外设REIN_TIM_MT6816_PWM_Init();
}/*** @brief MT6816_PWM采集中断回调* @param NULL* @retval NULL
**/
void REIN_MT6816_PWM_TIM_Callback(void)
{//定时器捕获中断通道1 (上升沿中断) (必须在更新中断前执行)if (__HAL_TIM_GET_FLAG(&MT6816_PWM_Get_HTIM, TIM_FLAG_CC1) != RESET){if (__HAL_TIM_GET_IT_SOURCE(&MT6816_PWM_Get_HTIM, TIM_IT_CC1) != RESET){__HAL_TIM_CLEAR_IT(&MT6816_PWM_Get_HTIM, TIM_IT_CC1);MT6816_PWM_Get_HTIM.Channel = HAL_TIM_ACTIVE_CHANNEL_1;//采集上升沿数据mt6816_pwm.period = HAL_TIM_ReadCapturedValue(&MT6816_PWM_Get_HTIM, TIM_CHANNEL_1) + 1; //获取PWM周期mt6816_pwm.count_rising = mt6816_pwm.count_update; //更新计数器镜像}}//定时器捕获中断通道2 (下降沿中断)if (__HAL_TIM_GET_FLAG(&MT6816_PWM_Get_HTIM, TIM_FLAG_CC2) != RESET){if (__HAL_TIM_GET_IT_SOURCE(&MT6816_PWM_Get_HTIM, TIM_IT_CC2) != RESET){__HAL_TIM_CLEAR_IT(&MT6816_PWM_Get_HTIM, TIM_IT_CC2);MT6816_PWM_Get_HTIM.Channel = HAL_TIM_ACTIVE_CHANNEL_2;//采集下降沿数据mt6816_pwm.h_width = HAL_TIM_ReadCapturedValue(&MT6816_PWM_Get_HTIM, TIM_CHANNEL_2) + 1; //获取PWM高宽度mt6816_pwm.count_falling = mt6816_pwm.count_update; //更新计数器镜像}}//定时器更新中断 (更新事件中断) (由更新事件触发 | 溢出事件触发)if (__HAL_TIM_GET_FLAG(&MT6816_PWM_Get_HTIM, TIM_FLAG_UPDATE) != RESET){if (__HAL_TIM_GET_IT_SOURCE(&MT6816_PWM_Get_HTIM, TIM_IT_UPDATE) != RESET){__HAL_TIM_CLEAR_IT(&MT6816_PWM_Get_HTIM, TIM_IT_UPDATE);//单次PWM全高全低检测if ( (mt6816_pwm.count_update != mt6816_pwm.count_rising) //(上升沿计数器镜像,更新计数器不相等)&& (mt6816_pwm.count_update != mt6816_pwm.count_falling) //(下降沿计数器镜像,更新计数器不相等)) {//读取PWM电平用于判定全高或全低if (MT6816_PWM_GPIO_Port -> IDR & MT6816_PWM_Pin) {mt6816_pwm.whole_h_flag = true; //置位100%标志mt6816_pwm.whole_l_flag = false; //清位0%标志}else {mt6816_pwm.whole_h_flag = false; //清位100%标志mt6816_pwm.whole_l_flag = true; //置位0%标志}}else {mt6816_pwm.count_update ++;mt6816_pwm.whole_h_flag = false; //清位100%标志mt6816_pwm.whole_l_flag = false; //清位0%标志}//单次PWM有效性确认if (0) {}else if ((mt6816_pwm.whole_h_flag)) mt6816_pwm.ready_once = false; //100%_PWM无效else if ((mt6816_pwm.whole_l_flag)) mt6816_pwm.ready_once = false; //0%_PWM无效//脉冲超长检测(无需检测)//脉冲超短检测(无需检测)else mt6816_pwm.ready_once = true;//可靠的PWM有效性确认if (mt6816_pwm.ready_once) {if (mt6816_pwm.ready_again) {mt6816_pwm.valid_width = mt6816_pwm.h_width;}else {mt6816_pwm.valid_width = 0;mt6816_pwm.ready_again = true;}}else {mt6816_pwm.valid_width = 0;mt6816_pwm.ready_again = false;}}}
}/*** @brief MT6816_PWM获取角度数据* @param NULL* @retval NULL
**/
void REIN_MT6816_PWM_Get_AngleData(void)
{//输出数据int32_t out = (mt6816_pwm.valid_width << 1) - 64;if (out < 0)mt6816_pwm.angle = 0;else if (out > 16383)mt6816_pwm.angle = 16383;elsemt6816_pwm.angle = out;
}#elif (MT6816_Mode == MT6816_Mode_ABZ)
/****************************** MT6816_ABZ ******************************/
/*** @brief TIM_MT6816_ABZ初始化* @param NULL* @retval NULL
**/
void REIN_TIM_MT6816_ABZ_Init(void)
{/* GPIO初始化 */GPIO_InitTypeDef GPIO_InitStruct = {0};/*GPIO Ports Clock Enable*/MT6816_ABZ_A_GPIO_CLK_ENABLE(); //启用ABZ_A端口时钟MT6816_ABZ_B_GPIO_CLK_ENABLE(); //启用ABZ_B端口时钟/*Configure GPIO pins*/GPIO_InitStruct.Pin = MT6816_ABZ_A_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //输入模式GPIO_InitStruct.Pull = GPIO_NOPULL; //禁用上下拉HAL_GPIO_Init(MT6816_ABZ_A_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pins*/GPIO_InitStruct.Pin = MT6816_ABZ_B_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //输入模式GPIO_InitStruct.Pull = GPIO_NOPULL; //禁用上下拉HAL_GPIO_Init(MT6816_ABZ_B_GPIO_Port, &GPIO_InitStruct);/* TIM初始化 */TIM_Encoder_InitTypeDef sConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};__HAL_RCC_TIM1_CLK_ENABLE();MT6816_ABZ_Get_HTIM.Instance = MT6816_ABZ_Get_TIM;MT6816_ABZ_Get_HTIM.Init.Prescaler = 0; //无预分频MT6816_ABZ_Get_HTIM.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数MT6816_ABZ_Get_HTIM.Init.Period = (4096 - 1); //12位周期MT6816_ABZ_Get_HTIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //不分频MT6816_ABZ_Get_HTIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //禁用自动重新加载sConfig.EncoderMode = TIM_ENCODERMODE_TI12; //双边沿四倍频采样sConfig.IC1Polarity = TIM_ICPOLARITY_RISING; //上升沿计数sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; //TI1FP1sConfig.IC1Prescaler = TIM_ICPSC_DIV1; //不分频sConfig.IC1Filter = 0; //禁用滤波器sConfig.IC2Polarity = TIM_ICPOLARITY_FALLING; //下降沿计数sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; //TF2FP2sConfig.IC2Prescaler = TIM_ICPSC_DIV1; //不分频sConfig.IC2Filter = 0; //禁用滤波器if (HAL_TIM_Encoder_Init(&MT6816_ABZ_Get_HTIM, &sConfig) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; //主机模式:复位sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; //禁用主机模式if (HAL_TIMEx_MasterConfigSynchronization(&MT6816_ABZ_Get_HTIM, &sMasterConfig) != HAL_OK){Error_Handler();}/*begin work*/HAL_TIM_Base_Stop(&MT6816_ABZ_Get_HTIM);HAL_TIM_Encoder_Start(&MT6816_ABZ_Get_HTIM, TIM_CHANNEL_ALL);
}
/****************************** MT6816_ABZ GPIO初始化******************************/
/*** @brief GPIO初始化(MT6816_ABZ)* @param NULL* @retval NULL
*/
void REIN_GPIO_MT6816_ABZ_Init(void)
{
#if (defined SENSOR_HVPP_CLK_ENABLE) || (defined MT6816_ABZ_Z_GPIO_CLK_ENABLE)GPIO_InitTypeDef GPIO_InitStruct = {0};
#endif#ifdef SENSOR_HVPP_CLK_ENABLE/* GPIO Ports Clock Enable */SENSOR_HVPP_CLK_ENABLE(); //启用MT6816_HVPP端口时钟/*Configure GPIO pin Output Level*/SENSOR_HVPP_GPIO_Port -> BRR = SENSOR_HVPP_Pin; //MT6816_HVPP引脚输出低电平,启动PWM+ABZ模式/*Configure GPIO pins*/GPIO_InitStruct.Pin = SENSOR_HVPP_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出GPIO_InitStruct.Pull = GPIO_NOPULL; //禁用上下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //低速HAL_GPIO_Init(SENSOR_HVPP_GPIO_Port, &GPIO_InitStruct);
#endif#ifdef MT6816_ABZ_Z_GPIO_CLK_ENABLE/* GPIO Ports Clock Enable */MT6816_ABZ_Z_GPIO_CLK_ENABLE(); //启用MT6816_ABZ_Z端口时钟/*Configure GPIO pins*/GPIO_InitStruct.Pin = MT6816_ABZ_Z_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; //上升沿触发中断GPIO_InitStruct.Pull = GPIO_NOPULL; //禁用上下拉HAL_GPIO_Init(MT6816_ABZ_Z_GPIO_Port, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_EnableIRQ(MT6816_ABZ_Z_EXTI_IRQn); //启用MT6816_Z中断
#endif
}/****************************** MT6816_ABZ ******************************/
MT6816_ABZ_Signal_Typedef mt6816_abz;/*** @brief MT6816_ABZ采集初始化* @param NULL* @retval NULL
**/
void REIN_MT6816_ABZ_Signal_Init(void)
{//采集数据mt6816_abz.sample_data = 0;//输出数据mt6816_abz.angle = 0;//配置外设REIN_TIM_MT6816_ABZ_Init();REIN_GPIO_MT6816_ABZ_Init();
}/*** @brief MT6816_ABZ采集Z脉冲中断回调* @param NULL* @retval NULL
**/
void REIN_MT6816_ABZ_ZPulse_Callback(void)
{//清除定时器计数值__HAL_TIM_SET_COUNTER(&MT6816_ABZ_Get_HTIM, 0);
}/*** @brief MT6816_ABZ获取角度数据* @param NULL* @retval NULL
**/
void REIN_MT6816_ABZ_Get_AngleData(void)
{//采集数据mt6816_abz.sample_data = __HAL_TIM_GET_COUNTER(&MT6816_ABZ_Get_HTIM) & 0x0FFF; //读取定时器计数值//输出数据mt6816_abz.angle = ((mt6816_abz.sample_data + 1) << 2) - 1; //获得数值0~16383
}#elif (MT6816_Mode == MT6816_Mode_SPI)
/****************************** MT6816_SPI ******************************/
/****************************** MT6816_SPI GPIO初始化******************************/
/*** @brief GPIO初始化(MT6816_SPI)* @param NULL* @retval NULL
*/
void REIN_GPIO_MT6816_SPI_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};#ifdef SENSOR_HVPP_CLK_ENABLE/* GPIO Ports Clock Enable */SENSOR_HVPP_CLK_ENABLE(); //启用MT6816_HVPP端口时钟/*Configure GPIO pin Output Level*/SENSOR_HVPP_GPIO_Port -> BSRR = SENSOR_HVPP_Pin; //MT6816_HVPP引脚输出高电平,启动PWM+SPI模式/*Configure GPIO pins*/GPIO_InitStruct.Pin = SENSOR_HVPP_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出GPIO_InitStruct.Pull = GPIO_NOPULL; //禁用上下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //低速HAL_GPIO_Init(SENSOR_HVPP_GPIO_Port, &GPIO_InitStruct);
#endif/* GPIO Ports Clock Enable */MT6816_SPI_CS_GPIO_CLK_ENABLE(); //启用MT6816_SPI_CS端口时钟/*Configure GPIO pin Output Level*/MT6816_SPI_CS_GPIO_Port -> BSRR = MT6816_SPI_CS_Pin; //CS引脚启动输出高电平/*Configure GPIO pins*/GPIO_InitStruct.Pin = MT6816_SPI_CS_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出GPIO_InitStruct.Pull = GPIO_NOPULL; //禁用上下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //低速HAL_GPIO_Init(MT6816_SPI_CS_GPIO_Port, &GPIO_InitStruct);
}/****************************** MT6816_SPI 接口初始化******************************/
/*** @brief SPI初始化(MT6816)* @param NULL* @retval NULL
**/
void REIN_SPI_MT6816_SPI_Init(void)
{/* AFIO初始化 */GPIO_InitTypeDef GPIO_InitStruct = {0};/*GPIO Ports Clock Enable*/MT6816_SPI_CLK_GPIO_CLK_ENABLE(); //启用CLK端口时钟MT6816_SPI_MOSI_GPIO_CLK_ENABLE(); //启用MOSI端口时钟MT6816_SPI_MISO_GPIO_CLK_ENABLE(); //启用MISO端口时钟/*Configure GPIO pins*/GPIO_InitStruct.Pin = MT6816_SPI_CLK_Pin;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用推挽GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速HAL_GPIO_Init(MT6816_SPI_CLK_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pins*/GPIO_InitStruct.Pin = MT6816_SPI_MOSI_Pin;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用推挽GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速HAL_GPIO_Init(MT6816_SPI_MOSI_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pins*/GPIO_InitStruct.Pin = MT6816_SPI_MISO_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //输入GPIO_InitStruct.Pull = GPIO_NOPULL; //禁用上下拉HAL_GPIO_Init(MT6816_SPI_MISO_GPIO_Port, &GPIO_InitStruct);/*Configure AFIO*/
#ifdef MT6816_SPI_AFIO_REMAPMT6816_SPI_AFIO_REMAP //启用备用的SPI_AFIO映射
#endif/* SPI初始化 */MT6816_SPI_SPI_CLK_ENABLE(); //启用SPI时钟MT6816_SPI_Get_HSPI.Instance = MT6816_SPI_Get_SPI;MT6816_SPI_Get_HSPI.Init.Mode = SPI_MODE_MASTER; //主机模式MT6816_SPI_Get_HSPI.Init.Direction = SPI_DIRECTION_2LINES; //双向传输MT6816_SPI_Get_HSPI.Init.DataSize = SPI_DATASIZE_16BIT; //数据位宽:16MT6816_SPI_Get_HSPI.Init.CLKPolarity = SPI_POLARITY_HIGH; //CLK空闲时高电平MT6816_SPI_Get_HSPI.Init.CLKPhase = SPI_PHASE_2EDGE; //第二边沿采样MT6816_SPI_Get_HSPI.Init.NSS = SPI_NSS_SOFT; //软件NSSMT6816_SPI_Get_HSPI.Init.BaudRatePrescaler = MT6816_SPI_Prescaler; //输入预设分频MT6816_SPI_Get_HSPI.Init.FirstBit = SPI_FIRSTBIT_MSB; //MSB传输MT6816_SPI_Get_HSPI.Init.TIMode = SPI_TIMODE_DISABLE; //禁用中断模式MT6816_SPI_Get_HSPI.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; //禁用CRC校验MT6816_SPI_Get_HSPI.Init.CRCPolynomial = 10; //CRC校验多项式if (HAL_SPI_Init(&MT6816_SPI_Get_HSPI) != HAL_OK){Error_Handler();}
}
MT6816_SPI_Signal_Typedef mt6816_spi;/*** @brief MT6816_SPI采集初始化* @param NULL* @retval NULL
**/
void REIN_MT6816_SPI_Signal_Init(void)
{//采集数据mt6816_spi.sample_data = 0;//输出数据mt6816_spi.angle = 0;//配置外设REIN_GPIO_MT6816_SPI_Init();REIN_SPI_MT6816_SPI_Init();
}/*** @brief MT6816_SPI采集获取角度数据* @param NULL* @retval NULL
**/
void RINE_MT6816_SPI_Get_AngleData(void)
{uint16_t data_t[2];uint16_t data_r[2];uint8_t h_count;data_t[0] = (0x80 | 0x03) << 8;data_t[1] = (0x80 | 0x04) << 8;for (uint8_t i = 0; i < 3; i++) {//读取SPI数据MT6816_SPI_CS_L();HAL_SPI_TransmitReceive(&MT6816_SPI_Get_HSPI, (uint8_t*)&data_t[0], (uint8_t*)&data_r[0], 1, HAL_MAX_DELAY);MT6816_SPI_CS_H();MT6816_SPI_CS_L();HAL_SPI_TransmitReceive(&MT6816_SPI_Get_HSPI, (uint8_t*)&data_t[1], (uint8_t*)&data_r[1], 1, HAL_MAX_DELAY);MT6816_SPI_CS_H();mt6816_spi.sample_data = ((data_r[0] & 0x00FF) << 8) | (data_r[1] & 0x00FF);//奇偶校验h_count = 0;for (uint8_t j = 0; j < 16; j++) {if (mt6816_spi.sample_data & (0x0001 << j))h_count++;}if (h_count & 0x01) {mt6816_spi.pc_flag = false;}else {mt6816_spi.pc_flag = true;break;}}if (mt6816_spi.pc_flag) {mt6816_spi.angle = mt6816_spi.sample_data >> 2;mt6816_spi.no_mag_flag = (bool)(mt6816_spi.sample_data & (0x0001 << 1));}
}#endif/****************************** MT6816 ******************************/
/****************************** MT6816 ******************************/
/****************************** MT6816 ******************************/
MT6816_Typedef mt6816;/*** @brief MT6816初始化* @param NULL* @retval NULL
**/
void REIN_MT6816_Init(void)
{
#ifndef MT6816_Mode
#error "NO define MT6816_Mode"
#endif
#if (MT6816_Mode == MT6816_Mode_PWM)REIN_MT6816_PWM_Signal_Init(); //初始化PWM接口
#elif (MT6816_Mode == MT6816_Mode_SPI)REIN_MT6816_SPI_Signal_Init(); //初始化SPI接口
#elif (MT6816_Mode == MT6816_Mode_ABZ)REIN_MT6816_ABZ_Signal_Init(); //初始化ABZ接口
#else
#error "MT6816_Mode Invalid !!!"
#endif//初始化阶段获取一次角度数据(过滤错误数据)(暂未查明复位后第一次读取数据丢失的原因)REIN_MT6816_Get_AngleData();}/*** @brief MT6816获取角度数据* @param NULL* @retval NULL
**/
void REIN_MT6816_Get_AngleData(void)
{
#ifndef MT6816_Mode
#error "NO define MT6816_Mode"
#endif
#if (MT6816_Mode == MT6816_Mode_PWM)REIN_MT6816_PWM_Get_AngleData(); //MT6816_PWM获取角度数据mt6816.angle_data = mt6816_pwm.angle;mt6816.angle = 360*mt6816.angle_data/16384.00f; //转换后的角度0 - 360
#elif (MT6816_Mode == MT6816_Mode_SPI)RINE_MT6816_SPI_Get_AngleData();mt6816.angle_data = mt6816_spi.angle;mt6816.angle = 360*mt6816.angle_data/16384.00f; //转换后的角度0 - 360
#elif (MT6816_Mode == MT6816_Mode_ABZ)REIN_MT6816_ABZ_Get_AngleData(); //MT6816_ABZ获取角度数据#else
#error "MT6816_Mode Invalid !!!"
#endif
}#if (MT6816_Mode == MT6816_Mode_PWM)
/*** @brief TIM3_IRQHandler
**/
void TIM3_IRQHandler(void)
{//TIM3的中断标志清除由PWM处理函数识别并清除REIN_MT6816_PWM_TIM_Callback(); //MT6816_PWM采集中断回调
}
#endif#if (MT6816_Mode == MT6816_Mode_ABZ)
/*** @brief EXTI15_10_IRQHandler
**/
void EXTI15_10_IRQHandler(void)
{if (__HAL_GPIO_EXTI_GET_IT(MT6816_ABZ_Z_Pin) != 0x00u){__HAL_GPIO_EXTI_CLEAR_IT(MT6816_ABZ_Z_Pin);REIN_MT6816_ABZ_ZPulse_Callback(); //编码器器Z脉冲中断}
}
#endif
- 🌿mt6816.h
/************************************************************************************** @project : XDrive_Step** @brief : Stepper motor with multi-function interface and closed loop function.** @brief : 具有多功能接口和闭环功能的步进电机** @author : unlir (知不知啊)** @contacts: QQ.1354077136******** @address : https://github.com/unlir/XDrive************************************************************************************** {Stepper motor with multi-function interface and closed loop function.}** Copyright (c) {2020} {unlir(知不知啊)}**** This program is free software: you can redistribute it and/or modify** it under the terms of the GNU General Public License as published by** the Free Software Foundation, either version 3 of the License, or** (at your option) any later version.**** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.**** You should have received a copy of the GNU General Public License** along with this program. If not, see <http://www.gnu.org/licenses/>.******************************************************************************
******/#ifndef MT6816_H
#define MT6816_H#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
//引用端口定义/********** MT6816 **********/
//MT6816模式控制(GPIO)
#define SENSOR_HVPP_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() //PA7
#define SENSOR_HVPP_GPIO_Port (GPIOA)
#define SENSOR_HVPP_Pin (GPIO_PIN_7)
//MT6816_PWM采集(AFIO & TIM)
#define MT6816_PWM_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() //PA6
#define MT6816_PWM_GPIO_Port (GPIOA)
#define MT6816_PWM_Pin (GPIO_PIN_6)
#define MT6816_PWM_TIM_CLK_ENABLE() __HAL_RCC_TIM3_CLK_ENABLE() //TIM3
#define MT6816_PWM_Get_TIM (TIM3)
#define MT6816_PWM_Get_HTIM (htim3)
#define MT6816_PWM_Get_IRQn (TIM3_IRQn) //TIM3中断
//MT6816_ABZ采集(GPIO)
#define MT6816_ABZ_Z_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() //PA10
#define MT6816_ABZ_Z_GPIO_Port (GPIOA)
#define MT6816_ABZ_Z_Pin (GPIO_PIN_10)
#define MT6816_ABZ_Z_EXTI_IRQn (EXTI15_10_IRQn) //EXTI15_10中断
//MT6816_ABZ采集(AFIO & TIM)
#define MT6816_ABZ_A_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() //PA8
#define MT6816_ABZ_A_GPIO_Port (GPIOA)
#define MT6816_ABZ_A_Pin (GPIO_PIN_8)
#define MT6816_ABZ_B_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() //PA9
#define MT6816_ABZ_B_GPIO_Port (GPIOA)
#define MT6816_ABZ_B_Pin (GPIO_PIN_9)
#define MT6816_ABZ_TIM_CLK_ENABLE() __HAL_RCC_TIM1_CLK_ENABLE() //TIM1
#define MT6816_ABZ_Get_TIM (TIM1)
#define MT6816_ABZ_Get_HTIM (htim1)
//MT6816_SPI采集(GPIO)
//#define MT6816_SPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //PB12
//#define MT6816_SPI_CS_GPIO_Port (GPIOB)
//#define MT6816_SPI_CS_Pin (GPIO_PIN_12)
//MT6816_SPI采集(AFIO & SPI)
//#define MT6816_SPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //PB13
//#define MT6816_SPI_CLK_GPIO_Port (GPIOB)
//#define MT6816_SPI_CLK_Pin (GPIO_PIN_13)
//#define MT6816_SPI_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //PB14
//#define MT6816_SPI_MISO_GPIO_Port (GPIOB)
//#define MT6816_SPI_MISO_Pin (GPIO_PIN_14)
//#define MT6816_SPI_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //PB15
//#define MT6816_SPI_MOSI_GPIO_Port (GPIOB)
//#define MT6816_SPI_MOSI_Pin (GPIO_PIN_15)
//#define MT6816_SPI_SPI_CLK_ENABLE() __HAL_RCC_SPI2_CLK_ENABLE(); //SPI2
//#define MT6816_SPI_Get_SPI (SPI2)
//#define MT6816_SPI_Get_HSPI (hspi2)
//#define MT6816_SPI_AFIO_REMAP __HAL_AFIO_REMAP_SPI2_ENABLE(); //SPI2_AFIO端口重新映射/********** MT6816 **********/
//MT6816_SPI采集(GPIO)
#define MT6816_SPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() //PA15
#define MT6816_SPI_CS_GPIO_Port (GPIOA)
#define MT6816_SPI_CS_Pin (GPIO_PIN_15)
//MT6816_SPI采集(AFIO & SPI)
#define MT6816_SPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //PB3
#define MT6816_SPI_CLK_GPIO_Port (GPIOB)
#define MT6816_SPI_CLK_Pin (GPIO_PIN_3)
#define MT6816_SPI_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //PB4
#define MT6816_SPI_MISO_GPIO_Port (GPIOB)
#define MT6816_SPI_MISO_Pin (GPIO_PIN_4)
#define MT6816_SPI_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //PB5
#define MT6816_SPI_MOSI_GPIO_Port (GPIOB)
#define MT6816_SPI_MOSI_Pin (GPIO_PIN_5)
#define MT6816_SPI_SPI_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE(); //SPI1
#define MT6816_SPI_Get_SPI (SPI1)
#define MT6816_SPI_Get_HSPI (hspi1)
#define MT6816_SPI_AFIO_REMAP __HAL_AFIO_REMAP_SPI1_ENABLE(); //SPI1_AFIO端口重新映射
#define MT6816_SPI_Prescaler (SPI_BAUDRATEPRESCALER_8)
//MT6816工作模式定义
#define MT6816_Mode_PWM (0x01) //MT6816工作在PWM模式 (支持该模式的硬件版本:XDrive_REIN_Basic_H1_0)
#define MT6816_Mode_ABZ (0x02) //MT6816工作在ABZ模式 (支持该模式的硬件版本:XDrive_REIN_Basic_H1_0)
#define MT6816_Mode_SPI (0x03) //MT6816工作在SPI模式 (支持该模式的硬件版本:XDrive_REIN_Basic_H1_0 / XDrive_REIN_Basic_H1_1)//MT6816工作模式配置
#define MT6816_Mode MT6816_Mode_PWM#if (MT6816_Mode == MT6816_Mode_PWM)
#include "tim.h"
/********** MT6816_PWM **********/
/********** MT6816_PWM **********/
/********** MT6816_PWM **********/
typedef struct {//采集数据(PWM)uint16_t h_width; //PWM高宽度uint16_t period; //PWM周期uint8_t count_rising; //PWM上升沿计数器镜像uint8_t count_falling; //PWM下降沿计数器镜像uint8_t count_update; //PWM更新计数器bool whole_h_flag; //PWM全高标志bool whole_l_flag; //PWM全低标志bool ready_once; //PWM就绪标志(完成一次PWM采集后置位)bool ready_again; //PWM就绪标志(完成二次PWM采集后置位)uint16_t valid_width; //PWM有效宽度//输出数据(PWM)uint16_t angle;
} MT6816_PWM_Signal_Typedef;//MT6816_PWM
void REIN_MT6816_PWM_Signal_Init(void); //MT6816_PWM采集初始化
void REIN_MT6816_PWM_TIM_Callback(void); //MT6816_PWM采集中断回调
void REIN_MT6816_PWM_Get_AngleData(void); //MT6816_PWM获取角度数据#elif (MT6816_Mode == MT6816_Mode_ABZ)
/********** MT6816_ABZ **********/
/********** MT6816_ABZ **********/
/********** MT6816_ABZ **********/
typedef struct {//采集数据(ABZ)uint16_t sample_data; //ABZ读取到的数据//输出数据(ABZ)uint16_t angle; //ABZ输出的角度
} MT6816_ABZ_Signal_Typedef;//MT6816_ABZ
void REIN_MT6816_ABZ_Signal_Init(void); //MT6816_ABZ采集初始化
void REIN_MT6816_ABZ_ZPulse_Callback(void); //MT6816_ABZ采集Z脉冲中断回调
void REIN_MT6816_ABZ_Get_AngleData(void); //MT6816_ABZ获取角度数据#elif (MT6816_Mode == MT6816_Mode_SPI)
#include "spi.h"
/********** MT6816_SPI **********/
/********** MT6816_SPI **********/
/********** MT6816_SPI **********/
typedef struct {//采集数据uint16_t sample_data; //SPI读取到的数据//输出数据uint16_t angle; //SPI输出的角度bool no_mag_flag; //磁铁数据有效标志bool pc_flag; //奇偶校验位
} MT6816_SPI_Signal_Typedef;//MT6816_SPI
void REIN_MT6816_SPI_Signal_Init(void); //MT6816_SPI采集初始化
void RINE_MT6816_SPI_Get_AngleData(void); //MT6816_SPI采集获取角度数据#endif/********** MT6816 **********/
/********** MT6816 **********/
/********** MT6816 **********/
typedef struct {uint16_t angle_data; //角度数据float angle; //换算陈0 - 360 角度数据
// bool rectify_valid; //校准数据有效标志
} MT6816_Typedef;
extern MT6816_Typedef mt6816;//MT6816
void REIN_MT6816_Init(void); //MT6816初始化
void REIN_MT6816_Get_AngleData(void); //MT6816获取角度数据#ifdef __cplusplus
}
#endif#endif
⛳驱动代码使用说明
- 🔖驱动代码基于
STM32F103
,SPI/ABZ/PWM 3方式读取MT6816磁编码器数据做过实测验证。 - 🌿SPI方式默认采用的是SPI1。
- 🌿ABZ方式需要用到TIM1定时器。
- 🌿PWM方式需要利用到TIM3定时器。
🔧STM32CubeMX
工程配置说明:
- 针对使用不同通讯方式:
-
SPI方式:使能spi1接口即可。(驱动代码中已经包含了对SPI1的初始化代码,其他方式相同,主要是为例生成驱动文件,用来包含
spi.h
、tim.h
头文件)
-
ABZ模式:使能定时器TIM1既可。
-
PWM方式:使能定时器TIM3即可。
-
🌟生成的驱动代码,默认初始化的函数用不到,全部注释掉:(驱动代码中已经包含了相关初始化代码)
-
📑调用方式:
REIN_MT6816_Init();//初始化MT6816
#if (MT6816_Mode == MT6816_Mode_PWM)HAL_NVIC_SetPriority(MT6816_PWM_Get_IRQn, 1, 0); //定时器捕获(MT6816_PWM_PWM)获取MT6816_PWM两个边沿计数值
#endif
#if (MT6816_Mode == MT6816_Mode_ABZ)HAL_NVIC_SetPriority(MT6816_ABZ_Z_EXTI_IRQn, 1, 0); //外部中断(MT6816_ABZ_Z脉冲) 矫正MT6816_ABZ信号
#endif
while(1) {REIN_MT6816_Get_AngleData(); //MT6816获取角度数据printf("angle_data:%d,angle:%.2f\r\n", mt6816.angle_data, mt6816.angle);HAL_Delay(1000);}
- 🔖以下资源性链接不公开,为避免文章和资源被爬取和盗用,不再对外公布相关资源链接,如果按照上面提供的驱动代码无法独立驱动起来,而你是真正需要这份源码作为参考,用于个人学习研究,可以私信作者,其具体文章和相关资源。
相关文章:
HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据
HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据 📚MT6816相关资料(来自商家的相关资料): 资料:https://pan.baidu.com/s/1CAbdLBRi2dmL4D7cFve1XA?pwd8888 提取码:8888📍驱动代码编写&…...
HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 多选题序号5
基础认证题库请移步:HarmonyOS应用开发者基础认证题库 注:有读者反馈,题库的代码块比较多,打开文章时会卡死。所以笔者将题库拆分,单选题20个为一组,多选题10个为一组,题库目录如下,…...
Tekion 选择 ClickHouse Cloud 提升应用性能和指标监控
本文字数:4187;估计阅读时间:11 分钟 作者:ClickHouse team 本文在公众号【ClickHouseInc】首发 Tekion 由前 Tesla CIO Jay Vijayan 于 2016 年创立,利用大数据、人工智能和物联网等技术,为其汽车客户解决…...
mysql之触发器的使用
cr一:创建goods表和orders表; mysql> use mydb16_tirgeer Database changed mysql> create table goods(-> gid char(8) primary key,-> name varchar(10),-> price decimal(8,2),->-> num int); Query OK, 0 rows affected (0.0…...
使用Java和Hazelcast实现分布式数据存储
使用Java和Hazelcast实现分布式数据存储 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 在分布式系统中,实现高效的数据存储和管理是非常重要的。Hazelcast作为一个内存数据网格(IMDG)&…...
Hi3751V560_SELinux
Hi3751V560_SELinux setenforce Enforcing setenforce Permissive(或“setenforce 0”) getenforce V560:demo本身的: [ 13.765161] type=1400 audit(1628821512.905:4): avc: denied { read } for pid=1926 comm="system_server" name="ifindex" d…...
邮件安全篇:邮件反垃圾系统运作机制简介
1. 什么是邮件反垃圾系统? 邮件反垃圾系统是一种专门设计用于检测、过滤和阻止垃圾邮件的技术解决方案。用于保护用户的邮箱免受未经请求的商业广告、诈骗信息、恶意软件、钓鱼攻击和其他非用户意愿接收的电子邮件的侵扰。 反垃圾系统的常见部署形式 2. 邮件反垃圾…...
LoRaWAN设备的两种入网方式(ABP和OTAA)
目录 一、OTAA 1、名词解释 2、入网流程 二、ABP 三、两种入网方式的比较 一、OTAA 1、名词解释 (1)AppEUI:64位(8字节)的唯一标识符,用于标识特定的应用程序或组织(如果用的是chirpstac…...
【Rust光年纪】极致性能与灵活选择:Rust语言数学优化库详解
Rust语言中的数学优化:六大利器汇总 前言 在当今信息时代,数据处理和数学优化成为了各行各业中不可或缺的重要环节。为了满足对高效、快速计算的需求,Rust语言逐渐成为了许多开发者的首选,因其性能优越、并发安全等特点。本文将…...
机器学习 | 回归算法原理——最小二乘法
Hi,大家好,我是半亩花海。很早便想学习并总结一本很喜欢的机器学习图书——立石贤吾的《白话机器学习的数学》,可谓通俗易懂,清晰形象。那就在此分享并作为学习笔记来记录我的学习过程吧!本章的回归算法原理基于《基于…...
.NET Core 中的字符串压缩方法
字符串压缩的概念 字符串压缩通常指的是通过算法减少字符串表示所需的数据量,同时保持字符串的原始信息或能够无损地恢复原始字符串。这种压缩可以是针对文本数据的特定算法,也可以是更通用的数据压缩算法。 .NET Core 中的字符串压缩方法 使用数据压…...
SQL 基础知识
SQL(结构化查询语言)是一种用于管理和操作关系数据库的标准编程语言。以下是一些 SQL 的基础知识: 基本概念 数据库(Database): 存储和管理数据的容器。一个数据库可以包含多个表。 表(Table&…...
【数据结构初阶】单链表经典算法题十二道——得道飞升(上篇)
目录 1、移除元素 2、反转链表 3、链表的中间节点 4、合并两个有序链表 Relaxing Time!!! ———————————————— 天气之子幻 ———————————————— 1、移除元素 思路: 创建一个新链表࿰…...
Python爬虫技术 第16节 XPath
XPath是一种在XML文档中查找信息的语言,尽管XML和HTML在语法上有区别,但XPath同样适用于HTML文档的解析,尤其是在使用如lxml这样的库时。XPath提供了一种强大的方法来定位和提取XML/HTML文档中的元素和属性。 XPath基础 XPath表达式由路径表…...
本地部署,Whisper: 开源语音识别模型
目录 简介 特点 应用 使用方法 总结 GitHub - openai/whisper: Robust Speech Recognition via Large-Scale Weak SupervisionRobust Speech Recognition via Large-Scale Weak Supervision - openai/whisperhttps://github.com/openai/whisper 简介 Whisper 是一个由 O…...
history,hash缓存那些事
vue-router 中的 createWebHistory,createWebHashHistory两种模式 createWebHistory 是基于 window.history 对象是HTML5提供的用于维护当前标签页浏览历史的对象,主要功能是前进后退和在不刷新页面的情况下,修改地址栏里的URL地址。histor…...
Spring Boot的Web开发
目录 Spring Boot的Web开发 1.静态资源映射规则 第一种静态资源映射规则 2.enjoy模板引擎 3.springMVC 3.1请求处理 RequestMapping DeleteMapping 删除 PutMapping 修改 GetMapping 查询 PostMapping 新增 3.2参数绑定 一.支持数据类型: 3.3常用注解 一.Request…...
Spark 解析嵌套的 JSON 文件
1、什么是嵌套的JSON文件? 嵌套的JSON文件是指文件中包含了嵌套的JSON对象或数组。例如,以下是一个嵌套的JSON文件的示例: {"name": "John","age": 30,"address": {"street": "123…...
VMware虚拟机中CentOS7自定义ip地址并且固定ip
配置固定ip(虚拟机) 前提:虚拟机网络配置成,自定义网络并选择VMnet8(NAT 模式) 操作(如下图):点击虚拟机–》设置–》–》硬件–》网络适配器–》自定义:特定虚拟网络–》选择:VMnet8(NAT 模式) 虚拟机网络设置 需要记…...
CCS(Code Composer Studio 10.4.0)编译软件中文乱码怎么解决
如果是所有文件都出现了中文乱码这时建议直接在窗口首选项中修改:选择"Window" -> "Preferences",找到"General" -> "Workspace",将"Text file encoding"选项设置为"Other&quo…...
Flutter 3 完全支持网页端
Flutter 3 可以用于开发网页端应用。自 Flutter 2.0 起,Flutter 就已经支持 Web 平台,并且在 Flutter 3 中得到了进一步的改进和优化。以下是使用 Flutter 3 开发网页端的一些优势和特点: Flutter 3 开发网页端的优势: 跨平台一致…...
vue.js入门
目录 一. 框架概述 二. vue常用命令 2.1 插值表达式 2.2 v-text 2.3 v-html 2.4 v-on 2.5 v-model 2.6 v-show 2.7 v-if 2.8 v-else 2.9 v-bind 2.10 v-for 三. vue生命周期函数 目录 一. 框架概述 二. vue常用命令 2.1 插值表达式 2.2 v-text 2.3 v-html 2…...
API签名认证
前言(项目背景): 这个API签名认证是API开放平台得一个重要环节,我们知道,这个API开发平台,用处就是给客户去调用现成得接口来完成某些事情得。 在讲API签名认证之前,我们先模拟一个场景并且介绍…...
C#进阶-基于.NET Framework 4.x框架实现ASP.NET WebForms项目IP拦截器
在这篇文章中,我们将探讨如何在 ASP.NET WebForms 中实现IP拦截器,以便在 ASMX Web 服务方法 和 HTTP 请求 中根据IP地址进行访问控制。我们将使用自定义的 SoapExtension 和 IHttpModule 来实现这一功能,并根据常用的两种文本传输协议&#…...
前端(1)HTML
1、标签 创建1.html文件,浏览器输入E:/frontheima/1.html,可以访问页面 页面展示 在VSCODE安装IDEA的快捷键,比如ctld复制一行、ctrlx剪切 <p id"p1" title"标题1">Hello,world!</p> <p id"p2"…...
【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十三章 设备树下的platform驱动
i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…...
Java正则表达式判断有无特殊字符
//^代表否定,匹配除了数字、字母、下划线的特殊字符。 private static final String SPECIAL_CHAR_PATTERN "[^a-zA-Z0-9_]"; Pattern pattern Pattern.compile(SPECIAL_CHAR_PATTERN); Matcher matcher pattern.matcher(userAccount); // 如果 find(…...
使用Java和Spring AMQP构建消息驱动应用
使用Java和Spring AMQP构建消息驱动应用 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 消息驱动应用程序在现代系统架构中扮演着重要角色,特别是在处理高并发和异步任务时。Spring AMQ…...
【NLP】提升文本生成多样性的实用方法
比如用T5模型,训练数据是inputText-outputText格式,预测时do_sample=False # 预测代码from transformers import TFAutoModelForSeq2SeqLM from transformers import AutoTokenizercheckpoint_local = "./path/" tokenizer = AutoTokenizer.from_pretrained(check…...
鸿蒙(HarmonyOS)下拉选择控件
一、操作环境 操作系统: Windows 11 专业版、IDE:DevEco Studio 3.1.1 Release、SDK:HarmonyOS 3.1.0(API 9) 二、效果图 三、代码 SelectPVComponent.ets Component export default struct SelectPVComponent {Link selection: SelectOption[]priva…...
Java类加载器实现机制详细笔记
1. 类加载器的基本概念 类加载器(ClassLoader):在Java中,类加载器负责将Java类动态加载到JVM中。它是实现动态类加载机制的核心组件,对于开发复杂应用程序(如插件系统、模块化设计等)至关重要。…...
Git之repo sync -l与repo forall -c git checkout用法区别(四十九)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...
【公式解释】《系统论》《控制论》《信息论》的共同重构:探索核心公式与深度解析
《系统论》《控制论》《信息论》的共同重构:探索核心公式与深度解析 关键词:系统论、控制论、信息论、状态空间方程、系统矩阵。 Keywords: System theory, Control theory, Information theory, State-space equations, System matrices. 核心公式与三论共同之处 在系统…...
电脑格式化好还是恢复出厂设置好?
电脑格式化好还是恢复出厂设置好?使用电脑的过程中,系统问题、病毒感染、性能下降等原因可能会导致我们考虑对电脑进行大规模的清理和恢复操作。本文将详细探讨电脑格式化和恢复出厂设置的区别、优缺点,以及不同场景选择哪种方法合适。 选择电…...
使用 Windows 应用程序 SDK 构建下一代应用程序
微软面临的最大问题之一是如何让 Windows 再次成为吸引开发者的平台。无论用户使用什么设备和操作系统,都可以很容易地将 Web 前端放在支持桌面和移动用户的云原生应用程序上。 我们处在一个奇怪的境地,唯一能利用最新 PC 硬件的应用程序是 Office、Phot…...
可消费的媒体类型和可生成的媒体类型
可消费的媒体类型和可生成的媒体类型 在 Spring MVC 中,“可消费的媒体类型”和“可生成的媒体类型”是两个重要的概念,用于控制控制器方法处理和返回的内容类型。它们分别通过 consumes 和 produces 属性来指定。下面是它们的详细区别: 可…...
C++中指针与迭代器的区别
C中的迭代器和指针都是用于访问和操作内存中的数据结构的机制,但它们在使用方式和功能上有一些关键的区别。 #mermaid-svg-23bevhEih3Ch4ucl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-23bevhEih3Ch…...
若依框架 : 生成代码
6.生成代码 6.1.配置生成设置 ruoyi-generator -> src -> main -> resources -> generator.yml 由于 案例中 表都有 前缀 为 tta_ , 这里设置去掉 6.2.生成代码 6.2.1.导入数据库中的表 6.2.2.修改设置 6.2.2.1.设置生成信息 点击 编辑 -> 生成信息 特别…...
RTMP协议解析
RTMP(Real Time Message Protocol)是一种由Adobe公司提出的应用层协议,主要用于实时音视频数据的传输。RTMP协议的主要有以下特点: 1. 多路复用:RTMP允许多个音视频数据流在单个TCP连接上进行传输。 2. 分包传输&…...
禁忌搜索算法(Tabu Search,TS)及其Python和MATLAB实现
禁忌搜索算法是一种现代启发式搜索方案,主要用于解决组合优化问题。该算法由George F. Lugeral于1986年首次提出,旨在增强局部搜索算法的性能,避免其陷入局部最优解。禁忌搜索利用一个称为“禁忌表”的数据结构,记住最近访问的解决…...
Meta发布Llama 3.1 405B模型:开源与闭源模型之争的新篇章
引言 在人工智能领域,开源与闭源模型之争一直是热点话题。近日,Meta发布了最新的Llama 3.1 405B模型,以其强大的性能和庞大的参数规模,成为了开源模型中的佼佼者。本文将详细介绍Llama 3.1 405B模型的性能、功能及其在开源领域的…...
Linux网络协议深度解析:从IP到TCP/IP堆栈
Linux网络协议深度解析是一个复杂而详细的主题,它涵盖了从基本的数据包传输到复杂的协议交互。以下是对"Linux网络协议深度解析:从IP到TCP/IP堆栈"这一主题的简要解析: IP协议(Internet Protocol) •作用:…...
AWS DMS MySQL为源端,如何在更改分区的时候避免报错
问题描述: 文档[1]中描述MySQL compatible Databases作为DMS任务的源端,不支持MySQL 分区表的 DDL 更改。 在源端MySQL进行分区添加时,日志里会出现如下报错: [SOURCE_CAPTURE ]W: Cannot change partition in table members…...
Java从基础到高级特性及应用
Java,作为一门历史悠久且广泛应用的编程语言,自1995年问世以来,便以其跨平台性、面向对象、自动内存管理等特点,在软件开发领域占据了举足轻重的地位。从桌面应用到企业级系统,从移动开发到云计算服务,Java…...
JavaScript(17)——事件监听
什么是事件? 事件是在编程时系统内发生的动作或发生的事情,比如用户在网页上单击一个按钮 什么是事件监听? 就是让程序检测是否有事件产生,一旦有事件触发,就立刻调用一个函数做出响应,也称为绑定事件或…...
Dav_笔记11:SQL Tuning Overview-sql调优 之 4
开发高效的SQL语句 本节介绍了提高SQL语句效率的方法: ■验证优化程序统计信息 ■审查执行计划 ■重构SQL语句 ■重组索引 ■修改或禁用触发器和约束 ■重组数据 ■随着时间的推移维护执行计划 ■尽可能少地访问数据 验证优化程序统计信息 查询优化器在确定最佳执行…...
vue3引入openlayers
安装ol包 OpenLayers作为 ol npm包提供,它提供了官方支持的API的所有模块。 官方地址:ol npm install ol模块和子模块约定 具有CamelCase名称的OpenLayers模块提供类作为默认导出,并且可能包含其他常量或函数作为命名导出: i…...
大数据管理中心设计规划方案(可编辑的43页PPT)
引言:随着企业业务的快速发展,数据量急剧增长,传统数据管理方式已无法满足高效处理和分析大数据的需求。建立一个集数据存储、处理、分析、可视化于一体的大数据管理中心,提升数据处理能力,加速业务决策过程࿰…...
Android --- 广播
广播是什么? 一种相互通信,传递信息的机制,组件内、进程间(App之间) 如何使用广播? 组成部分 发送者-发送广播 与启动其他四大组件一样,广播发送也是使用intent发送。 设置actionÿ…...
AR 眼镜之-蓝牙电话-实现方案
目录 📂 前言 AR 眼镜系统版本 蓝牙电话 来电铃声 1. 🔱 技术方案 1.1 结构框图 1.2 方案介绍 1.3 实现方案 步骤一:屏蔽原生蓝牙电话相关功能 步骤二:自定义蓝牙电话实现 2. 💠 屏蔽原生蓝牙电话相关功能 …...