2014-04-10 15:47:58 gaixm 阅读数 8741
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3398 人正在学习 去看看 朱有鹏

        概述:

           手机端打开编写的蓝牙通信软件,与单片机端蓝牙串口模块连接,而后,手机通过蓝牙发送读数据命令到单片机,单片机开始读取传感器信息,

将采集到得传感器信息通过蓝牙发送到手机端,手机端软件接收到后,显示。

       整体图:

        

       

      焊接板图:

     



        本项目涉及四个部分。

   一、手机端软件

   二、单片机端编程

   三、外设电路设计

   四、手机与单片机通信

     下面对四个部分进一步叙述。

  1、手机端软件

      手机端软件为安卓软件,只需要编写一个普通的蓝牙串口调试软件即可。但在编写手机端按安卓软件时,我利用一年前做安卓手机通

过蓝牙远程控制指纹识别器的源码改进,但却始终不能接收到蓝牙串口模块发送的数据。也就是说,手机可以给下位机发送信息,下位机成功接收,

但是却接收不到下位机上传的信息。我很是疑惑,我以为是蓝牙串口模块的问题,于是换了一个,结果还是一样。我一直坚信去年的源码没有问题,

但是却查不出原因在哪里。于是,我在相应的安卓蓝牙编程的书本上,找到讲解蓝牙部分的章节,按照步骤重新编写带代码,结果双向通信可以调通。

先前的问题正在研究之中,下面是正常运行源码中的部分代码:

  (1)蓝牙连接代码

 //接收活动结果,响应startActivityForResult()
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    	switch(requestCode){
    	case REQUEST_CONNECT_DEVICE:     //连接结果,由DeviceListActivity设置返回
    		// 响应返回结果
            if (resultCode == Activity.RESULT_OK) {   //连接成功,由DeviceListActivity设置返回
                // MAC地址,由DeviceListActivity设置返回
                String address = data.getExtras()
                                     .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
                // 得到蓝牙设备句柄      
                _device = _bluetooth.getRemoteDevice(address);
 
                // 用服务号得到socket
                try{
                	_socket = _device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));
                }catch(IOException e){
                	Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
                }
                //连接socket
            	Button btn = (Button) findViewById(R.id.Button03);
                try{
                	_socket.connect();
                	Toast.makeText(this, "连接"+_device.getName()+"成功!", Toast.LENGTH_SHORT).show();
                	btn.setText("断开");
                }catch(IOException e){
                	try{
                		Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
                		_socket.close();
                		_socket = null;
                	}catch(IOException ee){
                		Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
                	}
                	
                	return;
                }
                
                //打开接收线程
                try{
            		is = _socket.getInputStream();   //得到蓝牙数据输入流
            		}catch(IOException e){
            			Toast.makeText(this, "接收数据失败!", Toast.LENGTH_SHORT).show();
            			return;
            		}
            		if(bThread==false){
            			ReadThread.start();
            			bThread=true;
            		}else{
            			bRun = true;
            		}
            }
    		break;
    	default:break;
    	}
    }
    
 
