我参加了17届的智能车,最终进入了国赛,弥补了16届的遗憾。第二年参加智能车了,所用的大部分方法不同于16届所采取的方式,由于程序不是我一个人完成的,所以就不开源比赛的工程,和以前一样采用文章讲解和部分代码代码展示的方式,其中有很多的方法也是我从别人的代码中借鉴而来的。因为要准备其他的事情,所以更新的速度会断断续续。
在智能车的后期调车过程中,参数的调整一直是很麻烦的一点,为方便手动调参,减少电脑不断下载,所设计的菜单需要满足:
(1)通过按键调整显示不同的参数并修改
(2)将修改的参数通过flash保存至单片机中
(3)菜单代码的编写足够的简单方便移植
下面首先介绍flash的存参方式,我在本次比赛中使用的是逐飞科技的TC364,对应的开源库有介绍相应的函数,简单来说就是先擦除扇区内的数据再重新进行该扇区进行数据的写入。因为后期的参数较多,为便于修改,先定义一个一维数组保存参数,所使用的功能函数如下:
uint32 flashBuffer[80];
uint8 flash_buff[128];
uint8 read_buff[128];
uint8 dat;
//flash功能函数
/*
* 功能:flash数据擦除检查
* 输入:要检查的flash扇区,以及检查的页数
* 输出: 若擦除成功,返回1,否则返回0
*/
uint8_t flashClearCheck(uint32 sector_num, uint32 page_num){
int i;
for(i = 0; i < page_num; i++){
if(flash_check(sector_num, i)){
return 0;
}
}
return 1;
}
/*
* 功能:flash数据存储
* 输入:要存储的数据长度,以及扇区
* 输出:若写入成功返回1,否则返回0
*/
uint8_t flashSave(uint32 sector_num, uint32 Lenth){
int i;
for(i = 0; i < Lenth; i++){
eeprom_page_program(sector_num, i, &flashBuffer[i]);
}
for(i = 0; i < Lenth; i++){
if(!flash_check(sector_num, i)){
return 0;
}
}
return 1;
}
而如何对参数进行保存,就按照上述所说,先将对应的参数保存的数组中,再调用功能函数使其保存,因为后期需要使用按键,所以封装成函数,放到对应的按键触发方式内。
//-----扇区存取函数
void normal_param_store(){
eeprom_erase_sector(0); //擦除扇区0
if(flashClearCheck(0,80)){ //擦除成功
ips200_showstr(0,0,"delete_success");
flashBuffer[0] = float_conversion_uint32(motor_pid_left.pid[KP]);
flashBuffer[1] = float_conversion_uint32(motor_pid_left.pid[KI]);
flashBuffer[2] = float_conversion_uint32(motor_pid_left.pid[KD]);
flashBuffer[3] = speed.targrt_speed;
// flashBuffer[4] = ;
// flashBuffer[5] = ;
//
// flashBuffer[6] = ;
// flashBuffer[7] = ;
// flashBuffer[8] = ;
// flashBuffer[9] = ;
// flashBuffer[10] = ;
//
// flashBuffer[11] = ;
// flashBuffer[12] = ;
// flashBuffer[13] = ;
//
// flashBuffer[14] = ;
//
// flashBuffer[15] = ;
// flashBuffer[16] = ;
// flashBuffer[17] = ;
// flashBuffer[18] = ;
// flashBuffer[19] = ;
// flashBuffer[20] = ;
// flashBuffer[21] = ;
//
// flashBuffer[22] = ;
// flashBuffer[23] = ;
// flashBuffer[24] = ;
// flashBuffer[25] = ;
//ips200_showstr(0,1,"whether save");
dat=flashSave(0,80);
if(dat==0){
ips200_showstr(120,0,"save_success ");
}else{
ips200_showstr(120,0,"save_error ");
}
}else{
ips200_showstr(0,0,"delete_error");
}
}
void date_store1(){
eeprom_erase_sector(1); //擦除扇区0
if(flashClearCheck(1,80)){ //擦除成功
ips200_showstr(0,0,"delete_success");
// flashBuffer[0] = ;
// flashBuffer[1] = ;
// flashBuffer[2] = ;
// flashBuffer[3] = ;
// flashBuffer[4] = ;
// flashBuffer[5] = ;
//
// flashBuffer[6] = ;
// flashBuffer[7] = ;
// flashBuffer[8] = ;
// flashBuffer[9] = ;
// flashBuffer[10] = ;
//
// flashBuffer[11] = ;
// flashBuffer[12] = ;
// flashBuffer[13] = ;
//
// flashBuffer[14] = ;
//
// flashBuffer[15] = ;
// flashBuffer[16] = ;
// flashBuffer[17] = ;
// flashBuffer[18] = ;
// flashBuffer[19] = ;
// flashBuffer[20] = ;
// flashBuffer[21] = ;
//
// flashBuffer[22] = ;
// flashBuffer[23] = ;
// flashBuffer[24] = ;
// flashBuffer[25] = ;
ips200_showstr(0,1,"whether save");
dat=flashSave(1,80);
if(dat==0){
ips200_showstr(0,1,"save_success ");
}else{
ips200_showstr(0,1,"save_error ");
}
}else{
ips200_showstr(0,0,"delete_error");
}
}
如图为例对电机的三个参数进行修改,擦除扇区0,当擦除成功后,将对应的参数放到数组内就可以了。
最后,在每次初始化的时候对flash里的参数进行读取,不然显示的数值会出错。该函数可以放在初始化函数里
//-----扇区读取函数
void normal_param_read(void){
motor_pid_left.pid[KP] = flash_read(0,0,float);
motor_pid_left.pid[KI] = flash_read(0,1,float);
motor_pid_left.pid[KD] = flash_read(0,2,float);
speed.targrt_speed = flash_read(0,3,uint32);
ips200_showstr(30,0,"read_success");
}