小车设计
利用STM32作为智能小车的主控制器来驱动智能小车的直流电机工作,电机驱动芯片采用L298N微型集成电路电机驱动芯片,配合STM32核心板使用实现四个直流电机运行和pwm软件调速,通过改变直流电机占空比的电压来改变平均电压的数值,从而改变电机的转速变化来驱动轮式机器人运行。轮式机器人行驶的状态有:前进、后退、左转、右转和停止。当轮式机器人在行驶过程中遇到障碍物,红外避障检测模块检测周围障碍物,轮式机器人自动停止或转向。通过WIFI无线信号作为传输媒介,以上位机或手机作为控制端来控制机器人的运动以及将摄像头所拍摄的视频信息在控制端界面中显示,这样便可观察轮式机器人周围的环境并对机器人进行实时监控。主要设计步骤有:
(1)根据提出方案的功能需求对智能小车进行结构设计。
(2)根据主控制器的基本结构和特点,设计总体硬件电路模块。总体硬件电路模块的设计包括电机驱动电路设计、红外避障电路设计、无线传输电路设计等。
(3)选择符合系统设计需求的系统软件,并在该软件的基础上编写驱动代码和应用软件代码。针对系统功能的具体要求,从系统信号稳定传输的角度出发,对电机驱动、调速、无线路由器系统的改造、视频信息的接受与发送、红外避障模块的改造和控制端界面的设计等进行详细的分析与设计,并完成代码的编写与调试。
(4)把硬件开发板和软件平台结合起来,对视频监控智能小车整个系统进行了整体测试。对测试中出现的问题进行相关的改进工作,进一步提高系统工作的可靠性和稳定性。
根据提出方案的功能需求,对轮式机器人的整体结构进行设计,采用双面覆铜加硬的PCB板料作为轮式机器人的底盘,其优点是:不易变形、不易折断、轻量化、不易造成短路;选用抗干扰TT马达,其加入压敏抗组的转子可抵抗电机突然启动产生的火花干扰,避免触发信号错误,可有效降低马达启动噪音,并在启动时可提供更大电流,使马力更强;使用航模级抗滑橡胶轮胎内带海绵表面平整不易变形,在避障行走时刹车不易撞上障碍物。马达用马达锁片固定到机器人底盘上,轮子通过轴与马达相连。
在这里插入图片描述在这里插入图片描述
其余硬件设备均固定到机器人底盘上,包括电池座、红外避障传感器、wifi模块、摄像头、STM32单片机主控模块和L298N电机驱动芯片。机器人底盘俯视图示意图如图:
系统硬件设计
硬件系统主要由单片机主控模块、电源模块、电机驱动模块、红外避障模块控制终端模块和无线视频监控模块组成。硬件系统框图如图:
在这里插入图片描述
(1)主控模块
主控模块采用STM32F103为主控制器,STM32F103属于中低端的32位ARM微控制器,该系列芯片是意法半导体(ST)公司出品,其内核是Cortex-M3。该系列芯片按片内Flash的大小可分为三大类:小容量(16K和32K)、中容量(64K和128K)、大容量(256K、384K和512K)。芯片集成定时器,CAN,ADC,SPI,I2C,USB,UART,等多种功能。STM32F103可使用keil C语言编译,支持STLink-SWD在线调试,主要用于收集信息、处理数据、协调系统中的每个功能模块预计要完成的任务。在这里插入图片描述
(2)电源模块
电源模块在机器人的运行过程中,需要给单片机、电机、各大模块及传感器供电。为了保证系统的可靠供电,所以选择可充电的18650锂电池,如图3.5所示。**18650是锂离子电池的鼻祖–日本SONY公司当年为了节省成本而定下的一种标准性的锂离子电池型号,其中18表示直径为18mm,65表示长度为65mm,0表示为圆柱形电池。**常见的18650电池分为锂离子电池、磷酸铁锂电池。锂离子电池电压为标称电压为3.7v,充电截止电压为4.2v,磷酸铁锂电池标称电压为3.2V,充电截止电压为3.6v容量通常为1200mAh-3350mAh,常见容量是2200mAh-2600mAh。
(3)电机驱动模块
电机驱动模块采用L298N为电机驱动芯片,其原理图如图3.6所示。L298N是ST公司生产的一种高电压、大电流电机驱动芯片。该芯片采用15脚封装。主要特点是:工作电压高,最高工作电压可达46V;输出电流大,瞬间峰值电流可达3A,持续工作电流为2A;额定功率25W。内含两个H桥高电压大电流全桥式驱动器,可以用来驱动直流电动机和步进电动机、继电器线圈等感性负载;采用标准逻辑电平信号控制;具有两个使能控制端,在不受输入信号影响的情况下允许或禁止器件工作有一个逻辑电源输入端,使内部逻辑电路部分在低电压下工作;可以外接检测电阻, 将变化量反馈给控制电路。使用L298N芯片驱动电机,该芯片可以驱动一台两相步进电机或四相步进电机,也可以驱动两台直流电机,并联时可以驱动四台电机。此次研究将L298N配合STM32核心板无缝对插使用,实现无损扩展并对四个马达进行驱动和PWM调速。
控制终端模块有PC上位机和安卓手机两种,两种控制界面都能实现对于智能小车的各种运动状态的控制。
本模块采用720p高清USB摄像头,可以对轮式机器人的运动状态以及周围环境进行视频采集,然后将采集的视频数据通过无线信号返回到控制界面显示,以达到实时监控的目的。**USB接口是目前应用比较广泛的一种接口模式,几乎所有的产品都能支持,即插即用,具有强大的扩充能力,用起来十分方便。**依靠USB连接无线路由器获得的电压就能否满足摄像头正常工作需求的电压,这样就不用再接外部电压,使得电路设计更加简单方便。USB摄像头虽然在采集动态画面与成像清晰度上仍然无法与接口摄像头相比,但是其接口简单,即插即用,己经成为设计者的首选。本模块主要是用来完成轮式机器人与各个控制界面之间的通信,由于机器人移动性的特点,所以系统选用无线通信进行数据传输。无线通信的实现主要由无线路由器实现,通过无线路由器可以搭建一个局域网,并且在这局域网的基础上可以运行多种底层协议。控制终端与轮式机器人进行信号的控制和交互就是采用这种传输模式。首先运行于控制终端的网络程序通过局域网与轮式机器人建立起连接,待连接建立成功后,用户就可以使用控制终端的用户界面软件向轮式机器人发送各种控制指令和获取摄像头视频信息等数据。本系统设计将数字摄像头的驱动加载在无线路由器固件当中,当主控制器发出采集视频指令,摄像头开始工作。
系统软件设计
软件的设计包括:主程序的设计、电机驱动程序设计、红外循障程序设计、视频采集程序设计、无线数据传输程序设计。
(1)电机驱动程序
电机的驱动主要是对L298N驱动芯片的操作,运用PWM调速方法完成对电机进行驱动控制。脉冲宽度调制(PWM),简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。PWM波的产生可以通过时钟频率、自动重装值等参数进行设置,从而调节PWM波的占空比和输出频率,即对脉冲宽度的控制,PWM原理如图:
由图我们先假定定时器工作正处于向上计数PWM模式,且当CNT小于CCRx 时,输出0,当CNT大于等于CCRx 时输出 1。那么就可以得到如上的PWM示意图:当CNT值小于CCRx的时候,IO输出低电平(0),当CNT值大于等于CCRx的时候,IO输出高电平(1),当CNT达到ARR值的时候,重新归零,然后重新向上计数,依次循环改变CCRx的值,就可以改变PWM输出的占空比,改变ARR的值,就可以改变PWM输出的频率,这就是PWM输出的原理。由此可知PWM 技术就是把直流电压斩成一系列脉冲,通过改变脉冲的占空比获得所需的输出电压。
由图L298N芯片的原理图,引脚A,B可用于输入PWM脉宽调制信号对电机进行调速控制。如果无须调速可将两引脚接5V,使电机工作在最高速状态,既将短接帽短接。假设驱动的两台直流电机分别为M1和M2,当输入信号端IN1接高电平输入端IN2接低电平时,电机M1正转。当信号端IN1接低电平,IN2接高电平,电机M1反转。控制另一台电机是同样的方式,输入信号端IN3接高电平,输入端IN4接低电平,电机M2正转(反之则反转)。PWM信号端A控制M1调速,PWM信号端B控制M2调速 。可通过单片机IO口状态来控制小车运行,电机具体运行方式如图
电机驱动程序使用了单片机定时器的PWM功能,通过输出频率及占空比可变的PWM波来驱动电机。具体实现方法为:首先,使能定时器和相关IO口时钟。其次,对定时器进行初始化并设置其自动重转载值和预分频值,将计数模式设置为向上计数模式。最后,再使能预装载寄存器,使能定时器,通过改变比较值CCRX,达到不同的占空比效果。智能小车电机驱动程序流程图如图所示(以M1为例):
在这里插入图片描述
蓝牙
•蓝牙( Bluetooth® ) : 是一种无线技术标准,可实现固定设备、 移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波) 。 蓝牙技术最初由电信巨头爱立信公司于1994年创制, 当时是作为RS232数据线的替代方案。 蓝牙可连接多个设备, 克服了数据同步的难题。
如今蓝牙由蓝牙技术联盟(Bluetooth SpecialInterest Group, 简称SIG) 管理。 蓝牙技术联盟在全球拥有超过25,000家成员公司, 它们分布在电信、计算机、 网络、 和消费电子等多重领域。 IEEE将蓝牙技术列为IEEE 802.15.1, 但如今已不再维持该标准。 蓝牙技术联盟负责监督蓝牙规范的开发, 管理合蓝牙技术联盟的标准才能以“蓝牙设备” 的名义进入市场。 蓝牙技术拥有一套专利网络, 可发放给符合标准的设备。
与STM32接线方法 STM32F103C8T6
TXD----接PB11 RXD—接PB10
蓝牙模块安装
• 蓝牙模块上有RXD TXD GND VCC 注意位置方向
• 分别接到核心板J2上的 TD TX GND VCC
• RXD 对应 核心板J2 TD
• TXD 对应 核心板J2 TX
• GND 对应 核心板J2 GND
• VCC 对应 核心板J2 5V
TXD: 发送端, 一般表示为自己的发送端, 正常通信必须接另一个设备的RXD。
RXD: 接收端, 一般表示为自己的接收端, 正常通信必须接另一个设备的TXD。
正常通信时候本身的TXD永远接设备的RXD!
自收自发: 正常通信时RXD接其他设备的TXD, 因此如果要接收自己发送的数据顾名思义, 也就是自己接收自己发送的数据, 即自身的TXD直接连接到RXD, 用来测试本身的发送和接收是否正常,是最快最简单的测试方法, 当出现问题时首先做该测试确定是否产品故障。 也称回环测试。
软件部分代码
串口配置代码
#include "uart.h"
#include "interface.h"//UART function
//UART3 TxD GPIOB10 RxD GPIOB11
void USART3Conf(u32 baudRate)
{NVIC_InitTypeDef NVIC_InitStruct;//定义一个设置中断的结构体 USART_InitTypeDef USART_InitSturct;//定义串口1的初始化结构体GPIO_InitTypeDef GPIO_InitStruct;//定义串口对应管脚的结构体RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 , ENABLE);//打开串口管脚时钟//USART3_Tx_Pin Configure GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;//输出引脚GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;//设置最高速度50MHzGPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用输出GPIO_Init(GPIOB , &GPIO_InitStruct);//将初始化好的结构体装入寄存器//USART3_Rx_Pin ConfigureGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//GPIO模式悬浮输入GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;//输入引脚GPIO_Init(GPIOB, &GPIO_InitStruct);//将初始化好的结构体装入寄存器//USART3 Configure USART_InitSturct.USART_BaudRate = baudRate;//波特率9600USART_InitSturct.USART_WordLength = USART_WordLength_8b;//数据宽度8位USART_InitSturct.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitSturct.USART_Parity = USART_Parity_No;//无奇偶校验USART_InitSturct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitSturct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//使能发送与接收USART_Init(USART3 , &USART_InitSturct);//将初始化好的结构体装入寄存器 //USART1_INT ConfigureUSART_ITConfig(USART3 , USART_IT_RXNE , ENABLE);//使能接收中断
// USART_ITConfig(USART3 , USART_IT_TXE , ENABLE);USART_Cmd(USART3 , ENABLE);//打开串口USART_ClearFlag(USART3 , USART_FLAG_TC);//解决第一个数据发送失败的问题NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//打开该中断NVIC_Init(&NVIC_InitStruct);}void PutChar(u8 Data)
{USART_SendData(USART3 , Data);while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);//等待发送完毕
}
void PutStr(char *str)//发送一个字符串
{while(*str != '\0'){USART_SendData(USART3 , *str++);while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);//等待发送完毕}
}void PutNChar(u8 *buf , u16 size)
{u8 i;while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); //防止第一字节丢失for(i=0;i<size;i++){USART_SendData(USART3 , buf[i]);while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);//等待发送完毕}
}
电机驱动代码
#include "motor.h"
#include "interface.h"
#include "stm32f10x.h"//GPIO配置函数
void MotorGPIO_Configuration(void)
{ GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = FRONT_LEFT_F_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(FRONT_LEFT_F_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = FRONT_LEFT_B_PIN; GPIO_Init(FRONT_LEFT_B_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = FRONT_RIGHT_F_PIN; GPIO_Init(FRONT_RIGHT_F_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = FRONT_RIGHT_B_PIN; GPIO_Init(FRONT_RIGHT_B_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BEHIND_LEFT_F_PIN; GPIO_Init(BEHIND_LEFT_F_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BEHIND_LEFT_B_PIN; GPIO_Init(BEHIND_LEFT_B_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BEHIND_RIGHT_F_PIN; GPIO_Init(BEHIND_RIGHT_F_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BEHIND_RIGHT_B_PIN; GPIO_Init(BEHIND_RIGHT_B_GPIO, &GPIO_InitStructure); }//根据占空比驱动电机转动
void CarMove(void)
{ BEHIND_RIGHT_EN;/* //左前轮if(front_left_speed_duty > 0)//向前{if(speed_count < front_left_speed_duty){FRONT_LEFT_GO;}else{FRONT_LEFT_STOP;}}else if(front_left_speed_duty < 0)//向后{if(speed_count < (-1)*front_left_speed_duty){FRONT_LEFT_BACK;}else{FRONT_LEFT_STOP;}}else //停止{FRONT_LEFT_STOP;}*///右前轮if(front_right_speed_duty > 0)//向前{if(speed_count < front_right_speed_duty){FRONT_RIGHT_GO;}else //停止{FRONT_RIGHT_STOP;}}else if(front_right_speed_duty < 0)//向后{if(speed_count < (-1)*front_right_speed_duty){FRONT_RIGHT_BACK;}else //停止{FRONT_RIGHT_STOP;}}else //停止{FRONT_RIGHT_STOP;}//左后轮if(behind_left_speed_duty > 0)//向前{if(speed_count < behind_left_speed_duty){BEHIND_LEFT_GO;} else //停止{BEHIND_LEFT_STOP;}}else if(behind_left_speed_duty < 0)//向后{if(speed_count < (-1)*behind_left_speed_duty){BEHIND_LEFT_BACK;} else //停止{BEHIND_LEFT_STOP;}}else //停止{BEHIND_LEFT_STOP;}/* //右后轮if(behind_right_speed_duty > 0)//向前{if(speed_count < behind_right_speed_duty){BEHIND_RIGHT_GO;} else //停止{BEHIND_RIGHT_STOP;}}else if(behind_right_speed_duty < 0)//向后{if(speed_count < (-1)*behind_right_speed_duty){BEHIND_RIGHT_BACK;} else //停止{BEHIND_RIGHT_STOP;}}else //停止{BEHIND_RIGHT_STOP;}*/
}//向前
void CarGo(void)
{front_left_speed_duty=SPEED_DUTY;front_right_speed_duty=SPEED_DUTY;behind_left_speed_duty=SPEED_DUTY;behind_right_speed_duty=SPEED_DUTY;
}//后退
void CarBack(void)
{front_left_speed_duty=-SPEED_DUTY;front_right_speed_duty=-SPEED_DUTY;behind_left_speed_duty=-SPEED_DUTY;behind_right_speed_duty=-SPEED_DUTY;
}//向左
void CarLeft(void)
{front_left_speed_duty=-20;front_right_speed_duty=SPEED_DUTY;behind_left_speed_duty=-20;behind_right_speed_duty=SPEED_DUTY+10;//增加后轮驱动力
}//向右
void CarRight(void)
{front_left_speed_duty=SPEED_DUTY;front_right_speed_duty=-20;behind_left_speed_duty=SPEED_DUTY+10;//增加后轮驱动力behind_right_speed_duty=-20;
}//停止
void CarStop(void)
{front_left_speed_duty=0;front_right_speed_duty=0;behind_left_speed_duty=0;behind_right_speed_duty=0;
}void MotorInit(void)
{MotorGPIO_Configuration();CarStop();
}
中断代码
#include "IRCtrol.h"
#include "interface.h"unsigned char ir_rec_flag=0;//接收数据标志位 1 有新数据 0 没有
unsigned char IRCOM[4];//use time3 realize delay systick已经在main函数中使用了,在中断中不能重复使用
void Time3Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_TimeBaseStructure.TIM_Period = 1;TIM_TimeBaseStructure.TIM_Prescaler = (72 - 1);//72M / 72 = 1usTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
}//1us 延时
void DelayUs(vu32 nCount)
{u16 TIMCounter = nCount;TIM_Cmd(TIM3, ENABLE);TIM_SetCounter(TIM3, TIMCounter);while (TIMCounter>1){TIMCounter = TIM_GetCounter(TIM3);}TIM_Cmd(TIM3, DISABLE);
}//外部中断配置 红外遥控配置
void IRCtrolInit(void)
{GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;//定义一个外部中断相关的结构体NVIC_InitTypeDef NVIC_InitStructure; //定义一个中断的结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);GPIO_InitStructure.GPIO_Pin = IRIN_PIN;//配置使能GPIO管脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度GPIO_Init(IRIN_GPIO , &GPIO_InitStructure);GPIO_EXTILineConfig(IRIN_PORTSOURCE , IRIN_PINSOURCE);EXTI_InitStructure.EXTI_Line = IRIN_EXITLINE;//将对应的GPIO口连接到中断线上EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//中断事件类型,下降沿EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//选择模式,中断型EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能该中断EXTI_Init(&EXTI_InitStructure);//将配置好的参数写入寄存器NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //阶级为0,不可嵌套NVIC_InitStructure.NVIC_IRQChannel = IRIN_IRQCH;//打开PINA_8的外部中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//主优先级0,最高NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级,最低NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该模块中断NVIC_Init(&NVIC_InitStructure); //中断初始化,将结构体定义的数据执行Time3Init();
}/*******************************************************************************
* 函 数 名 :DelayIr
* 函数功能 :0.14MS 延时
* 输 入 :无
* 输 出 :无
*******************************************************************************/
void DelayIr(unsigned char x)
{while(x--){DelayUs(140);}
}void IRIntIsr(void)
{unsigned char j,k,N=0;DelayIr(15);if (IRIN==1) { return;} continue_time = 40;//连发信号,表示指令持续 40*5 = 200ms 无指令停车//确认IR信号出现while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。{DelayIr(1);}for (j=0;j<4;j++) //收集四组数据{ for (k=0;k<8;k++) //每组数据有8位{while (IRIN) //等 IR 变为低电平,跳过4.5ms的前导高电平信号。{DelayIr(1);}while (!IRIN) //等 IR 变为高电平{DelayIr(1);}while (IRIN) //计算IR高电平时长{DelayIr(1);N++; if (N>=30){ return;} //0.14ms计数过长自动离开。} //高电平计数完毕 IRCOM[j]=IRCOM[j] >> 1; //数据最高位补“0”if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;} //数据最高位补“1”N=0;}//end for k}//end for jk = ~IRCOM[3];if (IRCOM[2] != k){ return; }//指令转换switch(IRCOM[2]){case 0x46: ctrl_comm = COMM_UP;break;case 0x15: ctrl_comm = COMM_DOWN;break;case 0x44: ctrl_comm = COMM_LEFT;break;case 0x43: ctrl_comm = COMM_RIGHT;break;case 0x40: ctrl_comm = COMM_STOP;break;default : return;}ir_rec_flag = 1;}
主函数
#include "stm32f10x.h"
#include "interface.h"
#include "LCD1602.h"
#include "IRCtrol.h"
#include "motor.h"
#include "uart.h"//全局变量定义
unsigned int speed_count=0;//占空比计数器 50次一周期
char front_left_speed_duty=SPEED_DUTY;
char front_right_speed_duty=SPEED_DUTY;
char behind_left_speed_duty=SPEED_DUTY;
char behind_right_speed_duty=SPEED_DUTY;unsigned char tick_5ms = 0;//5ms计数器,作为主函数的基本周期
unsigned char tick_1ms = 0;//1ms计数器,作为电机的基本计数器
unsigned char tick_200ms = 0;//刷新显示char ctrl_comm = COMM_STOP;//控制指令
unsigned char continue_time=0;
unsigned char bt_rec_flag=0;//蓝牙控制标志位int main(void)
{delay_init();GPIOCLKInit();UserLEDInit();LCD1602Init();//IRCtrolInit();TIM2_Init();MotorInit();ServoInit();USART3Conf(9600);while(1){ if(tick_5ms >= 5){tick_5ms = 0;tick_200ms++;if(tick_200ms >= 40){tick_200ms = 0;LEDToggle(LED_PIN);}continue_time--;//200ms 无接收指令就停车if(continue_time == 0){continue_time = 1;CarStop();}//do somethingif(bt_rec_flag == 1)//接收到红外信号{bt_rec_flag = 0;switch(ctrl_comm){case COMM_UP: CarGo();break;case COMM_DOWN: CarBack();break;case COMM_LEFT: CarLeft();break;case COMM_RIGHT: CarRight();break;case COMM_STOP: CarStop();break;default : break;}LCD1602WriteCommand(ctrl_comm);}}}
}