You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
6.2 KiB
224 lines
6.2 KiB
#include "app.h"
|
|
#include "adc.h"
|
|
#include "tim.h"
|
|
#include "gpio.h"
|
|
#include "modbus.h"
|
|
|
|
/* ADC1_IN5:电流采样
|
|
* 采样电阻 0.1 欧姆,放大器增益 10 倍,因此 1V 对应 1A。
|
|
* 12 位 ADC,参考电压按 3.3V 计算。 */
|
|
#define ADC_REFERENCE_MV 3300U
|
|
#define ADC_MAX_CODE 4095U
|
|
#define CURRENT_MAX_MA 2000U
|
|
|
|
/* PWM 电流限幅占空比,范围 1~99,超范围按 99% 处理 */
|
|
#define PWM_DUTY_MIN 1U
|
|
#define PWM_DUTY_MAX 99U
|
|
#define PWM_DUTY_DEFAULT 99U
|
|
|
|
/* LED 状态灯闪烁时间(单位 ms) */
|
|
#define LED_ON_FORWARD_MS 800U
|
|
#define LED_OFF_FORWARD_MS 200U
|
|
#define LED_ON_REVERSE_MS 200U
|
|
#define LED_OFF_REVERSE_MS 800U
|
|
#define LED_ON_STOP_MS 500U
|
|
#define LED_OFF_STOP_MS 500U
|
|
|
|
/* 自动定位容许阈值寄存器 */
|
|
#define AUTO_POSITION_TOLERANCE_REG 9U
|
|
#define Encoder_Max 4200
|
|
|
|
static volatile uint8_t adcConversionDone = 0;
|
|
static uint16_t lastRegister5 = 0;
|
|
|
|
static void App_UpdateMotor(void);
|
|
static void App_SetCurrentLimit(uint16_t duty);
|
|
static void App_UpdateEncoderRegister(void);
|
|
static void App_ProcessZeroCommand(void);
|
|
static void App_UpdateLed(void);
|
|
|
|
void App_Init(void)
|
|
{
|
|
/* 上电默认:电机停止 */
|
|
HAL_GPIO_WritePin(IO_1_GPIO_Port, IO_1_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(IO_2_GPIO_Port, IO_2_Pin, GPIO_PIN_RESET);
|
|
|
|
/* 状态灯初始熄灭 */
|
|
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
|
|
|
|
/* 启动编码器读取 */
|
|
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);
|
|
|
|
/* 启动 PWM 输出,并按当前寄存器值设置电流限幅占空比 */
|
|
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
|
|
App_SetCurrentLimit(holdingRegisters[3]);
|
|
|
|
/* ADC校准 */
|
|
if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
|
|
{
|
|
Error_Handler();
|
|
}
|
|
/* 启动 ADC 中断采集 */
|
|
adcConversionDone = 0;
|
|
if (HAL_ADC_Start_IT(&hadc1) != HAL_OK)
|
|
{
|
|
Error_Handler();
|
|
}
|
|
}
|
|
|
|
void App_Process(void)
|
|
{
|
|
/* 先处理 Modbus 请求,可能更新寄存器 */
|
|
Modbus_Process();
|
|
|
|
App_UpdateMotor(); /*控制推杆上升下降包含自动和手动*/
|
|
App_SetCurrentLimit(holdingRegisters[3]); /*限制推杆电机电流*/
|
|
App_UpdateEncoderRegister(); /*获取定时器2计数值为编码器数值存到寄存器2*/
|
|
App_ProcessZeroCommand();/*设置当前位置为0*/
|
|
App_UpdateLed(); /*指示灯灯光切换*/
|
|
|
|
/* ADC 单次转换完成后重新启动下一轮转换 */
|
|
if (adcConversionDone != 0)
|
|
{
|
|
adcConversionDone = 0;
|
|
HAL_ADC_Start_IT(&hadc1);
|
|
}
|
|
}
|
|
|
|
static void App_UpdateMotor(void)
|
|
{
|
|
uint8_t io1 = (holdingRegisters[0] != 0) ? 1U : 0U;
|
|
uint8_t io2 = (holdingRegisters[1] != 0) ? 1U : 0U;
|
|
uint8_t up = 0U;
|
|
uint8_t down = 0U;
|
|
|
|
/*自动运行至指定位置,最下面值最大,最上面为0*/
|
|
if (holdingRegisters[6] != 0 && holdingRegisters[7] < Encoder_Max)
|
|
{
|
|
/* 自动定位模式:根据当前编码器值和目标位置决定运行方向 */
|
|
int32_t currentPosition = (int16_t)(uint16_t)__HAL_TIM_GET_COUNTER(&htim2);
|
|
int32_t targetPosition = (int16_t)holdingRegisters[7];
|
|
int32_t positionError = targetPosition - currentPosition;
|
|
int32_t tolerance = (int32_t)holdingRegisters[AUTO_POSITION_TOLERANCE_REG]; /*寄存器9*/
|
|
|
|
if (positionError > tolerance)
|
|
{
|
|
down = 1U;
|
|
}
|
|
else if (positionError < -tolerance)
|
|
{
|
|
up = 1U;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* 手动模式:保持原有 holdingRegisters[0]、[1] 控制逻辑 */
|
|
up = (io1 != 0 && io2 == 0) ? 1U : 0U;
|
|
down = (io1 == 0 && io2 != 0) ? 1U : 0U;
|
|
}
|
|
|
|
if (up != 0)
|
|
{
|
|
/* 正转:IO_1 高,IO_2 低 */
|
|
HAL_GPIO_WritePin(IO_1_GPIO_Port, IO_1_Pin, GPIO_PIN_SET);
|
|
HAL_GPIO_WritePin(IO_2_GPIO_Port, IO_2_Pin, GPIO_PIN_RESET);
|
|
}
|
|
else if (down != 0)
|
|
{
|
|
/* 反转:IO_1 低,IO_2 高 */
|
|
HAL_GPIO_WritePin(IO_1_GPIO_Port, IO_1_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(IO_2_GPIO_Port, IO_2_Pin, GPIO_PIN_SET);
|
|
}
|
|
else
|
|
{
|
|
/* 停止:两路都低 */
|
|
HAL_GPIO_WritePin(IO_1_GPIO_Port, IO_1_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(IO_2_GPIO_Port, IO_2_Pin, GPIO_PIN_RESET);
|
|
}
|
|
}
|
|
|
|
static void App_SetCurrentLimit(uint16_t duty)
|
|
{
|
|
if (duty < PWM_DUTY_MIN || duty > PWM_DUTY_MAX)
|
|
{
|
|
duty = PWM_DUTY_DEFAULT;
|
|
}
|
|
|
|
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty);
|
|
}
|
|
|
|
static void App_UpdateEncoderRegister(void)
|
|
{
|
|
int32_t enc = (int32_t)__HAL_TIM_GET_COUNTER(&htim2);
|
|
//holdingRegisters[2] = (uint16_t)(int16_t)enc;
|
|
holdingRegisters[2] = (int16_t)enc;
|
|
}
|
|
|
|
static void App_ProcessZeroCommand(void)
|
|
{
|
|
if (holdingRegisters[5] != lastRegister5)
|
|
{
|
|
lastRegister5 = holdingRegisters[5];
|
|
__HAL_TIM_SET_COUNTER(&htim2, 0);
|
|
}
|
|
}
|
|
|
|
static void App_UpdateLed(void)
|
|
{
|
|
static uint32_t lastToggle = 0;
|
|
static GPIO_PinState ledState = GPIO_PIN_RESET;
|
|
|
|
uint8_t io1 = (holdingRegisters[0] != 0) ? 1U : 0U;
|
|
uint8_t io2 = (holdingRegisters[1] != 0) ? 1U : 0U;
|
|
uint32_t onTime;
|
|
uint32_t offTime;
|
|
uint32_t period;
|
|
uint32_t elapsed;
|
|
|
|
if (io1 != 0 && io2 == 0)
|
|
{
|
|
onTime = LED_ON_FORWARD_MS;
|
|
offTime = LED_OFF_FORWARD_MS;
|
|
}
|
|
else if (io1 == 0 && io2 != 0)
|
|
{
|
|
onTime = LED_ON_REVERSE_MS;
|
|
offTime = LED_OFF_REVERSE_MS;
|
|
}
|
|
else
|
|
{
|
|
onTime = LED_ON_STOP_MS;
|
|
offTime = LED_OFF_STOP_MS;
|
|
}
|
|
|
|
period = (ledState == GPIO_PIN_SET) ? onTime : offTime;
|
|
elapsed = HAL_GetTick() - lastToggle;
|
|
|
|
if (elapsed >= period)
|
|
{
|
|
ledState = (ledState == GPIO_PIN_SET) ? GPIO_PIN_RESET : GPIO_PIN_SET;
|
|
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, ledState);
|
|
lastToggle = HAL_GetTick();
|
|
}
|
|
}
|
|
|
|
/* ADC 转换完成中断回调:把采样电压换算为电流(mA) */
|
|
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
|
|
{
|
|
if (hadc->Instance != ADC1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
uint32_t raw = HAL_ADC_GetValue(&hadc1);
|
|
uint32_t voltage_mv = (raw * ADC_REFERENCE_MV) / ADC_MAX_CODE;
|
|
uint16_t current_ma = (uint16_t)voltage_mv;
|
|
|
|
if (current_ma > CURRENT_MAX_MA)
|
|
{
|
|
current_ma = CURRENT_MAX_MA;
|
|
}
|
|
|
|
holdingRegisters[4] = current_ma;
|
|
adcConversionDone = 1;
|
|
}
|
|
|