יום שבת, 22 ביוני 2013

Arduino BlueTooth Guide




חשבתי לעצמי שאם כבר דיברנו על BlueTooth למה לא לשלב את Arduino בעניין, בעזרת Android נשלוט ב Arduino ונפעיל רכיבים עם חיבור סיראלי שעובר דרך ה BlueTooth, חיפשתי באינטרנט רכיב זול ואמין שיעשה את העבודה ומצאתי אותו ב  DX.com תמורת 6 דולר.



Wireless Bluetooth V2.0 RS232 TTL Transceiver Module

בסה"כ מדובר במודול מאוד פשוט, העבודה עם 4 פינים בלבד (1,2,12,13) , יש צורך להשתמש בספרייה NewSoftSerial על מנת שנוכל לדמות Uart נוסף עבור ה BlueTooth וצריך לעשות הצלבה בין ה RX וה TX של המודול מול הפינים שהגדרנו ב NewSoftSerial.


תמורת 2 דולר נוספים ניתן לקבל לוח שכולל את המודול, יחד עם פינים ו Led אדום שמהבהב שזה בהחלט משתלם ממקום שנבנה אותו בעצמנו.

שימו לב - המודול עובד על 3.3 V שימוש ב 5V עלול לשרוף אותו.

דרישות:
  • Arduino Uno / Nano
  • Wireless Bluetooth V2.0 RS232 TTL Transceiver Module
  • Wires
  • Android Tablet / Phone Support BlueTooth.
  • Servo


זאת הפעם הראשונה שאני משתמש ב Arduino Nano בבלוג, אין הבדל בהתנהגות שלו לבין ה Uno רק צריך להשים לב שיש פחות חיבורים ולהגדיר את הלוח בסביבה כפי שניתן לראות בדוגמה:



יש להגדיר את חוקי הדיבור בין ה Android ל Arduino, ההגדרה בקוד שאם מגיעה האות F ה Servo יתקדם קדימה ואם תגיע האות B ה Servo יתקדם אחורה בין כל בקשה ניכנס ל Delay של 25 ms על מנת לאפשר ל Servo לנוע.

קוד:

#include <NewSoftSerial.h>
#include <Servo.h> 

//break state
byte stateHold = false;
//forward state
byte stateForward = false;
//reverse state
byte stateReverse = false;

//commands: 
//F  = Servo move forward
//B = Servo move Backward
char FWDCMD = 'F';
char BWDCMD = 'B';

//Bluetooth section over software serial
//Arduino RX - 7 ,Arduino TX  - 6
NewSoftSerial bluetooth(7, 6);
byte b;

//Servo section
int servoPin = 3;
Servo myservo;

void setup() {
  //arduino serial for debugging
  Serial.begin(9600);   // opens serial port, sets data rate to 9600 bps
  Serial.flush();
  
  //attach servo to servo pin
   myservo.attach(servoPin);
   
  bluetooth.begin(9600);
  Serial.println("set bluetooth success");
}

void loop() {

  if (bluetooth.available()) {
    Serial.print("Android Send:");
    b = bluetooth.read();
    
    if((char)b == FWDCMD)
    {
        stateForward = true;
        stateHold = false;
        servoState();
        stateHold = true;
    
    }
    else if ((char)b == BWDCMD)
   {
       stateReverse = true;
        stateHold = false;
        servoState();
        stateHold = true;
   }   
   
    //print command in serial for debugging
    Serial.println((char)bluetooth.read(),BYTE);
    b = '\0';
  }
}


//change servo rotation by command
void servoState()
{
  if(stateHold == false)
    {
        myservo.attach(servoPin);
        if(stateForward == true)
        {
          stateReverse = false;
          myservo.write(0);
           delay(25);
           stateForward = false;
        }
        
        if(stateReverse == true)
        {
          stateForward = false;
           myservo.write(360);
           delay(25);
           stateReverse = false;
          
        }
        
         myservo.detach();
    }
}

מבנה סופי:



Android

