jiecang 推杆小板代码
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.

225 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;
}