2017년 8월 2일 수요일

온라인으로 전자부품 구입하기 - 엘리먼트14

무언가를 만들기 위해 부품을 구매하는 방법은 크게 온라인, 오프라인 구매로 나뉜다.
실제로 눈으로 보면서 원하는 부품을 구하는게 좋기는 하지만 매장의 위치가 구로나 용산쪽에 몰려있고 영업시간이 보통 일반 업무시간과 동일하다 보니 무언가 다른 일을 하면서 취미로 작업을 하는 사람들이 매장을 방문하기는 매우 힘들다.

그런 이유로 인해 대부분 온라인으로 주문하게 되는데 국내에서는 주로 디바이스마트, 엘레파츠 같은 곳을 사용하게 된다. 하지만 흔하게 많이 사용되는 부품은 준비가 되어 있어도 조금만 특이한 종류의 부품이 되면 없는 경우가 많다.

그래서 최근에 많이 사용하는 곳 중에 하나가 엘리먼트14이다. 싱가폴에 있는 글로벌 전자부품 유통회사인데 국내에 사무소가 있어 한글 웹사이트에서 주문하고 원화로 결재할 수 있어 상당히 편리하다. 60만가지의 재고를 보유하고 있고 MOQ(Minimum Order Quantity, 즉 최소 주문 수량)가 없어 여러 종류의 부품을 소량구매 할 수 있는것이 장점이다. 또한 국내에 서비스센터가 있어 국제전화나 영어에 대한 부담 없이 통화가 가능하다.

단 한가지 약점이자 장점일 수 있는 부분이 배송비인데 6만원 이상 주문시 무료 배송을 해 준다는 것이다. 그래서 저렴한 부품 한두개 구매시는 배보다 배꼽이 훨씬 더 큰 경우(제품가격은 몇천원, 배송비가 2~3만원)도 생길 수 있는데, 대신 구매할 것들을 모아 한번에 주문하면 배송비 무료인데도 불구하고 UPS나 DHL등을 사용해 매우 빠르게 국제배송이 된다는 것이다. 보통 주문 완료하고 3~4일 내로 부품을 받아볼 수 있다. AliExpress를 사용해 본 사람이라면 알리의 무료배송을 생각해보면 요새 많이 빨라졌다고는 해도 아주 운 좋으면 일주일에서 재수 없음 한두달까지도 걸리는데 비해 얼마나 큰 장점인지 바로 알 수 있을 것이다. 그래서 주문할 것이 5만원 조금 넘는 경우 나중에 써 보고 싶은 부품 한두개 추가해서 오히려 더 싸게 주문하곤 한다.

원래 element14의 웹사이트 주소는 http://www.element14.com 이지만 국내에서 저 주소로 들어가면 자동으로 http://kr.element14.com 으로 리다이렉션 되어 한글 홈페이지가 나타난다.


검색어는 정확하게 다 치지 않아도 자동완성 기능으로 입력한 단어로 시작하는 부품들을 보여주기 때문에 쉽게 찾을 수 있다.


원하는 부품을 선택하면 아래와 같이 상세정보와 가격이 나오게 된다. 재고가 없는 경우는 백오더가 들어가기 때문에 배송에 얼마나 걸릴지는 상황에 따라 달라지지만 재고가 있는 경우는 보통 정상적으로 주문이진행되면 며칠 내로 받아볼 수 있다.


장바구니에 추가하면 추가되었다는 메시지와 함께 계속 쇼핑을 할 것인지 장바구니로 갈것인지 물어보는 창이 팝업으로 뜬다. 그리고 화면 우측상단 부분의 장바구니에 현재 몇개의 품목이 들어있고 총액이 얼마인지 표시하는 부분이 업데이트 된다.


장바구니로 가 보면 넣어놓은 품목들을 볼 수 있다. 다 넣었으면 오른쪽에 있는 오렌지색 '주문' 버튼을 누르면 된다. 이 단계에서는 아직 handling charge는 '알수 없음'으로 표시된다.

주문 버튼을 누르면 먼저 로그인을 위한 화면이 나온다. 기존에 아이디를 가지고 있으면 로그인 하면 되고없으면 위쪽의 '지금 회원가입하세요' 링크를 눌러 먼저 가입을 해 주면 된다.

 로그인을 하면 아래와 같이 주문정보 검토를 위한 화면이 나온다. 청구서 배송 주소와 배송 주소를 다르게 지정할수도 있지만 개인의 경우 보통 같이 하므로 '내 배송주소와 내 송장주소가 동일함'을 체크해 주면 된다.


 주문 검토 화면을 아래로 스크롤하면 배송방법과 지불방법을 지정할 수 있는 부분이 나온다. 개인정보 보호정책 부분을 체크해주고 배송방법을 선택한다. '전체 주문 묶음배송' 아니면 '제품별 개별 배송' 중에 하나를 고르게 될 것이다. 제품별 개별배송을 선택해도 배송비를 추가로 부담하지는 않으므로 여러개의 부품을 주문하는데 각각 따로라도 먼저 받고 싶으면 '제품별 개별 배송'을 선택하면 된다.
'지불방법 및 세부정보' 부분에서는 거래 계정이 없다를 선택하면 된다. 그리고 신용카드 정보를 입력해 준다. 단 비자, 마스터 카드만 가능하고 아멕스나 JCB등은 사용할 수 없다. 그리고 해외에서 결재하는걸로 되기 때문에 국내 주문같이 공인인증서니 그런 것들이 필요 없이 간단하게 주문이 처리된다.
모든 정보를 입력했으면 '주문 검토 진행'을 눌러 마지막으로 다시 확인할 수 있다.


'이용 약관 동의'에 체크하고 주소 및 주문정보를 꼼꼼하게 확인해야 한다. 아래쪽에 보면 제품가격 및 handling charge가 나오는데 여기서는 제품가격이 57568원이라 추가로 handling charge가 2만원이 붙었다. 이런 경우 4~5천원짜리 부품 하나 추가해서 6만원만 넘겨주면 handling charge가 0원이 되어 오히려 더 싸지게 되니 이 방법을 꼭 활용하기 바란다. 모든것을 확인했으면 '주문적용' 버튼을 눌러주면 주문이 끝나게 된다.



