当前位置:文档之家› 单片机蓝牙控制小车

单片机蓝牙控制小车

课题:基于单片机的蓝牙控制小车专业:班级:学号:姓名:指导教师:设计日期:成绩:重庆大学城市科技学院电气信息学院目录1.设计目的作用 (2)2.设计要求 (2)3.设计的具体实现 (2)3.1设计原理 (2)3.2系统设计 (12)3.3系统实现 (13)4.总结 (19)参考文献 (20)附录 (21)附录1 (21)附录2 (22)C51蓝牙控制小车设计报告1设计目的与意义目的与意义:提高学生动手能力,培养学生的思维,巩固理论知识,让我们能对单片机更加深入的了解,加深同学们对单片机的认识,通过自己动手让小车跑起来还能让同学们更加有积极性,参与感,成就感。

让学生们亲自体验这门课程的神奇性。

因为无线技术的广泛使用,使蓝牙技术的发展成为了趋势之一,蓝牙可以发送和接受语音和数据,满足了大多数人的需求,它也融合了其他相关产品的特点,也是这样技术变得更多样性。

实现了无线控制小车,摆脱了有线控制的不方便,更加智能。

2设计要求SPP蓝牙串口调试助手 ----》聊天窗口--》1、在Bluetooth_Car项目中添加超声波躲避障碍功能(在小车前进的过程中,实时检测障碍物,一旦检测的距离,接近设定的值,触发蜂鸣器,报警系统工作,小车停止前进);2、在Bluetooth_Car项目中的串口中断服务函数中,添加小车前进的8个方向,前后左右,左前,右前,左后,右后;3、利用外部中断,强制停止小车运行(无论小车现在处于什么状态),蜂鸣器报警1s后,可再运行;4、用手机的蓝牙串口调试助手来远程操作小车。

3.设计的具体实现3.1设计原理芯片常识: STM8、C52 、STM32 、ARMC52:主要做末端的控制 11.0592MHZSTM32:主要做工业控制领域——智能设备 168MARM:主要做消费市场——手机==============单片机小车==========了解原理图和数据手册一、软件建立工程建立工程时芯片选择--》Atmel-->AT89C52设置芯片频率,选择生成16进制可执行文件。

=============中断========单片机获取外部数据的方式:1.程序控制方式a.无条件发送方式单片机认为外部设备一直都是准备好的,直接就拿数据使用。

b.条件判断方式在满足一定条件才获取数据。

2.中断方式由外部控制的,当有中断请求产生的时候,就可以在中断里面去实现获取数据。

3.DMA直接存储控制器当需要从外界获取数据的时候,DMA可以向CPU申请获取数据,由DMA直接获取数据。

使用DMA可以绕过CPU处理数据,降低CPU的使用率。

中断:当CPU正常运行的时候,突然收到一个中断请求(任务),完成中断任务之后立即返回原来的程序继续执行。

中断源:中断来源,发送中断的源头中断请求:中断发出的请求,申请执行任务中断响应:CPU响应中断请求,暂停正在执行的任务,转而执行中断任务8个中断源:INT0 外部中断0INT1 外部中断1INT2 外部中断2INT3 外部中断3T0 定时器0T1 定时器1T2 定时器2Uart 串口中断中断有优先级:分为4级,从0~3,数字越大优先级越高,高优先级的中断可以打断低优先级的中断。

中断的查询次序:在中断优先级相同的情况下,并且两个中断同时产生的时候,会优先执行查询次序级别高的中断.查询次序不能打断中断.中断服务函数:void INT1_func(void) interrupt 2{if()}小车两轮驱动:单片机的IO口不能直接驱动电机运行,必须使用驱动模块才可以。

电机转动原理:电机的两条线一根接电源正极,一根接负极就可以转动,当电极的方向改变,转动的方向也会改变。

BIA = 1;BIB = 0;控制右轮电机,如果想让轮子转动,只需要设置以上两个引脚,一个为1,一个为0.P0.0 左轮 1P0.1 左轮 0P0.2 右轮 1P0.3 右轮 0如果轮子想要动起来,需要接电源线。

思考:封装函数:前进、后退、停止、左前转、右前转、左后转、右后转=============定时器==============定时器就是定时,定时产生中断或者是计数。

