基于单片机的导盲拐杖设计——包含源码、硬件和论文

文章目录

  • 0 前言
  • 1 主要功能
  • 2 硬件设计(原理图)
  • 3 核心软件设计
  • 4 实现效果
  • 5 最后

  • 0 前言

    🔥
    这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

    为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

    🚩 毕业设计 基于单片机的导盲拐杖设计(源码+硬件+论文)

    🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:3分
  • 创新点:4分
  • 🧿 项目分享:

    https://gitee.com/sinonfin/sharing

    1 主要功能

    本设计模仿蝙蝠的超声应用能力和原理,在研究现有的电子式超声波测距系统的基础上,应用回声定位的原理,通过传感器发送超声波,然后获得并分析障碍物的回波信息,研制的一套超声波导盲系统[11]。系统采用STC89C52RC单片机作为控制器,利用超声测距的原理,设计了一种超声波导盲装置,该装置可以对盲人前方道路上的障碍物进行距离探测并把障碍物距离信息转换成语音提示,盲人可以根据提示音,避让障碍同时达到导盲作用。该系统具有硬件结构简单、工作可靠、测量误差小等特点。
    主要的设计有:

    主机功能

    1. 超声波测距测试距离并且显示;
    2. 可以按键设置报警距离,在阈值内可以发出语音播报和震动提示盲人如何行走;
    3. 按键按下可以播报当前时间,时钟ds1302获取;
    4. 整点报时;
    5. 具有gps定位系统,并可以通过sim800模块发送经纬坐标到家人手机上;
    6. 手机号可以自行设置;
    7. dht11检测湿度,当湿度过高时,发出语音提示;
    8. 角度传感器检测角度,判断是否摔倒,如果摔倒发送短信到预设手机号。

    从机为蓝牙耳机

    1. 接受主机发送的提示信号;
    2. 播放相应状态下的语音。

    2 硬件设计(原理图)

    该系统由单片机、超声波发射接收电路、液晶显示电路、声光报警模块、温湿度采集模块,GPS定位模块、短信SIM800模块、时钟模块、蓝牙模块以及运动轴模块组成,控制核心为单片机。单片机在接收到传感器的信息后,将传感器的信号转换为距离信息,通过语音播报或振动提示。




    3 核心软件设计

    本次设计采用是以单片机为主控核心,C语言为编程语言,所以采用的软件设计平台,我采用了Keil为主要的编译平台。该平台是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。Keil提供了包括C编译器、宏汇编、链接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境将这些部分组合在一起。运行Keil软件需要WIN系列操作系统。

    传感器对盲人拐杖状态的判定以及对周围环境的判定。

    从机部分将通过语音播报模块做出相应的语音播报

    本次按键模块需要软件逻辑设计实现对经纬度的显示、时间正点播报、时间设定以及安全距离设定。

    超声波电机振动警报模块检测到有障碍物在安全距离内时也会发出语音警报,同时主机的声光报警系统也会发出响声警报。

    为了避免盲人摔倒的意外发生,使用了MPU6050角度运动传感器,当盲人出了什么意外的时候,通过SIM800模块向盲人家属传递盲人摔倒的信息。

    关键代码

    #include "main.h"
    #include "uart.h"
    #include"lcd.h"
    #include"ds1302.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <INTRINS.H> 
    
    
    
    sbit     key_1    =  P1 ^ 0;	  //按键
    sbit     key_2    =  P1 ^ 1;	  //按键
    sbit     key_3    =  P1 ^ 2;	  //按键
    sbit     key_4    =  P1 ^ 3;	  //按键
    
    sbit     sw    =  P3 ^ 4;	  //串口切换
    sbit     ele    =  P3 ^ 6;	  //电机
    sbit  DHT11  = P3^7 ;  //dht11引脚定义
    sbit  buz  = P2^0 ;  //声光报警
    sbit     RX_1    =  P1 ^ 6;	   //超声波模块
    sbit     TX_1    =  P1 ^ 7;	  //超声波模块 
    
    
    unsigned int  time_juli=0;
    
    bit  flag =0;
    int juli_a = 0;
    bit chao_flag = 0;	  //超声波标量
    int juli_down = 300; //小于距离
    
    
    
    int X_mpu6050 = 0;
    int Y_mpu6050 = 0;
    
    char zf[3];
    
    
    unsigned char hour=0,min=0;sec=0;   //定义uchar类型变量 时 分 秒
    
    unsigned char warCount=0;//摔倒计数
    
    //unsigned char num=0;  
    
    
    int weidu_A = 0;		 //维度显示A、B、C度分秒
    int weidu_B = 0;
    int weidu_C = 0;
    int jingdu_A = 0;		 //精度显示A、B、C度分秒
    int jingdu_B = 0;
    int jingdu_C = 0;
    
    
    unsigned char user_number[11]= {0x31,0x33,0x31,0x30,0x30,0x32,0x36,0x31,0x30,0x36,0x39};//手机号
    
    unsigned char humiDown=0;//湿度下限
    
    bit showMode=0;//0-正常显示数据 1-显示gps
    
    unsigned char count = 0;
    int i=0; //用于for循环
    
    
    unsigned char   U8FLAG,k;
    unsigned char   U8count,U8temp;
    unsigned char   U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
    unsigned char   U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
    unsigned char   U8comdata;
    unsigned char dht11_temp = 0; //dht11温度 
    unsigned char dht11_humi = 0; //dht11湿度
    
    void Delay10ms(unsigned int c)   //误差 0us
    {
        unsigned char a, b;
    	//--c已经在传递过来的时候已经赋值了,所以在for语句第一句就不用赋值了--//
        for (;c>0;c--)
    	{
    		for (b=38;b>0;b--)
    		{
    			for (a=130;a>0;a--);
    		}          
    	}       
    }
    
    
    void beep()
    {
    	buz=0;
    	Delay10ms(20);
    	buz=1;
    	Delay10ms(20);
    }
    
    //
    
    
    //****************************************
    // 定义51单片机端口
    //****************************************
    sbit    SCL=P3^2;			//IIC时钟引脚定义
    sbit    SDA=P3^3;			//IIC数据引脚定义
    //****************************************
    // 定义MPU6050内部地址
    //****************************************
    #define	SMPLRT_DIV		0x19	//陀螺仪采样率,典型值:0x07(125Hz)
    #define	CONFIG			0x1A	//低通滤波频率,典型值:0x06(5Hz)
    #define	GYRO_CONFIG		0x1B	//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
    #define	ACCEL_CONFIG	0x1C	//加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
    #define	ACCEL_XOUT_H	0x3B
    #define	ACCEL_XOUT_L	0x3C
    #define	ACCEL_YOUT_H	0x3D
    #define	ACCEL_YOUT_L	0x3E
    #define	ACCEL_ZOUT_H	0x3F
    #define	ACCEL_ZOUT_L	0x40
    #define	TEMP_OUT_H		0x41
    #define	TEMP_OUT_L		0x42
    #define	GYRO_XOUT_H		0x43
    #define	GYRO_XOUT_L		0x44	
    #define	GYRO_YOUT_H		0x45
    #define	GYRO_YOUT_L		0x46
    #define	GYRO_ZOUT_H		0x47
    #define	GYRO_ZOUT_L		0x48
    #define	PWR_MGMT_1		0x6B	//电源管理,典型值:0x00(正常启用)
    #define	WHO_AM_I			0x75	//IIC地址寄存器(默认数值0x68,只读)
    #define	SlaveAddress	0xD0	//IIC写入时的地址字节数据,+1为读取
    //****************************************
    //延时
    //****************************************
    //void delay(unsigned int k)	
    //{						
    //	unsigned int i,j;				
    //	for(i=0;i<k;i++)
    //	{			
    //		for(j=0;j<121;j++);
    //	}						
    //}
    
    //**************************************
    //延时5微秒(STC90C52RC@12M)
    //不同的工作环境,需要调整此函数
    //当改用1T的MCU时,请调整此延时函数
    //**************************************
    void Delay5us()
    {
    	_nop_();_nop_();_nop_();_nop_();
    	_nop_();_nop_();_nop_();_nop_();
    	_nop_();_nop_();_nop_();_nop_();
    	_nop_();_nop_();_nop_();_nop_();
    	_nop_();_nop_();_nop_();_nop_();
    	_nop_();_nop_();_nop_();_nop_();
    }
    //**************************************
    //I2C起始信号
    //**************************************
    void I2C_Start()
    {
        SDA = 1;                    //拉高数据线
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        SDA = 0;                    //产生下降沿
        Delay5us();                 //延时
        SCL = 0;                    //拉低时钟线
    }
    //**************************************
    //I2C停止信号
    //**************************************
    void I2C_Stop()
    {
        SDA = 0;                    //拉低数据线
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        SDA = 1;                    //产生上升沿
        Delay5us();                 //延时
    }
    //**************************************
    //I2C发送应答信号
    //入口参数:ack (0:ACK 1:NAK)
    //**************************************
    void I2C_SendACK(bit ack)
    {
        SDA = ack;                  //写应答信号
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        SCL = 0;                    //拉低时钟线
        Delay5us();                 //延时
    }
    //**************************************
    //I2C接收应答信号
    //**************************************
    bit I2C_RecvACK()
    {
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        CY = SDA;                   //读应答信号
        SCL = 0;                    //拉低时钟线
        Delay5us();                 //延时
        return CY;
    }
    //**************************************
    //向I2C总线发送一个字节数据
    //**************************************
    void I2C_SendByte(uchar dat)
    {
        uchar i;
        for (i=0; i<8; i++)         //8位计数器
        {
            dat <<= 1;              //移出数据的最高位
            SDA = CY;               //送数据口
            SCL = 1;                //拉高时钟线
            Delay5us();             //延时
            SCL = 0;                //拉低时钟线
            Delay5us();             //延时
        }
        I2C_RecvACK();
    }
    //**************************************
    //从I2C总线接收一个字节数据
    //**************************************
    uchar I2C_RecvByte()
    {
        uchar i;
        uchar dat = 0;
        SDA = 1;                    //使能内部上拉,准备读取数据,
        for (i=0; i<8; i++)         //8位计数器
        {
            dat <<= 1;
            SCL = 1;                //拉高时钟线
            Delay5us();             //延时
            dat |= SDA;             //读数据               
            SCL = 0;                //拉低时钟线
            Delay5us();             //延时
        }
        return dat;
    }
    //**************************************
    //向I2C设备写入一个字节数据
    //**************************************
    void Single_WriteI2C(uchar REG_Address,uchar REG_data)
    {
        I2C_Start();                  //起始信号
        I2C_SendByte(SlaveAddress);   //发送设备地址+写信号
        I2C_SendByte(REG_Address);    //内部寄存器地址,
        I2C_SendByte(REG_data);       //内部寄存器数据,
        I2C_Stop();                   //发送停止信号
    }
    //**************************************
    //从I2C设备读取一个字节数据
    //**************************************
    uchar Single_ReadI2C(uchar REG_Address)
    {
    	uchar REG_data;
    	I2C_Start();                   //起始信号
    	I2C_SendByte(SlaveAddress);    //发送设备地址+写信号
    	I2C_SendByte(REG_Address);     //发送存储单元地址,从0开始	
    	I2C_Start();                   //起始信号
    	I2C_SendByte(SlaveAddress+1);  //发送设备地址+读信号
    	REG_data=I2C_RecvByte();       //读出寄存器数据
    	I2C_SendACK(1);                //接收应答信号
    	I2C_Stop();                    //停止信号
    	return REG_data;
    }
    //**************************************
    //初始化MPU6050
    //**************************************
    void InitMPU6050()
    {
    	Single_WriteI2C(PWR_MGMT_1, 0x00);	//解除休眠状态
    	Single_WriteI2C(SMPLRT_DIV, 0x07);
    	Single_WriteI2C(CONFIG, 0x06);
    	Single_WriteI2C(GYRO_CONFIG, 0x18);
    	Single_WriteI2C(ACCEL_CONFIG, 0x01);
    }
    //**************************************
    //合成数据
    //**************************************
    int GetData(uchar REG_Address)
    {
    	uchar H,L;
    	H=Single_ReadI2C(REG_Address);
    	L=Single_ReadI2C(REG_Address+1);
    	return (H<<8)+L;   //合成数据
    }
    
    
    
    
    void Delay(unsigned int j)
    {
    	unsigned char i;
    	for(;j>0;j--)
    	{
    		for(i=0;i<27;i++);
    	}
    }
    void Delay_10us(void)
    {
    	unsigned char i;
    	i--;
    	i--;
    	i--;
    	i--;
    	i--;
    	i--;
    }
    
    void  COM(void)
    {    
    	unsigned char i;
              
        for(i=0;i<8;i++)	   
    	{
    		
    	   	U8FLAG=2;	
    	while((!DHT11)&&U8FLAG++);
    		Delay_10us();
    		Delay_10us();
    		Delay_10us();
    	  	U8temp=0;
    	if(DHT11)U8temp=1;
    		U8FLAG=2;
    	while((DHT11)&&U8FLAG++);
    	   	//超时则跳出for循环		  
    	if(U8FLAG==1)break;
    	   	//判断数据位是0还是1	 	   	   
    		// 如果高电平高过预定0高电平值则数据位为 1 	   	 
    		U8comdata<<=1;
    	   	U8comdata|=U8temp;        //0
    	}//rof	   
    }
    
    void get_dht11(void)
    {
      //主机拉低18ms 
       DHT11=0;
       Delay(180);
       DHT11=1;
     //总线由上拉电阻拉高 主机延时20us
       Delay_10us();
       Delay_10us();
       Delay_10us();
       Delay_10us();
     //主机设为输入 判断从机响应信号 
       DHT11=1;
     //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行	  
       if(!DHT11)		 //T !	  
       {
       U8FLAG=2;
     //判断从机是否发出 80us 的低电平响应信号是否结束	 
       while((!DHT11)&&U8FLAG++);
       U8FLAG=2;
     //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
       while((DHT11)&&U8FLAG++);
     //数据接收状态		 
       COM();
       U8RH_data_H_temp=U8comdata;
       COM();
       U8RH_data_L_temp=U8comdata;
       COM();
       U8T_data_H_temp=U8comdata;
       COM();
       U8T_data_L_temp=U8comdata;
       COM();
       U8checkdata_temp=U8comdata;
       DHT11=1;
     //数据校验 
     
       U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
       if(U8temp==U8checkdata_temp)
       {
       	  U8RH_data_H=U8RH_data_H_temp;
       	  U8RH_data_L=U8RH_data_L_temp;
    	  U8T_data_H=U8T_data_H_temp;
       	  U8T_data_L=U8T_data_L_temp;
    	  dht11_temp = U8T_data_H;
    	  dht11_humi = U8RH_data_H;
    
       	  U8checkdata=U8checkdata_temp;
       }
    	 
    
    	 
    	 //fi
       }//fi
    
    }
    ///
    
    
    
    
    
    
    
    
    
    
    
    /********************************************************/
    void  StartModule_1() 		         //T1中断用来扫描数码管和计800MS启动模块
    {
    	  TX_1=1;			                 //800MS  启动一次模块
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_();
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_(); 
    	  _nop_();
    	  TX_1=0;
    }
    
    /*****************测距函数*******************/
    /********************************************************/
    void Conut_1(void)
    {
    //   float a;
       time_juli=TH0*256+TL0;
       TH0=0;
       TL0=0;
       //温度补偿
       juli_a=time_juli*1.87/10;       //算出来是mM	  11。0592M晶振
       if(flag==1)		      //超出测量
       {	 
        	flag=0;
    		juli_a = 0;
       }
      
    }
    
    
    void read_juli()
    {
    	chao_flag = 1; 	  //开始获取
    	//获取距离
    	StartModule_1();	//计算
     	while(!RX_1);		//当RX为零时等待
    	TH0=0;
    	TL0=0; 
    // 	TR0=1;			    //开启计数
     	while(RX_1);			//当RX为1计数并等待
    // 	TR0=0;				//关闭计数
    
     	Conut_1();
    	chao_flag = 0;	   //停止获取
    }
    
    
    
    
    
    
    
    
    
    void Uart1Send(uchar c)
    {
    	SBUF=c;
    	while(!TI);//等待发送完成信号(TI=1)出现
    	TI=0;	
    }
    
    
    //串行口连续发送char型数组,遇到终止号/0将停止
    void Uart1Sends(uchar *str)
    {
    	while(*str!='\0')													    
    	{
    		SBUF=*str;
    		while(!TI);//等待发送完成信号(TI=1)出现
    		TI=0;
    		str++;
    	}
    }
    
    void Uart_1Sends_B(uchar *str)
    {
    	char i=0;
    
    	
    	LCD_Write_Com(0xc0);  
    	LCD_Write_Data(user_number[0]);
    	LCD_Write_Data(user_number[1]);
    	LCD_Write_Data(user_number[2]);
    	LCD_Write_Data(user_number[3]);
    	LCD_Write_Data(user_number[4]);
    	LCD_Write_Data(user_number[5]);
    	LCD_Write_Data(user_number[6]);
    	LCD_Write_Data(user_number[7]);
    	LCD_Write_Data(user_number[8]);
    	LCD_Write_Data(user_number[9]);
    	LCD_Write_Data(user_number[10]);
    	
    	
    	
    	while(*str!='\0')
    	{
    		if(i==12)
    			SBUF = user_number[0];
    		else if(i==16)
    			SBUF = user_number[1];
    		else if(i==20)
    			SBUF = user_number[2];
    		else if(i==24)
    			SBUF = user_number[3];
    		else if(i==28)
    			SBUF = user_number[4];
    		else if(i==32)
    			SBUF = user_number[5];
    		else if(i==36)
    			SBUF = user_number[6];
    		else if(i==40)
    			SBUF = user_number[7];
    		else if(i==44)
    			SBUF = user_number[8];
    		else if(i==48)
    			SBUF = user_number[9];
    		else if(i==52)
    			SBUF = user_number[10];
    		else
    			SBUF=*str;
    		 	 		
    		while(!TI);//等待发送完成信号(TI=1)出现
    		TI=0;
    
    		str++;
    		i++;
    	}
    }
    
    
    
    //转换数据
    void switch_data(uchar a)
    {
    	switch(a)
    	{
    		case 0:  UartPrintf("0030"); break;
    		case 1:  UartPrintf("0031"); break;
    		case 2:  UartPrintf("0032"); break;
    		case 3:  UartPrintf("0033"); break;
    		case 4:  UartPrintf("0034"); break;
    		case 5:  UartPrintf("0035"); break;
    		case 6:  UartPrintf("0036"); break;
    		case 7:  UartPrintf("0037"); break;
    		case 8:  UartPrintf("0038"); break;
    		case 9:  UartPrintf("0039"); break;
    		default: UartPrintf("002E");break;
    	}
    }
    
    
    void sendMes()
    {
    	
    	   	Uart1Sends("AT+CMGF=1\r\n");
    		Delay10ms(300);//延时2秒
    
       		Uart1Sends("AT+CSCS=\"UCS2\"\r\n");
    		Delay10ms(300);//延时2秒
    		
    		Uart1Sends("AT+CSCA?\r\n");
    		Delay10ms(300);//延时2秒
    
    		Uart1Sends("AT+CSMP=17,167,0,24\r\n");
    		Delay10ms(300);//延时2秒
    
    		Uart_1Sends_B("AT+CMGS=\"00310033003300330033003300330039003200340033\"\r\n");//此处修改为对
    		Delay10ms(300);//延时2秒
    		Uart1Sends("970089815E2E52A9FF0C00670070007357506807FF1A");
    		//发送gps坐标
    		//维度
    		UartPrintf("7EF45EA6");
    		switch_data(weidu_A%100/10);
    		switch_data(weidu_A%10);
    		//度
    		UartPrintf("5EA6");
    		switch_data(weidu_B%100/10);
    		switch_data(weidu_B%10);
    		//分
    		UartPrintf("5206");
    		switch_data(weidu_C%100/10);
    		switch_data(weidu_C%10);
    		//秒
    		UartPrintf("79D20020");
    
    		//经度
    		UartPrintf("7ECF5EA6");
    		switch_data(jingdu_A/100);
    		switch_data(jingdu_A%100/10);
    		switch_data(jingdu_A%10);
    		//度
    		UartPrintf("5EA6");
    		switch_data(jingdu_B%100/10);
    		switch_data(jingdu_B%10);
    		//分
    		UartPrintf("5206");
    		switch_data(jingdu_C%100/10);
    		switch_data(jingdu_C%10);
    		//秒
    		UartPrintf("79D20020");
    	
    	
    	
    		Delay10ms(300);//延时2秒
    		Uart1Send(0x1a);
    		Delay10ms(300);//延时2秒
    }
    
    
    //输入手机号
    void inputTel()
    {
    
    }
    
    
    void checkWar()
    {
    	//检测距离
    	if(juli_a<juli_down)
    	{
    		//发送播报信息
    		Uart1Send(0xee);//字头
    		Uart1Send(0x03);//指令
    		Uart1Send(0x00);
    		Uart1Send(0x00);
    		ele=0;
    		beep();
    		beep();
    		beep();
    		ele=1;
    		Delay10ms(30);			
    	}
    	
    	//整点报时
    	 if((min==0)&&(sec<2))  
    	{
    		//发送播报信息
    		Uart1Send(0xee);//字头
    		Uart1Send(0x00);//指令
    		Uart1Send(hour);
    		Uart1Send(0x00);
    		beep();
    		
    		Delay10ms(30);
    	}
    

    4 实现效果



    5 最后

    包含内容

    🧿 项目分享:

    https://gitee.com/sinonfin/sharing

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于单片机的导盲拐杖设计——包含源码、硬件和论文

    发表评论