功能介绍与使用思路:
格式1(执行指令):@Num_cv_action:Num_cv_data;
下位机首先会将自己接收到的Num_cv_action与Num_cv_data发送回给上位机。由于此时的Num_cv_action也会带有@,上位机可根据此特性检查下位机接收到的内容是否正确。
当下位机完成相应的执行指令后,会发送 Finished!值得注意的是:上位机可根据此信息执行下一步内容若是上位机在下位机未完成执行指令A的情况下新发送了一个执行指令B,则B指令会直接覆盖A指令,下位机会直接去执行A指令 。这一机制可用于应对需要改变执行指令的突发情况。
格式2(普通消息):Num_cv_action:;
下位机会将自己接收到的Num_cv_action重新发送回给上位机(不带有@),可用于检查下位机接收消息是否正确。
代码如下:
放在各位的Open_mv.c文件中
/*****接收数据*****/
void Opencv_Receive_Data(uint8_t com_data_cv)
{
static uint16_t RxCounter = 0; //计数
static uint16_t RxBuffer[20] = {0};
RxBuffer[RxCounter++] = com_data_cv; //疯狂接收,直到遇到包尾,且上一个数据已经处理完;此时Rxcounter位于分号角标的下一位
if(com_data_cv == ';' && Num_cv_data_rescieve_success == 1)
{
Num_cv_rescieve_success = 1;
Num_cv_data_rescieve_success = 0;//将上一个标志位清0
// printf("RxCounter = %d\r\n", RxCounter);//日志输出
}
if(Num_cv_rescieve_success == 1) //如果完成接收,则将冒号前的内容(不含冒号)赋值给Num_cv_action
{
// printf("Received colon\n"); // 在此处添加日志输出
//Allow characters to be transferred to the string
for(uint8_t j = 0; RxBuffer[j] != ':'; j++,jiaobiao = j)//最后j落在在‘:’的数组角标上,但是接收数据没有接收到:
{
Num_cv_action[j] = (char)RxBuffer[j];
}
// printf("jiaobiao = %d\r\n", jiaobiao);//打印角标的值
Num_cv_action[jiaobiao] = '\0';
Num_cv_action_rescieve_success = 1;//这一状态完成标志位置1
Num_cv_rescieve_success = 0;//将上一个标志位置0,让他不在进入次操作
}
if(Num_cv_action_rescieve_success == 1) //若Num_cv_action已处理完成
{
printf("Received semicolon\r\n"); // 在此处添加日志输出
Num_cv_data = 0;//让数据为0
for(uint16_t i = RxCounter - 2;RxBuffer[i] != ':'; i--) //直到i位于冒号的位置,且每次轮询都来一个日志输出
{
Num_cv_data = (int32_t)(Num_cv_data + ((char)RxBuffer[i] - '0') * count_beilv); //Accumulate the number
count_beilv *= 10;
// printf("i = %d\r\n", i);//角标i的日志输出
}
// printf("jisuan_ok\r\n");
for(char i = 0;i < 20; i++)//清0
{
RxBuffer[i] = 0;
}
count_beilv = 1;//倍率计算位清1,方便后续使用
// printf("clean_ok!");
//处理相关标志位
Num_cv_action_rescieve_success = 0;//将上一个标志位置0,让他不在进入次操作
Num_cv_data_rescieve_success = 1;
RxCounter = 0;//接收数组的下角标置0;
execute_sign = 1;//将可执行标志位置1,表示下位机可以执行一次操作
printf_sign = 1;//可发送信息标志位置1,表示下位机可以在完成执行指令后发送一次信息
//发送相应数据
printf("%s", (char*)(Num_cv_action)); // 打印Num_cv_action值
printf("\r\n%d\r\n", Num_cv_data); // 打印Num_cv_data值
//试验
// if(strcmp((char *)&(Num_cv_action[0]), (char *)&(str_right[0])) == 0)
// {
// printf("OK!");
// }
// else
// {
// printf("%d\r\n", strcmp((char *)&(Num_cv_action[0]), (char *)&(str_right[0])));
// for(char j = 0; Num_cv_action[j] != '\0'; j++)
// {
// printf("%d的差值 = %d\r\n", j ,strcmp((char *)(&Num_cv_action[j]), (char *)&(str_right[0])));
// printf("%d个字符的ASCII码 = %d\r\n", j, (char)Num_cv_action[j]);
// }
// }
// RxCounter = 0; // Reset counter
//memset(RxBuffer, 0, sizeof(RxBuffer)); // Clear buffer
// printf("%s, %d\r\n", Num_cv_action, Num_cv_data); // Print the result
}
}
while(1)函数中的内容
if(Num_cv_action[0] == '@')//如果Num_cv_action是@开头,则为执行指令
{
if(strcmp((char *)(&Num_cv_action[1]),"right") == 0)//如果Num_cv_action
{
if(execute_sign == 1)
{
spin_Turn(right_90);
execute_sign = 0;
}
if(Spin_succeed_flag == 1 && printf_sign == 1)
{
printf_sign = 0;
printf("Finished!");
}
}
else if(strcmp((char *)(&Num_cv_action[1]),"left") == 0)
{
if(execute_sign == 1)
{
spin_Turn(left_90);
execute_sign = 0;
}
if(Spin_succeed_flag == 1 && printf_sign == 1)
{
printf("Finished!");
printf_sign = 0;
}
}
else if(strcmp((char *)(&Num_cv_action[1]),"ahead") == 0 && printf_sign == 1)
{
if(execute_sign == 1)
{
Car_go(Num_cv_data);
execute_sign = 0;
}
if(Stop_Flag == 1)
{
printf("Finished!");
printf_sign = 0;
}
}
}
在Keil5环境中使用C语言函数有一个需要注意的问题:数据类型转换
uint16_t等特有的数据类型多少会与char等C语言原生数据类型有出入,若是直接将int16_t用于C语言的函数中(如strcmp()),可能会出现一些无法解释的问题。反之亦然。