엘리먼트14으로 부품 구입하러 가기

* 이것은 '엘리먼트14 서포터즈'로서 엘리먼트14에서 제품(비글본 블랙)을 제공받아 작성된 글입니다.

조만간 구매한 비글본 블랙 리뷰를 올릴 예정입니다.

2017년 7월 13일 목요일

SIM5320E으로 3G 통신

SIM5320E는 SIMCOM이라는 회사에서 나온 3G 통신모듈이다.



다만 이 모듈을 구해도 바로 사용하기 힘들기 때문에 Adafruit에서 이 모듈의 breakout 보드를 구했다.
정확한 명칭은 Adafruit FONA 3G module로 사이트에 가 보면 US용과 EU용 두가지 버젼이 있는데 국내에서 사용하려면 꼭 EU 버젼으로 구해야 한다. 3G 주파수가 EU는 국내와 동일하게 2100MHz인데 비해 미국용은 1900MHz라 국내에서 사용할 수가 없다. 그리고 보드를 구매해도 딱 보드만 들어있기 때문에 별도로 2.1GHz 안테나와 GPS안테나를 구입해야만 사용할 수 있다. (단 GPS안테나는 옵션)



사진에서 볼 수 있는것처럼 보드의 위쪽에 커넥터와 SIM5320 모듈이 붙어있고 보드의 아래쪽에는 USIM 카드를 장착할 수 있는 소켓이 장착되어 있다.
저 보드는 휴대폰에서 마이크/스피거, 액정화면, 버튼이 빠진거라고 생각하면 된다. 즉 빠진 부품만 붙이면 완벽한 휴대폰을 만들어 줄 수도 있는 것이다.

저 모듈은 시리얼 포트를 통해 모뎀과 마찬가지로 AT 명령으로 모듈을 제어할 수 있으므로 아두이노같은마이크로 프로세서를 연결해 동작을 제어할 수 있다.


동작을 시켜보려면 휴대폰과 동일하게 개통된 USIM이 있어야 한다. 저 모듈은 일반크기의 USIM을 꼽아야 하므로 USIM adapter를 사용했다.


  먼저 보드의 아래쪽에 있는 USIM 소켓을 열어준다.


방향을 맞춰 USIM을 꼽아준다.


꼽은 다음 소켓을 닫아주면 된다. 위의 사진은 USIM이 장착 완료된 것이다.


 이제 사진의 화살표 부분에 마이크로USB 케이블을 꼽아 컴퓨터와 연결해준다. 단 Mac OS X에서는 디바이스 드라이버가 없어 장치가 인식되지 않고 윈도우와 리눅스에서만 인식된다. 여러개의 시리얼 포트로 인식되는데 만일 인식되지 않으면 디바이스 드라이버를 설치해 줘야 한다. 


케이블이 연결되면 USB커넥터와 오른쪽의 검은색 커넥터 사이에 있는LED가 빠르게 깜빡인다. 이때는 아직 전원이 켜지기 전이라 컴퓨터에는 장치가 인식되지 않고 전원을 켜 줘야만 인식된다. 오른쪽 검은색 커넥터 옆에 있는 PWR key라는 버튼을 눌러주면 모듈의 전원을 켜 주는 것이다.

 

전원이 켜지면 빠르게 깜빡이던 LED가 켜져있게 되고 컴퓨터에서는 새로운 시리얼 포트가 보이게 된다.



컴퓨터에서 시리얼 터미널 프로그램을 실행해 시리얼 포트를 연결해서 명령을 주면 모듈을 제어할 수 있는 상태가 된 것이다.
이제 여기서는 SimTech HS-USB AT Port 9000 (COM7) 포트를 열어준다. 일반 모뎀과 동일하게 AT 명령어를 사용하면 되고 사용할 수 있는명령 목록은 문서를 참고하면 된다.

SIM5320E AT command set

매우 많은 명령이 있어 아주 세밀하게 조작이 가능하지만 전화기로 사용하려면 몇개의 명령만으로도 충분하다.

시리얼 포트를 연 다음 전화를 걸고 받는걸 직접 해 보도록 하겠다. 단 전화 통화를 해야 하므로 마이크가 달려있는 이어폰을 모듈에 먼저 꼽아줘야 한다. 아래가 명령과 그에 대한 응답을 캡춰한 것이다. 굵은 글씨체가 내가 직접 입력한 명령들이고 나머지가 모듈이 출력하는 메시지이다.


at+creset
OK

START

+CPIN: READY

SMS DONE

+VOICEMAIL: INIT_STATE, 0, 0

PB DONE
at+creg
OK
at+creg?
+CREG: 0,1

OK
at+cops?
+COPS: 0,0,"KT",2

OK
atd[걸고자하는 전화번호];
OK

+WAP_PUSH: "REC UNREAD","114",,"17/07/13,11:40:56+36"
2406226170706C69636174696F6E2F766E642E7761702E6D6D732D6D65737361676500AF848C8298323376483744423134304746353030008D928A828E017C88058103093A8083687474703A2F2F642D6D6D73632E6B746677696E672E636F6D3A393038332F32337648374442313430474635303000

+WAP_PUSH: "REC UNREAD","114",,"17/07/13,11:40:56+36"
89078005EA31313400960EEAECA09CEBAAA9EC9786EC9D8C00

VOICE CALL: BEGIN

VOICE CALL: END: 000005

NO CARRIER

RING

RING

RING

RING

RING

MISSED_CALL: 01:23PM 07077374920
atd[걸고자하는 전화번호];
OK

VOICE CALL: BEGIN
at+chupVOICE CALL: END: 000015

OK
RING
ata
VOICE CALL: BEGIN

OK

VOICE CALL: END: 000007

NO CARRIER


