备战18届智能车视觉组-移植野火PID调试助手问题解决方案分享
问题一:上传数据时,无法显示波形
我分析出来的原因是 数据发送是正确的,因为数据格式的问题,假设上位机只解析10个字节,正确的是我下位机也发送10个字节,因为结构体分配内存原因,下位机发送了12个字节,相当于发送一样的数据,因为1个字节的数据占了4个字节的内存,相当于占格子了。如下图
图一:正确的数据格式 (在别的博客找的)
图二:错误的数据格式 (我的)
我猜测时野火定义结构体时出现的问题 ,可能是编译器版本的问题 下面两种结构体定义
A: typedef struct __packed
B: typedef __packed struct
野火的通信协议原来是B的写法,但是在编译器V6的下会报错只能使用A的写法(只能用v6版本,逐飞最新的库只能使用编译器v6版本)
两个结构体的定义区别就是 给变量分配内存的问题
A:这样定义 结构体会自动分配变量内存
B:这样定义 结构体不会自动对变量分配内存
举个列子:
typedef struct __packed 结构体这样定义的话
{
uint32_t head; // 包头 4个字节
uint8_t ch; // 通道 4个字节
uint32_t len; // 包长 4个字节
uint8_t cmd; // 命令 4个字节
}packet_head_t;
typedef __packed struct 结构体这样定义的话
{
uint32_t head; // 包头 4个字节
uint8_t ch; // 通道 1个字节
uint32_t len; // 包长 4个字节
uint8_t cmd; // 命令 1个字节
}packet_head_t;
所以最后解决方法是不使用结构体,采用定义变量的方式,自己定义变量内存。
//这是我用逐飞库改的
void set_computer_value(uint8_t cmd, uint8_t ch, void *data, uint8_t num)
{
uint8_t sum = 0; // 校验和
num *= 4; // 一个参数 4 个字节
static packet_head_t set_packet;
set_packet.head = FRAME_HEADER; // 包头 0x59485A53
set_packet.len = 0x0B + num; // 包长
set_packet.ch = ch; // 设置通道
set_packet.cmd = cmd; // 设置命令
//下面这四句话是我写的 原本是没有的
head_plus=FRAME_HEADER; // head_plus:定义的是uint32_t
ch_plus =ch; // ch_plus :定义的是uint8_t
len_plus = 0x0B + num; // len_plus :定义的是uint32_t
cmd_plus =cmd; // cmd_plus :定义的是uint8_t
sum = check_sum(0, (uint8_t *)&set_packet, sizeof(set_packet)); // 计算包头校验和
sum = check_sum(sum, (uint8_t *)data, num); // 计算参数校验和
//用逐飞库改的发送函数,用的是数组的形式发送
uart_write_buffer(UART_1,(uint8_t *)&head_plus,sizeof(head_plus)); // 发送数据头
uart_write_buffer(UART_1,(uint8_t *)&ch_plus, sizeof(ch_plus));// 发送通道
uart_write_buffer(UART_1,(uint8_t *)&len_plus, sizeof(len_plus));//发送包长
uart_write_buffer(UART_1,(uint8_t *)&cmd_plus, sizeof(cmd_plus));//发送命令
uart_write_buffer(UART_1,(uint8_t *)data, sizeof(data)); // 发送参数
uart_write_buffer(UART_1,(uint8_t *)&sum, sizeof(sum)); // 发送校验和
}
图三:这是我改完之后的函数
void set_computer_value(uint8_t cmd, uint8_t ch, void *data, uint8_t num)
{
static packet_head_t set_packet;
uint8_t sum = 0; // 校验和
num *= 4; // 一个参数 4 个字节
set_packet.head = FRAME_HEADER; // 包头 0x59485A53
set_packet.ch = ch; // 设置通道
set_packet.len = 0x0B + num; // 包长
set_packet.cmd = cmd; // 设置命令
sum = check_sum(0, (uint8_t *)&set_packet, sizeof(set_packet)); // 计算包头校验和
sum = check_sum(sum, (uint8_t *)data, num); // 计算参数校验和
usart1_send((uint8_t *)&set_packet, sizeof(set_packet)); // 发送数据头
usart1_send((uint8_t *)data, num); // 发送参数
usart1_send((uint8_t *)&sum, sizeof(sum)); // 发送校验和
}
图四:原来的函数
问题二:上位机发送pid和目标值时 ,出现 目标值发送出去了,但是下位机没有做出响应。
解决方法:串口接收中断的优先级要高于定时器计算pid的优先级,还要把上位机解析数据的函数放到接收数据的后面。
问题三:上位机发送目标值要连续点击两次才能发送成功,原因不知道是什么,
解决方法:最后我使用逐飞的FIFO库更换了数据缓存区的写法。
uint8 fifo_get_data[64]; // fifo 读取数据的缓冲区
uint32 fifo_data_count = 0;
void LPUART1_IRQHandler(void)
{
#if (DEBUG_UART_USE_INTERRUPT && PID_ASSISTANT_EN) // debug 串口中断
debug_interrupr_handler(); // 调用 debug 串口接收处理函数 数据会被 debug 环形缓冲区读取
//读取FIFO并将数据放进<fifo_get_data>最后清理缓存
fifo_data_count = debug_read_ring_buffer(fifo_get_data);
if (fifo_data_count != 0)
{
protocol_data_recv(fifo_get_data, fifo_data_count);
receiving_process();
}
#endif
LPUART_ClearStatusFlags(LPUART1, kLPUART_RxOverrunFlag); // 不允许删除
}
图五:改成FIFO缓存写法
uint8_t Recv1[128]={0};//串口接收缓存
uint8_t rx_cnt=0;//接收数据个数计数变量
int sizecopy=128;
uint8_t dr;
void LPUART1_IRQHandler(void)
{
#if (PID_ASSISTANT_EN)
uint8_t data;//接收数据暂存变量
uint8_t bufcopy[128];//最多只取前64个数据
if(kLPUART_RxDataRegFullFlag & LPUART_GetStatusFlags(LPUART1)) //接收中断
{
dr=uart_read_byte(UART_1);
Recv1[rx_cnt++]=dr;//接收的数据存入接收数组
}
LPUART_ClearStatusFlags(LPUART1, kLPUART_RxOverrunFlag); // 不允许删除
if(kLPUART_IdleLineFlag & LPUART_GetStatusFlags(LPUART1)) //空闲中断
{
LPUART_ClearStatusFlags(LPUART1, kLPUART_IdleLineFlag); // 不允许删除
//清空本地接收数组
memset(bufcopy,0,sizecopy);
memcpy(bufcopy,Recv1,rx_cnt);//有几个复制几个
protocol_data_recv(bufcopy, rx_cnt);
receiving_process();
memset(Recv1,0,sizecopy);
rx_cnt=0;
}
#endif
}
图六:垃圾写法