起因
先说一下为什么会想到做这个。
在大二的时候,为了赶当时风靡一时的大学生创新创业项目,跟两个同学一起找指导老师设想了一个红绿灯辨识系统。解决的实际问题是车辆在等红绿灯的时候容易被前面的大货车挡住视线,特别容易在不知道的情况下闯了红灯。就像下面这张图一样,过四岔路口的时候前面四辆车是商量好的嘛。。。
图片来源于网络,出处不明,有版权联系我删除。
当时视觉辨识特别流行,导致后来应聘的时候很多HR看到我简历以后都以为是用摄像头识别的。在这里也纠正一下,就像文章题目所述,是用无线信号的,红绿灯发送信号、车辆接收信号。
系统功能
随着道路车辆日益增多,传统交通信号灯的辨识可靠性下降。本系统基于此背景,为了使驾驶人员能够准确识别交通信号,提出并设计了一种基于双向方向角对比技术的交通信号灯辨识系统。系统主要由中央控制器,无线发射模块,无线接收模块,TFT液晶显示器等组成。车内外部分共同作用,以电磁波为信号传输的介质,通过对接收端和发射端两者检测出的方向角进行对比,提取出有效信息,通过显示器和语音系统展现给驾驶员。
总体设计
流程图如图
该辨识系统使用stm32作为车载端无线收发模块的主控芯片,用TFT液晶显示器、语音输出(当时做到了,这篇文章没写,如果以后整理好程序发上来的话应该会添上去,语音用的是BY8301-16P)作输入输出设备,本系统的具体处理过程有以下几点说明:
- 用单片机搭建一个交通信号灯模型,用于前期模拟一般情况的真实路口情况,由stm32主控芯片对信号灯模型的数据信号进行分析处理,并转化成无线信号由无线发射模块发出。
- 信号接收端依旧以stm32单片机作为主控芯片,对接收到的电磁信号进行加工处理,通过输出设备TFT触摸显示屏以及语音模块让司机可以得到所需求的数百米外的(或是不清晰的)交通信号灯的信息,从而实现整个系统的基本预期目标。
路口信号灯的模拟与信号发送
模拟
要想提高交通信号灯的辨识度,第一步便是需要一个正常状态的红绿灯路口。为了安全起见,我们在确认技术成熟之前不会在真实道路上进行实验,而是用单片机搭建一个与国内路口相似的信号灯模型,以便于调试。
此模型包含电源、单片机、LED节能灯、数码管等,与目前主流信号灯的电子控制、显示部分相同。电源用于供电,单片机用于主控和计时,LED节能灯用于显示信号灯的颜色,数码管用于显示倒计时。程序代码部分详见软件部分。
下图为在单片机开发板上测试时的实拍图:
这个模拟很简单,只要会流水灯和数码管的话基本上都能把程序写出来。
信号发送
在信号灯内安装控制芯片(51单片机)、倒计时用的数码管、红绿黄三种颜色的灯和一个GY-26型电子指南针模块(一个常用的指南针模块,接收串行数据0x31,也就是ASCII下的1,即可发送当前模块指定位置朝向的方向角,精确度高,能达到0.1度),指南针模块水平安装,规定其正方向所指的为虚拟北,其串口发出的数据即为实际北与虚拟北的夹角(记为θ),在车载接收端的电子指南针正方向安装时与车头方向保持一致,在循环获取方向角数据(记为α)后,与发送而来的θ角进行相减,令x=α-θ,x∈[0°,360°),x即为方向角的真值(差值)。
发射端将虚拟北视为正北,将360°方向角均分为8个相等的区间,每个区间的范围设置为45°,将区间北偏西22.5°-北偏东22.5°方向的信号灯状态与接收地址1关联;将区间北偏东22.5°-北偏东67.5°方向的信号灯状态与接收地址2关联;依次类推,直到八个方向的地址全部关联完毕,将各种状态与相应的地址以50ms为间隔分时发送。
车辆端也将方向角的真值(差值)x分成八段,按照与固定式信号灯相同的方法将第N个发射地址与第N个接收地址一一对应(N=1,2,3,4,5,6,7,8),实现无线接收模块准确接收所需要的信息,过滤其余7个干扰无线数据。
因为GY-26在接收到0x31后才会进行检测和发送数据,所以我先是写了一个发送0x31的程序,用一个51专门给它触发信号,其实确实不需要这么麻烦的,但当时为了省时间就这么简单粗暴:-)
程序很简单,也很短,直接复制上来。
#include <reg52.h>
#define jingzhen 11059200UL /*使用11.0592M晶体*/
#define botelv 9600UL /*波特率定义为9600*/
unsigned char txd[1]="1"; //待显示字符。
unsigned char rxd[]="000";
volatile unsigned char sending;
sbit beep=P2^3;
sbit dula=P2^6;
sbit wela=P2^7;
sbit led=P1^0;
sbit led1=P1^1;
sbit led2=P1^2;
sbit sr=P0^0;
sbit sy=P0^1;
sbit sg=P0^2;
void delay(float i)
{
float j,k;
for(j=i;j>0;j--)
for(k=90;k>0;k--);
}
void init(void) //串口初始化
{
EA=0; //暂时关闭中断
TMOD&=0x0F; //定时器1模式控制在高4位
TMOD|=0x20; //定时器1工作在模式2,自动重装模式
SCON=0x50; //串口工作在模式1
TH1=256-jingzhen/(botelv*12*16); //计算定时器重装值
TL1=256-jingzhen/(botelv*12*16);
PCON|=0x80; //串口波特率加倍
ES=1; //串行中断允许
TR1=1; //启动定时器1
REN=1; //允许接收
EA=1; //允许中断
}
void send(unsigned char d) //发送一个字节的数据,形参d即为待发送数据。
{
SBUF=d; //将数据写入到串口缓冲
sending=1; //设置发送标志
while(sending); //等待发送完毕
}
void sendc(unsigned char * pd)
{
while((*pd)!='\0') //发送字符串,直到遇到0才结束
{
send(*pd); //发送一个字符
pd++; //移动到下一个字符
}
}
unsigned int pp;
//unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
// 0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
int j,k,l=255;
int a1,a0;
int shijian,deng=2;
// void display(unsigned char sh_c,unsigned char g_c)
// {
// dula=0;
// P0=table[sh_c];
// dula=1;
// dula=0;
// wela=0;
// P0=0xfe;
// wela=1;
// wela=0;
// delay(5);
// P0=table[g_c];
// dula=1;
// dula=0;
// P0=0xfd;
// wela=1;
// wela=0;
// delay(5);
// }
//unsigned char UartGetChar(void)
//{
// unsigned char Result;
// if(RI==1) // 是否有数据到来
// { RI = 0;
// Result = SBUF; // 暂存接收到的数据
// }
// return Result;
//}
void main()
{
TMOD=0x01;
TR0=1;
TH0=(65536-46080)/256;// ?????11.0592,???????46080,?????50000?????????
TL0=(65536-46080)%256;//46080???,?50000*11.0592/12
ET0=1;
EA=1;
init();
led=0;
while(1)
{
delay(15);
sendc(txd);
}
}
void uart(void) interrupt 4 //串口发送中断
{
int m,i;
if(RI) //收到数据
{
rxd[i] = SBUF; //????48???????????????ASCII??
RI = 0;
m++;
if(m>7)
m =0 ;
// ES=0; //关串口中断
// rxd[i++]=SBUF;//????????
// RI=0; //????????
// ES=1;//?????
}
else
TI = 0;
sending=0;
}
void time0() interrupt 1
{ TH0=(65536-46080)/256;
TL0=(65536-46080)%256;
pp++;
}
注释写的很清楚,因为是用以前其他程序改的,有一些多余的地方懒得删了,就凑合着看吧。。。
GY-26发送出来的方向角数据也是串行的,而且有它的一整套编码方式,所以我又用了一个51将其解码,顺便用八根线转成串行数据(实际上我只传输方向角的十位,也就是0~35,所以只需要6根,2 的六次幂已经64了)给控制红绿灯的单片机来整合,整合完了以后接到zigbee上面,无线发送。
串行转并行的程序我上传过,点击下载,在这里下载应该是需要积分的,原来分数很高的,已经被我改低了,现在应该是四分,不想用积分或者对程序有疑惑的私信我,文章末尾也有我的其他联系方式,找我要我直接给你,就是有可能回复不及时,实在等不及就去链接下吧hhh说不定你是会员呢,不在乎这么点积分。
最后整合发送的程序我还没全部改好,因为很多注释要删,这里先放一些片段,等改好了会上传的。
并行口获取方向角数据:
sbit r0=P2^0;
sbit r1=P2^1;
sbit r2=P2^2;
sbit r3=P2^3;
sbit r4=P2^4;
sbit r5=P2^5;
sbit r7=P1^7;
angle=P2;
angle1=angle/10+0x30;
angle2=angle%10+0x30;
这样就把方向角的百位和十位提取出来了。
最后发送的格式是一个六位的串行数据,分别是:颜色+秒数+“0”+方向角(三位)。例如发送Rb180,就代表正南方向(180方向角即为南方)、红色(red)、剩余两秒(b是第二个字母)。同理,如果需要表达的是正北方黄灯还剩三秒,即为“Yc0000”,方向角由GY-26的数据产生,颜色和剩余时间由单片机内部生成,有可能会有疑惑:单片机怎么生成?信号灯就是由这个单片机控制的,单片机当然可以生成了。
下面是main函数部分,供参考。
void main()
{
init();
while(1)
{
txd[0]=0x52; //红灯
ledr=0;ledg=1;ledy=1;
ledr2=1;ledg2=0;ledy2=1;
led0r=0;led0g=1;led0y=1;
led0r2=1;led0g2=0;led0y2=1;
for(rr=14;rr>=4;rr--)
{
txd[1]=0x61+rr;
sendc(txd);
delay(100);
}
ledy2=0;ledr2=1;ledg2=1;
led0y2=0;led0r2=1;led0g2=1;
for(rr=3;rr>=0;rr--)
{
txd[1]=0x61+rr;
sendc(txd);
delay(100);
}
txd[0]=0x47; //绿灯
ledg=0;ledr=1;ledy=1;
ledg2=1;ledr2=0;ledy2=1;
led0g=0;led0r=1;led0y=1;
led0g2=1;led0r2=0;led0y2=1;
for(gg=11;gg>=0;gg--)
{
txd[1]=0x61+gg;
sendc(txd);
delay(100);
}
txd[0]=0x59; //黄灯
ledy=0;ledr=1;ledg=1;
ledg2=1;ledr2=0;ledy2=1;
led0y=0;led0r=1;led0g=1;
led0g2=1;led0r2=0;led0y2=1;
for(yy=4;yy>=0;yy--)
{
txd[1]=0x61+yy;
sendc(txd);
delay(100);
}
}
}
信号传输
收发器通过2.4GHz电磁波传输无线信号,发送端和接收端均采用ZigBee技术,因为我特别喜欢这个东西。正好这里需要的传输距离也适合使用zigbee,加上功耗什么的都满足要求。传输仍然使用UART串口异步通信协议和IEEE802.15.4标准的低功耗局域网协议。固定端(即信号灯端)采用高功率、强增益的天线,确保可以达到预期的信号强度;移动端(即车载端)采用低功耗、体积小的天线,便于组装,且符合节电的初衷。
车辆端的信号接收与显示
车辆端用的是stm32来做的,没继续用51的原因,既是项目需要(用上32会显得高端,更容易立项,当然也更难一点),也是因为51的运算能力在此有点不够用了,接收端是要显示的,彩色显示屏比较耗费运算能力,同时指南针模块(也就是GY-26)既要接收也要发送,在发送端用了好几个51来一起实现,接收端不想折腾了,直接上stm32,用的是F103zet6,算是比较低端的型号了。
接收
其实在stm32里面接收一个数据很简单,库很详细,再用上面说的那一套协议把接收到的数据解码就行了。但是有了数据内容,还需要把信号灯端的方向角和车辆自身的来进行比对,根据差值来“算”出来当前车辆行进方向的红绿灯状态。
算一下,此时stm32要有一个串口接收远程发送来的红绿灯信号。还要有另一个口进行车辆端的GY-26通讯(发送0x31、接收实时方向角数据)。两个串口在stm32里面肯定能实现,但是我当时找了很多地方都没有找到好的程序,后来自己改库函数,终于改好了,算是很有成就感。想改的根据买板子时候的说明书改,不想改的用我的程序。
显示
显示用的是开发板上面配套的LCD显示屏,主要显示当前信号灯颜色,在函数库里面有画各种颜色的圆环,用for循环把若干个不同半径的同心圆依次画出来就是实心圆了。再打上剩余时间和辅助的汉字即可。汉字可能有的时候打不上去,打不上去就用英文。
总结
工作时,在无线发射模块中,用单片机实现对交通信号灯的模拟,并对所产生的信号进行处理,使得交通信号灯的信息转化成无线信号发射出去,并尽量保证此信号不失真。在信号发射部分,为保证十字路口不同方向的车辆接收到正确的信号,发射端和接收端双指南针设计,使得系统可以在传输的信号中加上位置信息,比如某一时刻红灯的信号灯朝向为东偏南20度(及:正北反向角 为90+20=110度),那么发送的信号即为:“red_110\n”。在行驶中的车辆即将到达该路口时,信号接收模块以STM32F103ZET6芯片作为主控芯片将接收得到的信号内容与车辆端的指南针读数内容进行对比。若读出自身方向角为120度,相差度数为十度,小于45度,直接使用红灯信号,并进行显示;如车辆中的指南针读出自身方向角为190度,与110度相差80度,大于45度,但与90度相近,自动显示路口顺时针90度方向上的信号,并转化到输出设备TFT液晶显示屏以及语音模块,使得交通信号灯的数字信息转化成彩色电子屏以及音频及时传递给驾驶员,从而最终实现交通信号灯信号灯的远距离传输,达到增强交通信号灯辨识度的效果。TFT液晶显示屏、加装语音模块可显示交通信号灯的实时情况并通过语音播报 。
注
有疑问评论或私信我,看到就会回复,Email:evandjiang@qq.com
文章所述系统已经申请专利,请勿私自商用,专利号CN201821790980.X,欢迎去下载专利申请书看看,那里面有很多东西我这里都是一带而过的。但是大学的课程设计甚至毕业设计还是可以拿来玩玩的。