먼저 AT+CRESET 명령으로 모듈을 리셋 시킨다. 잠시 기다리면 초기화 과정이 끝나고 PB DONE이라는 메시지가 나올 것이다. 그럼 AT+CREG? 명령을 입력해 모듈이 통신사 3G망에 등록되었는가를 확인한다. 망에 등록이 되어야만 통신(전화 걸기/받기, 문자 송/수신, 데이터 전송등)이 가능하다. AT+CREG? 명령의 응답이 '+CREG: 0,1' 이런식으로 나오는데 여기서 맨 마지막 숫자가 '1'이 나와야 정상적으로 통신사의 망에 등록이 된 것이다. 만일 이 값이 1이 아니면 등록이 안된 것이므로 다시 확인해 봐야 한다. 모듈에 해당 USIM을 처음 꼽으면 망에 등록이 안되는 경우가 있는데 이 경우는 AT+CRESET 명령을 두세번 실행한 다음 다시 확인해보면 될 것이다. 

AT+COPS? 명령으로 어느 통신사를 사용하는지 확인할 수 있다. 현재 테스트에 사용한 USIM은 에넥스텔레콤 것으로 KT망을 빌려쓰는 MVNO이므로 KT망에 등록된 걸 확인할 수 있다.

전화를 걸려면 ATD 명령을 사용하면 된다. ATD 바로 뒤에 원하는 전화번호를 쓰고 ';'를 붙여주면 된다. 즉 010-2345-6789번으로 전화를 걸고 싶으면 'ATD01023456789;'라고 입력하면 된다. ATD 명령을 내리면 실제로 전화가 걸리고 전화를 받으면 음성통화가 가능하다. 만일 통화중에 모듈쪽에서 전화를 끊고 싶으면 'AT+CHUP' 명령을 내려주면 된다. 어느쪽이 끊건 통화가 끝나면 'VOICE CALL:END:000015' 같이 통화가 끝났다는 메시지와 함께 통화시간을 알려준다.

명령을 내리지 않고 가만히 놔둬도 전화가 오면 RING이라는 메시지가 출력된다. 의도하지는 않았지만 070에서 스팸전화가 와서 받지 않고 놔뒀더니 상대방이 벨이 몇번 울린 후에 끊어서 MISSED_CALL 이라는 메시지와 함께 시간 및 발신자 전화번호가 출력되었다. 전화가 왔을 때 받으려면 ATA 명령을 내리면 된다.

일단 모듈을 연결해 가장 기본적인 음성통화를 해 보았다. 다음에는 SMS 발신 및 인터넷 연결 방법에 대해 설명하도록 하겠다.

2017년 5월 18일 목요일

아두이노 실습] QDSP6064 Bubble Display (4 digit FND)

QDSP6064는 일명 Bubble display라고도 불리는데 4개의 FND가 하나의 패키지에 들어 있는 Common-Cathode 타입의 디스플레이이다.



크기는 크지 않아도 숫자 부분이 뽈록 튀어나와 렌즈 역할을 해 주기 때문에 숫자는 꽤 크게 보인다.


핀 배치는 위의 그림과 같고 Common-Cathode 타입이기 때문에 active high 구동을 하면 된다.


동작을 확인하기 위해 아두이노에는 위의 그림처럼 연결 해 주었다. 그리고 표시되는 카운트를 up/down 하기 위해 두개의 스위치를 추가했다. 우노의 경우 0,1번 핀은 시리얼 포트가 사용하고 있기 때문에 스위치를 추가할 핀이 모자르다. 그래서 아날로그 입력 A0, A1을 디지털 핀으로 사용하였다.


회로도 그림대로 브레드보드에 연결하고 스케치를 실행한 상태이다. 초기 카운트 값이 0이라 QDSP6064에 0000이 표시되고 있다.


동작 동영상은 위와 같다.

위에 사용한 스케치 코드는 다음과 같다.

#define UP A0
#define DN A1

const byte gDgtFont[] = {0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x72,0x7f,0x7b};
int gCnt = 0;

void setup() {
  int i;

  for (i=0;i<7;i++) pinMode(i+2, OUTPUT);
  for (i=0;i<4;i++) pinMode(i+9, OUTPUT);
  pinMode(UP,INPUT_PULLUP);
  pinMode(DN,INPUT_PULLUP);
  Serial.begin(115200);
}

void loop() {
  dispVal(gCnt);
  checkUpSw();
  checkDnSw();
}

void checkUpSw()
{
  static unsigned long last;
  static boolean prev = HIGH;
  unsigned long now = millis();
  boolean curr;

  if ((now-last)>10) {
    curr = digitalRead(UP);
    if ((HIGH==prev) && (LOW==curr)) {
      gCnt = (gCnt+1)%10000;
    }
    prev = curr;
    last = now;
  }
}

void checkDnSw()
{
  static unsigned long last;
  static boolean prev = HIGH;
  boolean curr;
  unsigned long now = millis();

  if ((now-last)>10) {
    curr = digitalRead(DN);
    if ((HIGH==prev) && (LOW==curr)) {
      gCnt = gCnt-1;
      if (-1 == gCnt) gCnt = 9999;
    }
    prev = curr;
    last = now;
  }
}

void dispVal(int val)
{
  static byte pos = 0;
  static unsigned long last = 0;

  if ((millis()-last)>2) {
    switch(pos) {
      case 0: dispDgt((val/1000),0); break;
      case 1: dispDgt((val/100)%10,1); break;
      case 2: dispDgt((val/10)%10,2); break;
      case 3: dispDgt((val%10),3); break;
    }
    pos = (pos+1) & 3;
    last = millis();
  }
}

void dispDgt(byte dgt, byte pos)
{
  int i;

  for (i=0;i<4;i++) digitalWrite(i+9, HIGH);
  for (i=0;i<7;i++) digitalWrite(i+2, (gDgtFont[dgt]&(1<<(6-i))));
  digitalWrite(pos+9, LOW);
}







2017년 5월 14일 일요일

윈도우 7에서 WannaCry 랜섬웨어 방어법 (Disable SMB v1.0 in Windows 7 for protecting attack from WannaCry ransomeware)



WannaCry 랜섬웨어때문에 난리들이 나서 어떻게 하면 되는가 기사들이 많이 나오고 있는데 전혀 현실적이지 못하게 윈도우 8.1 이상 기준의 방법을 소개하고 있다.

 랜섬웨어 피해 대응법 : 컴퓨터 켜기 전에 인터넷 선부터 뽑아라

