蓝牙远程控制小车实现

小车实物图模型和上位机控制软件

 

申报作品情况(科技发明制作)

 

 

作品全称

蓝牙全方向远程控制小车

作品设计

、发明的

目的和基

本思路、

创新点、

技术关键

和主要技

术指标

1.   设计目的:

该设计使用小车底板,减速直流电机,外加8051系统,和L298N模块,蓝牙模块,实现了蓝牙全方位远程控制小车。使用模块化、进化式方案解决个人难以开发制作小车的难题。同时增加上位机软件支持,使平台使用者机械设计与软件开发能力同时得到充分锻炼。

 

2.     基本思路:

从小车底板开始,进化式拓展模块功能,加装51单片机系统驱动小车运动,加装L298N模块实现小车控速转弯,加装蓝牙控制模块,实现远程控制,并在此基础上开发上位机软件进行远程控制,最终完成此作品。

 

3.     创新点:

1)      实现了蓝牙模块远程控制,具有易拓展性。

2)      实现双层底板的模型设计,具有稳定性功能。

3)      实现上位机软件和下位机小车的一体化控制系统

 

4.     关键技术:

1)      蓝牙传输

2)      51系统和L298N模块的小车驱动

3)      上位机软件

 

5.     主要技术指标:

1)      两轮驱动的轮式平台底盘

2)      数字化传输系统

3)      基于8051L298N的直流电机驱动

4)      动作控制信息的数字化传输系统

5)      配合学习平台的友好上位机支持软件

 

 

 

附:

作品硬件部分说明:

硬件构成:

1个小车底板

2个直流减速电机,

1个五号电池盒,

1个拨动开关

1L298N电机驱动模块,

1RICHMCU 51单片机开发板

1对蓝牙模块传输模块构成

 

 

51单片机和L298N模块电路图

8051P10~3L298NIN1~4,控制轮子的转向

P20~1ENAENB,通过控制使能端实现小车轮子的转速控制,实现小车转弯。

8051RX,TX接蓝牙模块,实现远程传输。

51板子的程序:
Car.c

#include
#define uchar unsigned char
#define V_TH  0XFF
#define V_TL  0XF6
#define V_TMOD 0X01

void init_sys(void);            /*系统初始化函数*/
void f_left();	//前进左转
void f_right();	//前进右转
void b_left();	//后退左转
void b_right();	//后退右转
void forward();	//前进
void back();	//后退
void stop();	//停止

//控制小车正反转
sbit IN1 = P0 ^ 0;
sbit IN2 = P0 ^ 1;
sbit IN3 = P0 ^ 2;
sbit IN4 = P0 ^ 3;
//控制小车转速
sbit ENA = P2 ^ 0;
sbit ENB = P2 ^ 1;

uchar ZKB1 = 80, ZKB2 = 80;	//控制轮子转速
uchar tmp;	//存放串口数据
void main (void)
{
    init_sys();
    ENA = 0;
    ENB = 0;
    ZKB1 = 90;
    ZKB2 = 90;
    IN1 = 0;
    IN2 = 0;
    IN3 = 0;
    IN4 = 0;
    TMOD |= 0x20;			// 定时器1工作于8位自动重载模式, 用于产生波特率
    TH1 = 0xFD;				// 波特率9600
    TL1 = 0xFD;
    SCON = 0x50;			// 设定串行口工作方式
    PCON &= 0xef;			// 波特率不倍增
    TR1 = 1;				// 启动定时器1
    while(1)
    {

        if(RI)						// 是否有数据到来
        {
            RI = 0;
            tmp = SBUF;				// 暂存接收到的数据
            switch(tmp)
            {
            case 'a':
                forward();
                break;
            case 'b':
                back();
                break;
            case 'c':
                f_left();
                break;
            case 'd':
                f_right();
                break;
            case 'e':
                b_left();
                break;
            case 'f':
                b_right();
                break;
            case 'g':
                stop();
                break;
            }
        }
    }
}
/******************************************************
*函数功能:对系统进行初始化,包括定时器初始化和变量初始化*/
void init_sys(void)            /*系统初始化函数*/
{
    /*定时器初始化*/
    TMOD = V_TMOD;
    TH0 = V_TH;
    TL0 = V_TL;
    TR0 = 1;
    ET0 = 1;
    EA = 1;
}
/*********************************************
*函数功能:控制方向*/

void forward()
{
    IN1 = 1;
    IN2 = 0;
    IN3 = 1;
    IN4 = 0;
}
void back()
{
    IN1 = 0;
    IN2 = 1;
    IN3 = 0;
    IN4 = 1;
}
void f_left()
{
    ZKB1 = 90;
    ZKB2 = 45;
    IN1 = 1;
    IN2 = 0;
    IN3 = 1;
    IN4 = 0;
}
void f_right()
{
    ZKB1 = 45;
    ZKB2 = 90;
    IN1 = 1;
    IN2 = 0;
    IN3 = 1;
    IN4 = 0;
}
void b_left()
{
    ZKB1 = 90;
    ZKB2 = 45;
    IN1 = 0;
    IN2 = 1;
    IN3 = 0;
    IN4 = 1;
}
void b_right()
{
    ZKB1 = 45;
    ZKB2 = 90;
    IN1 = 0;
    IN2 = 1;
    IN3 = 0;
    IN4 = 1;
}
void stop()
{
    IN1 = 1;
    IN2 = 1;
    IN3 = 1;
    IN4 = 1;
}
/********************************************************
/*中断函数*/
void timer0(void) interrupt 1 using 2
{
    static uchar click = 0;                /*中断次数计数器变量*/
    TH0 = V_TH;                                  /*恢复定时器初始值*/
    TL0 = V_TL;
    ++click;

    if (click >= 100) click = 0;

    if (click <= ZKB1)     /*当小于占空比值时输出高电平,高于时是低电平,从而实现占空比的调整*/
    {
        ENA = 1;
    }

    if (click > ZKB1)
    {
        ENA = 0;
    }

    if (click <= ZKB2)     /*当小于占空比值时输出高电平,高于时是低电平,从而实现占空比的调整*/
    {
        ENB = 1;
    }

    if (click > ZKB2)
    {
        ENB = 0;
    }

}


 

