代码
初始化代码
/**
* @brief 初始化调试
* @param 无
* @retval 无
*/
void debug_init(void)
{
debug_obj_init(&g_debug); /* 初始化所需内存 */
}
被上面代码调用
/**
* @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 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; /* 配置为最大允许速度 */
}
}
PID目标值上下位机同步
/**
* @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参数 */
}
底层函数
实现数据接收和发送
数据接收
这里我们以没有数据位的介绍
先通过判断接受到帧尾
uint8_t rev_data[ 17 ] ; /* 存放接收数据的数组 */
uint8_t rev_p = 0 ; /* 地址偏移量 */
void debug_handle( uint8_t *data )
{
if ( rev_p >= 17 ) /* 超过缓冲区最大长度 */
{
rev_p = 0 ; /* 地址偏移量清零,将该字节放到第一个字节内存位置 */
}
rev_data[ rev_p ] = *(data); /* 从地址里取出数据,存进数组 */
if (*data == DEBUG_DATA_END) /* 判断是否收到帧尾 */
{
/* 数据包长度为5个字节,判断第一个字节是否为帧头,是进入接收到帧头后,向前偏移4个地址接收到帧头 */
if (debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 4) % DEBUG_REV_MAX_LEN] == DEBUG_DATA_HEAD)
{
for (i = 0; i < 2; i++)
{
/* 取出帧头、数据类别,5个字节的数据包没有数据域 */
temp[i] = debug_rev_data[(debug_rev_p + DEBUG_REV_MAX_LEN - 4 + i) % DEBUG_REV_MAX_LEN];
}
/*下面就是CRC校验代码*/
#if EN_CRC /* 进行CRC校验,这里的+2 +3就是地址偏移到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 ++; /* 地址偏移,当存完上一个,地址向后偏移一位再向后偏移 */
}
例程中采用环形环形缓冲区
存放接收数据为17个字节
数据发送
/**
* @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); /* 发送数据到上位机 */
}
}