אני לא אחזור על דברים מהמאמר הקודם אבל צריך להשים לב למספר דברים בקוד, קודם כל ה Android צריך למצוא את ה Device ואח"כ להתחבר אליו עם UUID שמייצג תקשורת סיראלית, לאחר מכן נפתח Socket בין המכשיר ל Device, מעבירים את פקודות הדיבור שנקבעו מראש שדרכם נתקשר עם ה Arduino שבסופו של דבר יגרום ל Servo לזוז, בנוסף למחלקה BTClient שמבוססת על AsyncTask אנחנו נשתמש בכלי מקבילי נוסף שנקרא Runnable על מנת שנוכל לתכנת את התנהגות הכפתורים.


קוד:

package com.proxytypeblog.arduinobtapp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageButton;

public class MainActivity extends Activity {

private static final String TAG = "Activity";
BluetoothAdapter mBluetoothAdapter;
BTClient _client;
BluetoothDevice mDevice;

boolean flag = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

boolean check = loadBlueTooth();
if (!check) {
Log.e(TAG, "Error to connect bluetooth");
}

setForwardButton();
setBackwardButton();
}

private void setBackwardButton() {
ImageButton btn_backward = (ImageButton) findViewById(R.id.btn_backward);
btn_backward.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
flag = true;
new Thread(new Runnable() {
public void run() {
while (flag) {
try {
//make sleep like arduino
Thread.sleep(25);
//char B for backward servo
_client.write("B");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
break;
case MotionEvent.ACTION_UP:
flag = false;
break;

default:
break;
}

return false;
}
});
}

private void setForwardButton() {
ImageButton btn_forward = (ImageButton) findViewById(R.id.btn_forward);

btn_forward.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
flag = true;

new Thread(new Runnable() {
public void run() {
while (flag) {
try {
//make sleep like arduino
Thread.sleep(25);
//char F for forward servo
_client.write("F");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
break;
case MotionEvent.ACTION_UP:
flag = false;
break;

default:
break;
}

return false;
}
});

}

private boolean loadBlueTooth() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
return false;
}

mBluetoothAdapter.startDiscovery();
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
.getBondedDevices();

if (pairedDevices.size() > 0) {

for (BluetoothDevice device : pairedDevices) {

// the device i want to connect.
if (device.getName().contains("linvor"))
mDevice = device;

Log.d(TAG, device.getName());
}
}

// UUID service for serial
_client = new BTClient(mDevice, "00001101-0000-1000-8000-00805F9B34FB");
_client.execute("");

return true;
}

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

private class BTClient extends AsyncTask<String, String, String> {
private final String TAG = "AsyncTask";
private BluetoothSocket mmSocket;
private BluetoothDevice mmDevice;
private BluetoothAdapter mBluetoothAdapter;
private InputStream mmInStream;
private OutputStream mmOutStream;
private UUID mmUUID;

// getting the device with application unique key
public BTClient(BluetoothDevice device, String CODE) {
mmUUID = UUID.fromString(CODE);
mmDevice = device;
BluetoothSocket tmp = null;

// getting the your own device adpater
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

// try to create a socket
try {
tmp = device.createRfcommSocketToServiceRecord(mmUUID);
} catch (IOException e) {
e.printStackTrace();
}

mmSocket = tmp;

}

@Override
protected String doInBackground(String... params) {

// if the our adapter on discovering, cancel it
if (mBluetoothAdapter.isDiscovering())
mBluetoothAdapter.cancelDiscovery();

try {
// make the connection and collect the stream
mmSocket.connect();
mmInStream = mmSocket.getInputStream();
mmOutStream = mmSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}

String message = "";
int bytes;
byte[] buffer = new byte[1];
// keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
message = new String(buffer, 0, bytes);
mmSocket.getInputStream();

} catch (IOException e) {
Log.e(TAG, "disconnected", e);
break;
}
}

return null;
}

// write message to outputstream
public void write(String msg) {

try {
byte[] buffer = msg.getBytes("US-ASCII");
if (mmOutStream != null)
mmOutStream.write(buffer);

} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}

@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}

}
}


ממשק:



סרט דוגמה:




קבצי מקור:

https://sourceforge.net/projects/arduinobluetoot/

סיכום:

החודש הזה הוקדש ל BlueTooth וראינו כיצד לדבר אחד עם השני בפלטפורמות שונות, שילוב BlueTooth בפרוייקטים שלנו מאפשר לנו לשלוט בכל רכיב שנרצה במערכת בתנאי שהוא בטווח כמובן, וזו דרך יעילה וזולה להתנתק מהחוטים.

בהצלחה...

יום שבת, 15 ביוני 2013

Android BlueTooth Guide



במאמר האחרון בנושא ראינו כיצד ניתן להשתמש ב GPS שבמכשיר לצרכי האפליקציה שלנו אבל קיימים עוד רכיבים מגניבים שצריך לעבור עליהם, אחד הדברים שסקרנו אותי הוא כיצד אני יכול לשלוט בעזרת הסמארטפון או הטאבלט על מכשירים אחרים והחלטתי להתמקד ב BlueTooth כי כמעט כל מכשיר תומך בתקשורת הזאת והיא נחשבת לזולה ואמינה, ה"שן הכחולה" מבוססת על גלי רדיו קצרים בתדר 2.4 Mhz שעד טווח של מאה מטר ובשנת 1999 הוגדרה כתקן וקיבלה המון שיפורים עם השנים.


android.bluetooth

המפתחים של Android כתבו מרחב שמות של מחלקות שמאפשר לנו להשתמש ב Bluetooth ולבצע פעולות רבות כמו חיפוש מכשירים, אירוח משתמשים או התחברות למארח, ההתממשקות מבוססת על כתובת ה MAC במכשיר ועל פרמטר ייחודי של האפליקציה, על מנת שנוכל לתקשר ב BlueTooth יש לעבוד ב Thread נפרד ולתת מספר הרשאות בקובץ Manifest  כפי שניתן לראות בדוגמה:

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

המחלקות העיקריות הן:

רכיב ה BlueTooth שעל המכשיר

מכשיר חיצוני 

אירוח מכשירים חיצוניים

הקישור בין המכשירים


Android

הדוגמה הראשונה הופכת את המכשיר שלנו לשרת שממתין למכשירים חיצוניים שהתחברו אליו ובעצם אנחנו במצב האזנה אינסופי בעזרת AsyncTask שמאפשר לנו לעשות את התהליך ב Thread נפרד מבלי לחסום את האפליקציה.

private class BTListener extends AsyncTask<String, String, String> {

private BluetoothServerSocket mmServerSocket;
private OutputStream mmOutStream;
private InputStream mmInStream;
private final String NAME = "BlueTooth Test Application";
private UUID MY_UUID;
public String message = "";

//getting application uid and start to listen
public BTListener(String CODE) {
MY_UUID = UUID.fromString(CODE);

//getting device adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter
.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// no bluetooth adapter found.
return;
}

BluetoothServerSocket tmp = null;
try {
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(
NAME, MY_UUID);
} catch (IOException e) {
}

mmServerSocket = tmp;
}

// create listener to start serving the client.
private void executeListener() {

BluetoothSocket socket = null;
message = "";

while (true) {

try {
// enter to blocking mode until connection create, or timeout
socket = mmServerSocket.accept();

// getting the sockets
mmInStream = socket.getInputStream();
mmOutStream = socket.getOutputStream();

int bytesRead = 0;

int bufferSize = 1024;
byte[] buffer = new byte[1024];

message = "";
// get the message from client and update the gui.
while (true) {

bytesRead = mmInStream.read(buffer);

if (bytesRead != -1) {
while ((bytesRead == bufferSize)
&& (buffer[bufferSize] != 0)) {
message = message
+ new String(buffer, 0, bytesRead);
bytesRead = mmInStream.read(buffer);
}
// update the gui from another thread.
publishProgress(new String(buffer, 0, bytesRead));

}
}
} catch (IOException e) {
break;
} finally {
if (socket != null) {
try {
mmServerSocket.close();
} catch (IOException e) {
break;
}
}
}
}

}

// write message to the outputstream
public void write(String msg) {

byte[] buffer = msg.getBytes();
try {
mmOutStream.write(buffer);

} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}

@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);

}

@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
// sending information to function in the activity thread
setLblMessage(values[0]);
}

@Override
protected String doInBackground(String... params) {
executeListener();
return null;
}

}
}

