Freescale芯片智能小车程序分析
Freescale芯片智能小车程序分析
July 19, 2010
#include <hidef.h>
#include <MC9S12XS128.h>
#pragma LINK_INFO DERIVATIVE "mc9s12xs128"
#define PITTIME 5000 //50MS定时中断
#define speed_set1 3200
#define speed_set2 2000
#define NB 150 //直道最小速度
#define NS 250 //直道中小速度
#define Z 350 //中速
#define PS 500 //中高速
#define PB 600 //高速
#define NB1 275 //弯道最小速度
#define Z1 325 //中速
#define PS1 350 //中高速
#define PB1 375 //高速
int speed_data[5][7] = //直道速度表
{
{ NB, NB, NS, Z, PS, Z, NS },
{ NB, NS, Z, PS, PB, PB, Z },
{ NS, Z, PS, PB, PS, Z, NS },
{ Z, PS, PB, PS, Z, NS, NB },
{ NS, Z, NS, Z, NS, NB, NB }
};
int speed_data0[5][7] = //弯道速度表
{
{ NB1, NB1, NS1, Z1, PS1, Z1, NS1 },
{ NB1, NS1, Z1, PS1, PB1, PB1, Z1 },
{ NS1, Z1, PS1, PB1, PS1, Z1, NS1 },
{ Z1, PS1, PB1, PS1, Z1, NS1, NB1 },
{ NS1, Z1, NS1, Z1, NS1, NB1, NB1 }
};
int ad_data[10][11];
int ad_data1[11];
int pd_data[11];
int ad_min[11] = { 40, 20, 20, 30, 50, 50, 50, 50, 60, 50, 50 }; //新
int ad_mid[11];
int state;
int start_flag = 1; //启停标志
int straight_flag = 1; //直弯标志
int count = 0;
int B_cnt;
int B_cnt_last;
int count1 = 0; //赛道特殊状况检测次数
int count3 = 0; //直弯检测累计
int count4 = 0;
int state_first = 0; //赛道状态传递
int state_last = 0;
int state_now;
int state_e = 0;
int state_e_last;
int u;
int v = 200;
int steer_e; //舵机增量
float Kp = 2; //舵机K
float Kp_data[11] = { 0.6, 0.65, 0.82, 0.83, 0.84, 0.90, 0.95, 1.1, 1.35, 1.47, 1.59 };
float Kp_data2[11] = { 0 };
float Kd = 0.5; //舵机D
float Kp_s = 0.008; //速度K
float Ki_s = 0; //速度I
float Kd_s = 0; //速递D
int steer = 2600;
int speed; //光电编码器测速值
int speed_e_first = 0;
int speed_e_last = 0;
int speed_e;
int speed_set; //速度设定值
int motor_e;
int motor_pwm;
//初始化//
void PLL_Init(void) //PLLClK=2*OSCCLK*(SYNR+1/REFDV+1)
{
//锁相环=2*16=32MHz
REFDV = 1; //总线时钟=32/2=16MHz
SYNR = 1;
while (!(CRGFLG & 0x08));
CLKSEL = 0X08; //时钟选择,等待模式下锁相环停止工作
}
void PWM_Init(void)
{
PWME = 0x00;
PWMCTL = 0x70; //级联方式
PWMPOL = 0xff;
PWMCAE = 0xff; //对齐方式左对齐
PWMCLK = 0x30; //PWM时钟选择,23通道CLOCKSB
PWMPRCLK = 0x11; //PWM预分频,时钟源A=时钟源B=8MHz
PWMSCLA = 5;
PWMSCLB = 5;
PWMPER01 = 1000;
PWMDTY01 = 0;
PWMPER45 = 1000;
PWMDTY45 = 200;
PWMPER23 = 16000;
PWMDTY23 = 0;
PWME = 0x3f;
}
void AD_Init(void)
{
ATD0CTL0 = 0x0A;
ATD0CTL1 = 0x00; //7:1-外部触发,65:00-8位精度,4:放电,3210:ch
ATD0CTL2 = 0x40; //禁止外部触发, 中断禁止
ATD0CTL3 = 0xD8; //右对齐无符号,每次转换11个序列, No FIFO, Freeze模式下继续转
ATD0CTL4 = 0x01; //765:采样时间为4个AD时钟周期,ATDClock=[BusClock*0.5]/[PRS+1]
ATD0CTL5 = 0x30; //6:0特殊通道禁止,5:1连续转换 ,4:1多通道轮流采样
ATD0DIEN = 0x00; //禁止数字输入
}
void PIT_Init(void)
{
PITCFLMT_PITE = 0; //PIT关
PITCE_PCE0 = 1; //定时器通道0使能
PITMTLD0 = 160 - 1; //8位定时器初值设定。160分频,在16MHzBusClock下,为0.1MHz。即 10us.
PITLD0 = PITTIME - 1; //16位定时器初值设定。PITTIME*0.01MS 50ms定时
PITINTE_PINTE0 = 1; //定时器中断通道0中断使能
PITCFLMT_PITE = 1; //PIT使能
}
void PACA_Init(void) //初始化脉冲累加器A
{
TCTL3 = 0X40; //下降沿捕捉脉冲
PACTL = 0x40; //脉冲累加使能
PACNT = 0X0000;
}
//功能函数//
void delay_ms(int ms) //延时函数
{
int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 2770; j++); //16MHz--2ms
}
int abs(int num) //绝对值
{
if (num<0)
return -num;
else
return num;
}
void Reverse(int* arr, int b, int e) //数组元素对换
{
for (; b < e; b++, e--)
{
int temp = arr[e];
arr[e] = arr[b];
arr[b] = temp;
}
}
void RightShift(int* arr, int N, int K) //数组循环移位
{
K %= N;
Reverse(arr, 0, N - K - 1);
Reverse(arr, N - K, N - 1);
Reverse(arr, 0, N - 1);
}
//单片机处理/
void ATD_data(void) //AD采集
{
int i;
for (i = 0; i<10; i++)
{
while (!ATD0STAT0_SCF);
ad_data[i][0] = ATD0DR0L;
ad_data[i][1] = ATD0DR1L;
ad_data[i][2] = ATD0DR2L;
ad_data[i][3] = ATD0DR3L;
ad_data[i][4] = ATD0DR4L;
ad_data[i][5] = ATD0DR5L;
ad_data[i][6] = ATD0DR6L;
ad_data[i][7] = ATD0DR7L;
ad_data[i][8] = ATD0DR8L;
ad_data[i][9] = ATD0DR9L;
ad_data[i][10] = ATD0DR10L;
ATD0CTL5 = 0x30;
}
}
void PD_data(void) //AD数据处理
{
int i, j, k, temp;
for (i = 0; i<10; i++) //每个传感器采样10次的数据进行排序
{
for (j = 0; j<11; j++)
for (k = j + 1; k<10; k++)
{
if (ad_data[j][i]>ad_data[k][i])
{
temp = ad_data[j][i];
ad_data[j][i] = ad_data[k][i];
ad_data[k][i] = temp;
}
}
}
for (j = 0; j<11; j++) //对中间的两个值求平均作为本次采集的结果
ad_data1[j] = (ad_data[4][j] + ad_data[5][j]) / 2;
}
void STATE_data(void) //位置判断
{
int i;
B_cnt_last = B_cnt; //B_cnt为当前检测到黑线传感器的个数
B_cnt = 0;
for (i = 0; i<11; i++) //对采集的数据进行二值化处理
{
ad_mid[i] = ad_min[i] + 60;
(ad_data1[i]<ad_mid[i]) ? (pd_data[i] = 1) : (pd_data[i] = 0);
}
for (i = 0; i<11; i++) //位置计算,判断采集黑线传感器的个数
{
if (pd_data[i] == 1)
B_cnt++;
}
if (B_cnt == 1)
for (i = 0; i<11; i++) //判断黑线的位置
{
if (pd_data[i] == 1)
state = 2 * i - 10;
}
if (B_cnt == 2)
for (i = 0; i<10; i++)
{
if (pd_data[i] == 1 && pd_data[i + 1] == 1)
state = 2 * i + 1 - 10;
}
if (B_cnt>5 && B_cnt_last<6) //特殊状况,十字,起跑线
count1++;
}
void START_judge(void) //起跑线识别
{
int i, knum, SATurn;
int kA[4] = { 0 };
if (count1>2)
for (i = 0, knum = 0, SATurn = 0; i<10; i++)
if (pd_data[i] ^ pd_data[i + 1])
{
SATurn++;
kA[knum] = i;
knum++;
}
if (SATurn == 4)
if ((kA[1] - kA[0]) <= 2 && (kA[1] - kA[0]) >= 1 && //起跑线左白区域
(kA[2] - kA[1]) <= 2 && (kA[2] - kA[1]) >= 1 && //起跑线中黑区域
(kA[3] - kA[2]) <= 2 && (kA[3] - kA[2]) >= 1 && //起跑线右白区域
(B_cnt <= 9 && B_cnt >= 7)) //状态1传感器总数
start_flag = 0;
}
void STATE_judge(void) //滤波&&直弯判断
{
state_last = state_now;
state_now = state;
if (abs(state_now - state_last)>2)
{
state_now = state_last;
}
if (count3<40)
count3++;
if (abs(state_now)<5)
count4++;
if (count3 == 40 && count4>35)
{
straight_flag = 1;
count3 = 0;
count4 = 0;
}
if (count3 == 40 && count4<30)
{
straight_flag = 0;
count3 = 0;
count4 = 0;
}
Kp = Kp_data[abs(state_now)];
}
void STATE_e(void) //误差变化计算
{
if (count == 0)
{
state_first = state_now;
}
count++;
if (count>5)
{
state_e_last = state_e;
state_e = state_now - state_first;
count = 0;
}
}
void STEER_pd(void) //舵机PD控制
{
/* if(abs(state_now)<4) //速度对转角的影响,速度大时,直道K值取小
Kp-=speed/speed_set1;
if(abs(state_now)>4) //弯道K值随速度增大
Kp+=speed/speed_set2; */
//Kp=Kp_data[abs(state_now)];
steer = (int)(2550 + Kp*state_now * 70 + Kd*(state_e - state_e_last) * 70);
// steer+=(int)(Kp*(state_now-state_last)*80+Kd*(state_e-state_e_last)*80);
if (steer > 3400)
{
steer = 3400;
}
if (steer < 1700)
{
steer = 1700;
}
PWMDTY23 = steer;
}
void SPEED_set(void)
{
int i, j;
if (state_e>4)
i = 4;
else if (state_e<-4)
i = 0;
else
{
i = (state_e + 4) / 2;
j = (state_now + 10) / 3;
}
if (straight_flag == 1)
speed_set = speed_data[i][j];
if (straight_flag == 0)
speed_set = speed_data0[i][j];
// speed_e_first=speed_e_last;
speed_e_last = speed_e;
speed_e = speed_set - speed;
}
void SPEED_pd(void)
{
if (start_flag == 0)
{
delay_ms(50);
PWMDTY01 = 200;
}
else
{
if (speed_set - speed>300)
{
motor_pwm = 700;
}
else if (speed_set - speed<-300)
{
motor_pwm = 0;
}
else
{
motor_e = (int)(Kp_s*speed_e + Kd_s*(speed_e - speed_e_last));
//motor_e = (int)(Kp_s*(speed_e-speed_e_last)+Ki_s*speed_e+
// Kd_s*(speed_e-2*speed_e_last+speed_e_first));
motor_pwm = motor_e + v;
v = motor_pwm;
}
PWMDTY01 = motor_pwm;
}
}
/* 定时中断 */
\#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 66 PIT0(void)
{
PITTF_PTF0 = 1; //清中断标志位
speed = PACNT;
PACNT = 0x0000;
}
/********************************/
/* 主函数 */
/********************************/
void main(void)
{
PLL_Init();
PWM_Init();
AD_Init();
PIT_Init();
PACA_Init();
EnableInterrupts;
for (;;)
{
ATD_data();
PD_data();
STATE_data();
START_judge();
STATE_judge();
STATE_e();
SPEED_set();
STEER_pd();
SPEED_pd();
}
}这份源代码的不足和错误还是比较多, for(i=0;i<10;i++) //每个传感器采样10次的数据进行排序
排序采用了冒泡排序,效率大打折扣,而且采用排序的方法处理数据稳定但并不是特别好。更改排序算法效果也不明显。
for(j=0;j<11;j++) //对中间的两个值求平均作为本次采集的结果
ad_data1[j]=(ad_data[4][j]+ad_data[5][j])/2;
效果 这句求平均值浪费一个循环,完全可以将这个求平均放在排序循环下。
换一种思路,不排序,选出接受的最大最小的数据,排除后求平均,这样少了排序,理论上能减少时间复杂度,不过效果仍不明显。
改进算法似乎不能限于程序的微调,可以建立跑道模型,分析历年的跑道无非直道,90度弯道,s弯道,小幅度弯道,回环型道。对这些跑道建立最优模型,通过接受的数据大概估算出恰当的模型,然后利用最优的方法执行。再利用定时中断接受数据看看和估算的模型差别大不大,不大就继续执行,差别大就判断其他模型,如果都没有再利用这种及时探测行驶。
最后更新于