工作方式:定时器:主要产生定时中断计数器:计时计数工作模式:模式0:12位寄存器模式1:16位寄存器模式2:8位自动重装载寄存器模式3:两个8位寄存器,T1无效时钟周期:就是频率的倒数假设晶振12M,时钟周期是1/12us,实际上大多使用的是:1/11.0592状态周期:状态周期是时钟周期的两倍:1/12*2机器周期:12个时钟周期定为1个机器周期,如果晶振是12M,那么一个机器周期就刚好是1us。

寄存器:TCON 控制寄存器 TMOD 模式寄存器定时器0作模式1: TMOD.1 = 0 TMOD.0 = 1设置寄存器计数的初值:TL0和TH050ms = (65536-初值)* (1/11.0592*12)50000us = (65536-初值) * 1.0850746080 = 65536-初值初值 = 19456 ==》 0x4C00TH0 = 0x4C;TL0 = 0x00;=============串口==============一、计算机内部通讯的方式:UART(串口)、I2C、SPI、1-Write(单总线)二、数据通讯方式并行通讯:多个任务同时进行,增加速度。

串行通讯:数据只通过一根数据线传输,一位一位的传输数据。

三、串行通讯同步通讯:发送一位数据必须要接收一位数据,通过时钟线确定数据收发:I2C、SPI异步通讯:可以独立收发数据,不需要发送数据的时候接收数据。

:串口UART、1w总线单工:只能一方发送数据,一方接收数据(收音机)半双工:同一时刻只能一方发送数据,一方接收数据,但是方向可以转换。

(对讲机)全双工:数据在同一时刻可以收也可以发。

(电话)四、电平特性TTL和RS232TTL:0V~5V 0V表示数据0 3.3V/5V表示数据1RS232:-15V~+15V 3V~15V表示数据0 -15V~-3V表示数据1单片机直接使用的是TTL电平:VCC正极; GND负极; TXD数据发送; RXD数据接收五、串行通讯的协议六、单片机串口寄存器SCON控制寄存器串口选择方式1,8位UART,波特率可变。

