定时器器pwm输出主要涉:
在 PWM 输 出 模 式 下 ,通道根据TIMERx_CAR寄存器和TIMERx_CHxCV寄存器的值,输出
PWM波形。
根据计数模式,我们可以分为两种PWM波:
EAPWM 的周期由 TIMERx_CAR 寄存器值决定,占空比由 TIMERx_CHxCV 寄存器值决定。
图 15-42. EAPWM 时序图显示了 EAPWM 的输出波形和中断。
CAPWM 的周期由(2*TIMERx_CAR 寄存器值)决定,占空比由(2*TIMERx_CHxCV 寄存器
值)决定。 图 15-43. CAPWM 时序图显示了 CAPWM 的输出波形和中断。
在 PWM0 模 式 下 如 果 TIMERx_CHxCV 寄 存 器 的 值 大 于TIMERx_CAR寄存器的值,通道输出一直为有效电平。
在PWM0模式下(CHxCOMCTL==3’b110),如果TIMERx_CHxCV寄存器的值等于0,通道输出
一直为无效电平。
#include "bsp_time_pwm.h"
/*
定时器的基本初始化和打开更新中断
enable: 是否使能定时器
*/
void pwm_time_base_init(int enable)
{
/*定时器结构*/
timer_parameter_struct timer_initpara;
//开启定时器时钟
rcu_periph_clock_enable(RCU_TIMER0);
//结构体复位初始化
timer_deinit(TIMER0);
/* 初始化定时器结构体 */
timer_struct_para_init(&timer_initpara);
/* TIMER1 configuration */
timer_initpara.prescaler = 0; //定时器的时钟频率是108MHz
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;//
timer_initpara.counterdirection = TIMER_COUNTER_UP;//向上计数
timer_initpara.period = TIM_PERIOD - 1; //重载值
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; //不分频
timer_initpara.repetitioncounter = 0;//重复计数
timer_init(TIMER0, &timer_initpara);
if (enable)
timer_enable(TIMER0);//使能定时器
else
timer_disable(TIMER0);//失能定时器
}
/*pwm 输出配置*/
void pwm_output_config(int enable)
{
//生成pwm:
timer_oc_parameter_struct timer_ocintpara;
/* CH1,CH2 and CH3 configuration in PWM mode1 */
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_LOW;//pwm 输出极性
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;//输出通道使能
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;//pwm互补输出极性
timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;//输出通道失能
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_HIGH;//pwm输出通道空闲电平
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;//pwm输出互补通道空闲电平
//配置指定通带
timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_2, &timer_ocintpara);
/* CH0 50% */
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 500);
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM1);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);
/* CH1 50% */
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, 500);
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM1);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);
/* CH1 50% */
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2, 500);
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM1);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_2, TIMER_OC_SHADOW_DISABLE);
//TIM0这句很重要,没有这句不输出pwm 如果不是高级定时器就不需要
timer_primary_output_config(TIMER0, ENABLE);
/* 自动重载使能 */
timer_auto_reload_shadow_enable(TIMER0);
/* 使能定时器 */
if (enable)
timer_enable(TIMER0);
}
/*
使能定时器的更新中断
*/
void pwm_enable_it(void)
{
timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);//清除更新中断标记
timer_interrupt_enable(TIMER0, TIMER_INT_UP);//中断更新中断使能
nvic_irq_enable(TIMER0_UP_IRQn, 1, 1);//使能中断并设置优先级
}
/*
中断服务函数
*/
//void TIMER0_UP_IRQHandler(void)
//{
// if (SET == timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_UP))
// {
// /* 清除更新中断标志 */
// timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
//
// }
//}
/*
通道涉及gpio配置
*/
void pwm_gpio_config(void)
{
//使能gpio时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
//使能复用时钟
rcu_periph_clock_enable(RCU_AF);
/*配置gpio为复用上拉状态*/
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
}
/*
pwm 输出初始化
*/
void pwm_output_init(void)
{
pwm_gpio_config();
pwm_time_base_init(0);
pwm_output_config(1);
}
#ifndef _BSP_TIME_PWM_H_
#define _BSP_TIME_PWM_H_
#include "gd32f10x.h"
#define WORK_FREQ 10000
#define TIM_PERIOD 108000000/WORK_FREQ //1MHz/100
/*
使能定时器的更新中断
*/
void pwm_enable_it(void);
/*
pwm 输出初始化
*/
void pwm_output_init(void);
#endif
编码器博客:
https://blog.csdn.net/u010261063/article/details/125802765
#include "bsp_quadrature_encoder.h"
int encoder_overflow = -1;//定时器溢出变量统计,因为定时器一起动就会发生一次溢出,故设置为-1,方便计算
void init_quadrature_encoder(void)
{
timer_parameter_struct timer_initpara;
timer_ic_parameter_struct timer_icinitpara;
/* TIM2 时钟使能 */
rcu_periph_clock_enable(RCU_TIMER2);
rcu_periph_clock_enable(RCU_GPIOA);
//使能复用时钟
rcu_periph_clock_enable(RCU_AF);
/**TIM2 GPIO Configuration
PA6 ------> TIM2_CH1
PA7 ------> TIM2_CH2
*/
gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
timer_deinit(TIMER2);
timer_initpara.period = 65535;
timer_initpara.prescaler = 0;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2, &timer_initpara);
/* TIMER2 输入通道的配置 */
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;//上升沿
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;//
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV8;//改参数设置对于编码器不起作用
timer_icinitpara.icfilter = 0x05;
timer_input_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara);
timer_input_capture_config(TIMER2, TIMER_CH_1, &timer_icinitpara);
/*设置定时器工作为编码器模式*/
timer_quadrature_decoder_mode_config(TIMER2, TIMER_ENCODER_MODE2, TIMER_IC_POLARITY_RISING, TIMER_IC_POLARITY_RISING);
//使能更新中断
timer_interrupt_enable(TIMER2, TIMER_INT_UP);
nvic_irq_enable(TIMER2_IRQn, 1, 1);//使能中断并设置优先级
/* 开启自动重载-使能重载影子寄存器,使能后CAR寄存器的值设置后不会立即生效,只有在更新事件时才生效*/
timer_auto_reload_shadow_enable(TIMER2);
//使能定时器
timer_enable(TIMER2);
}
/*定时器2的中断服务函数*/
void TIMER2_IRQHandler(void)
{
if (SET == timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP))
{
/* 清除更新中断标志 */
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);
/*根据定时器的计数方向判定电机正转和反转,正转计数器+1 ,反转计数器-1*/
if((TIMER_CTL0(TIMER2)&TIMER_CTL0_DIR) == TIMER_CTL0_DIR)
encoder_overflow--;
else
encoder_overflow++;
}
}
#ifndef _BSP_ENCODER_H_
#define _BSP_ENCODER_H_
#include "gd32f10x.h"
extern int encoder_overflow;
void init_quadrature_encoder(void);
#endif
#include "bsp_pid_kernel.h"
#include "stdio.h"
#include "bsp_time_pwm.h"
PID_TypeDef g_speed_pid; /* 速度环 PID 参数结构体 */
/**
* @brief pid 初始化
* @param 无
* @retval 无
*/
void pid_init(void)
{
g_speed_pid.SetPoint = 0; /* 设定目标值 */
g_speed_pid.ActualValue = 0.0; /* 期望输出值 */
g_speed_pid.SumError = 0.0; /* 积分值 */
g_speed_pid.Error = 0.0; /* Error[1] */
g_speed_pid.LastError = 0.0; /* Error[-1] */
g_speed_pid.PrevError = 0.0; /* Error[-2] */
g_speed_pid.Proportion = KP; /* 比例常数 Proportional Const */
g_speed_pid.Integral = KI; /* 积分常数 Integral Const */
g_speed_pid.Derivative = KD; /* 微分常数 Derivative Const */
}
void set_pid_target(float dst_value )
{
g_speed_pid.SetPoint = dst_value; /* 设定目标值 */
}
void set_p_i_d(float kp,float ki, float kd)
{
g_speed_pid.Proportion = kp; /* 比例常数 Proportional Const */
g_speed_pid.Integral = ki; /* 积分常数 Integral Const */
g_speed_pid.Derivative = kd; /* 微分常数 Derivative Const */
}
#ifdef INCR_LOCT_SELECT
/*
* @brief pid 闭环控制----位置式PID
* @param *PID: PID 结构体变量地址
* @param Feedback_value:当前实际值
* @retval 期望输出值
*/
int32_t increment_pid_ctrl(PID_TypeDef *PID, float Feedback_value)
{
PID->Error = (float)(PID->SetPoint - Feedback_value); /* 计算偏差 */
// if(PID->SumError < PID->Integral * TIM_PERIOD)
PID->SumError += PID->Error; /* 累计偏差 */
PID->ActualValue = (PID->Proportion * PID->Error) /* 比例环节 */
+ (PID->Integral * PID->SumError) /* 积分环节 */
+ (PID->Derivative * (PID->Error - PID->LastError)); /* 微分环节 */
PID->LastError = PID->Error; /* 存储偏差,用于下次计算 */
return ((int32_t)(PID->ActualValue)); /* 返回计算后输出的数值 */
}
#else
/*
* @brief pid 闭环控制--增量式PID
* @param *PID: PID 结构体变量地址
* @param Feedback_value:当前实际值
* @retval 期望输出值
*/
int32_t increment_pid_ctrl(PID_TypeDef *PID, float Feedback_value)
{
PID->Error = (float)(PID->SetPoint - Feedback_value); /* 计算偏差 */
PID->ActualValue +=
/* 比例环节 */
(PID->Proportion * (PID->Error - PID->LastError))
/* 积分环节 */
+ (PID->Integral * PID->Error)
/* 微分环节 */
+ (PID->Derivative * (PID->Error - 2 * PID->LastError + PID->PrevError));
PID->PrevError = PID->LastError; /* 存储偏差,用于下次计算 */
PID->LastError = PID->Error;
return ((int32_t)(PID->ActualValue)); /* 返回计算后输出的数值 */
}
#endif
#ifndef _BSP_PID_KENEL_H_
#define _BSP_PID_KENEL_H_
#include "stdint.h"
#define INCR_LOCT_SELECT 0 /* 0:位置式 , 1:增量式 */
#if INCR_LOCT_SELECT
/* 增量式 PID 参数相关宏 */
#define KP 0.00f /* P 参数*/
#define KI 0.00f /* I 参数*/
#define KD 0.10f /* D 参数*/
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms*/
#else
/* 位置式 PID 参数相关宏 */
#define KP 3.1f /* P 参数*/
#define KI 0.8f /* I 参数*/
#define KD 0.005f /* D 参数*/
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms*/
#endif
#define __IO volatile
/**
* @brief pid 初始化
* @param 无
* @retval 无
*/
void pid_init(void);
void set_pid_target(float dst_value );
void set_p_i_d(float kp,float ki, float kd);
typedef struct
{
__IO float SetPoint; /* 目标值 */
__IO float ActualValue; /* 期望输出值 */
__IO float SumError; /* 偏差累计 */
__IO float Proportion; /* 比例系数 P */
__IO float Integral; /* 积分系数 I */
__IO float Derivative; /* 微分系数 D */
__IO float Error; /* Error[1],第 k 次偏差 */
__IO float LastError; /* Error[-1],第 k-1 次偏差 */
__IO float PrevError; /* Error[-2],第 k-2 次偏差 */
} PID_TypeDef;
extern PID_TypeDef g_speed_pid; /* 速度环 PID 参数结构体 */
#ifdef INCR_LOCT_SELECT
/*
* @brief pid 闭环控制----位置式PID
* @param *PID: PID 结构体变量地址
* @param Feedback_value:当前实际值
* @retval 期望输出值
*/
int32_t increment_pid_ctrl(PID_TypeDef *PID,float Feedback_value);
#else
/*
* @brief pid 闭环控制 ----增量式PID
* @param *PID: PID 结构体变量地址
* @param Feedback_value:当前实际值
* @retval 期望输出值
*/
int32_t increment_pid_ctrl(PID_TypeDef *PID,float Feedback_value);
#endif
#endif
#ifndef _BSP_PID_KENEL_H_
#define _BSP_PID_KENEL_H_
#include "stdint.h"
#define INCR_LOCT_SELECT 0 /* 0:位置式 , 1:增量式 */
#if INCR_LOCT_SELECT
/* 增量式 PID 参数相关宏 */
#define KP 0.00f /* P 参数*/
#define KI 0.00f /* I 参数*/
#define KD 0.10f /* D 参数*/
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms*/
#else
/* 位置式 PID 参数相关宏 */
#define KP 3.1f /* P 参数*/
#define KI 0.8f /* I 参数*/
#define KD 0.005f /* D 参数*/
#define SMAPLSE_PID_SPEED 50 /* 采样周期 单位 ms*/
#endif
#define __IO volatile
/**
* @brief pid 初始化
* @param 无
* @retval 无
*/
void pid_init(void);
void set_pid_target(float dst_value );
void set_p_i_d(float kp,float ki, float kd);
typedef struct
{
__IO float SetPoint; /* 目标值 */
__IO float ActualValue; /* 期望输出值 */
__IO float SumError; /* 偏差累计 */
__IO float Proportion; /* 比例系数 P */
__IO float Integral; /* 积分系数 I */
__IO float Derivative; /* 微分系数 D */
__IO float Error; /* Error[1],第 k 次偏差 */
__IO float LastError; /* Error[-1],第 k-1 次偏差 */
__IO float PrevError; /* Error[-2],第 k-2 次偏差 */
} PID_TypeDef;
extern PID_TypeDef g_speed_pid; /* 速度环 PID 参数结构体 */
#ifdef INCR_LOCT_SELECT
/*
* @brief pid 闭环控制----位置式PID
* @param *PID: PID 结构体变量地址
* @param Feedback_value:当前实际值
* @retval 期望输出值
*/
int32_t increment_pid_ctrl(PID_TypeDef *PID,float Feedback_value);
#else
/*
* @brief pid 闭环控制 ----增量式PID
* @param *PID: PID 结构体变量地址
* @param Feedback_value:当前实际值
* @retval 期望输出值
*/
int32_t increment_pid_ctrl(PID_TypeDef *PID,float Feedback_value);
#endif
#endif
#ifndef _BSP_MOTOR_CTRL_H_
#define _BSP_MOTOR_CTRL_H_
/*启动电机*/
void start_motor(void);
/*停止电机*/
void stop_motor(void);
/*电机速度控制*/
int set_motor_speed(int speed);
#endif
#include "bsp_base_time_it.h"
#include "gd32f10x.h"
#include "bsp_base_time_it.h"
#include "bsp_pid_kernel.h"
#include "bsp_motor_ctrl.h"
#include "stdio.h"
#include "bsp_time_pwm.h"
#include "debug.h"
#include "protocol.h"
#include "bsp_quadrature_encoder.h"
/*使用定时器3循环计算速度和pid*/
#define USE_TIME TIMER3
extern int encoder_overflow;
#if SPEED_PID
float motor_speed;
#else
int motor_speed;
#endif
/*
使能定时器的更新中断
*/
void bsp_timer_enable_it()
{
timer_interrupt_flag_clear(USE_TIME, TIMER_INT_FLAG_UP);//清除更新中断标记
timer_interrupt_enable(USE_TIME, TIMER_INT_UP);//中断更新中断使能
nvic_irq_enable(TIMER3_IRQn, 1, 1);//使能中断并设置优先级
}
void bsp_time_base_init(int enable)
{
/*定时器结构*/
timer_parameter_struct timer_initpara;
//开启定时器时钟
rcu_periph_clock_enable(RCU_TIMER3);
//结构体复位初始化
timer_deinit(USE_TIME);
/* 初始化定时器结构体 */
timer_struct_para_init(&timer_initpara);
/* TIMER1 configuration */
timer_initpara.prescaler = 108 - 1; //定时器的时钟频率是108MHz
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;//
timer_initpara.counterdirection = TIMER_COUNTER_UP;//向上计数
timer_initpara.period = 1000 - 1; //重载值
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; //不分频
timer_initpara.repetitioncounter = 0;//重复计数
timer_init(USE_TIME, &timer_initpara);
bsp_timer_enable_it();
if (enable)
timer_enable(USE_TIME);//使能定时器
else
timer_disable(USE_TIME);//失能定时器
}
void caculate_motor_speed(void)
{
#if SPEED_PID
static int last_cnt=0xffffffff;
static float speed_arry[5];
static int index=0;
int cur_cnt = TIMER_CNT(TIMER2) +65536*encoder_overflow;
if( last_cnt==0xffffffff)
{
motor_speed=0;
}
else
{
speed_arry[index%5]=(cur_cnt-last_cnt)*50*60/16;
}
if(index%5==4)
{
motor_speed = (speed_arry[0]+speed_arry[1]+speed_arry[2]+speed_arry[3]+speed_arry[4])*0.2;
}
index++;
last_cnt=cur_cnt;
#else
static uint8_t flag=1;
if(flag)
{
flag=0;
motor_speed=0;
}
else
{
motor_speed = TIMER_CNT(TIMER2) +65536*encoder_overflow;
}
printf("speed %d \r\n",motor_speed);
#endif
}
void motor_pid_ctrl(void)
{
int speed;
//pid计算
speed = increment_pid_ctrl(&g_speed_pid,motor_speed);
//控制电机pwm
set_motor_speed(speed);
int temp = motor_speed;
int temp2=g_speed_pid.SetPoint;
int duty = speed*1000/(TIM_PERIOD);
//波形显示
debug_send_wave_data(1,temp);
debug_send_wave_data(2,temp2);
debug_send_wave_data(3,duty);
}
void time_out_1ms(void)
{
static uint32_t ms=0;
ms++;
if(ms%20==19)//每20ms计算一次速度
{
caculate_motor_speed();
}
if(ms%100==99)//每100ms计算一次pid
{
motor_pid_ctrl();
}
}
/*
中断服务函数
*/
void TIMER3_IRQHandler(void)
{
if (SET == timer_interrupt_flag_get(USE_TIME, TIMER_INT_FLAG_UP))
{
/* 清除更新中断标志 */
timer_interrupt_flag_clear(USE_TIME, TIMER_INT_FLAG_UP);
//定时处理速度和pid计算
time_out_1ms();
}
}
#ifndef _BSP_BASE_TIMER_IT_H_
#define _BSP_BASE_TIMER_IT_H_
//速度pid和位置pid的切换宏
#if SPEED_PID
extern float motor_speed;
#else
extern int motor_speed;
#endif
extern float motor_speed;
void bsp_time_base_init(int enable);
#endif
/**
****************************************************************************************************
* @file debug.c
* @author 正点原子团队(ALIENTEK)
* @version V1.0
* @date 2021-10-14
* @brief pid上位机调试 代码
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
****************************************************************************************************
* @attention
*
* 实验平台:正点原子 F407电机开发板
* 在线视频:www.yuanzige.com
* 技术论坛:www.openedv.com/forum.php
* 公司网址:www.alientek.com
* 购买地址:openedv.taobao.com
*
* 修改说明
* V1.0 20211014
* 第一次发布
*
****************************************************************************************************
*/
#include "debug.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "gd32f10x.h"
#include "bsp_uart.h"
#define __IO volatile
/*************************************** 第一部分 CRC校验 ********************************************/
/* CRC 高位字节值表 */
static const uint8_t s_crchi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};
/* CRC 低位字节值表 */
const uint8_t s_crclo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
/**
* @brief CRC16校验
* @param *_pBuf:数据地址
* @param _usLen:数据长度
* @note 采用crc16-modbus,多项式hex:8005
* @retval 校验结果
*/
uint16_t crc16_calc(uint8_t *_pBuf, uint16_t _usLen)
{
uint8_t ucCRCHi = 0xFF; /* 高CRC字节初始化 */
uint8_t ucCRCLo = 0xFF; /* 低CRC 字节初始化 */
uint16_t usIndex; /* CRC循环中的索引 */
while (_usLen--)
{
usIndex = ucCRCLo ^ *_pBuf++; /* 计算CRC */
ucCRCLo = ucCRCHi ^ s_crchi[usIndex];
ucCRCHi = s_crclo[usIndex];
}
return ((uint16_t)ucCRCHi << 8 | ucCRCLo); /* 返回校验结果,高字节在高位 */
}
/*************************************** 第二部分 底层函数 ********************************************/
__IO uint8_t debug_rev_data[DEBUG_REV_MAX_LEN]; /* 存放接收数据的数组(环形缓冲区) */
__IO uint8_t debug_rev_p = 0; /* 地址偏移量 */
debug_data g_debug;
debug_data_rev debug_rev;
/**
* @brief 内存初始化
* @param *data:内存起始地址
* @retval 无
*/
void debug_obj_init(debug_data *data)
{
size_t obj_size = sizeof(debug_data);
memset(data, 0, (size_t)obj_size); /* 把指定范围内存清零 */
}
/**
* @brief 上位机数据解析
* @param *data:接收的数据(地址)
* @note 利用环形缓冲区来接收数据,再存进相应的结构体成员中
* @retval 无
*/
void debug_handle(uint8_t *data)
{
uint8_t temp[DEBUG_REV_MAX_LEN];
uint8_t i;
if (debug_rev_p >= DEBUG_REV_MAX_LEN) /* 超过缓冲区(数组)最大长度 */
{
debug_rev_p = 0; /* 地址偏移量清零 */
}
debug_rev_data[debug_rev_p] = *(data); /* 取出数据,存进数组 */
if (*data == DEBUG_DATA_END) /* 判断是否收到帧尾 */
{
if (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 4) % DEBUG_REV_MAX_LEN] == DEBUG_DATA_HEAD) /* 数据包长度为5个字节,判断第一个字节是否为帧头 */
{
for (i = 0; i < 2; i++)
{
temp[i] = debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 4 + i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别,5个字节的数据包没有数据域 */
}
#if EN_CRC /* 进行CRC校验 */
if (crc16_calc(temp, 2) == ((debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 4 + 2) % DEBUG_REV_MAX_LEN] << 8) | \
debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 4 + 3) % DEBUG_REV_MAX_LEN]))
#endif
{
if (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 4 + 1) % DEBUG_REV_MAX_LEN] == CMD_GET_ALL_DATA) /* 判断数据类别是否为:获取全部参数 */
{
debug_upload_data(&g_debug, TYPE_STATUS); /* 发送电机状态 */
debug_upload_data(&g_debug, TYPE_SPEED); /* 发送速度值 */
debug_upload_data(&g_debug, TYPE_HAL_ENC); /* 发送霍尔、编码器位置 */
debug_upload_data(&g_debug, TYPE_VBUS); /* 发送电压 */
debug_upload_data(&g_debug, TYPE_AMP); /* 发送电流 */
debug_upload_data(&g_debug, TYPE_TEMP); /* 发送温度 */
debug_upload_data(&g_debug, TYPE_SUM_LEN); /* 发送总里程 */
debug_upload_data(&g_debug, TYPE_BEM); /* 发送反电动势 */
debug_upload_data(&g_debug, TYPE_MOTOR_CODE); /* 发送电机类型 */
for (i = TYPE_PID1; i < TYPE_PID10; i++)
{
debug_upload_data(&g_debug, i); /* 发送PID参数 */
}
}
}
}
if (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 5) % DEBUG_REV_MAX_LEN] == DEBUG_DATA_HEAD) /* 数据包长度为6个字节,判断第一个字节是否为帧头 */
{
for (i = 0; i < 3; i++)
{
temp[i] = debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 5 + i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别、数据域 */
}
#if EN_CRC /* 进行CRC校验 */
if (crc16_calc(temp, 3) == ((debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 5 + 3) % DEBUG_REV_MAX_LEN] << 8) | \
debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 5 + 4) % DEBUG_REV_MAX_LEN]))
#endif
{
switch (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 5 + 1) % DEBUG_REV_MAX_LEN]) /* 判断数据类别 */
{
case CMD_SET_CTR_CODE: /* 下发控制指令 */
debug_rev.Ctrl_code = debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 5 + 2) % DEBUG_REV_MAX_LEN];
break;
case CMD_SET_CTR_MODE: /* 下发控制模式 */
debug_rev.Ctrl_mode = debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 5 + 2) % DEBUG_REV_MAX_LEN];
break;
}
}
}
if (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6) % DEBUG_REV_MAX_LEN] == DEBUG_DATA_HEAD) /* 数据包长度为7个字节,判断第一个字节是否为帧头 */
{
for (i = 0; i < 4; i++)
{
temp[i] = debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别、数据域 */
}
#if EN_CRC /* 进行CRC校验 */
if (crc16_calc(temp, 4) == ((debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + 4) % DEBUG_REV_MAX_LEN] << 8) | \
debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + 5) % DEBUG_REV_MAX_LEN]))
#endif
{
switch (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + 1) % DEBUG_REV_MAX_LEN]) /* 判断数据类别 */
{
case CMD_SET_SPEED: /* 设定电机速度 */
*(debug_rev.speed) = (int16_t)((debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + 2) % DEBUG_REV_MAX_LEN] << 8) | \
debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + 3) % DEBUG_REV_MAX_LEN]);
break;
case CMD_SET_TORQUE: /* 设定转矩 */
*(debug_rev.torque) = (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + 2) % DEBUG_REV_MAX_LEN] << 8) | \
debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 6 + 3) % DEBUG_REV_MAX_LEN];
break;
}
}
}
if (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 16) % DEBUG_REV_MAX_LEN] == DEBUG_DATA_HEAD) /* 数据包长度为17个字节,判断第一个字节是否为帧头 */
{
for (i = 0; i < 14; i++)
{
temp[i] = debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 16 + i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别、数据域 */
}
#if EN_CRC /* 进行CRC校验 */
if (crc16_calc(temp, 14) == ((debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 16 + 14) % DEBUG_REV_MAX_LEN] << 8) | \
debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 16 + 15) % DEBUG_REV_MAX_LEN]))
#endif
{
switch (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 16 + 1) % DEBUG_REV_MAX_LEN]) /* 判断数据类别 */
{
case CMD_SET_PID1:
case CMD_SET_PID2:
case CMD_SET_PID3:
case CMD_SET_PID4:
case CMD_SET_PID5:
case CMD_SET_PID6:
case CMD_SET_PID7:
case CMD_SET_PID8:
case CMD_SET_PID9:
case CMD_SET_PID10:
for (i = 0; i < 12; i++) /* 接收设定的PID参数 */
{
g_debug.pid[debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 16 + 1) % DEBUG_REV_MAX_LEN] - CMD_SET_PID1].pid.pidi8[i] = \
debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 16 + 2 + i) % DEBUG_REV_MAX_LEN];
}
break;
}
}
}
}
debug_rev_p ++;
}
/**
* @brief 数据上传
* @param *data:上传的数据(地址)
* @param upload_type:上传的数据类别
* @retval 无
*/
void debug_upload_data(debug_data *data, uint8_t upload_type)
{
uint8_t cur_data, i;
uint8_t upload_data[37]; /* 数据上传数组 */
upload_data[0] = DEBUG_DATA_HEAD; /* 数据包第1个字节(数组第0个元素),固定为帧头 */
cur_data = 2; /* 数据域从第3个字节(数组第2个元素)开始 */
switch (upload_type) /* 判断数据类别 */
{
case TYPE_STATUS: /* 设备状态 */
upload_data[1] = upload_type; /* 数据包第2个字节(数组第1个元素),固定为数据类别 */
upload_data[cur_data++] = data->status; /* 存入要发送的数据域 */
break;
case TYPE_SPEED: /* 电机速度 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (data->speed >> 8) & 0xFF; /* 先存入速度值高8位(小端模式中u16赋给u8类型,只取低8位) */
upload_data[cur_data++] = data->speed & 0xFF; /* 再存入速度值低8位 */
break;
case TYPE_HAL_ENC: /* 霍尔、编码器位置值 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (data->hall_p) & 0x08; /* 存入霍尔位置值 */
upload_data[cur_data++] = (data->encode_p >> 8) & 0xFF; /* 存入编码器位置值高8位 */
upload_data[cur_data++] = (data->encode_p) & 0xFF; /* 存入编码器位置值低8位 */
break;
case TYPE_VBUS: /* 电压,范围 0~100.99 V */
upload_data[1] = upload_type;
upload_data[cur_data++] = ((uint8_t)data->bus_vol) % 101; /* 存入电压值整数部分,整数部分不允许超过100 */
upload_data[cur_data++] = ((uint16_t)(data->bus_vol * 100)) % 100; /* 存入电压值小数部分,小数部分不允许超过99 */
break;
case TYPE_AMP: /* 电流 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (((int16_t)(data->amp[0] * 1000)) >> 8) & 0xFF; /* 存入U相电流高8位 */
upload_data[cur_data++] = ((int16_t)(data->amp[0] * 1000)) & 0xFF; /* 存入U相电流低8位 */
upload_data[cur_data++] = (((int16_t)(data->amp[1] * 1000)) >> 8) & 0xFF; /* 存入V相电流高8位 */
upload_data[cur_data++] = ((int16_t)(data->amp[1] * 1000)) & 0xFF; /* 存入V相电流低8位 */
upload_data[cur_data++] = (((int16_t)(data->amp[2] * 1000)) >> 8) & 0xFF; /* 存入W相电流高8位 */
upload_data[cur_data++] = ((int16_t)(data->amp[2] * 1000)) & 0xFF; /* 存入W相电流低8位 */
break;
case TYPE_TEMP: /* 温度 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (uint8_t)(data->temp[0] + 50); /* 存入驱动板温度 */
upload_data[cur_data++] = (uint8_t)(data->temp[1] + 50); /* 存入电机温度 */
break;
case TYPE_SUM_LEN: /* 总里程 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (data->sum_len >> 56) & 0xFF; /* 存入总里程 56~63 位 */
upload_data[cur_data++] = (data->sum_len >> 48) & 0xFF; /* 存入总里程 48~55 位 */
upload_data[cur_data++] = (data->sum_len >> 40) & 0xFF; /* 存入总里程 40~47 位 */
upload_data[cur_data++] = (data->sum_len >> 32) & 0xFF; /* 存入总里程 32~39 位 */
upload_data[cur_data++] = (data->sum_len >> 24) & 0xFF; /* 存入总里程 24~31 位 */
upload_data[cur_data++] = (data->sum_len >> 16) & 0xFF; /* 存入总里程 16~23 位 */
upload_data[cur_data++] = (data->sum_len >> 8) & 0xFF; /* 存入总里程 8~15 位 */
upload_data[cur_data++] = (data->sum_len >> 0) & 0xFF; /* 存入总里程 0~7 位 */
break;
case TYPE_BEM: /* 反电动势 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (int8_t)data->bem[0]; /* 存入U相反电动势电压整数部分 */
upload_data[cur_data++] = ((int16_t)(data->bem[0] * 100)) % 100; /* 存入U相反电动势电压小数部分 */
upload_data[cur_data++] = (int8_t)data->bem[1]; /* 存入V相反电动势电压整数部分 */
upload_data[cur_data++] = ((int16_t)(data->bem[1] * 100)) % 100; /* 存入V相反电动势电压小数部分 */
upload_data[cur_data++] = (int8_t)data->bem[2]; /* 存入W相反电动势电压整数部分 */
upload_data[cur_data++] = ((int16_t)(data->bem[2] * 100)) % 100; /* 存入W相反电动势电压小数部分 */
break;
case TYPE_MOTOR_CODE: /* 电机类型 */
upload_data[1] = upload_type;
upload_data[cur_data++] = data->motor_code; /* 存入电机类型 */
break;
case TYPE_TORQUE: /* 扭矩 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (((int16_t)(data->torque * 1000)) >> 8) & 0xFF; /* 存入扭矩值整数部分 */
upload_data[cur_data++] = ((int16_t)(data->torque * 1000)) & 0xFF; /* 存入扭矩值小数部分 */
break;
case TYPE_POWER: /* 功率 */
upload_data[1] = upload_type;
upload_data[cur_data++] = (((int16_t)(data->power * 100)) >> 8) & 0xFF; /* 存入功率值高8位 */
upload_data[cur_data++] = ((int16_t)(data->power * 100)) & 0xFF; /* 存入功率值低8位 */
break;
case TYPE_PID1: /* PID参数组别 */
case TYPE_PID2:
case TYPE_PID3:
case TYPE_PID4:
case TYPE_PID5:
case TYPE_PID6:
case TYPE_PID7:
case TYPE_PID8:
case TYPE_PID9:
case TYPE_PID10:
upload_data[1] = upload_type;
for (i = 0; i < 3; i++) /* 循环存入P、I、D系数值,每个系数占4个字节 */
{
upload_data[cur_data++] = data->pid[upload_type - TYPE_PID1].pid.pidi8[i * 4 + 0];
upload_data[cur_data++] = data->pid[upload_type - TYPE_PID1].pid.pidi8[i * 4 + 1];
upload_data[cur_data++] = data->pid[upload_type - TYPE_PID1].pid.pidi8[i * 4 + 2];
upload_data[cur_data++] = data->pid[upload_type - TYPE_PID1].pid.pidi8[i * 4 + 3];
}
break;
case TYPE_USER_DATA: /* 波形数据 */
upload_data[1] = upload_type;
for (i = 0; i < 16; i++) /* 循环存入1~16个通道波形数据 */
{
upload_data[cur_data++] = (data->user_data[i] >> 8) & 0xFF; /* 存入波形数据高8位 */
upload_data[cur_data++] = data->user_data[i] & 0xFF; /* 存入波形数据低8位 */
}
break;
default :
upload_data[1] = 0xFE; /* 数据类别错误,存入错误码0xFE */
break;
}
if (upload_data[1] == 0xFE) /* 数据类别错误,直接跳出 */
{
return;
}
else /* 数据类别正确 */
{
uint16_t crc_res = crc16_calc(&(upload_data[0]), cur_data); /* 进行CRC校验 */
upload_data[cur_data++] = (crc_res >> 8) & 0xFF; /* 存入校验结果高8位 */
upload_data[cur_data++] = (crc_res) & 0xFF; /* 存入校验结果低8位 */
upload_data[cur_data++] = DEBUG_DATA_END; /* 存入帧尾 */
//HAL_UART_Transmit(&g_uart1_handle, upload_data, cur_data, 0xFFFF); /* 发送数据到上位机 */
bsp_transmit(USART0,upload_data, cur_data, 0xFFFFFFFF);
}
}
/*************************************** 第三部分 应用层函数 ********************************************/
/**
* @brief 初始化调试
* @param 无
* @retval 无
*/
void debug_init(void)
{
debug_obj_init(&g_debug); /* 初始化所需内存 */
}
/**
* @brief 设置目标速度范围
* @param max_limit:最大值
* @param min_limit:最小值(反转时最大速度)
* @param step_max : 最大突变值
* @retval 无
*/
void debug_set_point_range(float max_limit, float min_limit, float step_max)
{
static float step_temp = 0.0;
if (abs((int)(*debug_rev.speed - step_temp)) > step_max) /* 判断速度突变是否超过允许范围 */
{
*debug_rev.speed = step_temp; /* 超过最大突变值,保持原来速度 */
}
step_temp = *debug_rev.speed; /* 保存本次速度 */
if (*debug_rev.speed >= max_limit) /* 超过限速 */
{
*debug_rev.speed = max_limit; /* 配置为最大允许速度 */
}
if (*debug_rev.speed <= min_limit) /* 超过限速 */
{
*debug_rev.speed = min_limit; /* 配置为最大允许速度 */
}
}
/*************************************** 开发板 ——> 上位机 ********************************************/
/**
* @brief PID数据上传
* @param PIDx :PID组(1~10)
* @param *SetPoint :目标速度地址
* @param P、I、D :PID参数
* @retval 无
*/
void debug_send_initdata(upload_type PIDx, float *SetPoint, float P, float I, float D)
{
debug_rev.speed = (float *)(SetPoint); /* 开发板和上位机共用一个PID目标值的内存地址,数据同步更方便 */
g_debug.pid[PIDx - TYPE_PID1].pid.pidf[0] = P; /* 传入P值 */
g_debug.pid[PIDx - TYPE_PID1].pid.pidf[1] = I; /* 传入I值 */
g_debug.pid[PIDx - TYPE_PID1].pid.pidf[2] = D; /* 传入D值 */
debug_upload_data(&g_debug, PIDx); /* 发送PID参数 */
}
/**
* @brief 电流数据上传
* @param U_I、V_I、W_I :三相电流数据
* @note 如果只有单相,习惯用U_I上传
* @retval 无
*/
void debug_send_current(float U_I, float V_I, float W_I)
{
g_debug.amp[0] = U_I; /* 传入U相电流值 */
g_debug.amp[1] = V_I; /* 传入V相电流值 */
g_debug.amp[2] = W_I; /* 传入W相电流值 */
debug_upload_data(&g_debug, TYPE_AMP); /* 发送电流数据 */
}
/**
* @brief 电压数据上传
* @param valtage :电压数据
* @retval 无
*/
void debug_send_valtage(float valtage)
{
g_debug.bus_vol = valtage; /* 传入电压值 */
debug_upload_data(&g_debug, TYPE_VBUS); /* 发送电压数据 */
}
/**
* @brief 功率数据上传
* @param power :功率数据
* @retval 无
*/
void debug_send_power(float power)
{
g_debug.power = power; /* 传入功率值 */
debug_upload_data(&g_debug, TYPE_POWER); /* 发送功率数据 */
}
/**
* @brief 速度数据上传
* @param speed :速度数据
* @retval 无
*/
void debug_send_speed(float speed)
{
g_debug.speed = (int16_t)(speed); /* 传入速度值 */
debug_upload_data(&g_debug, TYPE_SPEED); /* 发送速度数据 */
}
/**
* @brief 总里程数据上传
* @param len :总里程数据
* @retval 无
*/
void debug_send_distance(uint64_t len)
{
g_debug.sum_len = len; /* 传入总里程值 */
debug_upload_data(&g_debug, TYPE_SUM_LEN); /* 发送总里程数据 */
}
/**
* @brief 温度数据上传
* @param motor_temp :电机温度
* @param board_temp :驱动板温度
* @retval 无
*/
void debug_send_temp(float motor_temp, float board_temp)
{
g_debug.temp[0] = board_temp; /* 传入驱动板温度值 */
g_debug.temp[1] = motor_temp; /* 传入电机温度值 */
debug_upload_data(&g_debug, TYPE_TEMP); /* 发送温度数据 */
}
/**
* @brief 电机状态上传
* @param motor_codestae :电机状态
* @retval 无
*/
void debug_send_motorstate(motor_state motor_codestae)
{
g_debug.status = motor_codestae; /* 传入电机状态 */
debug_upload_data(&g_debug, TYPE_STATUS); /* 发送电机状态 */
}
/**
* @brief 电机类型上传
* @param motorcode :电机类型
* @retval 无
*/
void debug_send_motorcode(motor_code motorcode)
{
g_debug.motor_code = motorcode; /* 传入电机类型 */
debug_upload_data(&g_debug, TYPE_MOTOR_CODE); /* 发送电机类型 */
}
/**
* @brief 波形数据上传
* @param chx :通道,取值1~16
* @param wave:数据
* @retval 无
*/
void debug_send_wave_data(uint8_t chx, int16_t wave)
{
g_debug.user_data[chx - 1] = wave; /* 选择通道,传入数据 */
debug_upload_data(&g_debug, TYPE_USER_DATA); /* 发送波形数据 */
}
/*************************************** 上位机 ——> 开发板 ********************************************/
/**
* @brief 上位机PID参数接收
* @param PIDx :PID组(1~10)
* @param P、I、D :PID参数
* @retval 无
*/
void debug_receive_pid(upload_type PIDx, float *P, float *I, float *D)
{
*P = g_debug.pid[PIDx - TYPE_PID1].pid.pidf[0]; /* 接收P参数 */
*I = g_debug.pid[PIDx - TYPE_PID1].pid.pidf[1]; /* 接收I参数 */
*D = g_debug.pid[PIDx - TYPE_PID1].pid.pidf[2]; /* 接收D参数 */
}
/**
* @brief 上位机命令接收
* @param 无
* @retval 0:无效,1:停机,2:运行,3:刹车
*/
uint8_t debug_receive_ctrl_code(void)
{
static uint8_t rec_r = 0;
if (debug_rev.Ctrl_code >= 0x01 && debug_rev.Ctrl_code <= 0x03) /* 判断命令范围是否正确 */
{
rec_r++;
if (rec_r >= 2)
{
rec_r = 0;
debug_rev.Ctrl_code = 0;
}
return debug_rev.Ctrl_code; /* 返回命令 */
}
return 0;
}
/**
****************************************************************************************************
* @file debug.h
* @author 正点原子团队(ALIENTEK)
* @version V1.0
* @date 2021-10-14
* @brief pid上位机调试 代码
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
****************************************************************************************************
* @attention
*
* 实验平台:正点原子 F407电机开发板
* 在线视频:www.yuanzige.com
* 技术论坛:www.openedv.com/forum.php
* 公司网址:www.alientek.com
* 购买地址:openedv.taobao.com
*
* 修改说明
* V1.0 20211014
* 第一次发布
*
****************************************************************************************************
*/
#ifndef __DEBUG_H
#define __DEBUG_H
#include "stdint.h"
#define DEBUG_ENABLE 0 /* PID调试使能 */
#define EN_CRC 1 /* CRC校验,0:关闭,1:开启 */
#define DEBUG_DATA_HEAD 0xC5 /* 帧头 */
#define DEBUG_DATA_END 0x5C /* 帧尾 */
/*********************************** 开发板 ——> 上位机 *******************************************/
/* 数据类别 */
typedef enum
{
TYPE_ERROR = 0x0F, /* 故障类型 */
TYPE_STATUS = 0x10, /* 设备状态 */
TYPE_SPEED = 0x11, /* 速度 */
TYPE_HAL_ENC = 0x12, /* 霍尔、编码器位置值 */
TYPE_VBUS = 0x13, /* 电压 */
TYPE_AMP = 0x14, /* 电流 */
TYPE_TEMP = 0x15, /* 驱动板温度 */
TYPE_SUM_LEN = 0x16, /* 总里程 */
TYPE_BEM = 0x17, /* 反电动势 */
TYPE_MOTOR_CODE = 0x18, /* 电机类型 */
TYPE_TORQUE = 0x19, /* 扭矩 */
TYPE_POWER = 0x1A, /* 功率 */
TYPE_PID1 = 0x20, /* 用户PID1参数上报 */
TYPE_PID2 = 0x21, /* PID2 */
TYPE_PID3 = 0x22, /* PID3 */
TYPE_PID4 = 0x23, /* PID4 */
TYPE_PID5 = 0x24, /* PID5 */
TYPE_PID6 = 0x25, /* PID6 */
TYPE_PID7 = 0x26, /* PID7 */
TYPE_PID8 = 0x27, /* PID8 */
TYPE_PID9 = 0x28, /* PID9 */
TYPE_PID10 = 0x29, /* PID10 */
TYPE_USER_DATA = 0x30, /* 波形数据上报 */
}upload_type;
/* 故障类型 */
typedef enum
{
HALL_ENC_ERROR = 0x01, /* 编码器、霍尔错误 */
OVERSPEED_ERROR = 0x02, /* 电机过速 */
DB_OVERTEMP_ERROR = 0x04, /* 驱动板过温 */
M_OVERTEMP_ERROR = 0x08, /* 电机过温 */
DB_OVERVOL_ERROR = 0x10, /* 驱动板过压 */
DB_UNDERVOL_ERROR = 0x10, /* 驱动板欠压 */
DB_OVERCUR_ERROR = 0x10, /* 驱动板过流 */
UNKNOWN_ERROR = 0x10, /* 未知错误 */
}motor_error;
/* 电机状态 */
typedef enum
{
IDLE_STATE = 0x00, /* 空闲状态 */
RUN_STATE = 0x01, /* 运行状态 */
ERROR_STATE = 0x02, /* 错误状态 */
LRTOUT_STATE = 0x03, /* 堵转超时 */
BREAKED_STATE = 0x04, /* 刹车 */
}motor_state;
/* 电机类型 */
typedef enum
{
DC_MOTOR = 0x10, /* 直流有刷电机 */
BLDC_MOTOR = 0x11, /* 直流无刷电机 */
PMSM_MOTOR = 0x12, /* 永磁同步电机 */
STEP_MOTOR = 0x13, /* 步进电机 */
SERVO_MOTOR = 0x14, /* 伺服电机 */
EXCHANG_MOTOR = 0x15, /* 变频器(三相交流异步电机) */
HELM_MOTOR = 0x16, /* 舵机 */
}motor_code;
/* PID参数存放结构体 */
typedef struct
{
union
{
float pidf[3]; /* PID参数发送存放 */
int8_t pidi8[12]; /* PID参数接收存放 */
}pid;
}pid_struct;
/* 参数存放结构体(开发板——>上位机) */
typedef struct
{
uint8_t status; /* 电机状态 */
int16_t speed; /* 电机速度 */
uint8_t hall_p; /* 霍尔位置值 */
uint16_t encode_p; /* 编码器位置值 */
float bus_vol; /* 电压 */
float amp[3]; /* 电流 */
float temp[2]; /* 温度 */
uint64_t sum_len; /* 总里程 */
float bem[3]; /* 反电动势 */
uint8_t motor_code; /* 电机类型 */
float torque; /* 扭矩 */
float power; /* 功率 */
pid_struct pid[10]; /* 10组PID参数(收发共用) */
int16_t user_data[16]; /* 波形数据 */
}debug_data;
extern debug_data g_debug; /* 发送变量 */
/*********************************** 上位机 ——> 开发板 *******************************************/
/* 数据类别 */
typedef enum
{
CMD_GET_ALL_DATA = 0x19, /* 获取全部参数 */
CMD_SET_CTR_CODE = 0x21, /* 下发控制指令 */
CMD_SET_CTR_MODE = 0x22, /* 下发控制模式 */
CMD_SET_SPEED = 0x23, /* 设定速度 */
CMD_SET_TORQUE = 0x24, /* 设定转矩 */
CMD_SET_VF_VOL = 0x25, /* 设定VF电压 */
CMD_SET_VF_IF_FRE = 0x26, /* 设定V/F、IF频率 */
CMD_SET_IF_CUR = 0x27, /* 设定IF电流 */
CMD_SET_DQ_CUR_D = 0x28, /* 设定DQ电流D */
CMD_SET_DQ_CUR_Q = 0x29, /* 设定DQ电流Q */
CMD_SET_PID1 = 0x31, /* 设定PID1参数 */
CMD_SET_PID2 = 0x32, /* PID2 */
CMD_SET_PID3 = 0x33, /* PID3 */
CMD_SET_PID4 = 0x34, /* PID4 */
CMD_SET_PID5 = 0x35, /* PID5 */
CMD_SET_PID6 = 0x36, /* PID6 */
CMD_SET_PID7 = 0x37, /* PID7 */
CMD_SET_PID8 = 0x38, /* PID8 */
CMD_SET_PID9 = 0x39, /* PID9 */
CMD_SET_PID10 = 0x3A, /* PID10 */
}cmd_type;
/* 下发控制指令 */
typedef enum
{
HALT_CODE = 0x01, /* 停机 */
RUN_CODE = 0x02, /* 运行 */
BREAKED = 0x03, /* 刹车 */
}cmd_code;
/* 下发控制模式 */
typedef enum
{
SPEED_MODE = 0x01, /* 转速模式 */
TORQUE_MODE = 0x02, /* 转矩模式 */
IF_MODE = 0x03, /* IF模式 */
VF_MODE = 0x04, /* VF模式 */
DQ_MODE = 0x05, /* DQ模式 */
}cmd_mode;
/* 参数存放结构体(上位机——>开发板) */
typedef struct
{
uint8_t Ctrl_code;
uint8_t Ctrl_mode;
float *speed;
float *torque;
float pid[3];
}debug_data_rev;
extern debug_data_rev debug_rev; /* 接收变量 */
#define DEBUG_REV_MAX_LEN 17 /* 接收数据最大长度 */
/*****************************************************************************************************/
/* 底层驱动函数 */
void debug_obj_init(debug_data *data); /* 内存初始化 */
void debug_handle(uint8_t *data); /* 上位机数据解析 */
void debug_upload_data(debug_data * data, uint8_t upload_type); /* 数据上传 */
/* 应用层函数 */
void debug_init(void); /* 初始化调试 */
void debug_set_point_range(float max_limit,float min_limit,float step_max); /* 设置目标速度范围 */
void debug_send_initdata(upload_type PIDx,float *SetPoint,float P,float I,float D); /* PID初始化数据上传 */
void debug_send_current(float U_I,float V_I,float W_I); /* 电流数据上传 */
void debug_send_valtage(float valtage); /* 电压数据上传 */
void debug_send_power(float power); /* 功率数据上传 */
void debug_send_speed(float speed); /* 速度数据上传 */
void debug_send_distance(uint64_t len); /* 总里程数据上传 */
void debug_send_temp(float motor_temp,float board_temp); /* 温度数据上传 */
void debug_send_motorstate(motor_state motor_codestae); /* 电机状态上传 */
void debug_send_motorcode(motor_code motorcode); /* 电机类型上传 */
void debug_send_wave_data(uint8_t chx,int16_t wave); /* 波形数据上传 */
void debug_receive_pid(upload_type PIDx,float *P,float *I,float *D); /* 上位机PID参数接收 */
uint8_t debug_receive_ctrl_code(void); /* 上位机命令接收 */
#endif
debug_handle(rxbuffer+i);
uint32_t bsp_transmit(const uint32_t usart_periph,const uint8_t *data,const uint32_t size,const uint32_t timeout)
{
for(int i=0;i<size;i++)
{
cnt=10000;
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE) &&cnt--);
usart_data_transmit(USART0, (uint8_t)data[i]);
}
}
void atk_debug()
{
uint8_t debug_cmd = 0;
//更新pid参数
debug_receive_pid(TYPE_PID1, (float *)&g_speed_pid.Proportion,(float *)&g_speed_pid.Integral, (float *)&g_speed_pid.Derivative);
//debug_set_point_range(300, -300, 300); /* 设置目标速度范围 */
debug_cmd = debug_receive_ctrl_code(); /* 读取上位机指令 */
//电机的刹车控制
if (debug_cmd == BREAKED) /* 电机刹车 */
{
stop_motor(); /* 停止电机 */
pid_init(); /* 重置pid参数 */
debug_send_motorstate(BREAKED_STATE); /* 上传电机状态(刹车) */
debug_send_initdata(TYPE_PID1, (float *)(&g_speed_pid.SetPoint), KP, KI, KD);
} //电机启动控制
else if (debug_cmd == RUN_CODE) /* 电机运行 */
{
start_motor(); /* 开启电机 */
g_speed_pid.SetPoint = 30; /* 设置目标速度:30 RPM */
/* 标记电机启动 */
debug_send_motorstate(RUN_STATE); /* 上传电机状态(运行) */
}
}
void debug_send_wave_data(uint8_t chx,int16_t wave); /* 波形数据上传 */
https://gitee.com/chejia12/gd32-f103-c8-t6_-template
commit d83b648239fe33684442d3a32301a499da1b2581 (HEAD -> master)
Author: chejia <1085582540@qq.com>
Date: Tue Jul 26 16:35:33 2022 +0800
位置pid和速度pid