项目设计智能车最终代码
单片机源程序如下:
- #include "common.h"
- #include "camera.h"
- #include "gpio.h"
- #include "exti.h"
- #include "uart.h"
- #include "roadJudge.h"
- #include "arm_math.h"
- #include "FTM.h"
- #include "delay.h"
- #include "isr.h"
- //变量定义
- unsigned char threshold;
- unsigned char Is_SendPhoto=0;
- unsigned char Pix_data[V][H]={0},Bina_data[V][H]={0};// int *p=new int[len];V=50;H=150;
- int LeftBorder[V]={0},RightBorder[V]={0}, CenterLine[V]={0};//记录左右边界,和中间线
- unsigned char CCD_V,CCD_H;//
- unsigned char top_line=40,top_line1=50,top_line2=48;//为什么用char型
- long count,WhiteNum;
- unsigned char width_count=50;
- unsigned char width_min=50;
- unsigned char V_count=0; //采集行计数
- unsigned char jump_point;
- unsigned char last_top;//unsigned char到底是数还是字符啊?
- unsigned char top_top_line=49;
- unsigned char THRE[20];
- long thre_sum=0;
- unsigned char thread_count;
- unsigned char center_min=30;
- unsigned char left_line,right_line;
- unsigned int left_count,right_count;
- /* unsigned char left_tiaobian=0;
- unsigned char right_tiaobian=0;
- unsigned char left_guaidian=0;
- unsigned char right_guaidian=0;
- unsigned char left_tiaobian_row=0;
- unsigned char right_tiaobian_row=0;
- unsigned char left_guaidian_row=0;
- unsigned char right_guaidian_row=0;
- */
- //摄像头初始化
- void CameraInit()
- {
- exti_init(PORTC,1,rising_down); //行中断,PORTC1 端口外部中断初始化 ,上升沿触发中断,内部下拉,,,初始化外部中断,内部函数,设定外部中断(IO),
- disable_irq(89); //行中断关闭,,,89表示irq中断向量号
- disable_irq(90); //场中断关闭,,,新的一幅图像,下降沿有效
- exti_init(PORTD,1,falling_down); //场中断,PORTD1 端口外部中断初始化 ,下降沿触发中断,内部下拉
- }
- //二值化函数
- void BinaData()
- {
- int i=0,j=0;
- //count=0;
- unsigned char *p;
- for(i=0;i<V;i++)
- {
- p=Pix_data[i];
- for(j=0;j<H;j++)
- {
- if(*(p+j)>=threshold)
- {
- Bina_data[i][j]=1;
- // count++;
- }
- else Bina_data[i][j]=0;
- }
- }
- }
- //整场去燥
- void AllFilt()
- {
- count=0;
- //unsigned char sum;
- for(CCD_V=1;CCD_V<V-1;CCD_V++)
- {
- for(CCD_H=1;CCD_H<H-1;CCD_H++)
- {
- if(Bina_data[CCD_V][CCD_H]==1)
- { if((Bina_data[CCD_V-1][CCD_H]==1 || Bina_data[CCD_V+1][CCD_H]==1) && (Bina_data[CCD_V][CCD_H-1]==1 || Bina_data[CCD_V][CCD_H+1]==1))
- {
- Bina_data[CCD_V][CCD_H]=1;
- count++;
- }
- else
- Bina_data[CCD_V][CCD_H]=0;
- /* sum=0;
- sum=sum + Bina_data[CCD_V-1][CCD_H] + Bina_data[CCD_V-1][CCD_H-1] + Bina_data[CCD_V-1][CCD_H+1]
- + Bina_data[CCD_V][CCD_H-1] + Bina_data[CCD_V][CCD_H+1] + Bina_data[CCD_V+1][CCD_H+1]
- + Bina_data[CCD_V+1][CCD_H-1] + Bina_data[CCD_V+1][CCD_H];
- if(sum>=4) Bina_data[CCD_V][CCD_H]=1;
- else Bina_data[CCD_V][CCD_H]=0;
- */
- }
- else if(Bina_data[CCD_V][CCD_H]==0)
- {
- if((Bina_data[CCD_V-1][CCD_H]==0 || Bina_data[CCD_V+1][CCD_H]==0) && (Bina_data[CCD_V][CCD_H-1]==0 || Bina_data[CCD_V][CCD_H+1]==0))
- {
- Bina_data[CCD_V][CCD_H]=0;
- }
- else
- {
- Bina_data[CCD_V][CCD_H]=1;
- count++;
- }
- /*sum=0;
- sum=sum + Bina_data[CCD_V-1][CCD_H] + Bina_data[CCD_V-1][CCD_H-1] + Bina_data[CCD_V-1][CCD_H+1]
- + Bina_data[CCD_V][CCD_H-1] + Bina_data[CCD_V][CCD_H+1] + Bina_data[CCD_V+1][CCD_H+1]
- + Bina_data[CCD_V+1][CCD_H-1] + Bina_data[CCD_V+1][CCD_H];
- if(sum<=6) Bina_data[CCD_V][CCD_H]=0;
- else Bina_data[CCD_V][CCD_H]=1;*/
- }
- }
- }
- }
- //统计图像下半部分白点数
- void WhiteCount()
- {
- WhiteNum=0;
- for(CCD_V=0;CCD_V<25;CCD_V++)
- for(CCD_H=0;CCD_H<H;CCD_H++)
- if(Bina_data[CCD_V][CCD_H]==1)
- WhiteNum++;
- }
- //中心线提取,,,480*640,LINE去除掉起始行
- void get_center()
- {
-
- unsigned char *p;
- static unsigned char last_center=75;
- for(CCD_V=0;CCD_V<LINE;CCD_V++)//,,,为什么是前五行,视野最前方提取有何意义
- {
- p=Bina_data[CCD_V];
- for(CCD_H=75;CCD_H>1;CCD_H--)//中间往右
- {
- if((*(p+CCD_H)==0) && (*(p+CCD_H-1)==0) && (*(p+CCD_H-2)==0)) //右边黑线检测,,,连续三列为黑
- {
- RightBorder[CCD_V]=CCD_H;//记录列数
- break;//找到该行的左边界
- }
- else RightBorder[CCD_V]=0; //如果右边没有检测到有黑线
-
- }
-
- for(CCD_H=75;CCD_H<H-2;CCD_H++) //中间往左
- {
- if((*(p+CCD_H)==0) && (*(p+CCD_H+1)==0) && (*(p+CCD_H+2)==0)) //左边黑线检测
- {
- LeftBorder[CCD_V]=CCD_H;
- break;
- }
- else LeftBorder[CCD_V]=149; //如果左边没有检测到有黑线
-
- }
- CenterLine[CCD_V]=(LeftBorder[CCD_V]+RightBorder[CCD_V])/2; //计算中心线
-
- if(fabsf(CenterLine[4]-last_center)>=8) //基准,,,第五行有什么用?
- CenterLine[4]=last_center;
- last_center=CenterLine[4];
-
- if((LeftBorder[CCD_V]-RightBorder[CCD_V])>width_count) //判断赛道宽度,CCD_V=4
- width_count=LeftBorder[CCD_V]-RightBorder[CCD_V];//width_count最大值, CenterLine记录中间线, CenterLine[4]有什么特殊的?
-
- }
-
- for(CCD_V=LINE;CCD_V<V;CCD_V++)
- {
- p=Bina_data[CCD_V];
- for(CCD_H=(unsigned char )CenterLine[CCD_V-1];CCD_H>1;CCD_H--)//中间往右,,,为什么是四行的中间点,而不是75?
- {
- if((*(p+CCD_H)==0) && (*(p+CCD_H-1)==0) && (*(p+CCD_H-2)==0)) //右边黑线检测
- {
- RightBorder[CCD_V]=CCD_H;
- break;
- }
- else RightBorder[CCD_V]=0;
-
- }
-
- for(CCD_H=(unsigned char )CenterLine[CCD_V-1];CCD_H<H-2;CCD_H++) //中间往左,,,,能增加运算速度
- {
- if((*(p+CCD_H)==0) && (*(p+CCD_H+1)==0) && (*(p+CCD_H+2)==0)) //左边黑线检测
- {
- LeftBorder[CCD_V]=CCD_H;
- break;
- }
- else LeftBorder[CCD_V]=149;
-
- }
- CenterLine[CCD_V]=(LeftBorder[CCD_V]+RightBorder[CCD_V])/2;
-
-
- if((LeftBorder[CCD_V]-RightBorder[CCD_V])>width_count) ////判断赛道宽度
- width_count=LeftBorder[CCD_V]-RightBorder[CCD_V];//这真的是判断赛道宽度嘛?这简直在找最宽的赛道嘛?
-
- }
- }
- //
- void centeradjust()
- {
- for(CCD_V=top_line-1;CCD_V<V;CCD_V++)//四十行开始往上
- {
- if(LeftBorder[top_line-2]>=145 || LeftBorder[top_line-3]>=145)//如果上两行的左边界有一个大于145,(其实右边界),调整思路是什么?
- {
- CenterLine[CCD_V]= (int)((147-left_offset_row)*1.0/(V-1-top_line)*(CCD_V+2-top_line)+0.5)+
- left_offset_row; //这一堆可能在矫正些什么
- if(CenterLine[CCD_V]>=147) CenterLine[CCD_V]=147;//左边界最大到147,
- }
-
- if(RightBorder[top_line-2]<=5 || RightBorder[top_line-3]<=5)
- {
- CenterLine[CCD_V]=(int)((2-right_offset_row)*1.0/(V-1-top_line)*(CCD_V+2-top_line)+0.5)+right_offset_row;//右边界的矫正
- if(CenterLine[CCD_V]<=3) CenterLine[CCD_V]=2;
- }
- }
-
-
- }
- //起跑线,有点迷?
- void stop_line()
- {
- Right_dot=0;
- left_dot=0;
-
- if(stop_flag==1)
- {
- for(CCD_V=10;CCD_V<15;CCD_V++)
- {
- for(CCD_H=RightBorder[20];CCD_H<=CenterLine[20];CCD_H++)
- {
- if(Bina_data[CCD_V][CCD_H]==0)//为何不统计宽度?统计劳什子的黑点数
- Right_dot++;
- }
- for(CCD_H=CenterLine[20];CCD_H<=LeftBorder[20];CCD_H++)
- {
- if(Bina_data[CCD_V][CCD_H]==0)
- left_dot++;
- }
- if((LeftBorder[CCD_V]-RightBorder[CCD_V])<width_min)
- width_min=LeftBorder[CCD_V]-RightBorder[CCD_V]; //有点蒙了
- }
- if(Right_dot>=30 && Right_dot<=90 && left_dot<=90 && left_dot>=30 && top_line1>=45)
- {
- FTM_PWM_Duty(FTM0,CH4,1000);//要减速嘛?4,5通道是干嘛的?
- FTM_PWM_Duty(FTM0,CH5,0);
- if(gpio_get(PORTA,13)==0) delayms(50);//PORTA是干啥的?
- if(gpio_get(PORTA,14)==0) delayms(50);
- if(gpio_get(PORTA,15)==0) delayms(50);
- if(gpio_get(PORTA,16)==0) delayms(50);
- if(gpio_get(PORTA,12)==0) delayms(50);
- gpio_set(PORTC,19,0);
- }
- }
- }
- //中心线判断与矫正 顶端行求取,,,图像的模糊
- void TopGet()
- {
-
- for(CCD_V=8;CCD_V<V-2;CCD_V++)//又从第八行开始干啥?
- {
- if((CenterLine[CCD_V]-CenterLine[CCD_V+1])>center_error || (CenterLine[CCD_V+1]-CenterLine[CCD_V])>center_error) //中线误差三?突变嘛?
- {
- if((CenterLine[CCD_V+1]-CenterLine[CCD_V+2])>center_error || (CenterLine[CCD_V+2]-CenterLine[CCD_V+1])>center_error)//连续两行突变?
- {
- top_line1=CCD_V;//又干啥呀?
- break;
- }
- else ;
- }
- else
- top_line1=48;//这样啊
- if(LeftBorder[CCD_V]-RightBorder[CCD_V]<=30)
- {
- if(LeftBorder[CCD_V+1]-RightBorder[CCD_V+1]<=30)
- {
- top_line2=CCD_V;//30是允许通过行驶的宽度嘛?
- break;
- }
- else ;
- }
- }
- if(top_line1>=30 && top_line2>=30)
- top_line=(top_line2 < top_line1) ? top_line2 : top_line1;//找个最小的
-
- /*
- if(count>=5100)
- last_top=top_line;*/
- }
- void line_count()
- {
- left_line=0;
- right_line=0;
- for(CCD_V=0;CCD_V<49;CCD_V++)
- {
- if(LeftBorder[CCD_V]==149)
- left_line++;
- if(RightBorder[CCD_V]==0)
- right_line++;
- }
- }
- //十字交叉,,,没看太明白
- void CrossJudge()
- {
- if(count>=5000 && count<=5800 && right_line>=10 && left_line>=10)// && right_line<=18 && left_line<=18),,,count什么呀?
- {
- for(CCD_V=8;CCD_V<49;CCD_V++)
- {
- if(CenterLine[8]+CenterLine[7]-CenterLine[1]-CenterLine[0]<0)
- {
- if(LeftBorder[CCD_V] - LeftBorder[CCD_V-1]>= 3)
- {
- LeftBorder[CCD_V]=LeftBorder[CCD_V-1]-1;
- RightBorder[CCD_V]=RightBorder[5];
- }
- else if(LeftBorder[CCD_V]>=145)
- LeftBorder[CCD_V]=LeftBorder[CCD_V-1];
- else;
- }
-
- else if(CenterLine[8]+CenterLine[7]-CenterLine[1]-CenterLine[0]>0)
- {
- if(RightBorder[CCD_V] - RightBorder[CCD_V-1]<= -3)
- {
- RightBorder[CCD_V]=RightBorder[CCD_V-1]+1;
- LeftBorder[CCD_V]=LeftBorder[5];
- }
- else if(RightBorder[CCD_V]<= 5)
- RightBorder[CCD_V]=RightBorder[CCD_V-1];
- else;
- }
- CenterLine[CCD_V]=(LeftBorder[CCD_V]+RightBorder[CCD_V])/2;
- }
-
- for(CCD_V=49;CCD_V>top_line;CCD_V--)
- {
- for(CCD_H=CenterLine[top_line];CCD_H>RightBorder[top_line];CCD_H--)
- {
- if(Bina_data[CCD_V][CCD_H+1]==1 && Bina_data[CCD_V][CCD_H]==1)
- {
- if(Bina_data[CCD_V][CCD_H-1]==0 && Bina_data[CCD_V][CCD_H-2]==0)
- {
- RightBorder[CCD_V]=CCD_H;
- break;
- }
- }
- else RightBorder[CCD_V]=RightBorder[top_line];
- }
- for(CCD_H=CenterLine[top_line];CCD_H<LeftBorder[top_line];CCD_H++)
- {
- if(Bina_data[CCD_V][CCD_H+1]==1 && Bina_data[CCD_V][CCD_H]==1)
- {
- if(Bina_data[CCD_V][CCD_H+3]==0 && Bina_data[CCD_V][CCD_H+2]==0)
- {
- LeftBorder[CCD_V]=CCD_H;
- break;
- }
- }
- else LeftBorder[CCD_V]=LeftBorder[top_line];
- }
- CenterLine[CCD_V]=(LeftBorder[CCD_V]+RightBorder[CCD_V])/2;
- }
-
- for(CCD_V=48;CCD_V>=top_line;CCD_V--)
- {
- if((CenterLine[CCD_V]-CenterLine[CCD_V-1])>center_error || (CenterLine[CCD_V-1]-CenterLine[CCD_V])>center_error)
- {
- if((CenterLine[CCD_V]-CenterLine[CCD_V-2])>center_error || (CenterLine[CCD_V-2]-CenterLine[CCD_V])>center_error)
- {
- top_top_line=CCD_V;
- break;
- }
- else ;
- }
- }
-
- //中心线修正
-
- }
- }
-
- //=====================================
- //|| ||
- //|| 十字道处理 ||
- //|| ||
- //=====================================
- /* crossJudge()
- {
- char i,j;
- char left_tiaobian=0;
- char right_tiaobian=0;
- char left_guaidian=0;
- char right_guaidian=0;
- char left_tiaobian_row=0;
- char right_tiaobian_row=0;
- char left_guaidian_row=0;
- char right_guaidian_row=0;
-
-
- if(count>=5000 && count<=5800 && right_line>=10 && left_line>=10) //十字道判断条件1,整场黑点数2,白条宽度 3,斜十字能否准确判断!
- {
-
- //==========十字道处理========== //搜索左下边沿
- for(i=1;i<V;i++) //注意不要让数组溢出
- {
- //====左边线处理==
- //搜索拐点 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7?
- //左右要写的一样
- if(LeftBorder[i]>LeftBorder[i-1] || LeftBorder[i]>140) //抓住十字边界的延生特点左突变
- {
- left_guaidian= LeftBorder[i-3];
- left_guaidian_row=i-3;
- break;
- }
-
- }
- //搜索跳变点 //搜索左上边沿
- for(i=1;i<V;i++)
- {
- if(LeftBorder[i]-LeftBorder[i-1]<-10)
- {
-
- left_tiaobian= LeftBorder[i+2];
- left_tiaobian_row=i+2;
- break;
- }
- }
- //搜索完后再补线。
- //边线补线
- if((left_guaidian!=0)&&(left_tiaobian!=0)) //通过直线去补线效果更好
- {
- for(i=left_guaidian_row;i<=left_tiaobian_row;i++)
- LeftBorder[i]=(char)((left_tiaobian- left_guaidian)*1.0/( left_tiaobian_row-left_guaidian_row)*(i-left_guaidian_row)+0.5)+ left_guaidian;
-
-
- }
-
- //====右边线处理==
- //搜索拐点
- for(i=1;i<V;i++) //注意不要让数组溢出
- {
- //====右边线处理==
- //搜索拐点 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7?
- //左右要写的一样
- if(RighttBorder[i]<RightBorder[i-1] || RightBorder[i]<10) //抓住十字边界的延生特点左突变
- {
- right_guaidian= RightBorder[i-3];
- right_guaidian_row=i-3;
- break;
- }
-
- }
- //搜索跳变点 //搜索右上边沿
- for(i=1;i<V;i++)
- {
- if( RightBorder[i]- RightBorderr[i-1]>10)
- {
-
- right_tiaobian= RightBorder[i+2];
- right_tiaobian_row=i+2;
- break;
- }
- }
- //边线补线
- if((right_guaidian!=0)&&(right_tiaobian!=0))
- {
- for(i=right_guaidian_row;i<right_tiaobian_row-1;i++)
- RightBorder[i]=(char)(( right_tiaobian-right_guaidian)*1.0/( right_tiaobian_row- right_guaidian_row)*(i-right_guaidian_row)+0.5)+right_guaidian;
- }
-
-
-
- }
- //=================中心线重提取============
-
-
- for(i=0;i<V;i++)
-
- CenterLine[i]=(LeftBorder[i]+RightBorder[i])/2;
-
- }*/
- //小S
- void S_road()
- {
- long center_sum=0;
- //long left_sum=0,right_sum=0;
- // unsigned char left_ave=0,right_ave=0;
- if(count>5800)
- {
- for(CCD_V=5;CCD_V<=40;CCD_V++)
- {
- if(fabsf((LeftBorder[CCD_V]-LeftBorder[CCD_V+1])>=3)) LeftBorder[CCD_V]=LeftBorder[CCD_V-1];
- if(fabsf(RightBorder[CCD_V]-RightBorder[CCD_V+1])>=3) RightBorder[CCD_V]=RightBorder[CCD_V-1];
- CenterLine[CCD_V]=(LeftBorder[CCD_V]+RightBorder[CCD_V])/2;
- center_sum+=CenterLine[CCD_V];
- //right_sum+=RightBorder[CCD_V];
- //left_sum+=LeftBorder[CCD_V];
- }
- //left_ave=left_sum/19;
- //right_ave=right_sum/19;
-
-
- for(CCD_V=5;CCD_V<=44;CCD_V++)
- {
- CenterLine[CCD_V]=center_sum/35;//好吧,中线变直线了,完美
- /* if((right_line-left_line)>5)
- CenterLine[CCD_V]=CenterLine[CCD_V]-10;
- if((left_line-right_line)>5)
- CenterLine[CCD_V]=CenterLine[CCD_V]+10;*/
- }
-
- }
-
- }
- //发送图像到上位机
- void send_photo()
- {
- int i=0,j=0;
- //以下四句话是固定格式,是串口和上位机软件之间的协议
- uart_putchar(UART2,0);
- uart_putchar(UART2,255);
- uart_putchar(UART2,1);
- uart_putchar(UART2,0);
- for(i=V-1;i>=0;i--)
- for(j=H-1;j>=0;j--)
- {
- if(j==CenterLine[i]) uart_putchar(UART2,0); //中心线
- else if(j==RightBorder[i]) uart_putchar(UART2,0);
- else if(j==LeftBorder[i]) uart_putchar(UART2,0);
- else uart_putchar(UART2,Bina_data[i][j]);
- }
- }
- void SendImg()
- {
- disable_irq(89);
- disable_irq(90); //关闭场中断,防止串口发送图像数据进程被打乱
- if(gpio_get(PORTA,11)==0) thread();
- else threshold=135;
- BinaData();
-
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
K60 smartcar最终代码.rar
(1.83 MB, 下载次数: 33)
|