android物聯網初步,利用手機藍牙與單片機通信,實現led燈開關和定時

                轉載請註明出處。

                這次是一個課程設計,利用單片機開發一個物聯網系統。我們利用了手機藍牙與單片機板子上的藍牙通信,通過 控制信號來控制單片機上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);
		}
	}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章