作品的软件部分说明:

使用MFC编写实现,通过蓝牙远程控制小车。

主要实现代码CatDlg.c

// CarDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "Car.h"
#include "CarDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

void OpenComm(CString com);
void SendComm(CStringA str);

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CCarDlg 对话框




CCarDlg::CCarDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CCarDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCarDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, ID_STAT, state);
}

BEGIN_MESSAGE_MAP(CCarDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()

HANDLE hCom;//打开串口句柄

// CCarDlg 消息处理程序

BOOL CCarDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	OpenComm(L"COM3");
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CCarDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CCarDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCarDlg::OnQueryDragIcon()
{
	return static_cast(m_hIcon);
}


BOOL CCarDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if(pMsg->message==WM_KEYDOWN){
		switch(pMsg-> wParam) 
		{ 
		case   'W': 
			SendComm("a");
			SetDlgItemText(ID_STAT,L"前进(前)"); 
			break; 
		case   'Q': 
			SendComm("c");
			SetDlgItemText(ID_STAT,L"左拐(前)"); 
			break;
		case   'E': 
			SendComm("d");
			SetDlgItemText(ID_STAT,L"右拐(前)"); 
			break; 
		case   'S': 
			SendComm("b");
			SetDlgItemText(ID_STAT,L"后退(后)"); 
			break; 
		case   'A': 
			SendComm("e");
			SetDlgItemText(ID_STAT,L"左拐(后)"); 
			break; 
		case   'D': 
			SendComm("f");
			SetDlgItemText(ID_STAT,L"右拐(后)"); 
			break; 
		default: 
			break; 
		}
	}
	if(pMsg->message==WM_KEYUP){
		switch(pMsg-> wParam) 
		{ 
		case   'W': 
			SendComm("g");
			SetDlgItemText(ID_STAT,L"停止"); 
			break; 
		case   'Q': 
			SendComm("g");
			SetDlgItemText(ID_STAT,L"停止"); 
			break;
		case   'E': 
			SendComm("g");
			SetDlgItemText(ID_STAT,L"停止"); 
			break; 
		case   'S': 
			SendComm("g");
			SetDlgItemText(ID_STAT,L"停止"); 
			break; 
		case   'A': 
			SendComm("g");
			SetDlgItemText(ID_STAT,L"停止"); 
			break; 
		case   'D': 
			SendComm("g");
			SetDlgItemText(ID_STAT,L"停止"); 
			break; 
		default: 
			break; 
		} 
	}
	return CDialogEx::PreTranslateMessage(pMsg);
}

void OpenComm(CString num){
		/*串口的初始化*/
	hCom=CreateFile(num,GENERIC_READ|GENERIC_WRITE,
		0,NULL,OPEN_EXISTING,0,NULL);   //打开串口
	if(hCom==(HANDLE)-1)
	{
		AfxMessageBox(L"打开COM失败!");
	}
	else{
		SetupComm(hCom,100,100); //输入缓冲区和输出缓冲区的大小都是100
		COMMTIMEOUTS TimeOuts;
		//设定读超时
		TimeOuts.ReadIntervalTimeout=MAXDWORD;
		TimeOuts.ReadTotalTimeoutMultiplier=0;
		TimeOuts.ReadTotalTimeoutConstant=0;
		//在读一次输入缓冲区的内容后读操作就立即返回,
		//而不管是否读入了要求的字符。


		//设定写超时
		TimeOuts.WriteTotalTimeoutMultiplier=100;
		TimeOuts.WriteTotalTimeoutConstant=500;
		SetCommTimeouts(hCom,&TimeOuts); //设置超时
		DCB dcb;
		GetCommState(hCom,&dcb);
		dcb.BaudRate=9600; //波特率为9600
		dcb.ByteSize=8; //每个字节有8位
		dcb.Parity=NOPARITY; //无奇偶校验位
		dcb.StopBits=ONESTOPBIT ; //停止位
		SetCommState(hCom,&dcb);
		PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
	}
}
void CloseComm(){
		if(CloseHandle(hCom)==TRUE){

	}
	else{
		AfxMessageBox(L"关闭串口失败!");
		exit(0);
	}
}
void SendComm(CStringA str){
	int len=str.GetLength();
	DWORD dwBytesWrite=len;
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	BOOL bWriteStat;
	ClearCommError(hCom,&dwErrorFlags,&ComStat);
	bWriteStat=WriteFile(hCom,str,dwBytesWrite,& 
		dwBytesWrite,NULL);
	if(!bWriteStat)
	{
		AfxMessageBox(L"写串口失败!");
	}
}

欢迎大家拍砖!

另附源码下载地址:http://download.csdn.net/detail/hc260164797/4416085

 

你可能感兴趣的:(硬件开发)