사실 국내에서 윈도우 8 계열을 쓰는 사람은 진짜 손으로 꼽을테고 그나마 윈도우 10 아니면 7인데 실질적으로 대다수는 7이라고 본다.  저런 기사에 보면 제어판의 'Windows 기능 켜기/끄기'로 가서 'SMB 1.0/CIFS 파일 공유 지원' 기능을 끄면 된다고 하는데 윈도우 7에서는 그 메뉴로 가 봐도 저 항목이 아예 안 보인다.

해결책은 우선 윈도우 시작메뉴를 누른 다음 '보조프로그램'->'명령 프롬프트'로 간다.


명령 프롬프트를관리자권한으로실행해야하므로마우스오른쪽버튼을클릭해서 메뉴가 나오면 '관리자 권하으로 실행'을 선택해서 클릭한다.


명령 프롬프트를 관리자 권한으로 실행할건지 물어보면 '예'를 선택해준다.


명령 프롬프트 창이 열리면 아래와 같이 정확하게 입력해준다. 주의할 점은 'depend=', 'start=' 뒤에 꼭 한 칸을 띄고 입력해야 한다는 것이다.

sc.exe config lanmanworkstation depend= bowser/mrxsmb20/nsi
sc.exe config mrxsmb10 start= disabled


위와 같이 두 명령 다 '[SC] ChangeServiceConfig 성공'이라는 메시지가 나오면 이제 윈도우를 재시동하면 된다.

이번 랜섬웨어는 SMB v1.0의 취약점을 이용한 공격이기 때문에 SMB v1.0만 비활성화 시켜주면 기본적으로 이번 랜섬웨어의 공격은 막아낼 수 있지만 그래도 안전하게 기사에 있는 것 처럼 MS가 제공하는 패치도 설치해주면 된다.

http://www.catalog.update.microsoft.com/Search.aspx?q=KB4012598







2017년 5월 12일 금요일

BusPirate를 파이선으로 제어하기

수년간 AVR-ISP mkII를 사용해 ATMEL AVR 마이크로 컨트롤러를 프로그래밍 해 오다가, 오늘 처음으로 Bus Pirate를 사용해 보았다. 이 작은 보드는 단순히 마이컴 프로그래머가 아니고 기본적으로 마이컴 주변장치와의 시리얼 인터페이스이다. 보드를 USB에 연결하면 커맨드라인 인터페이스를 가지고 있는 시리얼 포트로 보이는데 이를 통해 핀의 on/off, 전압 측정 뿐 아니고 I2C, SPI, UART 심지어 HD44780 시리즈 LCD 프로토콜까지도 양방향으로 사용할 수 있도록 네이티브하게 지원한다.
HyperTerminal을 사용해 BusPirate와 직접 인터페이스 할 수도 있지만 TeraTerm을 사용하는걸 권장한다. 작은 회로에 전원을 공급할 수 있게 3.3V와 5V 전원을 공급할 수 있고, 만일 전류를 과도하게 소비하면 자동으로 전원 공급을 끊어버린다.
BusPirate는 $30 이하로 구할 수 있는 매우 훌륭한 개발툴이다. 또한 AVRDUDE를 통해 네이티브하게 AVR 프로그래머로 동작할 수 있다. 어셈블리 코드를 작성할수도 있지만 편의성을 위해 거의 항상 C로 프로그램을 작성한다. 나의 레퍼런스 (또는 유사한 작업을 하길 원하는 다른 사람의 레퍼런스)를 위해 윈도우에서 BusPirate로 AVR 마이컴을 프로그래밍 하기 위해 사용하는 가장 쉬운 방법을 포스팅한다. 또한 BusPirate와 연결한 다름 간단한 명령들을 실행하는 파이선 스크립트(파워 서플라이를 켜고 프로그래밍이 끝나면 곧바로 VCC의 전압을 리포팅)를 작성했다.

물론 파이선으로 BusPirate와 인터액션 할 수 있게 해 주는 팬시한 패키지도 있지만 내 방법의 장점은 네이티브 파이선 라이브러리에서 실행된다는 것이다. 이렇게 사용하고 싶으면 WinAVR과 python 3.1을 설치하면 된다. 코드가 파이선 2에서도 동작할것이라고 생각하지만 테스트를 해 보지는 않았다.



BusPirate가 제대로 동작하는지 확인하기 위해 BusPirate의 빌트인 테스트 루틴을 실행하는걸로 시작했다. 상세한 내용은 가이드를 참고하면 된다. 이 테스트는 아래 그림처럼 두 쌍의 핀을 서로 연결해 준 다음, BusPirate를 시리얼 터미널로 연결하고 '~' 명령을 실행하면 된다. 그러면 모든 유용한 정보를 출력해 준다.



다음은 모든 핀들을 동작시키기 위해 마이컴에서 실행될 코드이다. (main.c로 저장) 여기서는 MCU로 ATTiny85를 사용했다. 표준 클럭 설정(내장 RC클럭, 8MHz)을 사용하지만 외부 클럭소스나 크리스털을 사용하기 위해 퓨즈 설정을 바꾸길 원하면 engbedded's handy dandy fuse calculator를 사용해 계산한다.

#define F_CPU (8000000UL)
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
  DDRB = 255;
  while (1) {
    PORTB ^= 255;
    _delay_ms(500);
  }
}

코드 컴파일 및 MCU 프로그래밍을 위해 항상 같은 폴더에 bash 스크립트를 만들어 더블클릭하면 이전에 컴파일 된 파일들을 삭제하고, main.c를 컴파일 한 다음 BusPirate를 사용해 MCU에 프로그래밍 하게 해 놓았다. 스크립트에서 COM3는 자신의 컴퓨터에 BusPirate에 맞게 바꿔줘야 한다.

@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex
python up.py
 
