第一版代码,为了在EEPROM保存参数的时候走STM32的CRC,让Codex修改了一下,现在的效果是无法存储,codex表示原因是CRC方法不同,修改到一半今天的额度使用完了,有待后续解决CRC的bug
This commit is contained in:
161
Interface/Int_EEPROM24xx.c
Normal file
161
Interface/Int_EEPROM24xx.c
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "Int_EEPROM24xx.h"
|
||||
#include "i2c.h"
|
||||
|
||||
static uint8_t g_inited = 0u;
|
||||
static uint32_t g_last_hal_error = 0u;
|
||||
|
||||
static int32_t Int_EEPROM24xx_CheckRange(uint32_t mem_addr, uint16_t len)
|
||||
{
|
||||
uint32_t end_addr;
|
||||
|
||||
if (len == 0u)
|
||||
{
|
||||
return INT_EEPROM_ERR_ARG;
|
||||
}
|
||||
|
||||
end_addr = mem_addr + (uint32_t)len;
|
||||
if (end_addr < mem_addr)
|
||||
{
|
||||
return INT_EEPROM_ERR_RANGE;
|
||||
}
|
||||
|
||||
if (end_addr > INT_EEPROM24XX_MEM_SIZE_BYTES)
|
||||
{
|
||||
return INT_EEPROM_ERR_RANGE;
|
||||
}
|
||||
|
||||
return INT_EEPROM_OK;
|
||||
}
|
||||
|
||||
static uint16_t Int_EEPROM24xx_GetMemAddrSizeHal(void)
|
||||
{
|
||||
return (INT_EEPROM24XX_MEM_ADDR_SIZE == 1u) ? I2C_MEMADD_SIZE_8BIT : I2C_MEMADD_SIZE_16BIT;
|
||||
}
|
||||
|
||||
static int32_t Int_EEPROM24xx_WaitReady(void)
|
||||
{
|
||||
if (HAL_I2C_IsDeviceReady(&INT_EEPROM24XX_I2C_HANDLE,
|
||||
INT_EEPROM24XX_DEV_ADDR,
|
||||
20u,
|
||||
INT_EEPROM24XX_TIMEOUT_MS) == HAL_OK)
|
||||
{
|
||||
g_last_hal_error = 0u;
|
||||
return INT_EEPROM_OK;
|
||||
}
|
||||
|
||||
g_last_hal_error = HAL_I2C_GetError(&INT_EEPROM24XX_I2C_HANDLE);
|
||||
return INT_EEPROM_ERR_IO;
|
||||
}
|
||||
|
||||
int32_t Int_EEPROM24xx_Init(void)
|
||||
{
|
||||
if ((INT_EEPROM24XX_PAGE_SIZE == 0u) || (INT_EEPROM24XX_MEM_SIZE_BYTES == 0u))
|
||||
{
|
||||
return INT_EEPROM_ERR_ARG;
|
||||
}
|
||||
|
||||
if ((INT_EEPROM24XX_MEM_ADDR_SIZE != 1u) && (INT_EEPROM24XX_MEM_ADDR_SIZE != 2u))
|
||||
{
|
||||
return INT_EEPROM_ERR_ARG;
|
||||
}
|
||||
|
||||
g_inited = 1u;
|
||||
g_last_hal_error = 0u;
|
||||
return INT_EEPROM_OK;
|
||||
}
|
||||
|
||||
int32_t Int_EEPROM24xx_Read(uint32_t mem_addr, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
int32_t st;
|
||||
|
||||
if (g_inited == 0u)
|
||||
{
|
||||
return INT_EEPROM_ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (buf == 0)
|
||||
{
|
||||
return INT_EEPROM_ERR_ARG;
|
||||
}
|
||||
|
||||
st = Int_EEPROM24xx_CheckRange(mem_addr, len);
|
||||
if (st != INT_EEPROM_OK)
|
||||
{
|
||||
return st;
|
||||
}
|
||||
|
||||
if (HAL_I2C_Mem_Read(&INT_EEPROM24XX_I2C_HANDLE,
|
||||
INT_EEPROM24XX_DEV_ADDR,
|
||||
(uint16_t)mem_addr,
|
||||
Int_EEPROM24xx_GetMemAddrSizeHal(),
|
||||
buf,
|
||||
len,
|
||||
INT_EEPROM24XX_TIMEOUT_MS) == HAL_OK)
|
||||
{
|
||||
g_last_hal_error = 0u;
|
||||
return INT_EEPROM_OK;
|
||||
}
|
||||
|
||||
g_last_hal_error = HAL_I2C_GetError(&INT_EEPROM24XX_I2C_HANDLE);
|
||||
return INT_EEPROM_ERR_IO;
|
||||
}
|
||||
|
||||
int32_t Int_EEPROM24xx_Write(uint32_t mem_addr, const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
uint16_t written = 0u;
|
||||
|
||||
if (g_inited == 0u)
|
||||
{
|
||||
return INT_EEPROM_ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (buf == 0)
|
||||
{
|
||||
return INT_EEPROM_ERR_ARG;
|
||||
}
|
||||
|
||||
if (Int_EEPROM24xx_CheckRange(mem_addr, len) != INT_EEPROM_OK)
|
||||
{
|
||||
return INT_EEPROM_ERR_RANGE;
|
||||
}
|
||||
|
||||
while (written < len)
|
||||
{
|
||||
uint32_t cur_addr = mem_addr + (uint32_t)written;
|
||||
uint16_t page_off = (uint16_t)(cur_addr % INT_EEPROM24XX_PAGE_SIZE);
|
||||
uint16_t room = (uint16_t)(INT_EEPROM24XX_PAGE_SIZE - page_off);
|
||||
uint16_t remain = (uint16_t)(len - written);
|
||||
uint16_t chunk = (remain < room) ? remain : room;
|
||||
|
||||
if (HAL_I2C_Mem_Write(&INT_EEPROM24XX_I2C_HANDLE,
|
||||
INT_EEPROM24XX_DEV_ADDR,
|
||||
(uint16_t)cur_addr,
|
||||
Int_EEPROM24xx_GetMemAddrSizeHal(),
|
||||
(uint8_t *)&buf[written],
|
||||
chunk,
|
||||
INT_EEPROM24XX_TIMEOUT_MS) != HAL_OK)
|
||||
{
|
||||
g_last_hal_error = HAL_I2C_GetError(&INT_EEPROM24XX_I2C_HANDLE);
|
||||
return INT_EEPROM_ERR_IO;
|
||||
}
|
||||
|
||||
if (INT_EEPROM24XX_WRITE_CYCLE_MS > 0u)
|
||||
{
|
||||
HAL_Delay(INT_EEPROM24XX_WRITE_CYCLE_MS);
|
||||
}
|
||||
|
||||
if (Int_EEPROM24xx_WaitReady() != INT_EEPROM_OK)
|
||||
{
|
||||
return INT_EEPROM_ERR_IO;
|
||||
}
|
||||
|
||||
written = (uint16_t)(written + chunk);
|
||||
}
|
||||
|
||||
return INT_EEPROM_OK;
|
||||
}
|
||||
|
||||
uint32_t Int_EEPROM24xx_GetLastHalError(void)
|
||||
{
|
||||
return g_last_hal_error;
|
||||
}
|
||||
27
Interface/Int_EEPROM24xx.h
Normal file
27
Interface/Int_EEPROM24xx.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef INT_EEPROM24XX_H
|
||||
#define INT_EEPROM24XX_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#define INT_EEPROM_OK 0
|
||||
#define INT_EEPROM_ERR_ARG -1
|
||||
#define INT_EEPROM_ERR_IO -2
|
||||
#define INT_EEPROM_ERR_NOT_INIT -3
|
||||
#define INT_EEPROM_ERR_RANGE -4
|
||||
|
||||
/* Compile-time configuration for M24C64 on this board. */
|
||||
#define INT_EEPROM24XX_DEV_ADDR (0x50u << 1)
|
||||
#define INT_EEPROM24XX_I2C_HANDLE hi2c2
|
||||
#define INT_EEPROM24XX_PAGE_SIZE 32u
|
||||
#define INT_EEPROM24XX_MEM_ADDR_SIZE 2u
|
||||
#define INT_EEPROM24XX_MEM_SIZE_BYTES 8192u
|
||||
#define INT_EEPROM24XX_WRITE_CYCLE_MS 20u
|
||||
#define INT_EEPROM24XX_TIMEOUT_MS 100u
|
||||
|
||||
int32_t Int_EEPROM24xx_Init(void);
|
||||
int32_t Int_EEPROM24xx_Read(uint32_t mem_addr, uint8_t *buf, uint16_t len);
|
||||
int32_t Int_EEPROM24xx_Write(uint32_t mem_addr, const uint8_t *buf, uint16_t len);
|
||||
uint32_t Int_EEPROM24xx_GetLastHalError(void);
|
||||
|
||||
#endif
|
||||
75
Interface/Int_Encoder.c
Normal file
75
Interface/Int_Encoder.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "Int_Encoder.h"
|
||||
|
||||
// 函数:调整ABZ输出分辨率,step为分辨率
|
||||
void Int_Encoder_set_resolution(uint16_t step)
|
||||
{
|
||||
HAL_GPIO_WritePin(ENCODER1_EN_GPIO_Port, ENCODER1_EN_Pin, GPIO_PIN_SET); // 给芯片上电
|
||||
HAL_GPIO_WritePin(ENCODER_MODE_GPIO_Port, ENCODER_MODE_Pin, GPIO_PIN_SET); // 切换到I2C模式
|
||||
|
||||
// 配置I2C
|
||||
|
||||
Dri_I2C_Init();
|
||||
|
||||
// 按照手册给指定寄存器发送指定数据
|
||||
Dri_I2C_Start();
|
||||
Dri_I2C_WriteAddr(ENCODER_I2C_ADDR_WRITE); // 发送从机地址
|
||||
|
||||
Dri_I2C_WriteReg(0x09, 0xB3);
|
||||
Dri_I2C_WriteReg(0x0A, 0x05);
|
||||
Dri_I2C_Stop();
|
||||
HAL_Delay(1000); // 等待EEPROM编程完成
|
||||
|
||||
// 按照手册给芯片重新上电
|
||||
HAL_GPIO_WritePin(ENCODER1_EN_GPIO_Port, ENCODER1_EN_Pin, GPIO_PIN_RESET);
|
||||
HAL_Delay(100);
|
||||
HAL_GPIO_WritePin(ENCODER1_EN_GPIO_Port, ENCODER1_EN_Pin, GPIO_PIN_SET);
|
||||
|
||||
// ABZ_RES一共十位,低8位在0x31寄存器中,高两位在0x30寄存器中的最低两位
|
||||
// 读取ABZ_RES高两位所在寄存器的数据,保留不能修改的bits
|
||||
|
||||
uint8_t data = Dri_I2C_ReadReg(ENCODER_I2C_ADDR_READ, ENCODER_ABZ_RES_H);
|
||||
// debug_printf("read data = 0x%02x", data);
|
||||
uint8_t step_h = step >> 8;
|
||||
|
||||
// 需要写入高两位
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
{
|
||||
if (step_h & (1 << i))
|
||||
data |= (1 << i);
|
||||
else
|
||||
data &= ~(1 << i);
|
||||
}
|
||||
// debug_printf("write data = 0x%02x", data);
|
||||
|
||||
HAL_Delay(1000);
|
||||
|
||||
Dri_I2C_Start();
|
||||
Dri_I2C_WriteAddr(ENCODER_I2C_ADDR_WRITE);
|
||||
Dri_I2C_WriteReg(ENCODER_ABZ_RES_H, data);
|
||||
Dri_I2C_Stop();
|
||||
|
||||
Dri_I2C_Start();
|
||||
Dri_I2C_WriteAddr(ENCODER_I2C_ADDR_WRITE);
|
||||
Dri_I2C_WriteReg(ENCODER_ABZ_RES_L, step & 0xFF);
|
||||
Dri_I2C_Stop();
|
||||
}
|
||||
|
||||
void Int_Encoder_start(void)
|
||||
{
|
||||
// 初始化编码器的引脚(之前用作软件I2C)
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
GPIO_InitStruct.Pin = ENCODER1_A_Pin | ENCODER1_B_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
}
|
||||
|
||||
void Int_Encoder_Init(void)
|
||||
{
|
||||
DWT_init();
|
||||
Int_Encoder_set_resolution(0x03FF);
|
||||
Int_Encoder_start();
|
||||
HAL_TIM_Base_Start_IT(&htim12);
|
||||
}
|
||||
20
Interface/Int_Encoder.h
Normal file
20
Interface/Int_Encoder.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef __INT_ENCODER_H__
|
||||
#define __INT_ENCODER_H__
|
||||
|
||||
#include "Com_debug.h"
|
||||
#include "gpio.h"
|
||||
#include "tim.h"
|
||||
#include "SoftI2C.h"
|
||||
|
||||
#define ENCODER_I2C_ADDR 0x06
|
||||
#define ENCODER_I2C_ADDR_WRITE (ENCODER_I2C_ADDR << 1)
|
||||
#define ENCODER_I2C_ADDR_READ (ENCODER_I2C_ADDR << 1 | 0x01)
|
||||
|
||||
#define ENCODER_ABZ_RES_H 0x30 //只用低两位
|
||||
#define ENCODER_ABZ_RES_L 0x31
|
||||
|
||||
#define ENCODER_PULSES_PER_CIRCLE 4096
|
||||
|
||||
void Int_Encoder_Init(void);
|
||||
|
||||
#endif /* __INT_ENCODER_H__ */
|
||||
148
Interface/Int_Key.c
Normal file
148
Interface/Int_Key.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "Int_Key.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/* 单个按键扫描上下文:
|
||||
* raw_level 原始采样电平
|
||||
* stable_level 去抖后的稳定电平
|
||||
* long_started 是否已上报过长按开始事件
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GPIO_TypeDef *port;
|
||||
uint16_t pin;
|
||||
Key_t key;
|
||||
uint8_t stable_level;
|
||||
uint8_t raw_level;
|
||||
uint8_t long_started;
|
||||
uint32_t last_change_ms;
|
||||
uint32_t press_ms;
|
||||
} KeyScanCtx_t;
|
||||
|
||||
#define KEY_COUNT (5u)
|
||||
#define KEY_SCAN_PERIOD_MS (5u)
|
||||
#define KEY_DEBOUNCE_MS (20u)
|
||||
#define KEY_LONG_MS (400u)
|
||||
#define KEY_QUEUE_SIZE (12u)
|
||||
|
||||
static KeyScanCtx_t s_keys[KEY_COUNT] = {
|
||||
{KEY1_GPIO_Port, KEY1_Pin, KEY_1, 1u, 1u, 0u, 0u, 0u},
|
||||
{KEY2_GPIO_Port, KEY2_Pin, KEY_2, 1u, 1u, 0u, 0u, 0u},
|
||||
{KEY3_GPIO_Port, KEY3_Pin, KEY_3, 1u, 1u, 0u, 0u, 0u},
|
||||
{KEY4_GPIO_Port, KEY4_Pin, KEY_4, 1u, 1u, 0u, 0u, 0u},
|
||||
{KEY5_GPIO_Port, KEY5_Pin, KEY_5, 1u, 1u, 0u, 0u, 0u},
|
||||
};
|
||||
|
||||
static KeyAction_t s_queue[KEY_QUEUE_SIZE];
|
||||
static uint8_t s_q_head = 0u;
|
||||
static uint8_t s_q_tail = 0u;
|
||||
static uint32_t s_last_scan_ms = 0u;
|
||||
|
||||
static uint8_t queue_next(uint8_t v)
|
||||
{
|
||||
/* 环形队列下标递增。 */
|
||||
v++;
|
||||
if (v >= KEY_QUEUE_SIZE)
|
||||
{
|
||||
v = 0u;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static void push_action(Key_t key, KeyEvt_t evt)
|
||||
{
|
||||
/* 队列满时丢弃新事件,避免阻塞主循环。 */
|
||||
uint8_t next = queue_next(s_q_head);
|
||||
if (next == s_q_tail)
|
||||
{
|
||||
return;
|
||||
}
|
||||
s_queue[s_q_head].key = key;
|
||||
s_queue[s_q_head].evt = evt;
|
||||
s_q_head = next;
|
||||
}
|
||||
|
||||
void Int_Key_Task(void)
|
||||
{
|
||||
uint32_t now = HAL_GetTick();
|
||||
/* 固定周期扫描,避免过高频率浪费CPU。 */
|
||||
if ((uint32_t)(now - s_last_scan_ms) < KEY_SCAN_PERIOD_MS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
s_last_scan_ms = now;
|
||||
|
||||
for (uint8_t i = 0u; i < KEY_COUNT; i++)
|
||||
{
|
||||
KeyScanCtx_t *k = &s_keys[i];
|
||||
uint8_t raw = (HAL_GPIO_ReadPin(k->port, k->pin) == GPIO_PIN_RESET) ? 0u : 1u;
|
||||
|
||||
if (raw != k->raw_level)
|
||||
{
|
||||
k->raw_level = raw;
|
||||
k->last_change_ms = now;
|
||||
}
|
||||
|
||||
if ((uint32_t)(now - k->last_change_ms) >= KEY_DEBOUNCE_MS)
|
||||
{
|
||||
if (k->stable_level != k->raw_level)
|
||||
{
|
||||
k->stable_level = k->raw_level;
|
||||
|
||||
if (k->stable_level == 0u)
|
||||
{
|
||||
/* 稳定按下:记录按下时间,等待长按判断。 */
|
||||
k->press_ms = now;
|
||||
k->long_started = 0u;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 稳定释放:若未触发长按则上报CLICK,否则上报RELEASE。 */
|
||||
push_action(k->key, k->long_started ? KEY_EVT_RELEASE : KEY_EVT_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (k->stable_level == 0u)
|
||||
{
|
||||
uint32_t hold_ms = (uint32_t)(now - k->press_ms);
|
||||
if (hold_ms >= KEY_LONG_MS)
|
||||
{
|
||||
if (k->long_started == 0u)
|
||||
{
|
||||
/* 长按开始事件只上报一次。 */
|
||||
k->long_started = 1u;
|
||||
push_action(k->key, KEY_EVT_LONG_START);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Int_Key_PopAction(KeyAction_t *action)
|
||||
{
|
||||
/* 从事件队列弹出一个事件供上层消费。 */
|
||||
if (action == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_q_tail == s_q_head)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*action = s_queue[s_q_tail];
|
||||
s_q_tail = queue_next(s_q_tail);
|
||||
return true;
|
||||
}
|
||||
|
||||
Key_t Int_key_read(void)
|
||||
{
|
||||
/* 兼容旧接口:仅返回按键编号,不区分事件类型。 */
|
||||
KeyAction_t action;
|
||||
if (Int_Key_PopAction(&action))
|
||||
{
|
||||
return action.key;
|
||||
}
|
||||
return KEY_NONE;
|
||||
}
|
||||
12
Interface/Int_Key.h
Normal file
12
Interface/Int_Key.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef __INT_KEY_H__
|
||||
#define __INT_KEY_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "Com_type.h"
|
||||
#include "gpio.h"
|
||||
|
||||
void Int_Key_Task(void);
|
||||
bool Int_Key_PopAction(KeyAction_t *action);
|
||||
Key_t Int_key_read(void);
|
||||
|
||||
#endif /* __INT_KEY_H__ */
|
||||
207
Interface/Int_TMC2209.c
Normal file
207
Interface/Int_TMC2209.c
Normal file
@@ -0,0 +1,207 @@
|
||||
#include "Int_TMC2209.h"
|
||||
|
||||
/*
|
||||
* TIM2 CH1 使用 TOGGLE 模式输出 STEP:
|
||||
* 每次中断只翻转一次电平,两个中断才构成一个完整 STEP 脉冲。
|
||||
*/
|
||||
|
||||
// 静态变量,记录分频状态
|
||||
static uint8_t double_flag = 0;
|
||||
|
||||
void Int_TMC2209_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void Int_TMC2209_set_steps(Stepper_t *stepper)
|
||||
{
|
||||
/* 将目标运动参数换算为总步数和梯形/三角速度曲线参数 */
|
||||
// --- 参数单位定义 ---
|
||||
// stepper->distance -> 代表目标距离 (mm)
|
||||
// stepper->speed -> 代表目标速度 (mm/s)
|
||||
// stepper->acc -> 代表加速度 (mm/s^2)
|
||||
// stepper->start_speed -> 代表启动速度 (mm/s)
|
||||
|
||||
// 1. 计算总步数
|
||||
// 总步数 = 距离(mm) * 每毫米步数
|
||||
stepper->total_step = (uint32_t)(stepper->distance * STEPS_PER_MM);
|
||||
|
||||
// 2. 物理运动学公式计算加速距离
|
||||
// 公式: x = (v^2 - v0^2) / 2a
|
||||
// 单位全部统一为 mm, mm/s, mm/s^2
|
||||
float v_target = stepper->speed; // mm/s
|
||||
float v_start = stepper->start_speed; // mm/s
|
||||
float accel = stepper->acc; // mm/s^2
|
||||
|
||||
// 防止除0错误
|
||||
if (accel == 0 || v_target == 0)
|
||||
return;
|
||||
|
||||
// 计算加速所需的距离 (mm)
|
||||
float acc_distance_mm = (v_target * v_target - v_start * v_start) / (2.0f * accel);
|
||||
|
||||
// 将加速距离转换为加速步数
|
||||
stepper->acc_step = (uint32_t)(acc_distance_mm * STEPS_PER_MM);
|
||||
|
||||
// 3. 规划梯形/三角形速度曲线
|
||||
if (stepper->total_step < stepper->acc_step * 2)
|
||||
{
|
||||
// 距离太短,跑不到目标速度 -> 三角形加减速
|
||||
stepper->acc_step = stepper->total_step / 2;
|
||||
stepper->constant_step = 0;
|
||||
debug_printf("Model: Triangle, AccStep: %d", stepper->acc_step);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 距离足够 -> 梯形加减速
|
||||
stepper->constant_step = stepper->total_step - stepper->acc_step * 2;
|
||||
debug_printf("Model: Trapezoid, Acc: %d, Const: %d", stepper->acc_step, stepper->constant_step);
|
||||
}
|
||||
|
||||
// 4. 计算每一步的速度增量 (mm/s per step)
|
||||
// 逻辑:(目标速度 - 启动速度) / 加速步数
|
||||
// 含义:每走一步,速度增加多少 mm/s
|
||||
if (stepper->acc_step > 0)
|
||||
{
|
||||
stepper->speed_inc = (float)(v_target - v_start) / stepper->acc_step;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepper->speed_inc = 0;
|
||||
}
|
||||
|
||||
// 5. 初始化状态
|
||||
stepper->step_count = 0;
|
||||
stepper->current_speed = stepper->start_speed;
|
||||
stepper->state = ACCELERATE;
|
||||
}
|
||||
|
||||
void Int_stepper_run(void)
|
||||
{
|
||||
/* 仅用于调试的固定步进函数,不参与正式运行逻辑 */
|
||||
// 此函数用于测试,硬编码了步数,建议根据新的 STEPS_PER_MM 修改这里
|
||||
// 例如走 10mm:
|
||||
// uint32_t steps = 10 * STEPS_PER_MM * 2; // *2 是因为 toggle
|
||||
HAL_GPIO_WritePin(STEPPER123_EN_GPIO_Port, STEPPER123_EN_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(STEPPER1_DIR_GPIO_Port, STEPPER1_DIR_Pin, GPIO_PIN_SET);
|
||||
|
||||
// 这里的3200原来是转一圈,现在如果导程是8mm,3200次toggle (1600步) = 8mm
|
||||
for (uint16_t i = 0; i < 3200; i++)
|
||||
{
|
||||
HAL_GPIO_TogglePin(STEPPER_1_STEP_GPIO_Port, STEPPER_1_STEP_Pin);
|
||||
HAL_Delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Int_TMC2209_start(Stepper_t *stepper, Encoder_t *encoder)
|
||||
{
|
||||
/* 启动流程:
|
||||
* 1) 清零编码器基准
|
||||
* 2) 使能驱动并配置方向
|
||||
* 3) 计算速度曲线参数
|
||||
* 4) 配置并启动 TIM2 输出中断
|
||||
*/
|
||||
// 清零编码器值
|
||||
encoder->pulses = 0;
|
||||
encoder->overflow = 0;
|
||||
__HAL_TIM_SET_COUNTER(&htim1, 0);
|
||||
encoder->z = 0;
|
||||
HAL_GPIO_WritePin(ENCODER_MODE_GPIO_Port, ENCODER_MODE_Pin, GPIO_PIN_RESET);
|
||||
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
|
||||
|
||||
// 使能驱动
|
||||
HAL_GPIO_WritePin(STEPPER123_EN_GPIO_Port, STEPPER123_EN_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(STEPPER1_DIR_GPIO_Port, STEPPER1_DIR_Pin, stepper->dir);
|
||||
|
||||
// 复位分频标志位
|
||||
double_flag = 0;
|
||||
|
||||
// 设置步数参数
|
||||
Int_TMC2209_set_steps(stepper);
|
||||
|
||||
// [修改] 计算初始ARR (基于 mm/s)
|
||||
// 最小速度保护,防止ARR计算溢出
|
||||
if (stepper->start_speed < 0.1f)
|
||||
stepper->start_speed = 0.1f;
|
||||
|
||||
// 这里传入的是 mm/s
|
||||
uint32_t arr = CALC_ARR(stepper->start_speed);
|
||||
|
||||
debug_printf("Start Speed: %.2f mm/s, ARR: %d", stepper->start_speed, arr);
|
||||
|
||||
__HAL_TIM_SET_COUNTER(&htim2, 0);
|
||||
__HAL_TIM_SET_AUTORELOAD(&htim2, arr);
|
||||
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, arr / 2);
|
||||
|
||||
HAL_TIM_OC_Start_IT(&htim2, TIM_CHANNEL_1);
|
||||
}
|
||||
|
||||
void Int_TMC2209_stop(void)
|
||||
{
|
||||
/* 停止流程:停止STEP输出 -> 关闭驱动 -> 停止编码器计数 */
|
||||
HAL_TIM_OC_Stop_IT(&htim2, TIM_CHANNEL_1);
|
||||
HAL_GPIO_WritePin(STEPPER123_EN_GPIO_Port, STEPPER123_EN_Pin, GPIO_PIN_RESET);
|
||||
HAL_TIM_Encoder_Stop(&htim1, TIM_CHANNEL_ALL);
|
||||
}
|
||||
|
||||
extern Stepper_t stepper_1;
|
||||
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
|
||||
{
|
||||
/* TIM2中断中完成步进脉冲计数、速度状态机更新和ARR重装载 */
|
||||
if (htim->Instance == TIM2)
|
||||
{
|
||||
Stepper_t *s = &stepper_1;
|
||||
|
||||
double_flag++;
|
||||
|
||||
// 必须满2次中断(1个完整脉冲)才进行计算
|
||||
if (double_flag < 2)
|
||||
return;
|
||||
|
||||
s->step_count++;
|
||||
double_flag = 0;
|
||||
|
||||
// --- 状态机管理 ---
|
||||
switch (s->state)
|
||||
{
|
||||
case ACCELERATE:
|
||||
s->current_speed += s->speed_inc; // 这里的 speed_inc 单位是 mm/s per step
|
||||
if (s->step_count >= s->acc_step || s->current_speed >= s->speed)
|
||||
{
|
||||
s->current_speed = s->speed;
|
||||
s->state = CONSTANT;
|
||||
}
|
||||
break;
|
||||
|
||||
case CONSTANT:
|
||||
if (s->step_count >= (s->total_step - s->acc_step))
|
||||
s->state = DECELERATE;
|
||||
break;
|
||||
|
||||
case DECELERATE:
|
||||
s->current_speed -= s->speed_inc;
|
||||
if (s->current_speed < s->start_speed)
|
||||
s->current_speed = s->start_speed;
|
||||
|
||||
if (s->step_count >= s->total_step)
|
||||
{
|
||||
s->state = STOP;
|
||||
Int_TMC2209_stop(); // 内部会关闭中断,所以这里直接return即可
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case STOP:
|
||||
Int_TMC2209_stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 更新硬件 ---
|
||||
if (s->state != STOP)
|
||||
{
|
||||
// 传入 mm/s,计算新的 ARR
|
||||
uint32_t new_arr = CALC_ARR(s->current_speed);
|
||||
__HAL_TIM_SET_AUTORELOAD(&htim2, new_arr);
|
||||
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, new_arr / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
51
Interface/Int_TMC2209.h
Normal file
51
Interface/Int_TMC2209.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef __INT_TMC2209_H__
|
||||
#define __INT_TMC2209_H__
|
||||
|
||||
#include "main.h"
|
||||
#include "tim.h"
|
||||
#include "gpio.h"
|
||||
#include "usart.h"
|
||||
#include "Com_type.h"
|
||||
#include "Com_debug.h"
|
||||
|
||||
// TMC2209串口从机地址
|
||||
#define TMC2209_USART_SLAVE_ADDR 0x03
|
||||
#define TMC2209_GCONF_REG_ADDR 0x00
|
||||
|
||||
// ---------------- 机械参数定义 ----------------
|
||||
// 步进角 1.8° (200步/圈)
|
||||
#define STEPPER_CIRCLE_STEPS 200
|
||||
|
||||
// 细分设置 (8细分)
|
||||
#define STEPPER_SPLIT 8
|
||||
|
||||
// 丝杆导程 (转一圈前进 8mm)
|
||||
#define STICK_LEAD 8.0f
|
||||
|
||||
// [核心] 计算每毫米需要的脉冲数
|
||||
// 公式: (一圈步数 * 细分) / 导程
|
||||
// 例如: (200 * 8) / 8 = 200 步/mm
|
||||
#define STEPS_PER_MM ((float)(STEPPER_CIRCLE_STEPS * STEPPER_SPLIT) / STICK_LEAD)
|
||||
|
||||
// 定时器时钟频率 (4MHz)
|
||||
#define TIM_CLOCK_FREQ 4000000
|
||||
|
||||
// ---------------- 计算公式修改 ----------------
|
||||
|
||||
// [修改] 计算ARR的宏:根据线速度(mm/s)计算ARR值
|
||||
// 逻辑推导:
|
||||
// 1. 每秒脉冲数 (Hz) = 速度(mm/s) * 每毫米步数(steps/mm)
|
||||
// 2. 翻转频率 (Toggle Hz) = 每秒脉冲数 * 2 (因为一个脉冲包含高低电平两次中断)
|
||||
// 3. ARR = 定时器时钟 / 翻转频率 - 1
|
||||
// 传入参数 speed_mm_s 单位:mm/s
|
||||
#define CALC_ARR(speed_mm_s) ((uint32_t)((TIM_CLOCK_FREQ) / ((speed_mm_s) * STEPS_PER_MM * 2.0f) - 1))
|
||||
|
||||
/* 物理参数定义 */
|
||||
#define SOFT_LIMIT_MAX_MM 230.0f /* 丝杆有效量程上限 (mm) */
|
||||
#define SOFT_LIMIT_MIN_MM 0.0f /* 丝杆有效量程下限 (mm) */
|
||||
|
||||
void Int_TMC2209_init(void);
|
||||
void Int_TMC2209_start(Stepper_t *stepper, Encoder_t *encoder);
|
||||
void Int_TMC2209_stop(void);
|
||||
|
||||
#endif /* __INT_TMC2209_H__ */
|
||||
Reference in New Issue
Block a user