[14호]윈도우 WHQL 테스팅, 왜 진행해야 할까요?
윈도우 WHQL 테스팅, 왜 진행해야 할까요?
글 | 볼트마이크로 김선아 주임연구원
윈도우 사용자라면 한번쯤 아래와 같은 경고 창을 본적이 있을 것 입니다.
소프트웨어를 설치할 때 경고창이 발생하면 바이러스처럼 악성 소프트웨어는 아닐까 한번쯤 고민하게 됩니다.
이처럼 Microsoft Windows에서는 디지털 서명되지 않은 드라이버나 소프트웨어를 설치 시 경고창을 발생시키거나 실행을 차단하는 정책을 적용하고 있습니다. 바이러스 및 불법 소프트웨어를 설치 시도하는 사용자에게 경고하기 위한 방안이기도 하지만 WHQL 인증 (디지털 서명) 및 Windows Logo 부착을 권고함으로써 Microsoft OS의 요구에 맞게 디자인되고 테스트가 되었음을 증명할 수도 있습니다. 또한 사용자에게 제품 품질에 신뢰를 주고, 타사 제품과의 차별성과 경쟁력을 확보할 수 있는 정책으로써의 역할을 하고 있습니다.
그럼 WHQL 테스팅 및 윈도우 로고 획득에 관하여 더 자세히 알아보도록 하겠습니다.
1. WHQL 이란 무엇인가?
·Windows Hardware Quality Labs Testing(WHQL Testing)은 Microsoft Windows 운영체제에서 하드웨어와 소프트웨어가 안정적인 동작을 할 수 있도록 호환성에 대한 명확한 기준을 제시하고 있는데 이에 대한 인증 프로세스를 의미합니다.
·WHQL 인증 프로세스를 통과하게 되면 Microsoft에서는 디지털 서명 파일을 제공하고 Windows Logo를 사용할 수 있게 됩니다.
2. WHQL의 장점
·Windows Logo가 부착되었거나 WHQL 인증을 받은 제품은 Microsoft OS의 요구에 맞게 디자인 되고 테스트가 되었음을 증명합니다. 그렇기 때문에 사용자에게 제품 품질에 신뢰를 줄 수 있으며 타사 제품과의 차별성과 경쟁력을 확보 할 수 있습니다.
·DTM 테스트 (자동화된 스트레스 테스트)로 OS 별 제품의 문제점을 검증하고 Microsoft로부터 Windows Error Reporting과 Windows Update(WU)등의 서비스를 제공 받아 기술 지원 비용을 감소 시킬 수 있습니다.
·WHQL인증 및 Windows Logo를 획득한 제품들은 Windows Catalog와 HCL(Hardware Compatibility List)에 등록을 할 수 있습니다. 이로 인한 제품 홍보 효과 또한 기대할 수 있습니다.
3. WHQL의 종류
WHQL Testing 방법에는 아래와 같이 3가지로 구분이 가능합니다.
여기에서는 Windows Logo와 Signature 2가지에 대해 살펴보도록 하겠습니다.
i. Unclassified = signature only
·Windows Logo Program Category에 속하지 않는 종류의 Device 이거나 단순히 드라이버 설치할 경우 경고 창이 뜨는 것을 막고 싶을 때 unclassified 클래스로 드라이버 인증을 진행합니다.
·드라이버 singing을 목적으로 디바이스의 드라이버와 Windows OS와의 호환성 테스트만 진행 됨으로 Windows Logo를 제품에 부착할 수 없습니다.
·Unclassified(signature-only)로 진행하더라도 Windows Update에서 Driver 배포가 가능합니다.
ii. Windows Logo : 하드웨어 & 시스템 인증
·Windows Logo Program Category에 포함되는 장치로써 해당 Logo 테스트에 통과한 제품은 Windows Logo를 부착함으로써 타 제품과 구분을 하도록 자격을 부여하는 것 입니다.
·윈도우 로고 획득이 가능한 category의 목록은 아래 링크에서 확인이 가능합니다.
http://msdn.microsoft.com/en-us/windows/hardware/gg462990
·Windows Logo를 부착함에 따라 Windows에서 동작하는 제품에 대한 호환성 보장 그리고 품질 및 고객의 신뢰도 향상을 가져올 수 있습니다.
4. WHQL 인증 절차
i. WHQL 인증 준비 단계
A. VeriSign Class 3 ID 발급
·Windows Logo를 신청하기 위해서는 기업 인증 디지털 ID로 서명된 파일만이 사용되며, 이를 위해 VeriSign ID를 발급받아야 합니다.
·VeriSign ID를 발급 받음으로써 submission Package가 도용되거나 악성코드로부터 보호가 가능합니다.
·드라이버에 Embedded-sign을 적용함으로써 booting Time이 빨라질 수 있습니다.
·VeriSign 발급에는 일주일에서 한달 정도의 시간이 소요되어 미리 준비가 필요합니다.
·아래 링크된 한국 VeriSign 홈페이지에서 VeriSign발급에 대한 도움을 받으실 수 있습니다.
https://www.verisign.com.au/ts-sem-kr/?sl=6D09U-0000-01-00&gclid=CP7v-oyD_60CFUlU4god2UT8uw
B. sysdev.microsoft.com ( 구 Winqual ) 계정 가입
·https://sysdev.microsoft.com : Submssion 제출을 위해서는 DevCenter의 계정이 필요합니다. DevCenter에서는 인증을 제외하고도 Windows Hardware Development 와 관련된 Tool 문서 및 기술지원을 하고 있습니다.
ii. WHQL 인증 테스트 단계
A. Windows Logo requirement 확인 및 WLK(HCK) 다운로드 및 설치
·Windows Logo requirement 확인 : Windows Logo를 받기 위하여 필요한 기본적인 Spec을 확인하여 미리 준비한다면 테스트 중에 Fail이 발생하여 다시 수정하는 등의 초과시간 및 인력을 절약할 수 있습니다.
·WLK(HCK)설치 : WHQL인증에 필요한 관련 테스트를 할 수 있는 Tool입니다. Windows 7 OS까지는 WLK(Windows Logo Kit)를 사용하여 WHQL 인증 테스트를 진행하였지만 Windows 8이 출시됨에 따라 Windows 8까지 지원 가능한 HCK(Hardware Certification Kit)가 배포 되었으며 해당 Tool을 사용하여 아래 [그림6]과 같이 테스트 환경을 구축해야 합니다.
iii. WHQL 테스트 결과 제출 단계
A. WHQL Submission
·WHQL 인증 테스트 항목이 모두 Pass 되고 모든 항목의 테스트가 끝나면 테스트 결과 Log 파일(.cab)이 생성되게 됩니다. On-line 으로 Windows dashboard에 테스트 결과 Log 파일이나 제품을 보내어 인증을 받는 과정을 의미합니다.( 재 신청 시 비용 및 Package 재발송이 이루어져야 합니다. )
B. Submission 비용
·한 OS군(ex: XP32bit/64bit) 당 $250 의 비용이 발생합니다.
·Windows 8 OS의 경우 현재 정식으로 출시 된 버전이 아니라 Preview 버전이기 때문에 Preview 기간 동안에는 Windows 8 OS군에 한 하여 100$의 비용으로 Submission을 진행하고 있습니다. Windows 8의 정식 출시 이후에는 타 OS 와 동일하게 250$의 비용이 청구되게 됩니다.
·DUA(Driver Update Acceptable) Submission : 드라이버파일의 변경사항은 없지만 inf 파일에서의 변경사항이 발생하였을 경우에는 WHQL 인증 테스트를 처음부터 다시 진행하지 않고 inf파일만 수정하여 Submission을 진행할 수 있도록 간략한 Submission 절차인 DUA Submission 방법을 제공하고 있습니다. 해당 방법을 사용할 경우에는 100$의 비용이 청구되게 됩니다.
C. Submission 검토기간
·사정에 따라 최소 1일에서 최대 7일까지 소요됩니다. 그렇기 때문에 테스트 일정을 조금 여유롭게 계획하여 진행하는 것이 좋습니다.
D. WHQL Test and Review
·Submission 에서 Fail 이 발생할 경우 다시 WHQL 인증을 신청해야 하며, 재 신청 시 비용 및 Package 재 발송을 필요로 합니다. Pass를 할 경우에는 Windows Logo를 사용할 수 있으며 제품관련 정보를 Windows Catalog와 HCL(Hardware Compatibility List)에 등록 가능합니다.
5. Windows 8 정식 출시와 HCK
Windows 8의 정식 출시가 얼마 남지 않았습니다. 확연히 달라진 UI로 사람들의 기대를 증폭 시키고 있습니다. Windows 8의 출시에 앞서 개발자 및 기타 사용자들을 위해 Release Preview 버전을 MS사에서 배포하고 있습니다. 불법 소프트 웨어를 위한 피해 대비 및 경쟁력 강화를 위해 Windows Logo 및 인증 또한 제공하고 있습니다. WHQL 인증을 위해 사용해 오던 Tool이 WLK대신 HCK 라는 Tool로 변경된 차이점도 있습니다.
WLK에서 HCK로 Tool이 변화 됨에 따라 WLK와 어떠한 차이점이 있는지 또 어떠한 부분을 더 추가적으로 준비해야 하는지 알아 보도록 하겠습니다.
i. HCK 란?
·Hardware Certification Kit 로서 Windows 8이 출시됨에 따라 Windows 8의 인증을 지원하는 WLK의 업그레이드 버전 입니다.
ii. HCK 다운로드 및 설치
·http://msdn.microsoft.com/en-us/windows/hardware/hh852366 링크에서 다운로드 한 후에 설치합니다.
설치환경 : HCK Studio의 경우 Windows Server 2008 R2 English 버전에서만 설치 할 수 있습니다. 테스트 컴퓨터에 클라이언트 소프트웨어를 설치하면 자동으로 Studio에 등록됩니다.
iii. WLK1.6 VS HCK ?
WLK 1.6의 unclassified와 Windows Logo Class로 나누어져 있던 부분이 HCK에서는 Signature only와 Windows Logo 그리고 UEFI submission으로 변경되었습니다.
A. Signature-only 란?
·WLK의 unclassified와 동일한 Class로써 Windows Logo Class Category에 포함되지 않는 Device일 경우 HCK에서 Signature-only Class로 인식하여 테스트 진행을 도와주고 있습니다.
B. Windows Logo Class 란?
·WLK1.6과 동일하게 Windows Logo 획득이 가능한 Category에 포함되는 Device로서 해당 테스트를 모두 만족하면 Windows Logo 및 MS에서 제공하는 모든 Service를 이용할 수 있습니다.
C. UEFI 서명이란?
·Dash board에서 제공하는 새로운 서비스입니다. 이 서비스를 사용하면 x86 또는 x64 컴퓨터를 대상으로 지정한 UEFI 펌웨어 이진에 서명하여 Windows 8 PC에 설치할 수 있습니다. EBC(EFI 바이트코드) 파일은 /ALIGN:32 플래그를 사용하여 컴파일 해야 프로세스에 성공할 수 있습니다. 제출 패키지는 폴더가 없고 서명할 *.efi 파일만 포함된 CAB 라이브러리여야 합니다.
·WLK의 경우 WHQL인증 요청자가 Unclassified 또는 Windows Logo Class를 선택하여 테스트 진행이 가능하였습니다. 하지만 HCK의 경우 HCK Studio에서 자동으로 디바이스를 인식하여 Window Logo 획득에 가능한 테스트 항목을 모두 보여주는 방식으로 변경되었습니다.
iv. HCK Tool 및 Windows 8 인증을 받기 위하여 주의해야 할 점은?
WLK1.6에서 HCK로 툴이 변화함에 따라 테스트 항목 및 테스트 방법 또한 수정되었습니다. WLK와 동일한 테스트 항목이라 할지라도 HCK에서 Fail이 발생할 수 있기 때문에 HCK에서 요구하는 Spec을 미리 살펴보고 필요한 부분은 수정을 해야 합니다.
Windows Hardware Certification Requirement 다운로드 링크
http://msdn.microsoft.com/library/windows/hardware/jj128252
WLK1.6에서는 사용자가 테스트 Class를 선택하여 진행하였기 때문에 Windows Logo Class에 존재하는 Device라 할지라도 unclassified인증으로 Driver Signature-only가 가능했었습니다. 하지만 현재 HCK의 경우 HCK Studio에서 직접 디바이스를 인식하여 테스트 항목을 보여주는 형식으로 진행 되기 때문에 Windows Logo Category에 포함되는 Device일 경우 Signature-only로 인증 진행이 불가능하다는 점을 명심해야 합니다.
6. WHQL Testing의 HCK? WLK? 너무 어려워요.
앞서 HCK와 WLK 및 WHQL 인증에 대하여 상세히 설명해 드렸지만 아직도 WHQL 인증을 시작하기에 막막함을 느끼는 분들이 많으실 것으로 예상됩니다. 볼트마이크로는 다년간 WHQL Testing을 대행하면서 쌓은 노하우로 가장 빠르고 안전하게 제품 테스트를 돕는 WHQL Testing 대행 서비스를 제공하고 있습니다 또한 해당 문제점을 분석하여 해결할 수 있는 솔루션 제공까지 가능한 기술력을 보유하고 있습니다.
■ 볼트마이크로 WHQL Testing 대행 절차 소개 ■
(1) 볼트마이크로에 WHQL 인증 Testing 의뢰하기
·디바이스마트의 커스텀 서비스를 사용하여 편리하게 윈도우 인증의뢰가 가능합니다.
·제품에 대한 설명, 지원 OS 등 제품의 정보를 함께 전달해 주셔야 합니다.
http://www.devicemart.co.kr/design/index.php?tpl=window.htm
(2) DTM 테스트 접수 확인
·볼트마이크로에서 DTM 테스트 접수 확인 후에 견적서 및 인증에 필요한 기타 사항에 대하여 준비를 요청 드립니다
Ex) VeriSign ID 발급 및 Microsoft DashBoard 가입, 견적서 전달
(3) 디바이스 및 테스트 드라이버 전달
·테스트에 필요한 디바이스 및 드라이버를 전달 받습니다. 인증을 의뢰한 업체에서는 테스트 비용을 지급합니다.
(4) WHQL 테스트 진행
·의뢰 받은 모든 OS에 대하여 테스트를 진행합니다.
·테스트 중 문제점이 발생하였을 경우 Issue Report 전달해 드립니다. 인증을 의뢰한 업체에서는 해당 문제점을 수정하여 다시 볼트마이크로로 전달합니다.
(5) Submission 제출
·모든 테스트가 통과 되면 Microsoft에 최종 테스트 결과를 제출합니다.
·Submission이 통과 되면 서명된 Catalog File 및 Logo artwork를 다운로드 하여 인증의뢰 업체에 전달하게 됩니다.
볼트마이크로는 거의 모든 디바이스 그룹의 WHQL Testing을 수행한 경험이 있으며, 벤더로 문제점의 원인과 WHQL Testing통과를 위한 정확한 가이드를 제공하고 있습니다. WHQL 인증에 어려움을 느끼고 계신 모든 업체들의 길잡이가 되어 드릴 수 있도록 하겠습니다.
[14호]국제 LED EXPO & OLED EXPO 2012
[14호] 안드로이드를 이용한 탱크 조종
2012 DIY 프로젝트 작품 공모전 – 도전상
안드로이드를 이용한
탱크 조종
글 | 김종욱 bear1215@korea.com
심사평
근래 관심을 받는 안드로이드와 일반 주행 로봇을 결합한 작품이다. 무선조종기 대신 안드로이드 OS를 이용하여 해당 OS가 설치된 장비(폰, 태블릿 등)에서 로봇을 조종할 수 있도록 되어있다. 일반 사용자의 DIY 컨셉에 맞춰 본다면 쉽게 접근할 수 있는 내용이다. 단, 안드로이드 측 프로그램에 대한 구현방법에 대한 설명 등이 문서상 미흡한 것이 아쉬움으로 남는다.
개발 동기 및 목적
안드로이드를 이용한 탱크 조종을 하고자 하였다. 통신 방식은 블루투스를 이용하고 탱크측 제어는 Attiny2313를 이용하였고, 단순 전후진만이 아닌 다른 동작들을 추가 하였다. 1.전후진, 2.좌회전, 3.우회전, 4.좌후진, 5.우후진, 6.포탑 회전(좌우), 7.포신의 상하 이동, 8.포탄 발사(BB탄 발사), 9.전조등/후미등 켜기
단계별 과정
1. 구조도(상세 블럭도 및 회로도 참조)
전원은 기존의 밧데리를 이용한다. (9.7V 1000mA)
정전원 변환은 LM2575-5.0를 사용하였다. 전원은 9.7V를 모터 구동 전원으로 사용하고 제어부인 Attiny2313은 5.0V 전원을 사용한다.
탱크부 구성
기존의 RF 제어부를 제거하고 모터, 밧데리 등은 그대로 사용한다. 탱크의 구성은 아래의 표와 같다.
탱크 제어는 Attiny2313을 사용한다.
가. MPU : Attiny2313
나. 주모터 제어 : L293B(정역 회전용 2set)
다. 포탑 모터 : LB1630(정역 회전용 1set)
라. 포신 모터 : ULN2803(1/8)
마. 포 발사 모터 : ULN2803(1/8)
바. 전조등 : ULN2803(1/8)
사. 후미등 : ULN2803(1/8)
4. 탱크 제어부 통신 모듈
탱크 제어부와 안드로이드 폰 연결은 bluetooth모듈을 사용하였다.
5. 안드로이드 프로그램
Program : android측
tankControl.java
tankControl.java 소스보기
package kr.sunejune;
import android.R;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View.OnClickListener;
public class TankControl extends Activity implements OnClickListener {
private static final String TAG = “TankControl”;
private static final boolean D = false;
// Message types sent from the BluetoothChartService Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
// Key names received from the BluetoothChartService Handler
public static final String DEVICE_NAME = “device_name”;
public static final String TOAST = “toast”;
// Name of the connected device
private String mConnectedDeviceName = null;
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
// Local Bletooth adapetr
private BluetoothAdapter mBluetoothAdapter = null;
// Member object for the chat services
private SvrServer mSvcServer = null;
private TextView mStatus;
finish();
/*
// Called when the activity is first created.
static final int[] BUTTONS = {
R.id.ball,
R.id.turrent_left,
R.id.turrent_stop,
R.id.turrent_right,
R.id.f_center,
R.id.f_left,
R.id.f_right,
R.id.t_center,
R.id.t_left,
R.id.t_right,
R.id.c_center,
R.id.c_left,
R.id.c_right,
R.id.gun_up,
R.id.gun_dn,
R.id.gun_stop
};
*/
int ball_f = 0;
TextView _out1 = null;
TextView _out2 = null;
TextView _out3 = null;
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.tankcontrol);
setOnClickListener((ViewGroup)findViewById(R.id.tblButtons));
mStatus = (TextView)findViewById(R.id.txtStatus);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if( mBluetoothAdapter == null){
Toast.makeText(this, “Bluetooth is not available”, Toast.LENGTH_SHORT).show();
finish();
return;
}
_out1 = (TextView)findViewById(R.id.text1);
_out2 = (TextView)findViewById(R.id.text2);
_out3 = (TextView)findViewById(R.id.text3);
_out1.setText(“Hello”);
_out1.setBackgroundColor(0xFFFFFF00);
_out1.setGravity(Gravity.CENTER);
_out2.setText(“멈춤”);
_out2.setBackgroundColor(0xFFFF00FF);
_out2.setGravity(Gravity.CENTER);
_out3.setText(“멈춤”);
_out3.setBackgroundColor(0xFF00FFFF);
_out3.setGravity(Gravity.CENTER);
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
/*
if(D) Log.e(TAG,”++ ON START ++”);
if( !mBluetoothAdapter.isEnabled() ) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT );
}
else {
if(mSvcServer == null) {
mSvcServer = new SvrServer(this, mHandler);
}
}
*/
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.option_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.scan :
/*
Intent serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
*/
Intent serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent , REQUEST_CONNECT_DEVICE);
return true;
}
return false;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(D) Log.d(TAG,”onActivityResult”+resultCode);
switch(requestCode){
case REQUEST_CONNECT_DEVICE :
if(resultCode == Activity.RESULT_OK){
String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mSvcServer.connect(device);
}
break;
case REQUEST_ENABLE_BT :
if(resultCode == Activity.RESULT_OK){
if(mSvcServer == null) {
mSvcServer = new SvrServer(this, mHandler);
}
}
else {
Log.d(TAG,”BT not enable”);
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
break;
}
}
public void onInit(int status) {
if(D) Log.d(TAG, “onInit”);
}
private View[] getChildViews(ViewGroup group){
int childCount = group.getChildCount();
final View[] childViews = new View[childCount];
for(int index = 0; index < childCount; index++) {
childViews[index] = group.getChildAt(index);
}
return childViews;
}
private void setOnClickListener(ViewGroup group){
View[] childViews = getChildViews(group);
for(View view:childViews){
if(view instanceof Button) {
view.setOnClickListener(this);
}
else if(view instanceof ViewGroup) {
setOnClickListener((ViewGroup) view);
}
}
}
private int sendToQue(String data){
if(mSvcServer.getState() != SvrServer.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
return -1;
}
return mSvcServer.toQue(data);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if (D)
Log.i(TAG, “MESSAGE_STATE_CHANGE: ” + msg.arg1);
switch (msg.arg1) {
case SvrServer.STATE_CONNECTED:
mStatus.setText(R.string.status_connected_to);
mStatus.append(mConnectedDeviceName);
break;
case SvrServer.STATE_CONNECTING:
mStatus.setText(R.string.status_connecting);
break;
case SvrServer.STATE_LISTEN:
case SvrServer.STATE_NONE:
mStatus.setText(R.string.status_not_connected);
break;
}
break;
// TODO: remove MESSAGE_READ
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
// mConversationArrayAdapter.add(mConnectedDeviceName+”: ” +
// readMessage);
break;
case MESSAGE_DEVICE_NAME:
// save the connected device’s name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(),
“Connected to ” + mConnectedDeviceName,
Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(),
msg.getData().getString(TOAST), Toast.LENGTH_SHORT)
.show();
break;
}
}
};
public void gun_text()
{
Button b_up = (Button)findViewById(R.id.gun_up);
Button b_dn = (Button)findViewById(R.id.gun_dn);
Button b_st = (Button)findViewById(R.id.gun_stop);
b_up.setText(“포신 UP”);
b_dn.setText(“포신 DN”);
b_st.setText(“포멈춤”);
}
public void turrent_text()
{
Button b_up = (Button)findViewById(R.id.turrent_left);
Button b_dn = (Button)findViewById(R.id.turrent_right);
Button b_st = (Button)findViewById(R.id.turrent_stop);
b_up.setText(“포탑_좌”);
b_dn.setText(“포탑_우”);
b_st.setText(“포탑멈춤”);
}
public void move_text()
{
Button b1_1 = (Button)findViewById(R.id.f_left);
Button b1_2 = (Button)findViewById(R.id.f_center);
Button b1_3 = (Button)findViewById(R.id.f_right);
b1_1.setText(“전_좌”);
b1_2.setText(“전_전”);
b1_3.setText(“전_우”);
Button b2_1 = (Button)findViewById(R.id.c_left);
Button b2_2 = (Button)findViewById(R.id.c_center);
Button b2_3 = (Button)findViewById(R.id.c_right);
b2_1.setText(“좌_좌”);
b2_2.setText(“멈춤”);
b2_3.setText(“우_우”);
Button b3_1 = (Button)findViewById(R.id.t_left);
Button b3_2 = (Button)findViewById(R.id.t_center);
Button b3_3 = (Button)findViewById(R.id.t_right);
b3_1.setText(“후_좌”);
b3_2.setText(“후_후”);
b3_3.setText(“후_우”);
}
@Override
public void onClick(View v){
if(v instanceof Button) {
int btn_id = v.getId();
Button btn = (Button)findViewById( btn_id );
switch ( btn_id ) {
case R.id.ball :
if( ball_f == 0 ) {
if(sendToQue(“A”)==0) {
btn.setText(“발사중(A)”);
_out1.setText(“포 발사”);
ball_f = 1;
}
}
else {
sendToQue(“B”);
btn.setText(“발사대기(B)”);
_out1.setText(“Hello”);
ball_f = 0;
}
break;
case R.id.gun_up :
if(sendToQue(“C”) == 0) {
gun_text();
btn.setText(“..ing(C)”);
_out1.setText(“포신 UP”);
}
break;
case R.id.gun_dn :
if(sendToQue(“E”) == 0) {
gun_text();
btn.setText(“..ing(E)”);
_out1.setText(“포신 DOWN”);
}
break;
case R.id.gun_stop :
if(sendToQue(“D”) == 0) {
gun_text();
btn.setText(“STOP(D)”);
_out1.setText(“포신 STOP”);
}
break;
case R.id.turrent_left :
if(sendToQue(“F”) == 0) {
turrent_text();
btn.setText(“..ing(F)”);
_out2.setText(“좌”);
}
break;
case R.id.turrent_right :
if(sendToQue(“H”) == 0) {
turrent_text();
btn.setText(“..ing(H)”);
_out2.setText(“우”);
}
break;
case R.id.turrent_stop :
if(sendToQue(“G”) == 0) {
turrent_text();
btn.setText(“STOP(G)”);
_out2.setText(“멈춤”);
}
break;
case R.id.f_left :
if(sendToQue(“I”) == 0) {
move_text();
btn.setText(“..ing(I)”);
_out3.setText(“전_좌 “);
}
break;
case R.id.f_center :
if(sendToQue(“J”) == 0) {
move_text();
btn.setText(“..ing(J)”);
_out3.setText(“전_전 “);
}
break;
case R.id.f_right :
if(sendToQue(“K”) == 0) {
move_text();
btn.setText(“..ing(K)”);
_out3.setText(“전_우 “);
}
break;
case R.id.c_left :
if(sendToQue(“L”) == 0) {
move_text();
btn.setText(“..ing(L)”);
_out3.setText(“좌_좌 “);
}
break;
case R.id.c_center :
if(sendToQue(“M”) == 0) {
move_text();
btn.setText(“STOP(M)”);
_out3.setText(“멈춤”);
}
break;
case R.id.c_right :
if(sendToQue(“N”) == 0) {
move_text();
btn.setText(“..ing(N)”);
_out3.setText(“우_우 “);
}
break;
case R.id.t_left :
if(sendToQue(“O”) == 0) {
move_text();
btn.setText(“..ing(O)”);
_out3.setText(“후_좌 “);
}
break;
case R.id.t_center :
if(sendToQue(“P”) == 0) {
move_text();
btn.setText(“..ing(P)”);
_out3.setText(“후_후”);
}
break;
case R.id.t_right :
if(sendToQue(“Q”) == 0) {
move_text();
btn.setText(“..ing(Q)”);
_out3.setText(“후_우 “);
}
break;
}
}
}
}
Program : android측
SvrServer.java
SvrServer.java 소스보기
package kr.sunejune;
import java.util.UUID;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Handler;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
public class SvrServer {
// Debug
private static final String TAG = “SvrServer”;
private static final boolean D = false;
// Name for the SDP record when creating server socket
private static final String NAME =”TankCon”;
// Generic UUID for SPP
private static final UUID MY_UUID = UUID.fromString(“00001101-0000-1000-8000-00805F9B34FB”);
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAccepThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0;
public static final int STATE_LISTEN = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTED = 3;
public SvrServer(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
private synchronized void setState(int state) {
if( D ) Log.d(TAG, “setState()”+mState+”==>”+state);
mState = state;
mHandler.obtainMessage(TankControl.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState() {
return mState;
}
public synchronized void start() {
if(D) Log.d(TAG, “start” );
if(mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; }
if(mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; }
if(mAccepThread == null) { mAccepThread = new AcceptThread(); mAccepThread.start(); }
setState(STATE_LISTEN);
}
public synchronized void connect(BluetoothDevice device){
if(D) Log.d(TAG,”connect to:” + device);
if(mState == STATE_CONNECTING) {
if(mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; }
}
if(mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; }
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if(D) Log.d(TAG, “connected”);
if(mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; }
if(mConnectedThread != null) { mConnectedThread.cancel(); mConnectThread = null; }
if(mAccepThread != null) { mAccepThread.cancel(); mAccepThread = null; }
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
Message msg = mHandler.obtainMessage( TankControl.MESSAGE_DEVICE_NAME );
Bundle bundle = new Bundle();
bundle.putString( TankControl.DEVICE_NAME, device.getName() );
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop() {
if(D) Log.d(TAG,”stop”);
if(mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; }
if(mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; }
if(mAccepThread != null) { mAccepThread.cancel(); mAccepThread = null; }
setState(STATE_NONE);
}
public int toQue(String data) {
ConnectedThread r; // temp
synchronized(this) {
if(mState != STATE_CONNECTED ) return -1;
r = mConnectedThread;
}
return r.toQue(data);
}
private void connectionFail() {
if(D) Log.d(TAG,”connectionFail”);
setState(STATE_LISTEN);
Message msg = mHandler.obtainMessage( TankControl.MESSAGE_TOAST );
Bundle bundle = new Bundle();
bundle.putString(TankControl.TOAST, “Unable to connect device”);
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private void connectionLost() {
if(D) Log.d(TAG, “connectionLost”);
setState(STATE_LISTEN);
Message msg = mHandler.obtainMessage(TankControl.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(TankControl.TOAST, “Device connection was lost”);
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch ( IOException e ) {
Log.e(TAG, “listen() failed”, e);
}
mmServerSocket = tmp;
}
@Override
public void run() {
if(D) Log.d(TAG, “BEGIN mAcceptThread”+this);
setName(“AcceptThread”);
BluetoothSocket socket = null;
while( mState != STATE_CONNECTED ) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, “accept() failed”, e);
break;
}
if(socket != null) {
synchronized ( SvrServer.this ) {
switch(mState) {
case STATE_LISTEN :
case STATE_CONNECTING :
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE :
case STATE_CONNECTED :
try {
socket.close();
}catch (IOException e) {
Log.e(TAG,”Could not close unwanted socket”, e);
}
break;
}
}
}
}
if(D) Log.d(TAG,”END mAcceptThread”);
}
public void cancel() {
if(D) Log.d(TAG,”cancel”+this);
try {
mmServerSocket.close();
}catch(IOException e) {
Log.e(TAG,”close() of server failed”,e);
}
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}catch(IOException e) {
Log.e(TAG,”create() failed”, e);
}
mmSocket = tmp;
}
@Override
public void run() {
Log.i(TAG,”BEGIN ConnectThrtead”);
setName(“ConnectThread”);
mAdapter.cancelDiscovery();
try{
mmSocket.connect();
}catch(IOException e1) {
connectionFail();
try {
mmSocket.close();
}catch (IOException e2) {
Log.e(TAG,”unable to close() socket during connection failure”, e2);
}
SvrServer.this.start();
return;
}
synchronized ( SvrServer.this ) {
mConnectThread = null;
}
connected(mmSocket, mmDevice );
}
public void cancel() {
try {
mmSocket.close();
}catch(IOException e) {
Log.e(TAG,”close() of connect socket failed”, e);
}
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, “create ConnectedThread”);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, “temp sockets not created”, e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
@Override
public void run() {
Log.i(TAG, “BEGIN mConnectedThread”);
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
// TODO: add dogkick!!
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(TankControl.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, “disconnected”, e);
connectionLost();
break;
}
}
}
public int toQue(String in_data) {
int ret = 0;
try {
String data = in_data;
/*
if (0 < left) data += ‘F’;
else if (0 > left) {data += ‘B’; left = -left;}
else data +=’H';
if (0 < right) data += ‘F’;
else if (0 > right) {data += ‘B’; right = -right;}
else data +=’H';
if (left != 0) data += (char)(left&0xff);
if (right != 0) data += (char)(right&0xff);
*/
mmOutStream.write(data.getBytes());
ret = 0;
} catch (IOException e) {
Log.e(TAG, “Exception during write”, e);
ret = -1;
}
return ret;
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, “close() of connect socket failed”, e);
}
}
}
}
Program : android측
DeviceListActivity.java
DeviceListActivity.java 소스보기
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kr.sunejune;
import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
/**
* This Activity appears as a dialog. It lists any paired devices and
* devices detected in the area after discovery. When a device is chosen
* by the user, the MAC address of the device is sent back to the parent
* Activity in the result Intent.
*/
public class DeviceListActivity extends Activity {
// Debugging
private static final String TAG = “DeviceListActivity”;
private static final boolean D = false;
// Return Intent extra
public static String EXTRA_DEVICE_ADDRESS = “device_address”;
// Member fields
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the window
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
// Set result CANCELED incase the user backs out
setResult(Activity.RESULT_CANCELED);
// Initialize the button to perform device discovery
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
doDiscovery();
v.setVisibility(View.GONE);
}
});
// Initialize array adapters. One for already paired devices and
// one for newly discovered devices
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
// Find and set up the ListView for paired devices
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
// Find and set up the ListView for newly discovered devices
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
// Get the local Bluetooth adapter
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
// Get a set of currently paired devices
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + “\n” + device.getAddress());
}
} else {
String noDevices = getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// Make sure we’re not doing discovery anymore
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
}
// Unregister broadcast listeners
this.unregisterReceiver(mReceiver);
}
/**
* Start device discover with the BluetoothAdapter
*/
private void doDiscovery() {
if (D) Log.d(TAG, “doDiscovery()”);
// Indicate scanning in the title
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
// Turn on sub-title for new devices
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
// If we’re already discovering, stop it
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
mBtAdapter.startDiscovery();
}
// The on-click listener for all devices in the ListViews
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
// Cancel discovery because it’s costly and we’re about to connect
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
// Get the device MAC address, which is the last 17 chars in the View
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() – 17);
// Create the result Intent and include the MAC address
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
// Set result and finish this Activity
setResult(Activity.RESULT_OK, intent);
finish();
}
};
// The BroadcastReceiver that listens for discovered devices and
// changes the title when discovery is finished
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it’s already paired, skip it, because it’s been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + “\n” + device.getAddress());
}
// When discovery is finished, change the Activity title
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = getResources().getText(R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
}
6. AVR 프로그램
Program : ATTINY2313측
Program : ATTINY2313측 소스보기
/*
Project : USART TEST1
tiny2313_uart1.c
Date : 2008-05-23
Company : AvrMall.com
Chip type : ATtiny2313-10SI
Clock : 12.000000 MHz
Comment : ATTINY2313으로 UART송수신 테스트 프로그램
Used with AVRSTUDIO V4.14 (WINAVR) .
*/
#include <avr/io.h>
#define F_CPU 12000000UL // 16 MHz
//#define F_CPU 14.7456E6
//#include <util/delay.h>
// Common Functions.
void Delay_us(unsigned int time_us);
void Delay_ms(unsigned int time_ms);
void USART_Init(void);
void putchar_0(char data);
void com_puts(char sbuf[]);
void putchar_0(char data);
int getchar_0(void);
void cpu_setup(void);
void Delay_us(unsigned int time_us)
{
unsigned int i;
for(i=0; i<time_us; i++) // 4 cycle +
{
asm(“PUSH R0″); // 2 cycle +
asm(“POP R0″); // 2 cycle +
asm(“PUSH R0″); // 2 cycle +
asm(“POP R0″); // 2 cycle + =12 cycle for 11.0592MHZ
//asm(“PUSH R0″); // 2 cycle +
//asm(“POP R0″); // 2 cycle = 16 cycle = 1us for 16MHz
}
}
void Delay_ms(unsigned int time_ms)
{
unsigned int i;
for(i=0; i<time_ms;i++)
Delay_us(1000);
}
void USART_Init(void)
{
// 9600Bps, 8Data, 1 Stop, No Parity
UCSRA=0×00;
UCSRB=0×18;
UCSRC=0×06;
UBRRH=0×00;
UBRRL=0×12;
}
// COM1 스트링 송신 //
void com_puts(char sbuf[])
{
char ch;
int i = 0;
ch = sbuf[i++]; // 전송할 데이터
while(ch != 0){
putchar_0(ch); // 1바이트 송신
ch = sbuf[i++]; // 전송할 데이터
}
}
void putchar_0(char data)
{
/* Wait for empty transmit buffer */
while (!((UCSRA) & (1<<UDRE)));
/* Put data into buffer, sends the data */
UDR = data;
}
int getchar_0(void)
{
/* Wait for data to be received */
while ( !(UCSRA & (1<<RXC)) );
/* Get and return received data from buffer */
return(UDR);
}
void cpu_setup(void)
{
USART_Init();//USART 초기화
DDRB = 0b01111111; // Port B IO mode : b7 (Input), b6-b0(Output)
DDRD &= 0b01111100; // Port B IO mode : d0-1 (UART), b6-b2(Output)
}
int main(void)
{
unsigned char cmd;
unsigned char i_h=0;
unsigned char i_t=0;
unsigned char i_f=0;
unsigned char i_u=0;
cpu_setup(); // cpu 초기화
com_puts(“\r\n”);
com_puts(“- ATTINY2313 USART TEST -\r\n”);
com_puts(“Press a or b \r\n”);
while(1)
{
cmd = getchar_0();//PC로부터 받은 값을 d에 저장한다.
switch (cmd) {
case ‘i’ :
PORTB = 0b00000000;
break;
// 전조등(h:4) / 후미등(t:5) , off(o)
case ‘h’ :
case ‘R’ :
if(i_h == 1) {
PORTB &= 0b11001111;
i_h=0;
}
else {
PORTB |= 0b00010000;
i_h=1;
}
break;
case ‘t’ :
case ‘S’ :
if(i_t == 0) {
PORTB |= 0b00100000;
i_t=1;
}
else {
PORTB &= 0b11001111;
i_t=0;
}
break;
case ‘o’ :
case ‘T’ :
PORTB &= 0b11001111;
break;
// 포탄 발사(f:3:A) off(w:B)
case ‘f’ :
case ‘A’ :
if(i_f == 0) {
PORTB |= 0b00001000;
i_f=1;
}
else {
PORTB &= 0b11110111;
i_f=0;
}
break;
case ‘B’ :
case ‘q’ :
PORTB &= 0b11110111;
break;
// 포신 동작(u:2) off(c)
case ‘u’ :
case ‘C’ :
PORTB |= 0b00000100;
i_u=1;
break;
case ‘E’ :
PORTB &= 0b11111011;
i_u=0;
break;
case ‘c’ :
case ‘D’ :
PORTB &= 0b11111011;
break;
// 포탑 좌(l:0) 우(r:1) , off(m)
case ‘l’ :
case ‘F’ :
PORTB &= 0b11111100;
PORTB |= 0b00000001;
break;
case ‘r’ :
case ‘H’ :
PORTB &= 0b11111100;
PORTB |= 0b00000010;
break;
case ‘m’ :
case ‘G’ :
PORTB &= 0b11111100;
break;
// 이동 전진(w:2-1,3-0 , 4-1,5-0) 후진(x:2-0,3-1 , 4-0,5-1)
// 전좌(a:2-0,3-0 , 4-1,5-0) 전우(d:2-1,3-0 , 4-0,5-0) ,
// 후좌(a:2-0,3-1 , 4-0,5-0) 후우(d:2-0,3-0 , 4-1,5-0) ,
// off(s)
case ‘O’ : // 후좌
PORTD &= 0b10000011;
PORTD |= 0b01001000;
break;
case ‘Q’ : // 후우
PORTD &= 0b10000011;
PORTD |= 0b01010000;
break;
case ‘w’ :
case ‘J’ : // 전_전
PORTD &= 0b10000011;
PORTD |= 0b01010100;
break;
case ‘x’ :
case ‘P’ : // 후_후
PORTD &= 0b10000011;
PORTD |= 0b01101000;
break;
case ‘a’ :
case ‘I’ : // 전_좌
PORTD &= 0b10000011;
PORTD |= 0b01010000;
break;
case ‘d’ :
case ‘K’ : // 전우
PORTD &= 0b10000011;
PORTD |= 0b01000100;
break;
case ‘s’ :
case ‘M’ : // 멈춤
PORTD &= 0b10000011;
break;
default :
;
// putchar_0(‘c’);
}
Delay_ms(100);
}
}
7. 관련 회로도
7.1 전체 Block
7.3 L293B : 전후진용 주 모터 (좌우, 정, 역 회전 : 양방향)
7.4 LB1630 : 포탑 (정. 역 회전 : 양방향)
7.5 ULN2803 : 포신, 포발사, 전조등, 후미등 (정회전:단방향)
7.6 bluetooth : myBluetooh-EX 모듈
소요비용
탱크 : 75,000원
Attiny2313 보드 : 11,000원
제어 보드 제작 : 약 20,000원(손실까지)
블루투스 모듈 : 26,300원
전체 : 132,300원
참고 웹사이트
참고 Site
[14호]조립용 심전도 키트(EMG-KIT) 출시!
(주)피지오랩(www.physiolab.co.kr)에서 EMG(근전도) 신호를 증폭하고 필터링 기능을 제공하는 교육용 EMG-KIT를 출시했다. 매뉴얼과 함께 부품 전체가 제공되어 학생들이 직접 조립 및 측정을 함으로써, 근전도 측정 장치의 구성요소, 필터링 기법 및 전자회로의 원리 등 근전도 측정의 이해를 돕는 제품이다. EMG-KIT는 동사의 μDAQ-KIT, SimDAQ-KIT 등 시험 지원 키트들과 인터페이스가 용이한 구조로 설계되었으며, 리드선을 통해 근전도 측정 및 일정한 크기 이상의 근전도 신호 검출을 위한 LED 표시 기능을 함께 내장한 제품이다.
제품 사양
·크기 : 12cm(W) x 10cm(L) x 2.5cm(H)
·입력전원 : [기본 제공] 6V(3V x 2ea), 리튬코인전지 [부가 기능] SimDAQ-KIT 연결 시 자동 전원공급
·Selector : 필터 등의 설정 변경에 의한 출력 파형 관찰
·Test point : 8개 (각 회로구성단 출력)
·I/O : 외부장치(입ㆍ출력) 삽입연결 컨넥터 내장
·측정 : 근전도, 근전도 레벨에 따른 LED 점등 기능
제품설명 더보기
|
|||||||||||||||||||||||||||||||||
TEL. 051-325-2868
FAX. 051-325-2869
[14호]ARM1 S3C6410 Chip을 탑재한 Embedded Board, DSTARII70_CE 출시!
진영콘텍(www.jyct.com)에서 ARM1 S3C6410 Chip을 탑재한 Embedded Board를 출시했다. Windows CE 6.0 R3를 탑재하여 PC와 같은 사용자 인터페이스를 제공한다. Active Sync 지원으로 개발 환경의 다양화(File Viewer, Process Viewer 등 지원)를 요할 수 있다. 제품은 jEMB11 Main Board로 이뤄져 있으며, jEMB11 Sub Board는 다양한 LCD 지원을 위해 구성되며, TTL 및 LVDS, 터치스크린과 인버터 출력을 제공한다.
HARDWARE 사양
·CPU : samsung 53c6410, 32bit Risc
ARM1176JZF-S, 667Mhz (Async Mode)
·RAM : On Board 128M DDR(32bit Daa Bus)
·FLASH : On Board 256M SLC Nand Flash
·SD Memory : SD 지원(4GB) / SDHC 지원(16GB)
·Audio : Stereo Sound 입력 / 출력 지원
·Ethernet : 100Mbps (SMSC9220)
·Sound : 스테레오사운드 출력 및 입력 지원
·LCD : SAMSUNG 7inch Wide LMS700KF Resolution: 800×480
·Touch : 4선 저항 박막식 / Serial / USB 터치 지원
·POWER : DC 12V, 750mA
·Dimension : 172.4 x 114.5 x 33mm (WxHxD)
INTERFACE 사양
·Uart : RS232 : 2Ch / TTL : 1Ch
·Usb Host : Usb Host 1.1 지원 Keyboard / Mouse, Usb Memory 지원
·Usb Slave : Mini Usb Slave 2.0
·12C : 1Ch 지원
·SPI : 1Ch 지원
·IO : 8Port GPIO 지원
·Etc : RTC 지원
제품설명 더보기
TEL. 02-890-6400
FAX. 02-890-6406