비록 프로그래머가 +5V 핀을 통해 MCU에 전원을 공급해 주지만 프로그래밍이 끝나면 전원이 끊어진다.  수동으로 터미널 프로그램을 다시 열어 BusPirate에 재접속 하고 'm' 명령으로 모드를 리셋하고 '9' 명령으로 DIO 모드로 만든 다음 'W'명령으로 전원 출력을 재활성화 시키는 대신 이 모든것을 자동화 하길 원한다. 파이선을 사용하면 이 모든것을 쉽게 할 수 있다. 스크립트의 마지막 줄이 up.py를 호출한다. 이 팬시 스크립트는 전원을 켠 다음 심지어 Vcc라인의 전압까지도 출력 해 준다.  

""" python3 control of buspirate (SWHarden.com) """
import serial

BUSPIRATE_PORT = 'com3'

def send(ser.cmd):
  ser.write(str(cmd+'\n').encode('ascii'))
  for line in ser.readlines():
    print (line.decode('utf-8').strip())

ser = serial.Serial(BUSPIRATE_PORT, 115200, timeout=1)
assert ser.isOpen()
send(ser, '#')
send(ser, 'm')
send(ser, '9')
send(ser, 'W')
send(ser, 'v')
ser.close()
print ("disconnected!")

"burn.cmd"가 실행되면 코드가 컴파일되어 MCU에 프로그래밍 되고 전원공급을 켜고 Vcc의 전압을 알려준다. 출력은 다음과 같다.

C:\Users\scott\Documents\important\AVR\2016-07-13 ATTiny85 LEDblink>burn.cmd

Detecting BusPirate...
**
**  Bus Pirate v3a
**  Firmware v5.10 (r559)  Bootloader v4.4
**  DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
**  http://dangerousprototypes.com
**
BusPirate: using BINARY mode
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.12s

avrdude: Device signature = 0x1e930b
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (84 bytes):

Writing | ################################################## | 100% 3.12s

avrdude: 84 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex auto detected as Intel Hex
avrdude: input file main.hex contains 84 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 2.72s

avrdude: verifying ...
avrdude: 84 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

#
RESET

Bus Pirate v3a
Firmware v5.10 (r559)  Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
http://dangerousprototypes.com
HiZ>
m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>
9
Ready
DIO>
W
Power supplies ON
DIO>
v
Pinstates:
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk)
GND     3.3V    5.0V    ADC     VPU     AUX     CLK     MOSI    CS      MISO
P       P       P       I       I       I       I       I       I       I
GND     3.17V   5.00V   0.00V   0.00V   L       L       L       H       L
DIO>
disconnected!

이는 최소한의 케이스 시나리오지만 더 복잡한 태스크를 수행하도록 확장할 수 있다. 예를 들어 모든 커맨드가 단일 파이선 프로그램에서 실행될 수 있다. BusPirate의 수 많은 다른 프로토콜과 통신할 수 있는 능력을 감안하면 별도의 특별한 추가 라이브러리를 설치하지 않고 파이선에서 네이티브하게 제어할 수 있다는건 매우 편리하다.

--
Credit goes to Scott W. Harden




2017년 5월 11일 목요일

라즈베리 파이에서 MQTT를 이용해 ESP8266 제어하기

여기서는 라즈베리 파이, ESP8266(또는 와이파이 쉴드를 붙인 아두이노), PC를 MQTT로 연결해 보도록 하겠다.

이번에 하고자 하는 것은 라즈베리파이가 python을 사용해 PC에 있는 MQTT 브로커에 메시지를 보내면 그 메시지가 ESP8266으로 전달되어 거기에 있는 LED를 제어하는 것이다.

MQTT for PC


MQTT server(브로커)로 사용할 수 있는 옵션이 몇가지 있다. Amazon의 AWS IoT나 AdafruitIO 같은 서비스들은 클라우드 기반의 브로커이다. 각 서비스는 여러가지 장점이 있다. 프로젝트의 필요성에 따라 클라우드 기반 서비스를 사용할 필요가 있을수도 있다.

Mosquitto


자신의 호스트에 브로커를 실행하고 싶으면 오픈소스인 moqsuitto가 훌륭한 옵션이다. 이 브로커는 MQTT를 완전히 지원할 뿐 아니라 pub/sub를 위한 커맨드라인 유틸리티까지 제공한다.

윈도우를 사용하면 mosquitto.org에서 바이너리 인스톨러를 받을 수 있다. 리눅스의 경우 패키지 매니져에서 'mosquitto' 또는 'mosquitto-mqtt'를 찾으면 된다. 맥에서는 homebrew를 사용해 mosquitto를 설치할 수 있다.

* 맥에서 설치한 경우 '/usr/local/sbin'을 PATH에 넣어줘야 한다.

Running Mosquitto


Mosquitto는 디폴트로 1883번 포트를 사용하고 보안기능은 다 꺼져 있다. 처음 시작할 때는 이것으로 충분하지만 결국에는 보안기능을 추가해 줄 필요가 있다.

Mosquitto를 verbose 모드로 실행하길 권장한다. 그러면 출력을 보고 어떤 일이 일어나는지에 대한 아이디어를 얻을 수 있을 것이다.

MacMan:~ james$ mosquitto -v 
1456272937: mosquitto version 1.4.5 (build date 2015-11-09 14:23:46-0800) starting 1456272937: Using default config. 
1456272937: Opening ipv4 listen socket on port 1883. 
1456272937: Opening ipv6 listen socket on port 1883.

Testing Mosquitto


서버 코드를 verbose 모드에서 실행시키고, 추가로 두개의 명령어 프롬프트를 열어준다. 각각의 명령어 프롬프트에서 메시지 전송 테스트를 위해 mosquitto_pub와 mosquitto_sub를 사용할 것이다.

Subscribing to MQTT Topic with Mosquitto


먼저 클라이언트가"debug"라는 토픽을 subscribe하게 해 준다. 첫번째 명령어 프롬프트에서 아래 명령을 입력해 주면 된다.

$ mosquitto_sub -h 127.0.0.1 -i testSub -t debug

* -h : host flag는 mosquitto가 실행되고 있는 서버를 지정. 여기서는 localhost
* -i : identity flag 는 옵션이다. Client ID가 지정되지 않으면 mosquitto_sub가 임의로 만듬
* -t : topic flag 는 subscribe 하려고 하는 topic을 지정. 여기서는 "debug"