设置SCON寄存器:SCON = // 0101 0000 ==》 0x50PCON电源管理寄存器,设置SMOD的值SMOD默认值就是0,也可以主动设置为0.设置好之后需要开启总中断:EA = 1; ES = 1; 串口波特率计算:波特率 = (2^SMOD /32)* (定时器溢出率)9600 = (1 /32)* (11059200/12/(256-TH1)) 9600 = (1 /32)* (921600/(256-TH1))921600/(256-TH1) = 307200(256-TH1) = 3TH1 = 253 ==> 0xFD串口发送数据SUBF = 'h'; // 发送数据,还要判断是否发送3.2系统设计项目框图:3.3系统实现程序代码如下:#include <reg52.h> //器件配置文件#include <intrins.h>#define uint unsigned int#define uchar unsigned char#define LCM_Data P2#define Busy 0x80 //用于检测LCM状态字中的Busy标识sbit RX = P1^1 ;sbit TX = P1^2 ;sbit LCM_RW = P0^3; //定义LCD引脚sbit LCM_RS = P0^4;sbit LCM_E = P0^2;sbit FM = P0^7; //定义蜂鸣器sbit AIA = P2^3; //定义电机sbit AIB = P2^2;sbit BIB = P2^1;sbit BIA = P2^0;void LCMInit(void);void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData); void Delay5Ms(void);void Delay400Ms(void);void Decode(unsigned char ScanCode);void WriteDataLCM(unsigned char WDLCM);void WriteCommandLCM(unsigned char WCLCM,BuysC);void SendOneByte(unsigned char c);unsigned char ReadDataLCM(void);unsigned char ReadStatusLCM(void);unsigned char code mcustudio[] ={"YueQian "};unsigned char code email[] = {" "};unsigned char code Cls[] = {" "};unsigned char code ASCII[15] = {'0','1','2','3','4','5','6','7','8','9','.','-','M'};static unsigned char DisNum = 0; //显示用指针unsigned int time=0;unsigned long S=0;bit flag =0;unsigned char disbuff[4] ={ 0,0,0,0,};void Init_Int1(void){IT1 = 1; //下降沿触发EX1 = 1; //开启外部中断1EA = 1; //开启总中断}void delay_ms(uint x) //延时函数{uint i;while(x--){for(i=0;i<133;i++);}}void car_go() //控制小车的函数前进{AIA = 1; //运用电机的电位差来控制小车的前进方向AIB = 0;BIA = 1;BIB = 0;}void car_back() //后退{AIA = 0;AIB = 1;BIA = 0;BIB = 1;}void right() //右转课程设计正文{AIA = 1;AIB = 0;BIA = 1;BIB = 1;}void left() //左转{AIA = 1;AIB = 1;BIA = 1;BIB = 0;}void go_right() //右转前进{AIA = 1;AIB = 0;BIA = 1;BIB = 1;delay_ms(500);AIA = 1;AIB = 0;BIA = 1;BIB = 0;}void go_left() //左转前进{AIA = 1;AIB = 1;BIA = 1;BIB = 0;delay_ms(500);AIA = 1;课程设计正文AIB = 0;BIA = 1;BIB = 0;}void back_right() //右转后退{AIA = 1;AIB = 1;BIA = 1;BIB = 0;delay_ms(500);AIA = 0;AIB = 1;BIA = 0;BIB = 1;}void back_left() //左转后退{AIA = 1;AIB = 0;BIA = 1;BIB = 1;delay_ms(500);AIA = 0;AIB = 1;BIA = 0;BIB = 1;}void WriteDataLCM(unsigned char WDLCM) //写数据{ReadStatusLCM(); //检测忙LCM_Data = WDLCM;LCM_RS = 1;LCM_RW = 0;LCM_E = 0; //若晶振速度太高可以在这后加小的延时LCM_E = 0; //延时LCM_E = 1;}void WriteCommandLCM(unsigned char WCLCM,BuysC) //写指令BuysC为0时忽略忙检测{if (BuysC) ReadStatusLCM(); //根据需要检测忙LCM_Data = WCLCM;LCM_RS = 0;LCM_RW = 0;LCM_E = 0;LCM_E = 0;LCM_E = 1;}unsigned char ReadDataLCM(void) //读数据{LCM_RS = 1;LCM_RW = 1;LCM_E = 0;LCM_E = 0;LCM_E = 1;return(LCM_Data);}unsigned char ReadStatusLCM(void) //读状态{LCM_Data = 0xFF;LCM_RS = 0;LCM_RW = 1;LCM_E = 0;LCM_E = 0;LCM_E = 1;while (LCM_Data & Busy); //检测忙信号return(LCM_Data);}void LCMInit(void) //LCM初始化{LCM_Data = 0;WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号Delay5Ms();WriteCommandLCM(0x38,0);Delay5Ms();WriteCommandLCM(0x38,0);Delay5Ms();WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号WriteCommandLCM(0x08,1); //关闭显示WriteCommandLCM(0x01,1); //显示清屏WriteCommandLCM(0x06,1); // 显示光标移动设置WriteCommandLCM(0x0F,1); // 显示开及光标设置}//按指定位置显示一个字符void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData){Y &= 0x1;X &= 0xF; //限制X不能大于15,Y不能大于1if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;X |= 0x80; //算出指令码WriteCommandLCM(X, 1); //发命令字WriteDataLCM(DData); //发数据}//按指定位置显示一串字符void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData) {unsigned char ListLength;ListLength = 0;Y &= 0x1;X &= 0xF; //限制X不能大于15,Y不能大于1while (DData[ListLength]>0x19) //若到达字串尾则退出{if (X <= 0xF) //X坐标应小于0xF{DisplayOneChar(X, Y, DData[ListLength]); /显示单个字符ListLength++;X++;}}}void Delay5Ms(void) //5ms延时{unsigned int TempCyc = 5552;while(TempCyc--);}void Delay400Ms(void) //400ms延时{unsigned char TempCycA = 5;unsigned int TempCycB;while(TempCycA--){TempCycB=7269;while(TempCycB--);};}/**************超声波测距函数*************************/void Conut(void){time=TH0*256+TL0;TH0=0;TL0=0;S=(time*1.87)/100; //算出来是CM/*晶振为11.0592MHz时|t(us) = 计数* (12/11.0592) * (1/58)| = 计数* 0.0187| = (计数* 1.87)/100*/if((S>=700)||flag==1) //超出测量范围显示“-”{flag=0;DisplayOneChar(0, 1, ASCII[11]);DisplayOneChar(1, 1, ASCII[10]); //显示点DisplayOneChar(2, 1, ASCII[11]);DisplayOneChar(3, 1, ASCII[11]);DisplayOneChar(4, 1, ASCII[12]); //显示M}else{disbuff[0]=S%1000/100;disbuff[1]=S%1000%100/10;disbuff[2]=S%1000%10 %10;DisplayOneChar(0, 1, ASCII[disbuff[0]]);DisplayOneChar(1, 1, ASCII[10]); //显示点DisplayOneChar(2, 1, ASCII[disbuff[1]]);DisplayOneChar(3, 1, ASCII[disbuff[2]]);DisplayOneChar(4, 1, ASCII[12]); //显示M}}/********************************************************//*********** 定时器T0中断服务函数***********/void Timer0IRQ() interrupt 1 //T0中断用来计数器溢出,超过测距范围{flag=1;}/********************触发超声波模块************************************/ //超声波模块Trig控制端给大于10us的高电平触发模块测距void StartModule() //启动模块{TX=1; //启动一次模块_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();TX=0;}/********************************************************/ void delayms(unsigned int ms){unsigned char i=100,j;for(;ms;ms--){while(--i){j=10;while(--j);}}}/******************************/void SendOneByte(unsigned char c) //发送单个字符{SBUF = c;while(!TI);TI = 0;}/*********************************************************/void main(void){unsigned char TempCyc;Delay400Ms(); //启动等待,等LCM讲入工作状态LCMInit(); //LCM初始化Delay5Ms(); //延时片刻(可不要)DisplayListChar(0, 0, mcustudio);DisplayListChar(0, 1, email);ReadDataLCM(); //测试用句无意义for (TempCyc=0; TempCyc<10; TempCyc++)Delay400Ms(); //延时DisplayListChar(0, 1, Cls);FM = 1;// TMOD=0x01; //设T0为方式1;// TH0=0;// TL0=0;// ET0=1; //允许T0中断// EA=1; //开启总中断TMOD=0x21; //设T0为方式1,定时器1方式2;// 0010 0001课程设计正文SCON=0x50;TH1=0xFD;TL1=0xFD;TH0=0;TL0=0;TR0=1;ET0=1; //允许T0中断TR1=1; //开启定时器TI=1;ES = 1;EA=1; //开启总中断Init_Int1();while(1){StartModule();// DisplayOneChar(0, 1, ASCII[0]);while(!RX); //当RX为零时等待TR0=1; //开启计数while(RX); //当RX为1计数并等待TR0=0; //关闭计数Conut(); //计算FM = 1;AIA = 1;AIB = 1;BIA = 1;BIB = 1;//超声波测距检测if(S<20){FM = 0;AIA = 1;AIB = 1;BIA = 1;BIB = 1;课程设计正文}elseFM =1;delayms(80); //80MS}}void UARTInterrupt(void) interrupt 4{unsigned char buf;if(RI){RI = 0;//add your code here!buf = SBUF; //作回显没有任何作用SendOneByte(buf);if(buf == '1'){car_go();delay_ms(1000);}else if(buf == '2'){car_back();delay_ms(1000);}else if(buf == '3'){right();delay_ms(1000);}else if(buf == '4'){left();课程设计正文delay_ms(1000);}else if(buf == '5'){go_right();delay_ms(1000);}else if(buf == '6'){go_left();delay_ms(1000);}else if(buf == '7'){back_right();delay_ms(1000);}else if(buf == '8'){back_left();delay_ms(1000);}}elseTI = 0;}void Int1_Routine(void) interrupt 2{EX1 = 0;AIA = 1;AIB = 1;BIA = 1;BIB = 1;FM = 0;delay_ms(500);FM = 1;EX1 = 1;}总结学习单片机要有一定的c语言基础,单片机的基础知识我还是多多少少知道一些,可是让我直接来做这一个项目,我却无从下手。

相关主题