• 前言 本篇文章将围绕App与单片机的蓝牙通信来说说lz最近...单片机Android App的通信方案 环境 单片机 单片机:STC89C52 c语言 编写环境:Keil uVision4 烧录:stc-isp-15xx-v6.82 Android android sdk 16+

    源码传送门

    前言

    本篇文章将围绕App与单片机的蓝牙通信来说说lz最近进行开发的一些方案与思考
    此文分为三部分:

    • 单片机的PWM与串口通信
    • Android的蓝牙开发
    • 单片机与Android App的通信方案

    预览

    这里写图片描述
    这里写图片描述

    视频观看:

    http://v.youku.com/v_show/id_XMjQ5MTgyMTAwMA==.html

    环境

    单片机

    • 单片机:STC89C52
    • c语言
    • 编写环境:Keil uVision4
    • 烧录:stc-isp-15xx-v6.82

    Android

    • android sdk 16+
    • Android studio 1.0+

    单片机的PWM与串口通信

    PWM

    我相信PWM的概念大家都应该,如果还很模糊也可以去查查,可以看看这篇文章

    http://www.eepw.com.cn/article/275890.htm

    那么我们这里要说的,就是怎么通过程序去模拟pwm信号(有些单片机自带pwm处理,就无需写程序),从程序的方面讲,我们要模拟PWM,就是让高电平持续一小段时间,然后再让低电平持续一段时间,也就是改变占空比。
    那么再单片机中,这种关于频率的事情一般都是通过定时器来实现的,那么我的方案是这样的:
    设置一个全局变量t,PWM_T,每当定时器中断的时候使t自增1,当t等于100的时候,使之高电平,并让t等于0,当t等于PWM_T的时候,使之低电平,这样,我们就可以通过改变PWM_T的值来改变占空比,从而实现通过目标的电压,使之达到调节的效果(例如调节led灯的亮度,调节电机的速度等)

    /****************************************************
                   定时器0中断模拟PWM
                   调节led的亮度
    ****************************************************/
    int t = 0;
    int PWM_T = 0;   //占空比控制变
    void main()
    {
    	TMOD = 0x22;   //定时器0,工作模式2,8位定时模式
    	TH0=210;     //写入预置初值(取值1-255,数越大PWM频率越高)
    	TL0=210;     //写入预置值 (取值1-255,数越大PWM频率越高)
    	TR0=1;       //启动定时器
    	ET0=1;       //允许定时器0中断
    	EA=1;        //允许总中断
    	P1=0xff; 	 //初始化P1,输出端口
    	PWM_T=30;
    	while(1)      
    	{   	
    		if(!up)   //当up按键按下的时候
    		{
    			if(PWM_T<100)
    			{
    				PWM_T+=1;
    			}
    			delay_1ms(20);
    		}
    		if(!down)  //当down按键按下的时候
    		{
    			if(PWM_T>0)
    			{
    				PWM_T-=1;
    			}
    			delay_1ms(20);
    		}
    	 }  
    }
    
    timer0() interrupt 1  
    { 
    	t++;    //每次定时器溢出加1
    	if(t==100)   //PWM周期 100个单位
    	{
    		t=0;  //使t=0,开始新的PWM周期
    		P1=0x00;  //输出端口,使之低电平
    	} 
    	if(PWM_T==t)  //按照当前占空比切换输出为高电平
    	{  
    		P1=0xff;    //输出端口,使之高电平    
    	}
    }
    

    串口通信

    上面我们说了PWM调速,那么要达到app实时显示速度,就必须要单片机把速度传输给手机(在这里先用占空比模拟实时速度,道理是一样的,春节快递停了,测速模块还没到),那么我的首选方案肯定是单片机通过蓝牙串口发送给app,app接收并进行显示,这里我的蓝牙模块是hc-06。串口通信很容易,但在这个过程中我发现难的地方是数据格式的定义和数据的解析,也就是说要统一使用16进制,还是10进制,数据的头节点和尾节点的定义,或者说数据每一位所代表的参数,在这里先埋个伏笔,文章的后面会对我自己的方案进行介绍.

    Android蓝牙开发

    那么android为我们提供的关于蓝牙的api其实已经很强大了,通常的步骤为:

    1. 打开蓝牙
    2. 搜索蓝牙设备
    3. 进行配对
    4. 连接
    5. 数据的发送与接收

    开启蓝牙

    private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    /**
    * 打开蓝牙
    */
    public static void openBluetooth(@NonNull Activity activity) {
    	if (INSTANCE.bluetoothAdapter == null) {
                // 设备不支持蓝牙
                Toast.makeText(INSTANCE.context.getApplicationContext(), "您的设备似乎不支持蓝牙", Toast.LENGTH_SHORT).show();
                return;
    	}
    	Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    	activity.startActivityForResult(enableBtIntent, 6);
    }
    
    /**
    * 关闭蓝牙
    */
    public static void closeBluetooth() {
    	if (INSTANCE.bluetoothAdapter != null) {
    		INSTANCE.bluetoothAdapter.disable();
    	}
    }
    
    /**
    * 判断蓝牙是否打开
    * @return boolean 蓝牙是否打开
    */
    public static boolean isBluetoothOpen() {
    	return INSTANCE.bluetoothAdapter != null && INSTANCE.bluetoothAdapter.isEnabled();
    }
    

    搜索附近的蓝牙设备

    那么搜索蓝牙设备当然也是调用系统的api即可,然后系统通过广播接收者的方式告诉你,我找到设备了,下面po出代码

    /**
    * 搜索蓝牙设备
    */
    public static void searchDevices() {
    	INSTANCE.bluetoothDevices.clear();
    	if (INSTANCE.bluetoothAdapter != null) {
    		// 寻找蓝牙设备,android会将查找到的设备以广播形式发出去
    		INSTANCE.bluetoothAdapter.startDiscovery();
    	}
    }
    

    下面是所要接收的广播

    
        /**
         * 初始化过滤器
         */
        private void initIntentFilter() {
            // 设置广播信息过滤
            IntentFilter intentFilter = new IntentFilter();
            //搜索到设备
            intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
            intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
            intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
            //蓝牙状态改变
            intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
            //绑定状态改变
            intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
            // 注册广播接收器,接收并处理搜索结果
            registerReceiver(receiver, intentFilter);
        }
    

    那么当接收到广播的时候,只需调用BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)就可以取出对应的搜索的蓝牙设备

    蓝牙配对

     /**
         * 绑定设备
         *
         * @param device BluetoothDevice对象
         * @return 是否绑定成功
         */
        public static boolean bondDevice(BluetoothDevice device) {
            if (INSTANCE.bluetoothAdapter == null) {
                return false;
            }
            // 取消蓝牙设备搜索
            INSTANCE.bluetoothAdapter.cancelDiscovery();
            try {
                if (device.getBondState() == BluetoothDevice.BOND_NONE) {
                    // 设备未配对,进行配对操作
                    Method method = BluetoothDevice.class.getMethod("createBond");
                    method.invoke(device);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }
    

    蓝牙连接

    	BluetoothSocket socket;
    	//获取一个uuid值
    	UUID uuid = uuidCandidates.get(candidate++);
    	//根据android不同sdk调用不同的api
    	if (secure) {
    		socket= device.createRfcommSocketToServiceRecord(uuid);
    	} else {
    		socket= device.createInsecureRfcommSocketToServiceRecord(uuid);
    	}
    

    数据的发送与接收

    参考了网上很多关于蓝牙数据通信的做法,好多都是每发送一次数据都关闭socket,但是那样我觉得并不好,因为socket的开启与关闭都是比较耗费资源的,那么我的方案是开启一个线程保持socket连接进行蓝牙数据的接收与发送。

    public class TouchMsgThread extends Thread {
        private  BluetoothSocket socket;
        private  InputStream inputStream;
        private  OutputStream outputStream;
        private  Handler handler;
        public TouchMsgThread(BluetoothSocket socket, Handler handler) {
            this.socket = socket;
            InputStream input = null;
            OutputStream output = null;
            this.handler = handler;
            try {
                input = socket.getInputStream();
                output = socket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
            this.inputStream = input;
            this.outputStream = output;
        }
        public void run() {
            while (true) {
                try {
                    int count = 5;
                    byte[] bytes = new byte[count];
                    int readCount = 0; // 已经成功读取的字节的个数
    	              while (readCount < count) {
                        readCount += inputStream.read(bytes, readCount, count - readCount);
                   }
                    int s = BinaryToHexString(bytes);
                    Message message=handler.obtainMessage();
                    message.what = 333;
                    message.obj=s;
                    handler.sendMessage(message);
                } catch (Exception e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
        public void write(byte[] bytes) {
            try {
                byte[] b = {-1,1,2,3,-1};
                outputStream.write(b);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public void cancel() {
            try {
                if(outputStream!=null){
                    outputStream.close();
                    outputStream = null;
                }
                if(inputStream!=null){
                    inputStream.close();
                    inputStream = null;
                }
                //socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //数据的检验,这里暂时先忽略
        public static int BinaryToHexString(byte[] bytes) {
            int result = 0;
            String temp = "";
            for(int i=0;i<5;i++){
                byte b = bytes[i];
                if(i==2){
                    temp = Integer.toHexString((b & 0xff));
                }
                if(i==3){
                    String hex = Integer.toHexString((b & 0xff));
                    result = Integer.parseInt(temp+hex, 16);
                }
            }
            return result;
        }
    }
    

    单片机与Android的通信方案

    制定协议

    那么上面我们已经讲了单片机与Android怎么样通过蓝牙进行信息交互了,但是在实际应用中,二者之间传递的信息类型太多了,比如实时速度,电量,还有车子灯光打开,或者修改车子密码等等信息,那么单片机或者app要怎么去判断传递过来的是哪种信息呢?那么我们就必须去制定一套数据协议,这里看看我的方案,协议规定:

    包头 类型位 数据位 数据位 结束位
    0xFF 0x** 0x** 0x** 0xFF

    那么我们的数据位可以分别代表高二位和低二位,那么通常情况下这种方案就可以满足我们的需求了。举个例子:

    类型位 数据位 数据位 功能
    0X00 0X02 0X00 前进
    0X00 0X01 0X00 后退
    0X00 0X03 0X00 左转
    0X00 0X04 0X00 右转
    0X00 0X00 0X00 停止
    0X02 0x00 0X01 车灯亮
    0X02 0x00 0X02 车灯灭
    0X03 雷达数据高位 雷达数据低位 发送雷达数据

    协议的解析

    未完待续

    展开全文
  • 之前两篇都是在说与手机的连接,连接方法,主动配对连接,都是手机与手机的操作,做起来还是没问题的,但是最终的目的是与单片机的蓝牙模块的通信。   下面是到目前为止尝试的与单片机通信方法,没有成功,但是...

    之前两篇都是在说与手机的连接,连接方法,和主动配对连接,都是手机与手机的操作,做起来还是没问题的,但是最终的目的是与单片机的蓝牙模块的通信。

     

    下面是到目前为止尝试的与单片机的通信方法,没有成功,但是从思路上来说没有问题,最大的问题是与单片机配对的时候,单片机的蓝牙模块的PIN配对码是写死的,固定为1234,

    而手机这边连接配对都是自动生成的PIN配对码,这种方式在手机与手机配对的时候是极为方便的,但是在这里与单片机连接却成了最大的问题,因为手机自动生成而且每次都不一样,所以没法与单片机蓝牙模块的1234相同也就没法陪对了。下面只是介绍的到目前为止我们的大题思路,具体代码很多,而且涉及到项目也就没有贴。

    如果关于上面的问题哪位同学有思路或者做过类似的项目还请指点。

     

    首先,如何开启蓝牙设备和设置可见时间:

    private void search() {
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            if (!adapter.isEnabled()) {
                adapter.enable();
            }
            Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            enable.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600); //3600为蓝牙设备可见时间
             startActivity(enable);
            Intent searchIntent = new Intent(this, ComminuteActivity.class);
            startActivity(searchIntent);
        }


    正式开始与蓝牙模块进行通信

    public class ComminuteActivity extends Activity {
        private BluetoothReceiver receiver;
        private BluetoothAdapter bluetoothAdapter;
        private List<String> devices;
        private List<BluetoothDevice> deviceList;
        private Bluetooth client;
        private final String lockName = "YESYOU";
        private String message = "000001";
        private ListView listView;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.search_layout);
    
            listView = (ListView) this.findViewById(R.id.list);
            deviceList = new ArrayList<BluetoothDevice>();
            devices = new ArrayList<String>();
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            bluetoothAdapter.startDiscovery();
            IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
            receiver = new BluetoothReceiver();
            registerReceiver(receiver, filter);
    
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    setContentView(R.layout.connect_layout);
                    BluetoothDevice device = deviceList.get(position);
                    client = new Bluetooth(device, handler);
                    try {
                        client.connect(message);
                    } catch (Exception e) {
                        Log.e("TAG", e.toString());
                    }
                }
            });
        }
    
        @Override
        protected void onDestroy() {
            unregisterReceiver(receiver);
            super.onDestroy();
        }
    
        private final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case Bluetooth.CONNECT_FAILED:
                        Toast.makeText(ComminuteActivity.this, "连接失败", Toast.LENGTH_LONG).show();
                        try {
                            client.connect(message);
                        } catch (Exception e) {
                            Log.e("TAG", e.toString());
                        }
                        break;
                    case Bluetooth.CONNECT_SUCCESS:
                        Toast.makeText(ComminuteActivity.this, "连接成功", Toast.LENGTH_LONG).show();
                        break;
                    case Bluetooth.READ_FAILED:
                        Toast.makeText(ComminuteActivity.this, "读取失败", Toast.LENGTH_LONG).show();
                        break;
                    case Bluetooth.WRITE_FAILED:
                        Toast.makeText(ComminuteActivity.this, "写入失败", Toast.LENGTH_LONG).show();
                        break;
                    case Bluetooth.DATA:
                        Toast.makeText(ComminuteActivity.this, msg.arg1 + "", Toast.LENGTH_LONG).show();
                        break;
                }
            }
        };
    
        private class BluetoothReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (isLock(device)) {
                        devices.add(device.getName());
                    }
                    deviceList.add(device);
                }
                showDevices();
            }
        }
    
        private boolean isLock(BluetoothDevice device) {
            boolean isLockName = (device.getName()).equals(lockName);
            boolean isSingleDevice = devices.indexOf(device.getName()) == -1;
            return isLockName && isSingleDevice;
        }
    
        private void showDevices() {
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
                    devices);
            listView.setAdapter(adapter);
        }
    }

    这里需要提一下的是,startDiscovery()这个方法和它的返回值,它是一个异步方法,会对其他蓝牙设备进行搜索,持续时间为12秒。

    搜索过程其实是在System Service中进行,我们可以通过cancelDiscovery()方法来停止这个搜索。在系统搜索蓝牙设备的过程中,系统可能会发送以下三个广播:ACTION_DISCOVERY_START(开始搜索),

    ACTION_DISCOVERY_FINISHED(搜索结束)

    和ACTION_FOUND(找到设备)。

    ACTION_FOUND这个才是我们想要的,这个Intent中包含两个extra fields:    EXTRA_DEVICE和EXTRA_CLASS,

    包含的分别是BluetoothDevice和BluetoothClass

    EXTRA_DEVICE中的BluetoothDevice就是我们搜索到的设备对象,从中获得设备的名称和地址。

    EXTRA_CLASS中的BluetoothClass是搜索到的设备的类型,比如搜索到的是手机还是耳机或者其他,之后我会写一篇关于它的介绍

    在这个上面我现在在想,是否通过判断搜索到的设备类型来识别单片机蓝牙模块与手机蓝牙的不同,采取不一样的配对方式,从而不自动生成配对码。不知是否可行,一会尝试。

     

     搜索到该设备后,我们就要对该设备进行连接和通信。

    public void connect(final String message) {
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    BluetoothSocket tmp = null;
                    Method method;
                    try {
                        method = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                        tmp = (BluetoothSocket) method.invoke(device, 1);
                    } catch (Exception e) {
                        setState(CONNECT_FAILED);
                        Log.e("TAG", e.toString());
                    }
                    socket = tmp;
                    try {
                        socket.connect();
                        isConnect = true;
                    } catch (Exception e) {
                        setState(CONNECT_FAILED);
                        Log.e("TAG", e.toString());
                    }
    	       if (isConnect) {
                        try {
                            OutputStream outStream = socket.getOutputStream();
                            outStream.write(getHexBytes(message));
                        } catch (IOException e) {
                            setState(WRITE_FAILED);
                            Log.e("TAG", e.toString());
                        }
                        try {
                            InputStream inputStream = socket.getInputStream();
                            int data;
                            while (true) {
                                try {
                                    data = inputStream.read();
                                    Message msg = handler.obtainMessage();
                                    msg.what = DATA;
                                    msg.arg1 = data;
                                    handler.sendMessage(msg);
                                } catch (IOException e) {
                                    setState(READ_FAILED);
                                    Log.e("TAG", e.toString());
                                    break;
                                }
                            }
                        } catch (IOException e) {
                            setState(WRITE_FAILED);
                            Log.e("TAG", e.toString());
                        }
                    }
    
                    if (socket != null) {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            Log.e("TAG", e.toString());
                        }
                   }
           }
    }

     这里包括写入和读取,用法和基本的Socket是一样的,但是写入的时候,需要将字符串转化为16进制:

    private byte[] getHexBytes(String message) {
            int len = message.length() / 2;
            char[] chars = message.toCharArray();
            String[] hexStr = new String[len];
            byte[] bytes = new byte[len];
            for (int i = 0, j = 0; j < len; i += 2, j++) {
                hexStr[j] = "" + chars[i] + chars[i + 1];
                bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);
            }
            return bytes;
        }


     

    连接设备之前需要UUID,所谓的UUID,就是用来进行配对的,全称是Universally Unique Identifier,是一个128位的字符串ID,用于进行唯一标识。网上的例子,包括谷歌的例子提供的uuid,通用的"00001101-0000-1000-8000-00805F9B34FB"也试过了,在配对的时候都是自动生成了配对码,也无法正常与单片机的蓝牙模块连接,所以,我就利用反射的原理,让设备自己提供UUID尝试。到这里其实我有点怀疑自己对于UUID的理解是否正确了。

                在谷歌提供的例子中,我们可以看到谷歌的程序员的程序水平很高,一些好的编码习惯我们可以学习一下,像是在try..catch中才定义的变量,我们应该在try...catch之前声明一个临时变量,然后再在try...catch后赋值给我们真正要使用的变量。这种做法的好处就是:如果我们直接就是使用真正的变量,当出现异常的时候,该变量的使用就会出现问题,而且很难进行排查,如果是临时变量,我么可以通过检查变量的值来确定是否是赋值时出错。

       

    作者:jason0539

    微博:http://weibo.com/2553717707

    博客:http://blog.csdn.net/jason0539(转载请说明出处)

    展开全文
  • android手机接收并波形图显示单片机通过蓝牙传输的传感器数据
  • 实现Android手机通过蓝牙控制51单片机小车 #一、材料: 1.stc51单片机最小系统板(最好带上拉电阻); 2.HC-02蓝牙芯片; 3.蓝牙小车,带驱动; 4.充电宝; 5.Android手机及app; #二、硬件连接 1.把小车...

    基于51单片机与Android手机通信的android蓝牙小车

    (班门弄斧,请各位大神批评指正,烦请提出宝贵意见。)
    整车图片

    #一、材料:

    1.stc51单片机最小系统板(最好带上拉电阻);

    2.HC-02蓝牙芯片;

    3.减速电机,电机驱动;

    4.充电宝(感谢刘帆同学赞助的充电宝);

    5.车架是自己设计,3D打印出来的,打印件下载

    5.Android手机及app,APP下载

    部分零件

    减速电机

    二、硬件连接

    1.把小车电机驱动上的四根控制线接在单片机4个IO口上;

    2.把HC-02的rxd接在单片机的txd上,txd接在单片机的rxd上;

    3.把单片机、HC-02、小车电机驱动的电源线接在充电宝输出上;

    4.把码盘(用于测速)上的GND、VCC连上电源,输入连在51单片机的IO 口上;

    4.给单片机烧程序;

    5.打开Android手机扫描蓝牙,连接测试;

    6.手机控制小车。
    #三、调试过程及相关代码

    1.调试HC-02蓝牙芯片(买的时候店家会送调试程序及教程);

    2.调试单片机蓝牙通信;

    (1).扫描,连接,键盘模式。

    (2).右上角三点,设定IO模式,接收:hex字符串,发送:hex字符串。

    (3).配置键盘值(发送给蓝牙芯片的字符串就是这个);

    (4).前进(1A),长按(1A),释放(DD)

    (5).左转(1B),长按(1B),释放(DD)

    (6).后退(1F),长按(1F),释放(DD)

    (7).右转(1C),长按(1C),释放(DD)

    (8).刹车(DD),长按(DD),释放(DD)
    3.相关代码

    /*
    程序名称: 蓝牙手机遥控小车
    功能原理: 利用智能手机app连接HC-02蓝牙芯片实现蓝牙串口通信,
               利用stc51单片机控制电机驱动模块驱动小车 。
    扩展功能:循迹、避障等。
    */
    #include "reg52.h"    //此文件中定义了单片机的一些特殊功能寄存器
    #define time_0 5
    typedef unsigned int u16;	  //对数据类型进行声明定义
    typedef unsigned char u8;
    
    sbit output_date1=P2^7;
    sbit output_date2=P2^6;
    sbit output_date3=P2^5;
    sbit output_date4=P2^4;
    sbit STA=P1^0;
    
    #define GO_STAIGHT  {output_date1=1,output_date2=0,output_date3=1,output_date4=0;}	        //前进
    #define GO_BACK     {output_date1=0,output_date2=1,output_date3=0,output_date4=1;}			//后退
    #define TURN_RIGHT	{output_date1=0,output_date2=1,output_date3=1,output_date4=0;}		    //右转
    #define TURN_LEFT   {output_date1=1,output_date2=0,output_date3=0,output_date4=1;}		    //左转
    #define STOP_CAR    {output_date1=0,output_date2=0,output_date3=0,output_date4=0;}			//停车
    
    
    #define USART_MAX_RECV_LEN	40
    u8 USART_RX_BUF[USART_MAX_RECV_LEN];
    u16 USART_RX_STA=0; 
    
    void delay(u16 n);
    void UsartInit();
    void USART_SendData();
    
    
    
    void delay(u16 n)   //1ms   (误差 -0.651041666667us)
    {
       u16 i ;
        unsigned char a,b;
    	for(i=1;i<=n;i++)
    	{
        for(b=102;b>0;b--)
            for(a=3;a>0;a--);
    	}
    }
    
    
    void UsartInit()
    {
    	SCON=0X50;			//设置为工作方式1
    	TMOD=0X20;			//设置计数器工作方式2
    	PCON=0X80;			//波特率加倍
    	TH1=0XFa;			//计数器初始值设置,注意波特率是9600的
    	TL1=0XFa;
    	ES=1;						//打开接收中断
    	EA=1;						//打开总中断
    	TR1=1;					//打开计数器
    }
    
    void USART_SendData(u8 datbuf[])
    {
    	u8 i=0;
    	for(i=0;i<1;i++)
    	{
    		SBUF=datbuf[i];//将接收到的数据放入到发送寄存器
    		while(!TI);//等待发送数据完成
    		TI=0;//清除发送完成标志位	
    	}
    }
    
    
    void main()
    {	u8	date_get=0;
    	STA=0;
    	UsartInit();  //串口初始化
    
    	
    	while(1)
    	{
    		
    		date_get=USART_RX_BUF[0];
    		switch(date_get)
    		{
    			case 0x1B:				//左转
    					 		  
    					TURN_LEFT;		
    					USART_SendData(USART_RX_BUF);
    					 delay(time_0);
    
    					break;	
    			case 0x1A:				 //前进		  
    				    GO_STAIGHT;					
    					USART_SendData(USART_RX_BUF); 
    					delay(time_0);
    					break;
    			case 0x1F:				 //后退
    						  
    				    GO_BACK;
    					USART_SendData(USART_RX_BUF); 
    					delay(time_0);
    					break;
    			case 0x1C:				 //右转			  
    					TURN_RIGHT;
    					USART_SendData(USART_RX_BUF); 
    					delay(time_0);
    					break;
    			case 0xDD:
    							  //停
    					STOP_CAR;
    					USART_SendData(USART_RX_BUF); 
    					delay(time_0); 
    					STOP_CAR;
    				
    		}
    	            	STOP_CAR;  
    	}		
    }
    
    void Usart() interrupt 4		//串口中断
    {
    	u8 res;
    	res=SBUF;
    	USART_RX_BUF[0]=res;
        RI=0;//清除接收中断标志位	
    								 
    }
    
    
    展开全文
  • 刚好碰到这蓝牙通信方面的项目,上网也看过其他人在蓝牙这方面写的博客,但大多都不全,给一些初触蓝牙的开发者造成一定的麻烦,自己当初也费了不少劲。所以把自己参考网上的一些资料用Android studio写的代码完全放...
  • 就是手机收到其他设备发来的一个消息,然后手机就可以播放铃声,也就是事件触发
  • 先简单说说情景:软件需要给硬件设备的单片机发送一串byte数组,用于打开软件与硬件设备之间的通讯通道,软件命令发送完,接着就打开一个线程用于接收从硬件设备回传的数据,然后开始做其他的一些操作。但是现在出现...

    前段时间一直在加班,单身狗的周末也搭进去了…只是为了解决一个莫名其妙的bug,不过最终bug还是拜倒在了朕的强大气场下,哈哈哈,现在就在这里好好吐槽下软件遇上硬件的坑;

    先简单说说情景:软件需要给硬件设备的单片机发送一串byte数组,用于打开软件与硬件设备之间的通讯通道,软件命令发送完,接着就打开一个线程用于接收从硬件设备回传的数据,然后开始做其他的一些操作。但是现在出现的问题是命令发送了,会出现偶尔接收不到数据,刚开始还以为是硬件部门的问题,请硬件部门的人过来协助,结果发现软件发送的指令单片机也是接收到了的,那么是我写的程序有问题?NO~

    中间的各种脑残调试,这里就不细说了,说说最终得到的分析结果:从软件发送指令到单片机接收到指令,其实是需要时间的,至于这个时间大概在两百毫秒以内,而软件在发送了这段指令之后,就直接执行后面的接收操作,但是这个时候单片机有可能还没有接收到软件发送的指令,通道没有打开,而我的程序已经在开始读取数据了(读个鬼啊,什么都没有),这样就造成了我的操作界面一直处于等待的状态…那为什么有时候又可以读取到数据了?因为从发送数据到单片机接收数据,这个时间不可控的,为什么不可控,这里我猜测跟系统资源及单片机内的程序有关,这种情况就好像当电脑内存紧张时,软件运行速度会降低一样(当然这种情况要毕竟很少),而单片机程序部分如果接收到指令后还做了其他耗时操作这个也是有可能的…知道了原因,那么在程序发送命令后,就简单粗暴的强制线程睡眠一秒Thread.sleep(200),其实这种方法,依然存在问题,正确的最好的办法是让单片机在接收到我发出的命令后返回一个响应(但是要跟硬件部门沟通了~~~)

    展开全文
  • android 使用串口Modbus协议和单片机进行通信  我所使用的232串口,使用485串口的请慎重,这232串口485还是不一样的,这里所说的是232串口通信。 首先你需要导入架包一些必要文件,在最后会附上图片源码,...

    android 使用串口Modbus协议和单片机进行通信

     我所使用的232串口,使用485串口的请慎重,这232串口和485还是不一样的,这里所说的是232串口通信。

    首先你需要导入架包和一些必要文件,在最后会附上图片和源码,这里简单说一下通信的步骤。

      1、使用SerialPortOpt创建对象,然后设置相关数据的初始值:串口号、波特率、数据位,校验位等(来这里看资料的,相信对这些名词有了一定了解,这里不做赘述);

      

    serialPort=new SerailPortOpt();
    		serialPort.mDevNum=0;
    		serialPort.mDataBits=8;
    		serialPort.mSpeed=9600;
    		serialPort.mStopBits=1;
    		serialPort.mParity='n';

     2、打开串口,设置相关参数,并获取输入输出流;

    serialPort.openDev(serialPort.mDevNum);
    			//需要先打开串口在设置相关参数
    			serialPort.setSpeed(serialPort.mFd, serialPort.mSpeed);
    			serialPort.setParity(serialPort.mFd,serialPort.mDataBits,
    					serialPort.mStopBits, serialPort.mParity);
    			//获得输入、输出流
    			mInputStream = serialPort.getInputStream();
    			mOutputStream = serialPort.getOutputStream();

    3、开启线程接收数据;

    /*
    	 * 开启线程接收数据
    	 */
    	private class ReadThread extends Thread{
    		byte[] buf = new byte[512];
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			super.run();
    			if (mInputStream == null){
    				return;
    			}//判断接收的数据是否为空,若为null之后返回继续接收
    			//	mTimer.stopThread();//接收到数据,循环发送的线程stop————————————————————————————
    			int size;
    			size = serialPort.readBytes(buf);
    			if(size>0){
    				byte[] dest = new byte[size];
    				byteLinkedList.offer(dest);//使用队列接收数据
    				/*System.arraycopy(buf, 0, dest, 0, size);//复制数组***********
    				System.out.println("在真正数据之前");
    				for(byte dest1:dest){
    					System.out.println("刚接手到的数据"+dest1);
    				}
    				 */
    				onDataReceived();
    			}
    		}

    4、开启线程发送数据;

    /*
    	 * 开启发送线程
    	 */
    	private class SendThread extends Thread{
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			super.run();
    			sendMsg();
    		}
    	}
    

    5、关闭串口。

    serialPort.closeDev(serialPort.mFd);

      串口中的循环发送线程

    /*
    	 * 定时连续发送的线程
    	 */
    	private class TimerSend extends Thread{
    		private long m_lTimer = 50;	//default 100ms
    		private boolean m_bRunFlag = true;
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			super.run();
    			while (m_bRunFlag){
    				sendMsg();
    				if (m_lTimer <= 0){			//must over 0ms
    					m_lTimer = 50;
    				}
    				try {
    					Thread.sleep(m_lTimer);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    <span style="font-size:18px;">这些过程中涉及的方法并没有说明,不过可以知道了大体的思路,也算是对串口有了一定的了解,但是这些并没有涉及到Modbus协议,Modbus协议是很重要且很简单的协议,网上有很对介绍,若果有找不到的朋友,我这里附上一份Modbus协议的介绍,中文版的。对于modbus协议,收发机制要明白,一些东西都是和单片机规定好的,需要写死,具体做法我还在摸索中,不过我可以简单做到单片机发送的数据可以读取并解析,这里包括CRC的校验,对发送数据的CRC计算和返回数据的CRC校验,在串口助手中可以试验成功。这些可以看我的源码了。  下面附上开头所说的一些照片,很容易明白了</span>

    Modbus协议介绍中文版

    我的源码

    有错就找我

    这里的源码已经删除了,可以去看另一篇文章,里面也有源码,比这感觉更好一些。网址:http://blog.csdn.net/sky_918/article/details/52807436

    
    展开全文
  • 目录说在前面说明关键代码结果 说在前面 单片机:HC6800-ES,晶振12MHz 蓝牙模块:BT08(兼容HC-06、HC-05) ...该App功能为通过蓝牙接收...主要是接收发送数据,在参考的代码里面设置了数据格式,有些东西我...
  • Android通过串口向单片机发送一条16进制的指令,单片机收到以后会返回一条相同格式的命令。Android与PC上的串口助手调试,可以正确收发数据;单片机与串口助手调试,也可以正确收发数据。但是Android直接与单片机...
  • 最近辛辛苦苦的终于把落下了七八个月的Android蓝牙开发搞完了,其中的痛苦不堪回首啊。感谢那些帮了大忙的老师同学们!辛苦归辛苦,收获总是有的,因而在此总结一下关键所在,以勉励自己!  网上说的好多的...
  • 这次期末的课程设计做了一个智能灯光控制系统,系统整体的功能不在此赘述,系统主要是要实现下位机同上位机的通信,上位机选用的是Android手机端,下位机是52单片机,通过蓝牙模块实现通信。虽然系统很简单,但还是...
  • 今天调试了一下Android的串口程序,能够实现与PC端的串口收发,数据解析均没有问题,同时编写了单片机的串口收发程序,与PC端通信没有问题; 现把单片机的9针串口与Android的9针串口用串口线连接,无法通信单片机...
  • Android app实现与单片机的TCP通信 一、main activity layout layout 截图如上 二、main activity.java (一)需要用到的相关知识 1、socket 2、handler 3、onClickListener 4、Thread (二)主要代码实现 ...
  • 本篇只要是实现与51单片机通信功能,所以我想要尽量的简化一下。话不多说上代码! //先是ui线程的部分 这部分主意是监听控件 蓝牙的连接需要单独写一个线程 //此部分代码只是截取 缺少的部分都可以脑补的出来。。...
  • 1、Android蓝牙编程  蓝牙3.0及以下版本编程需要使用UUID,UUID是通用唯一识别码(Universally Unique Identifier),这是一个软件构建的标准,也是被开源基金会组织应用在分布式计算环境领域的一部分。在蓝牙3.0...
  • 《安卓与单片机进行usb hid通信》https://blog.csdn.net/Alone_1314/article/details/70242396 百度经验里的: 《android如何支持hid设备》https://jingyan.baidu.com/article/6b182309f19265ba58e159b7.html .....
1 2 3 4 5 ... 20
收藏数 2,602
精华内容 1,040