서버에서는 topic을 만들지 않았다는걸 주목해라. Topic은 subscriber나 publisher가 처음 지정할 때 만들어진다.

Publish to MQTT Topic with Mosquitto


이제 topic을 기다리는 클라이언트를 가지고 있으므로, 다른 클라이언트가 그 topic을 publish하게 해 본다.

$ mosquitto_pub -h 127.0.0.1 -i testPublish -t debug -m 'Hello World'


이제 첫번째 명령어 프롬프트 화면을 보면 publish된 메시지가 와 있는것을 확인할 수 있다. mosquitto_pub와 mosquitto_sub 명렁 모두 --help 플래그로 확인 해 봐라. 매우 여러가지 유용한 옵션들을 찾아볼 수 있을 것이다.

이제 mosquitto 브로커가 정상 동작하고 있는것이 확인되었으므로 디바이스와 통신을 하게 해 보자.

MQTT for Raspberry Pi (Python)


라즈베리 파이에서 MQTT 메지시를 보내고 받을 수 있는 옵션으로는 mosquitto를 설치하는 것이다. 그러면 라즈베리 파이에서도 동일하게 mosquitto_pub와 mosquitto_sub 명령어를 사용할 수 있다.

다른 방법으로는 자신이 선호하는 언어용 MQTT 라이브러리를 사용하는 것이다. 여기서는 파이선을 사용한다.

Install MQTT for Python


여기서 사용할 MQTT library는 Paho Python Client이다. 오픈소스로 가장 최신의 MQTT를 지원한다.

설치는 간단하다. 먼저 'pip'를 설치하고 나서 아래 명령을 실행한다.

$ pip install paho-mqtt

* 만일 python3를 사용한다면 'pip' 대신 'pip3'를 사용해야 하는걸 잊지 마라.

Example MQTT Python Code for Raspberry Pi


Paho는 MQTT 서버와 통신을 매우 쉽게 만들어 준다.

import paho.mqtt.publish as publish
import time
print ("Sending 0...")
publish.single("ledStatus", "0", hostname="macman")
time.sleep(1)
print ("Sending 1...")
publish.single("ledStatus", "1", hostname="macman")

진짜 간단하다. 스크립트에 서버가 실행되고 있는 호스트 이름(여기서는 'macman'), Topic (여기서는 'ledStatus'), 메시지(여기서는 '0' 또는 '1')만 알려주면 된다.

이 MQTT 튜토리얼 예제에서는 '0'을 보내고 1초 기다린 후에 '1'을 보낸다. 이 동작은 ESP8266에 있는 LED가 잠깐동안 꺼졌다 다시 켜지게 만든다.


이제 RPi가 MQTT 메시지를 보내게 만들었으니 그 메시지를 받도록 만들어 보자. 다음 섹션은 ESP8266이 topic "ledStatus"의 메시지를 받아 실제로 LED를 깜빡이게 만들 것이다.

MQTT for ESP8266


PubSubClient는 아두이노 기반의 MQTT 클라이언트이다. 단지 몇 줄의 코드만으로 매우 쉽게 topic을 subscribe하거나 새로운 topic을 publish할 수 있다.

여기서는 ESP8266을 프로그래밍 하기 위해 아두이노 IDE를 사용했다.

Installing MQTT for Arduino IDE


아두이노 IDE에 PubSubClient를 설치하는건 간단하다. Github에서 수동으로 설치하거나 또는 Arduino Package Installer를 사용할 수 있다.


Arduino ESP8266 and Uno Note


Ethernet 쉴드가 장착된 Uno와 ESP8266간에 스위칭에는 별도의 추가적인 노력이 필요 없다. 라이브러리는 양쪽 모두 잘 동작한다.

Code Example for Arduino MQTT


PubSubCilent에 포함되어 있는 예제는 매우 훌륭하다. 예제에는 특히 MQTT에 대한 ESP8266 코드도 들어있다. 처음 시작할 때 그것들도 꼭 확인해 보기 바란다.

아래는 WiFi에 연결하고 "ledStatus" topic을 subscribe하는 코드이다. ESP8266이 메시지를 받으면 그에 따라 ledPin을 on/off한다.

#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_INA219.h>

// Connect to the WiFi
const char* ssid = "Dear John";
const char* password = "password123";
const char* mqtt_server = "macman";

WiFiClient espClient;
PubSubClient client(espClient);

const byte ledPin = 0; // Pin with LED on Adafruit Huzzah

void callback(char* topic, byte* payload, unsigned int length) {
 Serial.print("Message arrived [");
 Serial.print(topic);
 Serial.print("] ");
 for (int i=0;i<length;i++) {
  char receivedChar = (char)payload[i];
  Serial.print(receivedChar);
  if (receivedChar == '0')
  // ESP8266 Huzzah outputs are "reversed"
  digitalWrite(ledPin, HIGH);
  if (receivedChar == '1')
   digitalWrite(ledPin, LOW);
  }
  Serial.println();
}


void reconnect() {
 // Loop until we're reconnected
 while (!client.connected()) {
 Serial.print("Attempting MQTT connection...");
 // Attempt to connect
 if (client.connect("ESP8266 Client")) {
  Serial.println("connected");
  // ... and subscribe to topic
  client.subscribe("ledStatus");
 } else {
  Serial.print("failed, rc=");
  Serial.print(client.state());
  Serial.println(" try again in 5 seconds");
  // Wait 5 seconds before retrying
  delay(5000);
  }
 }
}

void setup()
{
 Serial.begin(115200);

 client.setServer(mqtt_server, 1883);
 client.setCallback(callback);

 pinMode(ledPin, OUTPUT);
}

void loop()
{
 if (!client.connected()) {
  reconnect();
 }
 client.loop();
}


모든 마법은 "callback" 함수 안에서 일어난다. 실제 코드에서는 받은 메시지를 처리하는 함수를 작성하고 싶을 것이다. 여기서는 topic에 대해 한글자 메시지만을 보내기 때문에 이 간단한 코드로 충분하다.

Conclusion


이 MQTT 튜토리얼은 매우 기초적이다. 하지만 라즈베리 파이, ESP8266을 MQTT 브로커가 실행되고 있는 PC에 연결하는데 필요한 최소한의 것을 보여준다.

