专案动机(1/2)
专案动机(2/2)
系统功能
硬体清单
GPS测速
GPS测速与仪表板之误差
反射投影
系统架构
装置电路图
遭遇问题
装置组装完成图
实际展示影片:
Youtube:
优酷:
http://v.youku.com/v_show/id_XNzI5MzE2Njcy.html
(由于反射膜为半透明非全反射,会透光,因此从外部所看到七段显示器的数字会是颠倒的。)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
最后附上本专案所用到的源代码,工程我就不打包了,下面已经几乎包括全部的东西
Android 行动装置端主程序
package com.helmethud; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.UUID; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.location.Criteria; import android.location.GpsSatellite; import android.location.GpsStatus; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; public class HelmetHud extends Activity { // 除錯用標記 private static final String TAG = "HELMETHUDCLIENT"; private static final boolean D = true; // Bluetooth相關變量 private BluetoothAdapter mBluetoothAdapter = null; private BluetoothSocket btSocket = null; private OutputStream outStream = null; // Well known SPP UUID (will *probably* map to // RFCOMM channel 1 (default) if not in use); // see comments in onResume(). private static final UUID MY_UUID = UUID .fromString("00001101-0000-1000-8000-00805F9B34FB"); // ==> hardcode bluetooth server's MAC address here <== // private static String address = "98:D3:31:40:03:34"; private boolean BTIsConnected = false; // 藍芽是否已連線flag private boolean hasFirstMatch = false; // 藍芽是否已經過第一次配對flag private boolean ReceiverIsRegisted = false; // BroadcastReceiver是否已註冊flag // 線程HANDLE相關變量 private Handler connectBTHandler = new Handler(); private Handler sendBTMsgHandler = new Handler(); private Handler sendBTTestMsgHandler = new Handler(); private Handler hudThreadHandler = new Handler(); private Handler getSpeedThreadHandler = new Handler(); Handler msgHandler; // UI相關變量 private Button btnDiscovery, btnConnect, btnSend, btnStartHud; private Spinner spinner; private ArrayAdapter<String> arrayAdapterDeviceName; private static final String[][] devicesStr = { { "Plz select device...", "" } }; private List<String> allDevices, allDevicesAddress; private int selectedAddress = 0; // GPS定位相關變量 final String SERVERNAME = Context.LOCATION_SERVICE; LocationManager locationManager; float speed = 0, lastSpeed = 0; // 車速 int satelliteCount = 0; // 當前衛星個數 Date gpdDate = new Date(); StringBuilder tempBuilder = new StringBuilder(); TextView tvGPSState, tvGPSInfo; private static final int STATIC_CONTINUED_TIME = 6000; // 判斷靜止持續時間(毫秒) EditText et1; // 測試用輸入框 private boolean IsTesting = false; // 程序執行是否為發送測試訊息 int sum = 0; // SendMsgThread傳送藍芽訊息線程執行總次數 private static final int BT_RECONNECT_LIMIT_TIME = 300; // 線程最大允許執行次數;值訂為300以防止低階設備效能不足而出錯 private static final int NEED_BT_RECONNECT_DEVICE_MAX_SDK = 13; // 需要重新連線的裝置Android_SDK_API最大版本 /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_helmet_hud); setTitle("Not connected"); et1 = (EditText) findViewById(R.id.editText1); btnDiscovery = (Button) findViewById(R.id.btnDiscovery); btnConnect = (Button) findViewById(R.id.btnConnect); btnSend = (Button) findViewById(R.id.btnSend); spinner = (Spinner) findViewById(R.id.spinner1); allDevices = new ArrayList<String>(); for (int i = 0; i < devicesStr.length; i++) { allDevices.add(devicesStr[i][0]); } allDevicesAddress = new ArrayList<String>(); for (int i = 0; i < devicesStr.length; i++) { allDevicesAddress.add(devicesStr[i][1]); } /* new ArrayAdapter物件並將allDevices傳入 */ arrayAdapterDeviceName = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, allDevices); arrayAdapterDeviceName .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(arrayAdapterDeviceName); btnStartHud = (Button) findViewById(R.id.btnStartHud); // btnStartHud.setEnabled(false); //測試時保持可用 tvGPSState = (TextView) findViewById(R.id.tvGPSState); tvGPSInfo = (TextView) findViewById(R.id.tvGPSInfo); btnDiscovery.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); Log.e(TAG, "Cancel discovery"); } mBluetoothAdapter.startDiscovery(); // 開始搜尋裝置 } }); btnConnect.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub connectBTHandler.post(ConnectBTThread); } }); btnSend.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub IsTesting = true; sendBTTestMsgHandler.post(SendBTTestMsgThread); } }); spinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub parent.setVisibility(View.VISIBLE); selectedAddress = position; } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); btnStartHud.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub IsTesting = false; hudThreadHandler.post(HudThread); btnStartHud.setEnabled(false); } }); msgHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0) { // 結束發送測試訊息線程並重新連接藍芽以重置(避免發送訊息過多而當機) sendBTTestMsgHandler.removeCallbacks(SendBTTestMsgThread); Log.e(TAG, "removecallbacks!"); // 關閉藍芽通道 if (outStream != null) { try { outStream.flush(); outStream = null; } catch (IOException e) { Log.e(TAG, "ON PAUSE: Couldn't flush output stream.", e); } } try { if (BTIsConnected) { BTIsConnected = false; btSocket.close(); btSocket = null; } } catch (IOException e2) { Log.e(TAG, "ON PAUSE: Unable to close socket.", e2); } // 重新連線藍芽 sum = 0; Log.e(TAG, "Reconnecting..."); connectBTHandler.post(ConnectBTThread); } else if (msg.what == 1) { // 開啟發送測試訊息線程 Log.e(TAG, "post"); sendBTTestMsgHandler.post(SendBTTestMsgThread); } else if (msg.what == 2) { // 重新連線藍芽 Log.e(TAG, "Reconnecting..."); connectBTHandler.post(ConnectBTThread); } } }; // TODO: Bluetooth Initial if (D) Log.e(TAG, "+++ ON CREATE +++"); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show(); finish(); return; } if (!mBluetoothAdapter.isEnabled()) { Toast.makeText(this, "Please enable your BT and re-run this program.", Toast.LENGTH_LONG).show(); finish(); return; } if (D) Log.e(TAG, "+++ DONE IN ON CREATE, GOT LOCAL BT ADAPTER +++"); // 註冊一個BroadcastReceiver,等等會用來接收搜尋到裝置的消息 IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); registerReceiver(mReceiver, filter); ReceiverIsRegisted = true; } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { BluetoothDevice device = null; // 當收尋到裝置時 if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) { Log.e(TAG, "Discovered"); // 取得藍芽裝置這個物件 device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 取得裝置名稱字串 String newDeviceName = device.getName().toString(); // 取得裝置MAC地址 String newDeviceAddress = device.getAddress().toString(); // 先比較添加的值是否已存在,不存在才可添加入Spinner選單 for (int i = 0; i < arrayAdapterDeviceName.getCount(); i++) { if (newDeviceName.equals(arrayAdapterDeviceName.getItem(i))) { return; } } if (!newDeviceName.equals("")) { arrayAdapterDeviceName.add(newDeviceName); // 將值添加到adapter allDevicesAddress.add(newDeviceAddress); // 將地址添加到ArrayList arrayAdapterDeviceName.notifyDataSetChanged(); } } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent .getAction())) { device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch (device.getBondState()) { case BluetoothDevice.BOND_BONDING: Log.e(TAG, "Bluetooth device is pairing..."); break; case BluetoothDevice.BOND_BONDED: Log.e(TAG, "Pairing complete"); break; case BluetoothDevice.BOND_NONE: Log.e(TAG, "Cancel paring"); break; default: break; } } } }; Runnable ConnectBTThread = new Runnable() { @Override public void run() { // TODO Auto-generated method stub // Blocking connect, for a simple client nothing else can // happen until a successful connection is made, so we // don't care if it blocks. if (selectedAddress == 0) { return; } // 停止搜尋以減少資源消耗 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); Log.e(TAG, "Cancel discovery"); } // 連結到該裝置 BluetoothDevice device = mBluetoothAdapter .getRemoteDevice(allDevicesAddress.get(selectedAddress) .toString()); try { btSocket = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { // TODO Auto-generated catch block Log.e(TAG, "Connect: Socket creation failed.", e); } try { btSocket.connect(); BTIsConnected = true; Log.e(TAG, "ON RESUME: BT connection established, data transfer link open."); } catch (IOException e) { try { btSocket.close(); BTIsConnected = false; } catch (IOException e2) { Log.e(TAG, "ON RESUME: Unable to close socket during connection failure", e2); } } Log.e(TAG, "BTisConnected = " + Boolean.toString(BTIsConnected)); Message msg = msgHandler.obtainMessage(); if (!BTIsConnected) { btnSend.setEnabled(false); btnStartHud.setEnabled(false); setTitle("Not connected"); Log.e(TAG, "Try reconnect"); msg.what = 2; msgHandler.sendMessage(msg); // 重新連線 } else { btnSend.setEnabled(true); btnStartHud.setEnabled(true); setTitle("Connected"); // Create a data stream so we can talk to server. if (D) Log.e(TAG, "+ ABOUT TO SAY SOMETHING TO SERVER +"); if (IsTesting && hasFirstMatch) { msg.what = 1; msgHandler.sendMessage(msg); // 已重新連線,恢復發送測試訊息 } hasFirstMatch = true; } } }; Runnable SendBTMsgThread = new Runnable() { @Override public void run() { sum++; // Check if BT connection was established. if (!BTIsConnected) { return; } try { outStream = btSocket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "ON RESUME: Output stream creation failed.", e); BTIsConnected = false; setTitle("Not connected"); } // Send msg start symbol String messageStart = "S"; byte[] msgBufferStart = messageStart.getBytes(); try { outStream.write(msgBufferStart); } catch (IOException e) { Log.e(TAG, "ON RESUME: Exception during write.", e); BTIsConnected = false; setTitle("Not connected"); } // send msg String message = Integer.toString((int) (speed)); // String message=et1.getText().toString(); byte[] msgBuffer = message.getBytes(); try { outStream.write(msgBuffer); } catch (IOException e) { Log.e(TAG, "ON RESUME: Exception during write.", e); BTIsConnected = false; setTitle("Not connected"); } // Send msg end symbol String messageEnd = "E"; byte[] msgBufferEnd = messageEnd.getBytes(); try { outStream.write(msgBufferEnd); } catch (IOException e) { Log.e(TAG, "ON RESUME: Exception during write.", e); BTIsConnected = false; setTitle("Not connected"); } Message msg = msgHandler.obtainMessage(); if ((android.os.Build.VERSION.SDK_INT < NEED_BT_RECONNECT_DEVICE_MAX_SDK) && (sum > BT_RECONNECT_LIMIT_TIME)) { msg.what = 0; msgHandler.sendMessage(msg); // 重新連線以確保藍芽通道連線順暢,不重連可能會當機 } Log.e(TAG, "sendThread: " + sum + " times."); } }; Runnable SendBTTestMsgThread = new Runnable() { @Override public void run() { sum++; // Check if BT connection was established. if (!BTIsConnected) { return; } try { outStream = btSocket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "ON RESUME: Output stream creation failed.", e); BTIsConnected = false; setTitle("Not connected"); } // Send msg start symbol String messageStart = "S"; byte[] msgBufferStart = messageStart.getBytes(); try { outStream.write(msgBufferStart); } catch (IOException e) { Log.e(TAG, "ON RESUME: Exception during write.", e); BTIsConnected = false; setTitle("Not connected"); } // send msg String message = et1.getText().toString(); byte[] msgBuffer = message.getBytes(); try { outStream.write(msgBuffer); } catch (IOException e) { Log.e(TAG, "ON RESUME: Exception during write.", e); BTIsConnected = false; setTitle("Not connected"); } // Send msg end symbol String messageEnd = "E"; byte[] msgBufferEnd = messageEnd.getBytes(); try { outStream.write(msgBufferEnd); } catch (IOException e) { Log.e(TAG, "ON RESUME: Exception during write.", e); BTIsConnected = false; setTitle("Not connected"); } // 以下為循環發送訊息測試,若只發送一次則不需要 // Message msg = msgHandler.obtainMessage(); // // if ((android.os.Build.VERSION.SDK_INT < // NEED_BT_RECONNECT_DEVICE_MAX_SDK) // && sum > BT_RECONNECT_LIMIT_TIME) { // msg.what = 0; // msgHandler.sendMessage(msg); // 重新連線以確保藍芽通道連線順暢,不重連可能會當機 // } else { // msg.what = 1; // msgHandler.sendMessage(msg); // } // Log.e(TAG, "sendThread: " + sum + " times."); } }; Runnable HudThread = new Runnable() { @Override public void run() { // TODO Auto-generated method stub initControl(); } }; private void initControl() { // GPS啟動 locationManager = (LocationManager) this.getSystemService(SERVERNAME); if (getGpsStates()) { getLocation(); } else { Toast.makeText(this, "Please enable your GPS, and re-run this program. ", Toast.LENGTH_LONG).show(); btnStartHud.setEnabled(true); hudThreadHandler.removeCallbacks(HudThread); } } // 打開GPS public boolean getGpsStates() { if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { return true; } else return false; } private void getLocation() { try { Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度 criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(true); criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗 // String provider = locationManager.getBestProvider(criteria, // true); // 獲取GPS信息 // 設置監聽器,自動更新的最小時間為間隔(N*1000)秒或最小位移變化超過N米 locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1 * 1000, (float) 0.5, locationListener); getSpeedThreadHandler.post(GetSpeedThread); // 改用GetSpeedThread來得到速度 locationManager.addGpsStatusListener(gpsstatusListener); } catch (Exception e) { } } // 移動判定線程 Runnable GetSpeedThread = new Runnable() { @Override public void run() { // TODO Auto-generated method stub if (speed == lastSpeed) { //若和五秒前的速度一樣,則視為靜止,速度為零 speed = 0; tvGPSInfo.setText("GPS Info" + "\n" + " 速度 = " + speed + "km/h" + "\n Thread Sum = " + sum); if (BTIsConnected) { sendBTMsgHandler.post(SendBTMsgThread); } else { setTitle("Not connected"); } } else { lastSpeed = speed; } getSpeedThreadHandler.postDelayed(GetSpeedThread, STATIC_CONTINUED_TIME); } }; private final LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { speed = (float) (location.getSpeed() * 3.6);// 速度 if (speed < 3.0) { // 速度修正,若時速在3km/h內則視為0km/h,因為要位移0.85m以上,時速才會高於3.06km/h,0.85m相當於沒有動,視為是定位的誤差 speed = 0; } tvGPSInfo.setText("GPS Info" + "\n" + " 速度 = " + speed + "km/h" + "\n Thread Sum = " + sum); if (BTIsConnected) { sendBTMsgHandler.post(SendBTMsgThread); } else { setTitle("Not connected"); } } public void onProviderDisabled(String provider) { // WriteDB(null); } public void onProviderEnabled(String provider) { } public void onStatusChanged(String provider, int status, Bundle extras) { // "<locationListener>本地監聽狀態改變\n"); switch (status) { case LocationProvider.AVAILABLE: // "<locationListener>有可用衛星\n"); break; case LocationProvider.OUT_OF_SERVICE: // "<locationListener>無可用衛星服務\n"); break; case LocationProvider.TEMPORARILY_UNAVAILABLE: // "<locationListener>暫時無可用衛星服務\n"); break; } } }; private final GpsStatus.Listener gpsstatusListener = new GpsStatus.Listener() { private GpsStatus gpsStatus; public void onGpsStatusChanged(int event) { gpsStatus = locationManager.getGpsStatus(null); switch (event) { case GpsStatus.GPS_EVENT_FIRST_FIX: // GPS時間 gpdDate = new Date(gpsStatus.getTimeToFirstFix()); break; case GpsStatus.GPS_EVENT_SATELLITE_STATUS: // 得到所有收到的衛星的信息,包括 衛星的高度角、方位角、信噪比、和偽隨機號(衛星編號) Iterable<GpsSatellite> allSatellites; allSatellites = gpsStatus.getSatellites(); tempBuilder.delete(0, tempBuilder.length()); for (GpsSatellite gpsstate : allSatellites) { tempBuilder.append("方位角 " + gpsstate.getAzimuth()); tempBuilder.append("\n"); tempBuilder.append("高度角 " + gpsstate.getElevation()); tempBuilder.append("\n"); tempBuilder.append(" 偽隨機號(衛星編號)" + gpsstate.getPrn()); tempBuilder.append("\n"); tempBuilder.append(" 信噪比 " + gpsstate.getSnr()); tempBuilder.append("\n"); } int maxSatellites = gpsStatus.getMaxSatellites(); Iterator<GpsSatellite> it = gpsStatus.getSatellites() .iterator(); int satellite = 0; while (it.hasNext() && satellite <= maxSatellites) { // GpsSatellite s = it.next(); it.next(); satellite++; } // 計算衛星個數,可在此打印出衛星的其它信息 satelliteCount = satellite; tempBuilder.append("當前衛星個數:" + satellite + "\n"); tvGPSState.setText("GPS State" + "\n" + " 當前衛星個數:" + satellite); break; case GpsStatus.GPS_EVENT_STARTED: // Event sent when the GPS system has started. // "<gpsstatusListener>開始信號GPS_EVENT_STARTED\n"); break; case GpsStatus.GPS_EVENT_STOPPED: // Event sent when the GPS system has stopped. // "<gpsstatusListener>結束信號GPS_EVENT_STOPPED\n"); break; default: // "<gpsstatusListener>沒有獲取到狀態信息\n"); break; } } }; @Override public void onStart() { super.onStart(); if (D) Log.e(TAG, "++ ON START ++"); } @Override public void onResume() { super.onResume(); if (D) { Log.e(TAG, "+ ON RESUME +"); Log.e(TAG, "+ ABOUT TO ATTEMPT CLIENT CONNECT +"); } } @Override public void onPause() { super.onPause(); if (D) Log.e(TAG, "- ON PAUSE -"); } @Override public void onStop() { super.onStop(); if (D) Log.e(TAG, "-- ON STOP --"); } @Override public void onDestroy() { super.onDestroy(); if (D) Log.e(TAG, "--- ON DESTROY ---"); if (outStream != null) { try { outStream.flush(); } catch (IOException e) { Log.e(TAG, "ON PAUSE: Couldn't flush output stream.", e); } } if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); Log.e(TAG, "Cancel discovery"); } try { if (BTIsConnected) { btSocket.close(); BTIsConnected = false; } } catch (IOException e2) { Log.e(TAG, "ON PAUSE: Unable to close socket.", e2); } if (ReceiverIsRegisted) { unregisterReceiver(mReceiver); } removeListener(); } private void removeListener() { try { locationManager.removeUpdates(locationListener); locationManager.removeGpsStatusListener(gpsstatusListener); } catch (Exception e) { } } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { // TODO Auto-generated method stub return super.onMenuItemSelected(featureId, item); } @Override public boolean onCreateOptionsMenu(Menu menu) { // TODO Auto-generated method stub return super.onCreateOptionsMenu(menu); } }
Android 行动装置端主介面Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".HelmetHud" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/btnDiscovery" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="0.5" android:text="Discovery" /> <Button android:id="@+id/btnConnect" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="0.5" android:text="Connect" /> </LinearLayout> <Spinner android:id="@+id/spinner1" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnStartHud" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="18dp" android:text="Start HUD" /> <TextView android:id="@+id/tvGPSState" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="GPS State" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/tvGPSInfo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="GPS Info" android:textAppearance="?android:attr/textAppearanceLarge" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" > <EditText android:id="@+id/editText1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="0.5" android:ems="10" > <requestFocus /> </EditText> <Button android:id="@+id/btnSend" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="0.5" android:text="SendTestMSG" /> </LinearLayout> </LinearLayout>
安全帽端设备Arduino主程序
#define CMD_MAXNUM 5 #define LED_DIGIT_NUM 8 int DIO_Pin = 8; //pin 14 on the 75HC595(DIO) int RCK_Pin = 9; //pin 12 on the 75HC595(RCLK) int SCK_Pin = 10; //pin 11 on the 75HC595(SCLK) // 蜂鳴器變量 int melody = 523; int duration = 500; // 500 miliseconds unsigned char LED_0F[] = {// 0 1 2 3 4 5 6 7 8 9 0xC0,0xCF,0x92,0x86,0x8D,0xA4,0xA0,0xCE,0x80,0x84 }; //顛倒後的字元 // 全局變量 unsigned char SEG[LED_DIGIT_NUM]; //用於LED的4位顯示緩存 char cmd[CMD_MAXNUM]; //藍芽接收的字串(車速) void SEG_OUT(unsigned char X) { unsigned char i; for(i=LED_DIGIT_NUM;i>=1;i--) { if (X&0x80) digitalWrite(DIO_Pin, HIGH); else digitalWrite(DIO_Pin, LOW); X<<=1; digitalWrite(SCK_Pin, LOW); digitalWrite(SCK_Pin, HIGH); } } void DisplaySegment(void) { unsigned char led_table; // 查表指針 unsigned char i; //顯示第1位 if(SEG[0]!=0) { led_table = LED_0F[SEG[0]]; i = led_table; SEG_OUT(i); SEG_OUT(0x01); digitalWrite(RCK_Pin, LOW); digitalWrite(RCK_Pin, HIGH); } //顯示第2位 if(SEG[0]!=0 || SEG[1]!=0) { led_table = LED_0F[SEG[1]]; i = led_table; SEG_OUT(i); SEG_OUT(0x02); digitalWrite(RCK_Pin, LOW); digitalWrite(RCK_Pin, HIGH); } //顯示第3位 if(SEG[0]!=0 || SEG[1]!=0 || SEG[2]!=0) { led_table = LED_0F[SEG[2]]; i = led_table; SEG_OUT(i); SEG_OUT(0x04); digitalWrite(RCK_Pin, LOW); digitalWrite(RCK_Pin, HIGH); } //顯示第4位 led_table = LED_0F[SEG[3]]; i = led_table; SEG_OUT(i); SEG_OUT(0x08); digitalWrite(RCK_Pin, LOW); digitalWrite(RCK_Pin, HIGH); } // 設定整個四合一型七段顯示器想要顯示的數字 // 參數number的範圍應是0~9999 void setNumber(int number) { int n0, n1, n2, n3; n3 = number / 1000; number %= 1000; n2 = number / 100; number %= 100; n1 = number / 10; n0 = number % 10; // 每位數值清零 SEG[0]=0; SEG[1]=0; SEG[2]=0; SEG[3]=0; // 求出每個位數的值後,分別更新 // 因為要實現反射式HUD,所以位置要顛倒 SEG[0]=n3; //第一位字元 SEG[1]=n2; //第二位字元 SEG[2]=n1; //第三位字元 SEG[3]=n0; //第四位字元 DisplaySegment(); } void setup() { Serial.begin(9600); // 藍牙模組預設baud rate = 9600 pinMode(DIO_Pin, OUTPUT); pinMode(RCK_Pin, OUTPUT); pinMode(SCK_Pin, OUTPUT); } void loop() { while (Serial.available()) //connected { memset(cmd, 0, CMD_MAXNUM); if(Serial.read() == 'S') { for(int i=0;i<CMD_MAXNUM;i++) { cmd[i] = Serial.read(); if(cmd[i]=='E') { cmd[i]=0; break; } else if(cmd[i]<48 || cmd[i]>57) { cmd[i]=0; i--; continue; } } cmd[CMD_MAXNUM-1]='\0'; Serial.print(cmd); Serial.print("\n"); } } setNumber(atoi(cmd)); if(atoi(cmd)>=70) { // 在 pin7 上輸出聲音,每個音階響 1 秒 tone(7, melody, duration); } }
原文地址:http://blog.csdn.net/yehjordan/article/details/32730163