על מנת להשלים את התמונה אנחנו צריכים מכשיר שיתחבר ל Android בהתחלה חשבתי להתחבר עם מכשיר Android נוסף, האמת שזו הזדמנות לשלב פלטפורמה נוספת כמו מחשב פיסי רגיל ובעזרת .Net לכתוב את הקוד , אבל העסק לא בא בחבילה אחת כמו ב Android וצריך להשתמש בספריות צד שלישי, החלטתי להשתמש עבור הדוגמה ב 32Feet.net שהיא מאוד נוחה וכמובן חינמית, המחלקה הזו יוצרת חיבור עם המכשיר שלנו ובעצם פותחת את ה Socket שמאפשר למכשירים לתקשר אחד עם השני, בדומה ל Android גם פה ניכנס למצב האזנה אינסופי ובעזרת BackgroundWorker נעשה זאת ב Thread חיצוני. 



.Net

מקבלים את רשימת המכשירים שמארחים בעזרת הפונקציה getAdapter ,יוצרים אובייקט חדש מסוג BTDesktopCLient ומעמיסים עליו את המכשיר המתאים יחד עם המפתח היחודי של האפליקציה.

using InTheHand.Net.Sockets;

 public class BTDesktopCLient
    {
        //return message to gui.
        public delegate void _delegateReadHandler(string msg);
        public event _delegateReadHandler readHandler;

        private const int MSGSIZE = 1024;

        BluetoothClient _client;
        BluetoothDeviceInfo _peer;
        BackgroundWorker _worker;
        Stream _peerStream;
        Guid _uid;
        private BluetoothAddress bluetoothAddress;
        private Guid _gu;

        public static BluetoothDeviceInfo[] getAdapter()
        {
            BluetoothClient tmp = new BluetoothClient();
            return tmp.DiscoverDevices();
        }

        //getting the device with application unique key
        public BTDesktopCLient(BluetoothDeviceInfo peer, Guid uid)
        {
            _uid = uid;
            _peer = peer;
            _worker = new BackgroundWorker();
            _worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
         
            connect();
            _worker.RunWorkerAsync();
        }

        //make the first connection with the device 
        //sending the unique application UID.
        public void connect()
        {
            try
            {
                _client = new BluetoothClient();
                BluetoothEndPoint ep = new BluetoothEndPoint(_peer.DeviceAddress, _uid);
                _client.Connect(ep);
                _peerStream = _client.GetStream();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        //write to the socket
        public void Write(string msg)
        {
            if (!_client.Connected)
                return;
            try
            {

                byte[] msgBuff = Encoding.ASCII.GetBytes(msg);
                _peerStream.Write(msgBuff, 0, msgBuff.Length);
                _peerStream.Flush();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void _worker_DoWork(object sender, DoWorkEventArgs e)
        {
            //entering infinity loop
            looper();
        }

        void looper()
        {
            //starting listening to the connected socket for incoming stream
            while (true)
            {
                byte[] buff = new byte[MSGSIZE];
                int bytesRead = 0;

                bytesRead = _peerStream.Read(buff, 0, buff.Length);
                while (bytesRead != 0)
                {
                    readHandler(Encoding.ASCII.GetString(buff).Trim());
                    buff = new byte[MSGSIZE];
                    bytesRead = _peerStream.Read(buff, 0, buff.Length);
                }
             
            }
        }
    }

יופי, אז עד עכשיו ראינו כיצד Android מארח חיבורים חיצוניים כמו מחשב הפיסי הרגיל שיש לנו בבית השלב הבא הוא להפוך את מחשב הפיסי למארח של משתמש Android  אם נשים לב לקוד נראה ש BTListener מקבל רק את המפתח היחודי של האפליקציה ולעומת זאת ה BTDesktopCLient מקבל מפתח ו Device שאליו הוא מעוניין להתחבר נהפוך את התהליך בעזרת מחלקות נוספות.

Android

עכשיו על ה Android לחפש מכשירים וליזום את החיבור, ההבדל העיקרי הוא שיש לבצע Discovering בדומה ל BTDesktopClient ב .Net, על מנת שנוכל למצוא את המכשיר המארח ואת זה עושים בעזרת פונקציה פשוטה כמו בדוגמה הבאה:

private void discovery() {
mBluetoothAdapter.startDiscovery();
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
.getBondedDevices();

if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
Log.d(TAG, device.getName());
//send the wanted device to BTClient
}
}
}


לאחר שמצאנו את המכשיר  נייצר אובייקט מסוג BTClient ונעביר אליו את ה Device ואת המפתח הייחודי של האפליקציה גם הפעם נצטרך להעזר ב AsyncTask על מנת לרוץ ברקע.

private class BTClient extends AsyncTask<String, String, String> {
                private final String TAG = null;
private BluetoothSocket mmSocket;
private BluetoothDevice mmDevice;
private BluetoothAdapter mBluetoothAdapter;
private InputStream mmInStream;
private OutputStream mmOutStream;
private UUID mmUUID;

//getting the device with application unique key
public BTClient(BluetoothDevice device, String CODE) {
mmUUID = UUID.fromString(CODE);
mmDevice = device;
BluetoothSocket tmp = null;

//getting the your own device adpater
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

//try to create a socket
try {
tmp = device.createRfcommSocketToServiceRecord(mmUUID);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

mmSocket = tmp;

}

@Override
protected String doInBackground(String... params) {

//if our adapter on discovering, cancel it
if(mBluetoothAdapter.isDiscovering())
mBluetoothAdapter.cancelDiscovery();
try {
//make the connection and collect the streams
mmSocket.connect();
mmInStream = mmSocket.getInputStream();
mmOutStream = mmSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}

byte[] buffer = new byte[1024];
int bytes;
String message = "";

// keep listening to the InputStream while connected
while (true) {
try {
// read from the InputStream
bytes = mmInStream.read(buffer);
message = message + new String(buffer, 0, bytes);

publishProgress(new String(buffer, 0, bytes));
mmSocket.getInputStream();

} catch (IOException e) {
Log.e(TAG, "disconnected", e);
break;
}
}

return null;
}

//write message to the outputstream
public void write(String msg) {

byte[] buffer = msg.getBytes();
try {
mmOutStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}

@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}

@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//sending information to function in the activity thread
setLblMessage(values[0]);
}

}


.Net

בדומה ל Android גם פה נאזין במצב אינסופי על המפתח הייחודי ובעזרת BackgroundWorker ,נמתין עד שמשתמש יבקש להתחבר ונפתח Socket מולו.

using InTheHand.Net.Sockets;

public class BTDesktopListener
    {
        // return message to gui.
        public delegate void _delegateReadHandler(string msg);
        public event _delegateReadHandler readHandler;

        private const int MSGSIZE = 1024;

        Guid _uid;
        BluetoothListener _listener;
        BluetoothClient _client;
        Stream _peerStream;

        BackgroundWorker _worker;

        // getting application uid and start to listen
        public BTDesktopListener(Guid uid)
        {
            _uid = uid;
            _worker = new BackgroundWorker();
            _worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
            _worker.RunWorkerAsync();

        }


        // create listener to start serving the client.
        void _worker_DoWork(object sender, DoWorkEventArgs e)
        {
           //entering infinity loop
            looper();
        }

        void looper()
        {
            _listener = new BluetoothListener(_uid);
            _listener.Start();

            while (true)
            {
                // enter to blocking mode until connection create, or timeout
                _client = _listener.AcceptBluetoothClient();
                _peerStream = _client.GetStream();
                byte[] buff = new byte[MSGSIZE];
                int bytesRead = 0;

                // getting the socket
                bytesRead = _peerStream.Read(buff, 0, buff.Length);
                while (bytesRead != 0)
                {
                    // get the message from client and update the gui.
                    readHandler(Encoding.ASCII.GetString(buff).Trim());
                    buff = new byte[MSGSIZE];
                    bytesRead = _peerStream.Read(buff, 0, buff.Length);
                }
            }
        }

        //write to the socket
        public void Write(string msg)
        {
            if (!_client.Connected)
                return;

            try
            {
                byte[] msgBuff = Encoding.ASCII.GetBytes(msg);
                _peerStream.Write(msgBuff, 0, msgBuff.Length);
                _peerStream.Flush();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

    }

כיצד זה נראה ב Android:


כיצד זה נראה ב PC:


סיכום:

ראינו את התהליך משני צדדי המטבע ועכשיו ניתן לשלב בין הפלטפורמות או לעבוד על כל פלטפורמה בנפרד, המאמר הזה הוא נקודת ציון להמשך שבו נשלב את ה Android עם מערכות משובצות מחשב אחרות ונוכל לשלוט בהן מרחוק.

קבצי מקור:

טיפולי שיניים משהו?

יום שבת, 1 ביוני 2013

HomeMade PCB Design Guide




אני לא מומחה גדול באלקטרוניקה, יש אנשים שזה המקצוע שלהם, אבל תמיד משך אותי תכנון לוחות, רובנו מקבלים את הלוחות כמובן מאליו ולא תמיד מעניין אותנו ממה בדיוק מורכב הלוח ,מספיק לנו דף ב Manual כדאי להחליט אם הלוח טוב מספיק, לאחר שהחלטתי להכניס את נושא ה Embedded לאתר זה משך אותי פנימה והרצון לדעת ממה כל העסק מורכב מאוד מסקרן אותי, החלטתי לכתוב מאמר כיצד ניתן לעצב ולבנות לוחות מבלי לצאת מהבית במיוחד עבור אב-טיפוס לפני שהולכים להדפיס אותו בכמויות.

PCB - Printed Circuit Board

אין הגדרה יותר טובה ממה שרשום בכותרת מדובר על מעגל מודפס שמכיל רכיבים אלקטרונים ומחבר בינהם בעזרת זרם חשמלי, יש המון סוגים של משטחים עבור יצירת PCB רובם עשויים מנחושת וניתן למצוא אותם בגדלים שונים, חלק מהמשטחים הם דו צדדים וניתן להדפיס משני הצדדים, בצורה זו ניתן לתכנן לוחות מורכבים יותר ולחסוך מקום, העברת התוכניות למשטח נעשת בעזרת שקף ומגהץ (כמו שנראה במאמר) או בעזרת קרני UV.



עבור הדוגמה של התהליך נבנה לוח עם Voltage Regulator שיוריד את הספק הזרם ל 5 V על מנת שנוכל לעבוד עם רכיבים עם צריכת חשמל נמוכה ועדיין להשתמש בשנאי ישן של 9 V.

כללי זהירות:

  • עבודה עם זרם חשמלי שמעל 5 V , שימו לב לא להשתמש בספקים שמעל 9 V - ראו הוזהרתם על אחריותכם בלבד.
  • Voltage Regulator מתחמם בזמן הורדת הזרם, ככל שהזרם גבוה יותר ככה הוא מתחמם יותר ועלול להישרף - ראו הוזהרתם על אחריותכם בלבד.
  • יצירת הלוח מתבצעת בעזרת חומצה מאוד מסוכנת, מומלץ להשתמש בה באיזור עם אוורור ואין לגעת בה באופן ישיר, יש להצטייד בכפפות פלסטיק ומשקפי מגן - ראו הוזהרתם על אחריותכם בלבד.



תכנון המעגל:

נתכנן את המעגל ע"ג Solder less Breadboard שבמקרה שיש טעות תמיד נוכל לתקן או להוסיף רכיבים נוספים לפני שאנחנו הולכים לייצר את האב טיפוס הראשוני.

Fritzing

http://fritzing.org/

זו סביבה שדרכה ניתן לתכנן את הלוח, היא מגיעה עם המון רכיבים ולוחות והיא מאוד פשוטה לעבודה, ניתן לייצר ממנה את התוכניות המדוייקות של הלוח לצורך הדפסה או לשלוח את התוכנית לחברה חיצונית שתדפיס אותה באופן מקצועי, יש 3 מצבי תצוגה שונים שמאפשרים לנו לקפוץ בין ה Breadboard ל Schematic ול PCB בצורה נוחה, נתכנן את המעגל בעזרת התוכנה ואח"כ נחבר פיזי את הרכיבים ללוח ה Breadboard.


כשנעבור למצב PCB נבדוק כיצד המעגל המודפס נראה (צריך לסדר אותו קצת..):


דרישות:

  • Voltage Regulator - 7805CT
  • 2 Capacitor - 10uf
  • Power Jack Connector
  • 330 Ohm Resistor
  • Led
  • Wires
  • Solder less Breadboard
  • Multimeter
  • Pins Header
  • 9 v Adapter




מבנה סופי:


 ל Voltage Regulator יש 3 רגליים, הרגל אמצעית מחוברת ל GND, הרגל העליונה מחוברת לשנאי והרגל התחתונה מוציאה 5 V, נמדוד בעזרת ה Multimeter את הזרם לפני ה Voltage Regulator ואח"כ נמדוד שוב אחרי ה Voltage Regulator ונוודא שאנחנו מקבלים את הזרם המתאים.

הכנת הלוח:

לאחר שהכנו את המעגל ובדקנו אותו ניתן לייצר את התוכניות ישירות מ Fritzing כ PDF ואח"כ להדפיס אותו על שקף בעזרת מדפסת ביתית.


כשעושים Export ל PDF מקבלים מספר קבצים, נשתמש בקובץ ה Bottom שהוא בעצם החלק האחורי (זה עם הנחושת), ובצדו השני נרכיב את הרכיבים, שימו לב זה מאוד מבלבל מומלץ להדפיס על דף רגיל ,לנסות להרכיב את הרכיבים ולראות שאין טעות.

שימו לב! - הלוח מתוכנן על משטח חד צצדי של PCB , חשוב לוודא שכל הרכיבים נמצאים בשכבה המתאימה.

דרישות:

  • PCB Half Side
  • Ferric Chloride - חומצה
  • Transparent Paper -  שקפים
  • Black Permanent Marker - טוש
  • Sand Paper - נייר זכוכית
  • Paper Tape - נייר סלוטייפ
  • Bowl - קערה לחומצה
  • Bowl - קערה למים
  • Iron - מגהץ
  • Rubber gloves - כפפות גומי
  • Goggles - משקפי מגן


נדפיס את התוכנית ע"ג שקף ואחר כך נחתוך את ה PCB לפי המידות:




נשפשף את הלוח בנייר זכוכית עד למראה זוהר:




נעטוף בעזרת נייר סלוטייפ את התוכנית צמודה ללוח:




נלחץ על הלוח את המגהץ, למספר דקות עד שנקבל גוון חום של נייר הסלוטייפ, מפעילים לחץ על דפנות הלוח ומרכזו על מנת שהתוכנית תעבור בשלמותה.


נכניס את הלוח לקערת מים ונוריד את הנייר הסלוטייפ יחד עם השקף, התוכנית צריכה לעבור ללוח במקרה שלא הכל עבר כמו שצריך נשתמש בטוש על מנת לתקן איזורים דהויים או חסרים, מומלץ לעשות הדגשה נוספת.



נכין את החומצה, נרתיח מים חמים, היחס הוא אחד לשליש, כלומר כוס מים ושליש כוס חומצה , במקרה שלי החומצה מגיעה כדוריות שנמסות במים ונותנות להם גוון אדום, נמתין בין 20 ל 30 דקות להשלמת פעולת החומצה.




נשטוף את הלוח במים על מנת שהחומצה תרד ובעזרת ניר הזכוכית נוריד את הדיו של התוכנית על מנת שיחשף לנו המעגל




הרכבת הלוח:

זהו מעגל המודפס מוכן, השלב הבא הוא להכין את הלוח עם כל המרכיבים, נעשה חורים בעזרת Dremel ונלחים את החלקים לפי התוכנית.




דרישות:
  • Soldering Iron - מלחם
  • Solder - בדיל
  • Dremel
  • Third Hand - יד שלישית




מבנה סופי:





בדיקות אחרונות:

נוודא בפעם האחרונה שהזרם הסופי שמקבלים הוא 5 V ללא הפרעות.



סיכום:

סיימנו את התהליך אומנם הוא ארוך ודורש קצת שיעורי מלאכה אבל בהחלט היה שווה את זה, מעכשיו נוכל לתכנן בעצמנו את הלוחות עבור הפרוייקטים שלנו מבלי לצאת מהבית.

הורדת התוכנית:

זה חי!!!!