다음에는 MQTT를 통해 어떻게 더 복잡한 메시지를 보낼 수 있는가를 설명하겠다.




2017년 5월 9일 화요일

아두이노 실습] 푸쉬버튼 long press, short press 판단하기

아두이노에서 푸쉬버튼 스위치의 long press와 short press를 구분하기 위해서는 스위치가 눌린 시간을 기록해 놓은 다음 눌린 스위치가 떨어질 때 스위치가 눌려있던 기간을 계산해 특정 시간보다 짧으면 short press, 길면 long press로 판단 해 주면 된다.



이번 실험을 위해 연결한 회로이다. 13번 핀에 시스템이 동작하는지 확인하기 위한  heartbeat LED를 연결 해 주고 4번 핀에 푸쉬버튼 스위치를 연결해 주었다. 4번 핀의 pinMode로 INPUT_PULLUP을 사용할 것이기 때문에 추가로 저항을 연결할 필요는 없다.

#define SW 4
#define RELEASED 0
#define SHORT_PRESS 1
#define LONG_PRESS  2
#define SW_THRESHOLD  500

#define HB_LED 13

void setup() {
  pinMode(HB_LED, OUTPUT);
  pinMode(SW, INPUT_PULLUP);
  Serial.begin(115200);
}

void loop() {
  static boolean hbLedStat = LOW;
  static unsigned long last;
  int swState = readSw();
 
  if (SHORT_PRESS == swState) {
    Serial.println("SWITCH SHORT PRESSED");
  } else if (LONG_PRESS == swState) {
    Serial.println("SWITCH LONG PRESSED");
  }
  if ((millis()-last) >= 500) {
    digitalWrite(HB_LED, hbLedStat);
    hbLedStat = !hbLedStat;
    last = millis();
  }
}

int readSw()
{
  static boolean prev = HIGH;
  static unsigned long last, pressed;
  boolean curr;

  if ((millis()-last) >= 10) {
    curr = digitalRead(SW);
    if ((HIGH==prev)&&(LOW==curr)) {
      pressed = millis();
      prev = LOW;
    } else if ((LOW==prev)&&(HIGH==curr)) {
      prev = HIGH;
      if ((millis()-pressed) > SW_THRESHOLD) {
        return LONG_PRESS;
      } else {
        return SHORT_PRESS;
      }
    }
    last = millis();
  }
  return RELEASED;
}


코드는 위와 같다. 프로그램이 실행되면 heartbeat LED는 1초 간격으로 계속 깜빡이고 스위치를 눌렀다 떼면 누르고 있던 시간 길이에 따라 short press, long press를 판정해 시리얼 포트로 결과를 출력해 준다.



아두이노 실습] Push button 스위치로 FND 카운트 증가/감소

2개의 push button으로 FND의 숫자 카운트를 up/down 시키는 실습

회로도...여기서는 Common Anode 타입의 FND를 사용


 브레드보드 연결도



4번핀에 연결된 스위치로 숫자 카운트를 up, 5번핀에 연결된 스위치로 숫자 카운트를 down하는 스케치

#define FND_A 13
#define FND_B 12
#define FND_C 11
#define FND_D 10
#define FND_E 9
#define FND_F 8
#define FND_G 7
#define FND_DP 6

#define UP  4
#define DN  5

#define dW digitalWrite
#define ON LOW
#define OFF HIGH

int gCnt = 0;

void setup() {
  for (int i=6;i<14;i++) pinMode(i, OUTPUT);
  pinMode(UP, INPUT_PULLUP);
  pinMode(DN, INPUT_PULLUP); 
}

void loop() {
  readUpSw();  // UP 스위치 처리
  readDnSw();  // DOWN 스위치 처리
  dispFnd(gCnt);
}

void dispFnd(int val)
{
  static int prevVal = -1;

  if (prevVal != val) {   // FND에 표시할 값이 바뀐 경우에만 표시를 변경
    switch (val) {
      case 0:
        dW(FND_A, ON); dW(FND_B, ON); dW(FND_C, ON); dW(FND_D, ON); dW(FND_E, ON); dW(FND_F, ON); dW(FND_G, OFF);
        break;
      case 1:
        dW(FND_A, OFF); dW(FND_B, ON); dW(FND_C, ON); dW(FND_D, OFF); dW(FND_E, OFF); dW(FND_F, OFF); dW(FND_G, OFF);
        break;
      case 2:
        dW(FND_A, ON); dW(FND_B, ON); dW(FND_C, OFF); dW(FND_D, ON); dW(FND_E, ON); dW(FND_F, OFF); dW(FND_G, ON);
        break;
      case 3:
        dW(FND_A, ON); dW(FND_B, ON); dW(FND_C, ON); dW(FND_D, ON); dW(FND_E, OFF); dW(FND_F, OFF); dW(FND_G, ON);
        break;
      case 4:
        dW(FND_A, OFF); dW(FND_B, ON); dW(FND_C, ON); dW(FND_D, OFF); dW(FND_E, OFF); dW(FND_F, ON); dW(FND_G, ON);
        break;
      case 5:
        dW(FND_A, ON); dW(FND_B, OFF); dW(FND_C, ON); dW(FND_D, ON); dW(FND_E, OFF); dW(FND_F, ON); dW(FND_G, ON);
        break;
      case 6:
        dW(FND_A, ON); dW(FND_B, OFF); dW(FND_C, ON); dW(FND_D, ON); dW(FND_E, ON); dW(FND_F, ON); dW(FND_G, ON);
        break;
      case 7:
        dW(FND_A, ON); dW(FND_B, ON); dW(FND_C, ON); dW(FND_D, OFF); dW(FND_E, OFF); dW(FND_F, ON); dW(FND_G, OFF);
        break;
      case 8:
        dW(FND_A, ON); dW(FND_B, ON); dW(FND_C, ON); dW(FND_D, ON); dW(FND_E, ON); dW(FND_F, ON); dW(FND_G, ON);
        break;
      case 9:
        dW(FND_A, ON); dW(FND_B, ON); dW(FND_C, ON); dW(FND_D, ON); dW(FND_E, OFF); dW(FND_F, ON); dW(FND_G, ON);
        break;
    }
    prevVal = val;
  }
}