(2)手机蓝牙发送数据代码
 //发送数据线程
    public class SendThread extends Thread{
    	public void run(){
    		int i=0;
        	int n=0;
        	try{
        		OutputStream os = _socket.getOutputStream();   //蓝牙连接输出流
        		byte[] bos = edit0.getText().toString().getBytes();
        		for(i=0;i

  (3)手机蓝牙接收数据代码
//接收数据线程
    Thread ReadThread=new Thread(){
    	
    	public void run(){
    		int num = 0;
    		byte[] buffer = new byte[1024];
    		byte[] buffer_new = new byte[1024];
    		int i = 0;
    		int n = 0;
    		bRun = true;
    		//接收线程
    		while(true){
    			try{
    				while(is.available()==0){
    					while(bRun == false){}
    				}
    				while(true){
    					num = is.read(buffer);         //读入数据
    					n=0;
    					
    					String s0 = new String(buffer,0,num);
    					fmsg+=s0;    //保存收到数据
    					for(i=0;i

   
  2、单片机端
       单片机采用Arduino开发板,因其简单易学。
       单片机端的代码比较简单,是一些对应的传感器采集数据代码和串口通讯代码。

  3、外设焊接。
    外设有两个传感器,一个蓝牙串口模块。
    蓝牙串口模块负责蓝牙通信,传感器负责采集信息。
   
  4、手机与单片机通信
    首先,约定一个命令 符,当单片机端接收到手机端发送的命令符时,即开始采集传感器信息,将采集到得信息进行加工,然后传给
安卓手机。安卓手机接收数据后,随即显示出来。

   做成此项目用了三天时间,其中两天时间纠结与蓝牙单向通信问题,一直没有眉目。
剩下一天用半天调通手机端蓝牙串口调试软件,半天焊接电路板,写Arduino端程序,连接布线等。



2015-06-02 14:26:10 renqian1991 阅读数 3468
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3398 人正在学习 去看看 朱有鹏

                转载请注明出处。

                这次是一个课程设计,利用单片机开发一个物联网系统。我们利用了手机蓝牙与单片机板子上的蓝牙通信,通过 控制信号来控制单片机上led灯的亮灭和定时。

 网上有很多的搜索蓝牙的例程,大家可以自己去看,由于本次我们是与特定的设备连接,因此直接使用Mac地址连接,不在使用搜索功能,当然如果大家采用搜索到设备后在连接也可以。我们将蓝牙连接和数据收发放在一个service中,由于蓝牙socket读是阻塞的,因此我们新开一个线程专门用于接收板子的信号。

             在service的onCreate()方法中,我们连接指定的蓝牙,并获得其io流,在新开一个线程用于socket读。

            记得在mk文件中给该service添加intent-filter。

            

	/**
	 * 服务初始化
	 */
	@Override
	public void onCreate() {
		// TODO 自动生成的方法存根
		initBluetooth();
		super.onCreate();
	}

        /**
	 * 初始化蓝牙适配器
	 */
	public void initBluetooth(){
		bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
		if(bluetoothAdapter==null){//等于null时通知主界面,设备不支持蓝牙
			
			Intent intent = new Intent();
			intent.setAction(Constants.ERROR);
			sendBroadcast(intent);
		}else {
			if(!bluetoothAdapter.isEnabled())//蓝牙未开启时,开启蓝牙
		{
			bluetoothAdapter.enable();
		}
		connectDevice();
	}
	}
	
	/**
	 * 链接设备
	 */
	private void connectDevice(){
		device = bluetoothAdapter.getRemoteDevice(Constants.ADDRESS);//输入要连接的蓝牙的Mac地址,在说明书上可以查到
		if(device==null){//为空,连接失败
			
			Intent intent = new Intent();
			intent.setAction(Constants.ERROR);
			sendBroadcast(intent);
			
		}else {
			
			
			try {
			
				socket = device.createRfcommSocketToServiceRecord(Constants.MY_UUID);//uuid,一般为00001101-0000-1000-8000-00805F9B34FB
				socket.connect();//获得socket接口
				inputStream = socket.getInputStream();//获得输入流,另起线程监听输入
				receiveThread = new ReceiveThread(inputStream);
                new Thread(receiveThread).start();
	            outputStream = socket.getOutputStream();
				Intent intent = new Intent();//发送广播,已连接
				intent.setAction(Constants.CONNECTED);
				sendBroadcast(intent);
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			
			}
		}
		
	}
	

	/**
	 * 接收反馈信号的线程
         * 判断反馈信号,更新主界面ui
	 * @author qian ren
	 *
	 */
	class ReceiveThread implements Runnable{
		
		InputStream in;
		int msg;
       public ReceiveThread(InputStream in){
    	   this.in=in;
       }
		@Override
		public void run() {
			// TODO 自动生成的方法存根
			while(true){
				try {
					msg=in.read();
					System.out.println("msg: "+msg);
					switch (msg) {
					case 1://发送广播,台灯打开
						Intent intentOn = new Intent();
						intentOn.setAction(Constants.ON);
						sendBroadcast(intentOn);
						break;
                    
					case  2://发送广播,台灯关闭
						Intent intentOff = new Intent();
						intentOff.setAction(Constants.OFF);
						sendBroadcast(intentOff);
						break;
						
					case 3://发送广播,定时完成
						Intent intentTimer = new Intent();
						intentTimer.setAction(Constants.TIMER);
						sendBroadcast(intentTimer);
						break;
						
					default:
						break;
					}
				} catch (IOException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
			}
		}
		
	}

 初始化完成后,在onStartCommond()方法中发送控制信号给板子。


	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO 自动生成的方法存根
		
		String control;
	   control = intent.getStringExtra("control");
	   if(control.equals("on")){//打开台灯
		   byte [] buffer = new byte[]{1,25,1,2};
		   try {
			outputStream.write(buffer);
			outputStream.flush();
			System.out.println("on");
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	   }else if (control.equals("off")) {//关闭台灯
		   byte [] buffer = new byte[]{1,26,1,2};
		   try{
		   outputStream.write(buffer);
			outputStream.flush();
			System.out.println("off");
		   }catch(IOException e){
			   e.printStackTrace();
		   }
			
		}else if (control.equals("timer")) {//定时
			byte hour = (byte) intent.getIntExtra("hour",0);
			byte minute = (byte) intent.getIntExtra("minute",1);
			byte [] buffer =new byte[]{1,hour,minute,2};
			
			try{
		
			outputStream.write(buffer);
			outputStream.flush();
			System.out.println("timer");
		}catch(IOException e){
			e.printStackTrace();
		}
		}
	
	
		return super.onStartCommand(intent, flags, startId);
	}
  现在,service已经写完了,我们再来写主界面,主界面有一个Switcher来转换灯的开关状态,并有一个按钮可以跳转到另一个activity实现定时。还有一个imageview通过不断更换背景来展示灯的亮灭。如图所示




下面是关灯开灯的逻辑实现,通过启动service来实现信号的发送。

首先是连接设备:

/**
	 * 链接设备
	 */
	private void connectDevice() {
		// TODO 自动生成的方法存根
	Intent intent = new Intent();
	intent.setAction(Constants.LAMP_SERVICE);
	intent.putExtra("control", "connect");
	startService(intent);
	}


然后在switcher的状态改变回调方法中,实现开关控制

class SwitchChangedListener implements OnCheckedChangeListener{

		@Override
		public void onCheckedChanged(CompoundButton buttonView,
				boolean isChecked) {
			// TODO 自动生成的方法存根
			if(isChecked){
				
				Intent intent = new Intent();
				intent.setAction(Constants.LAMP_SERVICE);
				intent.putExtra("control", "on");
				startService(intent);
			}else {
				
				Intent intent = new Intent();
				intent.setAction(Constants.LAMP_SERVICE);
				intent.putExtra("control", "off");
				startService(intent);
			}
		}
		
	}


发送消息后必然会接受到反馈,我们用broadcastreceiver来接受service收到的反馈信号。记得在oncreate方法中绑定receiver。

/**
	 * 更新界面的broadcastreceiver
	 * @author qian ren
	 *
	 */
	class UpdateUiReceiver extends BroadcastReceiver{

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO 自动生成的方法存根
			String action = intent.getAction();
			if(action.equals(Constants.CONNECTED)){
				progressBar.setVisibility(View.INVISIBLE);
				ToastDisplay("台灯已经连接");
				System.out.println("device has been connected");
			}else if (action.equals(Constants.ERROR)) {
				progressBar.setVisibility(View.INVISIBLE);
				ToastDisplay("未连接到台灯,请检查设备");
				System.out.println("device can't connect");
			}else if (action.equals(Constants.ON)) {
				background.setImageResource(R.drawable.lamp_on);
				ToastDisplay("台灯已经打开");
				System.out.println("lamp on");
			}else if (action.equals(Constants.OFF)) {
				background.setImageResource(R.drawable.lamp_off);
				ToastDisplay("台灯已经关闭");
				System.out.println("lamp off");
			}else if (action.equals(Constants.TIMER)) {
				background.setImageResource(R.drawable.lamp_on);
				ToastDisplay("台灯将在"+hour+"小时"+minute+"分后自动关闭  ");
				System.out.println("timing has been finished");
			}
		}
		
	}
定时功能在另一个activity中实现,通过点击闹钟图标跳到另一个activity。


定时功能比较简单,使用timerpicker。




首先监听timechange的回调方法得到定时的时间。

public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
		// TODO 自动生成的方法存根
		this.hour = hourOfDay;
		this.minute = minute;
	}
然后在点击确定键时将信号发送给service。

public void onClick(View v) {
		// TODO 自动生成的方法存根
		if(hour==0){
			hour=countDown.getCurrentHour();
		}else if (minute==0) {
			minute=countDown.getCurrentMinute();
		}
		Intent intent = new Intent();
		intent.setAction(Constants.LAMP_SERVICE);
		intent.putExtra("control", "timer");
		intent.putExtra("hour", hour);
		intent.putExtra("minute", minute);
		startService(intent);
		
		Intent intentBack = new Intent();
		intentBack.putExtra("hour", hour);
		intentBack.putExtra("minute", minute);
		TimerActivity.this.setResult(Constants.RESPONSE,intentBack);
		this.finish();
	}
上面的setresult是为了在主界面得到设置的时间,进而刷新UI,因此主界面可以使用startactivityforresult来启动该定时界面。

	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO 自动生成的方法存根
		if(requestCode==Constants.REQUEST && resultCode ==Constants.RESPONSE){
			hour = data.getIntExtra("hour", 0);
			minute = data.getIntExtra("minute", 1);
		}
	}



2018-05-02 22:11:29 dok12 阅读数 10628
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3398 人正在学习 去看看 朱有鹏

打算利用蓝牙芯片HC06实现手机和单片机之间的简单通信。工具包括淘宝上淘的stc单片机实验板一块,hc-06蓝牙模块一个,杜邦线,win7电脑一部,安卓手机一部,相关软件:单片机小精灵,串口通讯助手,keil以及单片机烧录软件,蓝牙通讯软件APP。软件基本上都是免安装直接运行的。

工作流程简单总结下为以下3步:
1.利用单片机小精灵软件,做好烧录程序,确定波特率应该设置为2400
2.hc-06蓝牙模块进入AT模式,串口通讯助手成功将蓝牙模块波特率设置为2400
3.将烧录程序通过keil编译成功后烧录至单片机实验板上,手机上安装好APP,设置完成后运行,确定成功。

步骤(2)见


https://blog.csdn.net/dok12/article/details/80152239
步骤(3)见
https://blog.csdn.net/dok12/article/details/801730

本篇先介绍步骤1。工具,单片机小精灵软件,免安装,直接运行。

打开单片机小精灵软件,选择串口波特率选项。必须选择好晶振和波特率。其他选项,c语言还是汇编,是否串口中断,波特率加倍,允许接收都自己决定。
因为淘宝买到的单片机实验板是12M晶振,蓝牙模块的默认波特率是9600。所以一开始输入这两项数据。
结果发现误差太大,必须修改。晶振改不了,只好改波特率了。
修改波特率为2400后误差控制在千分之一点六,效果不错,得到了一个C语言的串口通信基本框架了。

根据这个框架做了个C语言程序,目标是对单片机实现蓝牙通讯,实现不同的单片机流水灯效果,并且得到回复数字8。
#include <reg51.h>
unsigned char k;
void InitUART(void)
{
    TMOD = 0x20;
    SCON = 0x50;
    TH1 = 0xF3;
    TL1 = 0xF3;
    PCON = 0x00;
    EA = 1;
    ES = 1;
    TR1 = 1;
}
/*******延时函数*************/
void delay(unsigned int i)
{
    unsigned char j;
    for(i; i > 0; i--)   
        for(j = 255; j > 0; j--);
}
void main(void)
{	k=0;
    InitUART();
	while  (1){
	if(k==1)
	{P1=0xff;delay(500);P1=0x00;delay(500);}
	else if (k==2)
	{P1=0x01;delay(500);P1=0xfe;delay(500);}
	else 
	{P1=0x02;delay(500);P1=0xfd;delay(500);}
	}
}
void SendOneByte(unsigned char c)
{
    SBUF = c;
    while(!TI);
    TI = 0;
}

void UARTInterrupt(void) interrupt 4
{
    if(RI)
    {
        RI = 0;
        //add your code here!
		k++;
		if(k>2)k=0;
		SendOneByte(8);
    }
    else
        TI = 0;
}






2018-08-01 14:39:28 qq_42246939 阅读数 145
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3398 人正在学习 去看看 朱有鹏

这一篇是代码篇之蓝牙连接,主要讲如何开启蓝牙,搜索蓝牙设备,连接蓝牙设备。

  •     大致的步骤就是,首先是权限,用到蓝牙的那些权限就那几个,但是要特别注意的是在android7.0的系统上,如果要用到蓝牙,必须加入地理位置授权(谷歌那边的规定),然后我们注册广播,来监视我们需要的广播,比如BluetoothDevice.ACTION_FOUND,这条广播就是我们开启蓝牙搜索的时候,一些被我们发现的蓝牙就会自动发送这条广播,然后我们通过监视这条广播来得到这些被发现的蓝牙。也就是说我们首先要注册蓝牙广播,然后创建一个蓝牙接收器来监视一些我们要的广播。最后我们在ListView表上选择我们要连接的蓝牙设备,点击连接,这也就是列表点击事件来处理啦。

实战部分----------------------------------------------------------------------------------------------------------

首先定义一些我们需要用到的变量(包括后面我们发送数据那一篇文章也需要用到)

private BluetoothAdapter bluetoothAdapter;    //本地蓝牙适配器
private BluetoothSocket bluetoothSocket;
private BluetoothDevice bluetoothDevice;
private BlueReceiver blueReceiver;
private Button send;
private List <String> list =new ArrayList<>();
private ListView listView;
private EditText editText;
private ArrayAdapter<String> adapter;
private final UUID MY_UUID = UUID
        .fromString("00001101-0000-1000-8000-00805F9B34FB");
private final String NAME = "Bluetooth_Socket";
private IntentFilter filter;

一:首先我们的想法是在菜单上面的蓝牙连接按钮上实现蓝牙开启,蓝牙搜索,加载布局,然后在列表上实现连接功能。

 ①:首先显示菜单

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main,menu);
    return true;
}

②:菜单点击事件

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.bluetooth) {
        if (!bluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, 200);
            //
        }
        bluetoothPermissions();//地理位置授权
        bluetoothAdapter.startDiscovery();//蓝牙开始搜索
        setContentView(R.layout.bluetooth);//加载RecycleView布局
        listView = findViewById(R.id.list_item1);
        listView.setOnItemClickListener(this);//列表点击事件
    }
    return  true;
}

首先,我们开启蓝牙,需要各种权限,在文件中AndroidManifest.xml中加入权限,如下:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

在这里要注意的是,在Android7.0版本后,我们蓝牙搜索的前提是要添加一个关于地理位置的权限(上面代码的bluetoothPermissions()就是地理位置授权方法 

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

③:注册蓝牙广播

     注册蓝牙广播接收器,我们可以在onStart()方法中实现,也是在打开这个程序的时候实现蓝牙注册。代码如下: 

@Override
   protected void onStart() {
       super.onStart();
       blueReceiver  = new BlueReceiver();
       filter = new IntentFilter();
       filter.addAction(BluetoothDevice.ACTION_FOUND);//发现蓝牙动作
       filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束动作
       filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//搜素开始动作
       registerReceiver(blueReceiver, filter);//注册
       Log.d("CZK", "蓝牙广播接受器注册完毕");
   }

然后我们还得在onStop()方法上取消注册:

@Override
protected void onStop() {
    super.onStop();
    unregisterReceiver(blueReceiver);
    Log.d("CZK",  "取消注册");
}

 

④:注册完毕,接下来我们需要一个广播接收器。代码如下:

/*******************************************蓝牙接收器**************************************/
public class BlueReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //发现其他蓝牙设备,如果该蓝牙设备没有被连接,则显示在列表上。
        if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
                //发现蓝牙设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                //获取该蓝牙设备
            if(device.getBondState()!=BluetoothDevice.BOND_BONDED){
                //通过getBondState获取状态,判断是否匹配
                list.add(device.getName()+":"+device.getAddress()+"\n");
                adapter = new ArrayAdapter<>(MainActivity.this,android.R.layout.simple_list_item_1,android.R.id.text1,list);
                listView.setAdapter(adapter);
                adapter.notifyDataSetChanged();
                //显示在列表上面
                Log.d("CZK", "蓝牙发现目标");
            }
        }
        if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
            setTitle("开始搜索");
            Log.d("CZK","蓝牙搜索开始");
            Toast.makeText(MainActivity.this,"开始搜素",Toast.LENGTH_SHORT).show();
        }
        if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
            setTitle("搜索完成(请选择配对设备)");
            Log.d("CZK","蓝牙搜索结束");
            Toast.makeText(MainActivity.this,"搜素结束",Toast.LENGTH_SHORT).show();
        }
        
    }
}

⑤:地理位置授权,蓝牙可见:

*************************************蓝牙discoverable************************/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode==200){
        Intent dis=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        dis.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
        startActivity(dis);
        Log.d("CZK", "discoverable");//刷新
    }
}
/*************************************地理位置授权请求************************/
private void bluetoothPermissions() {
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{
                android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
        Log.d("CZK", "地理位置授权成功 ");
    }
}

/*************************************地理位置授权处理******************************************/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode){
        case 1:
            if(grantResults.length > 0&& grantResults[0]==PackageManager.PERMISSION_GRANTED){
                Toast.makeText(MainActivity.this,"地理授权成功",Toast.LENGTH_SHORT);
            }
            else {
                Toast.makeText(MainActivity.this,"地理授权失败",Toast.LENGTH_SHORT);

            }

    }
}

⑥:连接蓝牙:

@Override
/*****************************************列表点击事件**************************************/
public void onItemClick(final AdapterView<?> adapterView, View view, int i, long l) {
    if(bluetoothAdapter.isDiscovering()){
        //如果还在搜索,则停止搜索
        bluetoothAdapter.cancelDiscovery();
    }
    String s = adapter.getItem(i);
    String address = s.substring(s.indexOf(":")+1).trim();
    if (bluetoothDevice == null){
        bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
        //getRemoteDevice()得到指定蓝牙的BluetoothDevice
    }
     try {
            if (bluetoothSocket == null){
                // 获取到客户端接口(获得对象)
                bluetoothSocket = bluetoothDevice
                        .createRfcommSocketToServiceRecord(MY_UUID);
                // 向服务端发送连接
                bluetoothSocket.connect();
                Log.d("CZK", "连接成功");
            }else {
                Log.d("CZK","bluetoothSocket != null");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

总结,在这一节上,我们仅仅实现的是蓝牙连接,在后面一节中将会学到连接之后,发送数据。

2017-11-21 18:17:19 zxdynamite 阅读数 11492
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3398 人正在学习 去看看 朱有鹏

怕忘

蓝字是链接,打开会有更多惊喜。

  • 首先,可以明确的是,与单片机进行通信的时候,会很明确的知道是有多少个数据;
    所以我们就可以根据其长度设置要存取的byte[]长度;
  • 其次,蓝牙的接收和发送试药建立在独立线程里面的;
    搜索和配对/通信(后来在某篇博客里面发现,说是和单片机通信的话可以直接连接,完了可以试试)
  • 再之,就是和单片机通信的时候,它发送的都是16进制的东西,所以要么转换,要么直接用byte[];
  • 最后,读取的时候,InputStream有read(),read(byte[] b),read(byte[] b,int off,int len),可以参考↓使用;
    read()和read(byte[] b)
    read(byte[] b,int off,int len)
        while(true){
                        try {
                                num = inputStream.read(buffer_z);//buffer_z和buffer_z_new都是1024
                                n=0;
                                for(i=0;i<num;i++){
                                    buffer_z_new[n] = buffer_z[i];
                                    n++;
                                }
                                String s =bytesToHexString(buffer_z_new);//因为单片机发出的是16进制的,直接读取会是乱码,于是进行了转换。
                                smsg+=s.trim();
                                if(inputStream.available()==0)break;//有时候会因为某些原因,会出现有数据但是位0的问题,可以尝试添加延时;
                            } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
public static String bytesToHexString(byte[] bytes) {
        String result = "";
        for (int i = 0; i < bytes.length; i++) {
            String hexString = Integer.toHexString(bytes[i] & 0xFF);
            if (hexString.length() == 1) {
                hexString = '0' + hexString;
            }
            result += hexString.toUpperCase();
        }
        return result;
    }

但是以上读取的时候,有时候会出现丢包的现象,后来再百般询问,浏览之后,得到的结论是:
如果ble需要对事件广播进行监听;如果只是普通蓝牙直接使用接口函数即可,但是需要使用循环(for)不断读一个字节的函数,不能直接读一串。

比如:

            int i = 0,size = 0;
            byte[] oneByte = new byte[1];
            for(i = 0; i< 64386;i++){
                //读后面所有数据
                size = inputStream.read(oneByte, 0, 1);
                if (size != 1)
                {
                    return;
                }

                bufData[i] = oneByte[0];//将循环出来的每一个字节存放在总byte[]里面。
            }
  • 如果出现大量的0的时候,可以尝试让线程sleep一下。

以上。

没有更多推荐了,返回首页