boolean readUpSw()
{
  static boolean prev = HIGH;
  static unsigned long last;
  boolean curr;

  if ((millis()-last)>10) {
    curr = digitalRead(UP);
    if ((HIGH==prev)&&(LOW==curr)) {   // UP SW가 눌린 시점
      gCnt = (gCnt+1)%10;
    }
    prev = curr;
    last = millis();
  }
}

boolean readDnSw()
{
  static boolean prev = HIGH;
  static unsigned long last;
  boolean curr;

  if ((millis()-last)>10) {
    curr = digitalRead(DN);
    if ((HIGH==prev)&&(LOW==curr)) {  // DOWN SW가 눌린 시점

      gCnt = gCnt-1;
      if (-1 == gCnt) gCnt = 9;
    }
    prev = curr;
    last = millis();
  }
}






2017년 1월 17일 화요일

아두이노 듀에에서 TRNG(True Random Number Generator) 사용하기

아두이노 듀에는 ATMEL의 SAM3X8E (ARM Cortex M3)를 사용하는데 이 칩은 하드웨어 TRNG(True Random Number Generator)를 가지고 있다.
아두이노 환경에서 이 TRNG를 사용하는 방법을 소개한다.



가장 간단한 방법은 다음과 같다.

void setup()

  Serial.begin(115200);
  pmc_enable_periph_clk(ID_TRNG);
  trng_enable(TRNG);
}

void loop()
{
  uint32_t t = trng_read_output_data(TRNG);
  Serial.println(t);
  delay(50);
}

pmc_enable_periph_clk 는 hardware/arduino/sam/system/libsam/source/pmc.c 에 정의되어 있고 trng_enable(), trng_read_output_data() 는 hardware/arduino/system/libsam/source/trng.c 에 정의되어 있다. 엄밀히 말하면 데이터를 읽기 전에 random number generator에서 데이터를 읽을 수 있을 때 까지 기다려야 한다. 하지만 SAM3X8E의 TRNG가 빠르기 때문에 (매 84 클럭 사이클마다 랜덤넘버 하나를 생성) 따로 기다리지 않아도 안전하다. 위의 코드에서 생성된 랜덤 넘버는 unsigned 32비트 숫자로 취급한다.

다른 방법으로는 TRNG 인터럽트를 활성화해서 랜덤넘버가 생성될 때 마다 인터럽트가 그 값을 처리하도록 할 수도 있다.

void setup()

  Serial.begin(115200);
  pmc_enable_periph_clk(ID_TRNG);
  trng_enable(TRNG);

  NVIC_DisableIRQ(TRNG_IRQn);
  NVIC_ClearPendingIRQ(TRNG_IRQn);
  NVIC_SetPriority(TRNG_IRQn, 0);
  NVIC_EnableIRQ(TRNG_IRQn);
  trng_enable_interrupt(TRNG);
}

void TRNG_Handler(void)
{
  uint32_t stat = trng_get_interrupt_status(TRNG);

  if ((stat & TRNG_ISR_DATRDY) == TRNG_ISR_DATRDY) {
    int r = trng_read_output_data(TRNG);
    Serial.println(r);
  }
}

void loop()
{
}

여기서는 TRNG ISR의 상태를 확인해 랜덤넘버를 읽기 전에 값이 생성되었는지 본다. trng_read_output_data 가 리턴하는 값은 signed 또는 unsigned로 해석해도 상관 없다. 위의 예제에서는 signed 32비트 integer로 처리하기 때문에 랜덤값은 0을 기준으로 위/아래로 균등하게 분포하고 있다. NVIC_* 루틴은 hardware/arduino/sam/system/CMSIS/CMSIS/Include/core_cm3.h 에 inline 되어 있다.

데이터쉬트를 보면 SAM3X8E의 TRNG는 American NIST Special Publication 800-22와 Diehard Random Tests를 통과했다고 쓰여 있다.

2017년 1월 5일 목요일

라즈베리 파이 제로 테스트 패드 배치 (Raspberry Pi Test Pad Layout)

라즈베리 파이 제로는 크기가 작다 보니 제대로(?) 활용을 하려면 주변에 몇가지 장치들을 붙여줘야 한다. 특히 USB 허브를 붙이려고 할 때 USB 케이블을 이용하면 케이블이 옆으로 튀어나와 보기에도 안좋고 케이블이 빠지기도 쉽다.
그래서 해결책은 보드의 아래쪽 면에 테스트 패드들을 활용하는 것이다. 기본적인 전원 신호, USB 데이터 신호선, SD카드 신호선들이 나와 있어 이 패드에 납땜을 하거나 아니면 좀 더 깔끔한 방법으로는 스프링이 들어있는 pogo pin을 이용하면 바깥쪽으로 튀어나온 케이블 없이 깔끔하게 주변회로를 부착할 수 있다.

USB 무선랜 동글을 직접 납땜





스프링이 달려 있는 pogo pin으로 납땜하지 않고 연결



Test pad의 위치는 다음과 같다.

라즈베리 파이 제로 v1.2 (클릭하면 크게 확대해 볼 수 있음)

라즈베리 파이 제로 v1.3 (클릭하면 크게 확대해 볼 수 있음)

주의할 것은 라즈베리 파이 v1.2와 v1.3의 테스트 패드 위치가 다르다. v1.2는 카메라 커넥터가 없는 초기모델이고 v1.3은 카메라 커넥터가 붙어있는 모델이다. 최근에 구입한 사람이라면 대부분 v1.3이겠지만 인터넷에서 pogo pin으로 연결하는 보드를 구입하는 경우 버젼을 꼭 확인하고 구입해야만 한다.

USB 허브를 연결하려면 PP1, PP6, PP22, PP23에 각각 +5V, GND, D+, D- 선을 연결해 주면 된다.
반대로 전원 공급을 마이크로USB 케이블을 이용하지 않고 라즈베리 파이에 직접 공급하고 싶은 경우에도 PP1, PP6에 +5V, GND를 연결해 줘도 된다.