728x90

출처 : 라즈베리파이에서 Node.js 사용하기 [ 1. Node.js 및 기타 모듈 설치 ]
라즈베리파이 Node.js 최신버전 설치 :: 생각 정리소
[라즈하이파이] Runeaudio를 이용한 오디오 시스템 만들기 | - 산딸기마을

라즈베리파이 업데이트

$ sudo rpi-update
$ sync
$ sudo reboot

node.js 제거 (방법1)

출처 : 라즈베리파이 Node.js 최신버전 설치 :: 생각 정리소

$ sudo apt-get remove nodered -y
$ sudo apt-get remove nodejs nodejs-legacy -y
$ sudo apt-get remove npm -y

기존 설치된 node.js 제거

출처 : Installing Node.js v4.0.0 on a Raspberry Pi (All Models) - Blog - Wia

$ sudo apt-get remove --purge nodejs

node.js 설치

출처 : Raspberry Pi에 Node-JS 설치하기 - MY - LIFE - Tistory

$ wget https://nodejs.org/dist/v4.0.0/node-v4.0.0-linux-armv7l.tar.gz
$ tar -xvf node-v4.0.0-linux-armv7l.tar.gz
$ sudo mv node-v4.0.0-linux-armv7l /opt

node.js 경로 추가

$ sudo vi /etc/profile

NODE=/opt/node-v4.0.0-linux-armv7l
NODE_PATH=$NODE/lib/node_modules
PATH=$PATH:$NODE/bin:$NODE_PATH

node.js 설치 확인

$ command node -v
v4.0.0
728x90
728x90

출처 : Raspberry Pi: Control WS2812B (NeoPixels) With Bluetooth LE
Eclipse Kura™ Documentation
The Pi4J Project

Bluetooth 모듈이 내장된 블루이노2로 BLE 송신하고, 라즈베리파이3의 Bluetooth 모듈로 수신 받아 데이터처리 해보았습니다.

블루이노2 코드

#include <RFduinoBLE.h>

int Potent=2;
boolean is_connect;

void setup() {
  // put your setup code here, to run once:
  RFduinoBLE.deviceName = "bluexmas";

  // this is the data we want to appear in the advertisement
  //RFduinoBLE.advertisementData = "My BLE LED";
  
  //RFduinoBLE.advertisementInterval = MILLISECONDS(300);
  //RFduinoBLE.txPowerLevel = -20;  // (-20dbM to +4 dBm)
    
  Serial.begin(9600);  
  Serial.println("Start Test");      // With more than 15 characters thie Start Test keeps happening

  // start the BLE stack
  RFduinoBLE.begin();  
}

void loop() {
  char BPM_lcd[10];
  
  RFduino_ULPDelay(100);  
  // Switch to lower power mode
  //RFduino_ULPDelay(INFINITE);
  //RFduino_ULPDelay( SECONDS(1) ); //sample once per second

  if (is_connect) {
    int sensorValue = analogRead(Potent);
    Serial.println(sensorValue);             // debug value

    //sprintf(BPM_lcd, "%10d", sensorValue);
    //lcd.println(BPM_lcd);     
    
    RFduinoBLE.sendInt(sensorValue);  //sends the char array
  }
}

void RFduinoBLE_onConnect() {
  // Debug message printed to Serial interface
  Serial.println("RFduino connected");
  is_connect = true;
}

void RFduinoBLE_onDisconnect() { 
  // Debug message printed to Serial interface
  Serial.println("RFduino disconnected");
  is_connect = false;
}

void RFduinoBLE_onReceive(char *data, int len) {
  // Debug message printed to Serial interface
  Serial.println("Data received: ");
  for(int i=0;i<len;i++)
    Serial.print(data[i]);
    Serial.println();
    Serial.println(data);
}

Blueinno.java

BLE 관련 코드만 보기 편하게 하기 위해서 모터 제어 관련 코드는 빼고 블루이노2와 통신하는 부분만 공개

package ble.blueinno2;

import java.util.List;
import java.util.Scanner;

import org.eclipse.kura.KuraException;
import org.eclipse.kura.bluetooth.BluetoothDevice;
import org.eclipse.kura.bluetooth.BluetoothGatt;
import org.eclipse.kura.bluetooth.BluetoothGattService;
import org.eclipse.kura.bluetooth.BluetoothLeNotificationListener;
import org.eclipse.kura.bluetooth.BluetoothLeScanListener;
import org.eclipse.kura.linux.bluetooth.util.BluetoothProcess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Blueinno implements BluetoothLeNotificationListener, BluetoothLeScanListener {
	
	private static final Logger logger = LoggerFactory.getLogger(BluetoothProcess.class);

	private BluetoothGatt m_bluetoothGatt;
	private BluetoothDevice m_device;
	private boolean m_connected;

	public Blueinno(BluetoothDevice bluetoothDevice) {
		// m_device = bluetoothDevice;
		m_connected = false;
	}

	public BluetoothDevice getBluetoothDevice() {
		return m_device;
	}

	public void setBluetoothDevice(BluetoothDevice device) {
		m_device = device;
	}

	public boolean isConnected() {
		return m_connected;
	}

	public boolean connect(BluetoothLeNotificationListener listener) throws KuraException {
		m_bluetoothGatt = m_device.getBluetoothGatt();
		logger.info("접속시도");
		boolean connected = m_bluetoothGatt.connect();
		if (connected) {
			m_bluetoothGatt.setBluetoothLeNotificationListener(listener);
			logger.info("리스너등록");
			m_connected = true;
			return true;
		} else {
			// If connect command is not executed, close gatttool
			m_bluetoothGatt.disconnect();
			m_connected = false;
			return false;
		}
	}

	public void disconnect() {
		if (m_bluetoothGatt != null) {
			m_bluetoothGatt.disconnect();
			m_connected = false;
		}
	}

	/*
	 * Discover services
	 */
	public List<BluetoothGattService> discoverServices() {
		return m_bluetoothGatt.getServices();
	}

	@Override
	public void onScanFailed(int errorCode) {
		// TODO Auto-generated method stub
		System.out.println("error = " + errorCode);
	}

	@Override
	public void onScanResults(List<BluetoothDevice> devices) {
		logger.info("onScanResults = " + devices.size());

		for (BluetoothDevice device : devices) {
			logger.info("Found Bluetooth Device " + device.getName() + " [" + device.getAdress() + "]");
		}
		
		System.out.print("ble address > ");
		Scanner scanner = new Scanner(System.in);
		String blc_address = scanner.next();
		
		BluetoothDevice nurum_device = null;
		for (BluetoothDevice device : devices) {
			if (device.getAdress().equals(blc_address)) {
				nurum_device = device;
			}
		}
		
		if (nurum_device != null) {
			//ble_nurum = new Blueinno(nurum_device);
			this.setBluetoothDevice(nurum_device);
			try {
				if (this.connect(this)) {
					System.out.println("ble connect");
					
					Runnable aa = new Runnable() {
						
						@Override
						public void run() {
							while (true) {
								try {
									String sensorValue = m_bluetoothGatt.readCharacteristicValue("0x000e");
									System.out.println(sensorValue);
									
									// 모터제어
									// 생략
								} catch (KuraException e1) {
									e1.printStackTrace();
								}
								try {
									Thread.sleep(100);
								} catch (Exception e) {
									
								}
							}
						}
					};
					
					Thread bb = new Thread(aa);
					bb.start();
				}
			} catch (KuraException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public void onDataReceived(String handle, String value) {
		System.out.println("handle: " + handle + " value: " + value);
	}
}

BlueinnoMain.java

package ble.blueinno2;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.eclipse.kura.linux.bluetooth.le.BluetoothLeScanner;

public class BlueinnoMain {
	
	Logger logger = Logger.getLogger(this.getClass());

	private Blueinno blueinno = null;
	
	public static void main(String[] args) throws Exception {
		BlueinnoMain bletest = new BlueinnoMain();
		bletest.init();
		bletest.startScan();
	}
	
	public void init() {
		Logger.getRootLogger().setLevel(Level.DEBUG);
		logger.info("초기화");
		blueinno = new Blueinno();
	}

	public void startScan() throws InterruptedException {
		BluetoothLeScanner m_bls = new BluetoothLeScanner();
		m_bls.startScan("hci0", blueinno);
		Thread.sleep(10000);
		m_bls.killScan();
	}
}

실행


728x90
728x90

출처 : Eclipse Kura™ Documentation
The Pi4J Project

라즈베리파이2에 BLE 동글이와 BLE 스마트 버튼인 nurum으로 클릭 이벤트를 받아서
GPIO를 이용해서 LED를 컨트롤 해보았습니다.

BleNurum class

package bletest;

import java.util.List;

import org.eclipse.kura.KuraException;
import org.eclipse.kura.bluetooth.BluetoothDevice;
import org.eclipse.kura.bluetooth.BluetoothGatt;
import org.eclipse.kura.bluetooth.BluetoothGattService;
import org.eclipse.kura.bluetooth.BluetoothLeNotificationListener;

public class BleNurum {

	private BluetoothGatt m_bluetoothGatt;
	private BluetoothDevice m_device;
	private boolean m_connected;

	public BleNurum(BluetoothDevice bluetoothDevice) {
		m_device = bluetoothDevice;
		m_connected = false;
	}

	public BluetoothDevice getBluetoothDevice() {
		return m_device;
	}

	public void setBluetoothDevice(BluetoothDevice device) {
		m_device = device;
	}

	public boolean isConnected() {
		return m_connected;
	}

	public boolean connect(BluetoothLeNotificationListener listener) throws KuraException {
		m_bluetoothGatt = m_device.getBluetoothGatt();
		boolean connected = m_bluetoothGatt.connect();
		if (connected) {
			m_bluetoothGatt.setBluetoothLeNotificationListener(listener);
			m_connected = true;
			return true;
		} else {
			// If connect command is not executed, close gatttool
			m_bluetoothGatt.disconnect();
			m_connected = false;
			return false;
		}
	}

	public void disconnect() {
		if (m_bluetoothGatt != null) {
			m_bluetoothGatt.disconnect();
			m_connected = false;
		}
	}

	/*
	 * Discover services
	 */
	public List<BluetoothGattService> discoverServices() {
		return m_bluetoothGatt.getServices();
	}
}

BleTestMain class

package bletest;

import java.nio.ByteBuffer;
import java.util.List;
import java.util.Scanner;

import org.eclipse.kura.KuraException;
import org.eclipse.kura.bluetooth.BluetoothDevice;
import org.eclipse.kura.bluetooth.BluetoothLeNotificationListener;
import org.eclipse.kura.bluetooth.BluetoothLeScanListener;
import org.eclipse.kura.linux.bluetooth.le.BluetoothLeScanner;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;

public class BleTestMain implements BluetoothLeScanListener, BluetoothLeNotificationListener {
	
	private BleNurum ble_nurum = null;
	private GpioController gpio = null;
	private GpioPinDigitalOutput led_01 = null;
	private GpioPinDigitalOutput led_02 = null;
	
	public static void main(String[] args) throws Exception {
		BleTestMain bletest = new BleTestMain();
		bletest.init();
		bletest.startScan();
	}
	
	public void init() {
		// create gpio controller
		gpio = GpioFactory.getInstance();
		led_01 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_08, "Red LED", PinState.HIGH);
		led_02 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_09, "Blue LED", PinState.HIGH);
		// set shutdown state for this pin
		led_01.setShutdownOptions(true, PinState.LOW);
		led_02.setShutdownOptions(true, PinState.LOW);
		led_01.low();
		led_02.low();
	}

	public void startScan() throws InterruptedException {
		BluetoothLeScanner m_bls = new BluetoothLeScanner();
		m_bls.startScan("hci0", this);

		Thread.sleep(3000);

		m_bls.killScan();
	}

	@Override
	public void onScanFailed(int errorCode) {
		// TODO Auto-generated method stub
		System.out.println("error = " + errorCode);
	}

	@Override
	public void onScanResults(List<BluetoothDevice> devices) {
		System.out.println("onScanResults = " + devices.size());

		for (BluetoothDevice device : devices) {
			System.out.println("Found Bluetooth Device " + device.getName() + " [" + device.getAdress() + "]");
		}
		
		System.out.print("ble address > ");
		Scanner scanner = new Scanner(System.in);
		String blc_address = scanner.next();
		
		BluetoothDevice nurum_device = null;
		for (BluetoothDevice device : devices) {
			if (device.getAdress().equals(blc_address)) {
				nurum_device = device;
			}
		}
		
		if (nurum_device != null) {
			ble_nurum = new BleNurum(nurum_device);
			try {
				if (ble_nurum.connect(this)) {
					System.out.println("ble connect");
				}
			} catch (KuraException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public static byte[] decode(String hex) {

		String[] list = hex.split("(?<=\\G.{2})");
		ByteBuffer buffer = ByteBuffer.allocate(list.length);
		System.out.println(list.length);
		for (String str : list)
			buffer.put(Byte.parseByte(str, 16));

		return buffer.array();

	}

	@Override
	public void onDataReceived(String handle, String value) {
		String val = new String( decode(value.replaceAll("\\p{Z}", "")) );
		
		System.out.println("handle: " + handle + " value: " + value + " / " + val);
		
		if (val.equals("!1")) {
			led_01.toggle();
		}
		
		if (val.equals("!2")) {
			led_02.toggle();
		}
		
		if (val.equals("!3")) {
			led_01.low();
			led_02.low();
		}		
		
		if (val.equals("!H")) {
			ble_nurum.disconnect();
			gpio.shutdown();
			System.exit(1);
		}
	}
}

실행

$ sudo java -cp .:pi4j-core.jar:org.apache.commons.io_2.4.0.jar:org.eclipse.equinox.io_1.0.400.v20120522-2049.jar:org.eclipse.osgi_3.8.1.v20120830-144521.jar:org.eclipse.osgi.services_3.3.100.v20120522-1822.jar:org.eclipse.osgi.util_3.2.300.v20120522-1822.jar:org.eclipse.soda.dk.comm_1.2.1.jar:slf4j.api_1.6.4.jar:slf4j.jdk14_1.6.4.jar:slf4j.log4j12_1.6.0.jar:usb4java-javax_1.0.0.jar bletest.BleTestMain

728x90
728x90

마우스 반응 속도 개선

출처 : 라즈베리파이 무선마우스 속도 감도 문제 해결

cmdline.txt 파일의 첫줄에 usbhid.mousepoll=0 추가 / 디폴트가 8로 너무 빠르다 싶으면 숫자를 올려준다.

$ sudo vi /boot/cmdline.txt

최신 버전으로 업데이트

$ sudo apt-get update
$ sudo apt-get upgrade

XRDP 사용

출처 : Introducing PIXEL - Raspberry Pi
Raspberry Pi Adds Beautiful "Pixel" Desktop Environment To ...

최신 라즈베리파이OS인 PIXEL의 경우 기본적으로 VNC서버가 설치되어 있으므로, XRDP를 사용하실 경우 VNC 서버를 삭제 해야됩니다.

VNC서버 삭제 (RealVNC가 설치되어 있는 경우 사용)

$ sudo apt-get autoremove --purge realvnc
$ sudo apt-get purge realvnc-vnc-server

XRDP 설치

$ sudo apt-get install xrdp

라즈베리파이 펌웨어 업데이트

출처 : 라즈베리파이 펌웨어 업데이트 하기 (firmware update on the R-Pi)

$ sudo apt-get install ca-certificates
Reading package lists... Done
Building dependency tree       
Reading state information... Done
ca-certificates is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
$ sudo apt-get install git-core
Reading package lists... Done
Building dependency tree       
Reading state information... Done
git-core is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

리눅스 정보

$ uname -a
Linux raspberrypi 4.4.21-v7+ #911 SMP Thu Sep 15 14:22:38 BST 2016 armv7l GNU/Linux

HC-06 UART 설정

출처 : Raspberry Pi 3 UART baud rate workaround
RaspberryPi3でシリアル通信を行う - Qiita
Brian Dorey.com | Raspberry Pi 3 UART Boot Overlay Part Two

환경파일 /boot/config.txt 수정

내용 추가 dtoverlay=pi3-miniuart-bt, enable_uart=1, core_freq=25

$ sudo vi /boot/config.txt

변경후

# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi
dtoverlay=pi3-miniuart-bt
enable_uart=1
core_freq=250

해상도 변경

출처 : studymake.blogspot.kr: [00076] 라즈베리파이 해상도 변경하는 방법

$ sudo vi /boot/config.txt

아래 해당 부분의 주석 제거

hdmi_force_hotplug = 1
hdmi_group = 2
hdmi_mode = 16 # 16 = 1024x768   60 Hz
hdmi_drive = 1

한글 폰트 설치

$ sudo apt-get install ttf-unfonts-core

한글 입력기 설치

$ sudo apt-get install fcitx-hangul

node.js 설치

출처 : Installing Node.js v4.0.0 on a Raspberry Pi (All Models) - Blog - Wia

$ wget https://nodejs.org/dist/v4.0.0/node-v4.0.0-linux-armv7l.tar.gz
$ tar -xvf node-v4.0.0-linux-armv7l.tar.gz
$ cd node-v4.0.0-linux-armv7l
$ sudo cp -R * /usr/local/

node.js 설치 확인

$ command node -v
v4.0.0

스마트미러 설치

출처 : Smart Mirror 스마트 미러 만들기- 4 Smart Mirror GitHub 다운 및 실행

$ mkdir test-smart-mirror
$ cd test-smart-mirror
$ git clone https://github.com/evancohen/smart-mirror.git
Cloning into 'smart-mirror'...
remote: Counting objects: 3760, done.
remote: Compressing objects: 100% (107/107), done.
remote: Total 3760 (delta 56), reused 0 (delta 0), pack-reused 3653
Receiving objects: 100% (3760/3760), 10.85 MiB | 2.09 MiB/s, done.
Resolving deltas: 100% (2072/2072), done.
Checking connectivity... done.
$ cd smart-mirror
$ cp config.example.js config.js
$ npm install

스마트미러 실행

$ npm start

스마트미러 실행 화면


$ lsusb
Bus 001 Device 004: ID 148f:3070 Ralink Technology, Corp. RT2870/RT3070 Wireless Adapter
Bus 001 Device 006: ID 0d8c:013c C-Media Electronics, Inc. CM108 Audio Controller
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub


$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0


728x90
728x90

출처 : Raspberry Pi to Arduino SPI Communication

spi 확인

$ gpio load spi
gpio: Unable to load/unload modules as this Pi has the device tree enabled.
  You need to run the raspi-config program (as root) and select the
  modules (SPI or I2C) that you wish to load/unload there and reboot.
  There is more information here:
      https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=97314

배선

소스 - Arduino (Master)

/*************************************************************
 SPI_Hello_Raspi
   Configures an ATMEGA as an SPI slave and demonstrates
   bidirectional communication with an Raspberry Pi SPI master
   by repeatedly sending the text "Hello Raspi"
****************************************************************/


/***************************************************************
 Global Variables
  -hello[] is an array to hold the data to be transmitted
  -marker is used as a pointer in traversing data arrays
/***************************************************************/

unsigned char hello[] = {'H','e','l','l','o',' ',
                         'R','a','s','p','i','\n'};
byte marker = 0;
 

/***************************************************************  
 Setup SPI in slave mode (1) define MISO pin as output (2) set
 enable bit of the SPI configuration register 
****************************************************************/ 
                    
void setup (void)
{
 
  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);

  Serial.begin(115200);
}  

/***************************************************************  
 Loop until the SPI End of Transmission Flag (SPIF) is set
 indicating a byte has been received.  When a byte is
 received, load the next byte in the Hello[] array into SPDR
 to be transmitted to the Raspberry Pi, and increment the marker.
 If the end of the Hell0[] array has been reached, reset
 marker to 0.
****************************************************************/

void loop (void)
{

  if((SPSR & (1 << SPIF)) != 0)
  {
    SPDR = hello[marker];
    marker++;
   
    if(marker > sizeof(hello))
    {
      marker = 0;
    }  
  }

  Serial.println('test');
}

소스 - Raspberry PI (Slave)

/**********************************************************
 SPI_Raspi_Arduino
   Configures an Raspberry Pi as an SPI master and
   demonstrates a basic bidirectional communication scheme
   with an Arduino slave.  The Raspberry Pi transmits
   commands to perform addition and subtraction on a pair
   of integers and the Ardunio returns the result

Compile String:
g++ -o SPI_Raspi_Arduino SPI_Raspi_Arduino.cpp
***********************************************************/

#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <iostream>
#include <cstring>
#include <unistd.h>

using namespace std;


/**********************************************************
Housekeeping variables
***********************************************************/
int results;
int fd;

/**********************************************************
Declare Functions
***********************************************************/

int spiTxRx(unsigned char txDat);
int sendCommand(char i, int j, int k);

/**********************************************************
Main
***********************************************************/

int main (void)
{

/**********************************************************
Setup SPI
Open file spidev0.0 (chip enable 0) for read/write access
with the file descriptor "fd"
Configure transfer speed (1MkHz)
***********************************************************/

   fd = open("/dev/spidev0.0", O_RDWR);

   unsigned int speed = 1000000;
   ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

/**********************************************************
An endless loop that repeatedly sends the demonstration
commands to the Arduino and displays the results
***********************************************************/

   while (1)
   {

      results = sendCommand('a', 510, 655);

      cout << "Addition results:" << endl;
      cout << "510 + 655 = " <<  (int)(results) << endl;


      results = sendCommand('s', 1000, 250);

      cout << "Subtraction results:" << endl;
      cout << "1000 - 250 = " <<  (int)(results) << endl <<endl; 

      sleep(1);

     }

}

/**********************************************************
spiTxRx
 Transmits one byte via the SPI device, and returns one byte
 as the result.

 Establishes a data structure, spi_ioc_transfer as defined
 by spidev.h and loads the various members to pass the data
 and configuration parameters to the SPI device via IOCTL

 Local variables txDat and rxDat are defined and passed by
 reference.  
***********************************************************/

int spiTxRx(unsigned char txDat)
{
 
  unsigned char rxDat;

  struct spi_ioc_transfer spi;

  memset (&spi, 0, sizeof (spi));

  spi.tx_buf        = (unsigned long)&txDat;
  spi.rx_buf        = (unsigned long)&rxDat;
  spi.len           = 1;

  ioctl (fd, SPI_IOC_MESSAGE(1), &spi);

  return rxDat;
}


/**********************************************************
sendCommand
 Demonstration of a protocol that uses the spiTxRx function
 to send a formatted command sequence/packet to the Arduino
 one byte at and capture the results
***********************************************************/


int sendCommand(char command, int j, int k)
{

unsigned char resultByte;
bool ack;

/**********************************************************
Unions allow variables to occupy the same memory space
a convenient way to move back and forth between 8-bit and
16-bit values etc.

Here three unions are declared: two for parameters to be 
passed in commands to the Arduino and one to receive
the results
***********************************************************/

union p1Buffer_T       
{
  int p1Int;
  unsigned char  p1Char [2];
} p1Buffer;

union p2Buffer_T      
{
  int p2Int;
  unsigned char  p2Char [2];
} p2Buffer;

union resultBuffer_T     
{
  int resultInt;
  unsigned char  resultChar [2];
} resultBuffer;


  p1Buffer.p1Int = j;
  p2Buffer.p2Int = k;
  resultBuffer.resultInt = 0;

/**********************************************************
An initial handshake sequence sends a one byte start code
('c') and loops endlessly until it receives the one byte 
acknowledgment code ('a') and sets the ack flag to true.
(Note that the loop also sends the command byte while 
still in handshake sequence to avoid wasting a transmit
cycle.)
***********************************************************/

  do
  {
    ack = false;

    spiTxRx('c');
    usleep (10);


    resultByte = spiTxRx(command);
    if (resultByte == 'a')
    {
      ack = true;
    }
    usleep (10);  

   }
  while (ack == false);

/**********************************************************
Send the parameters one byte at a time.
***********************************************************/

  spiTxRx(p1Buffer.p1Char[0]);
  usleep (10);


  spiTxRx(p1Buffer.p1Char[1]);
  usleep (10);


  spiTxRx(p2Buffer.p2Char[0]);
  usleep (10);


  spiTxRx(p2Buffer.p2Char[1]);
  usleep (10);

/**********************************************************
Push two more zeros through so the Arduino can return the
results
***********************************************************/


  resultByte = spiTxRx(0);
  resultBuffer.resultChar[0] = resultByte;
  usleep (10);


  resultByte = spiTxRx(0);
  resultBuffer.resultChar[1] = resultByte;
  return resultBuffer.resultInt;

}

컴파일

$ g++ -o SPI_Raspi_Arduino SPI_Raspi_Arduino.cpp

실행

$ sudo ./SPI_Raspi_Arduino
Addition results:
510 + 655 = 108
Subtraction results:
1000 - 250 = 28672
 
Addition results:
510 + 655 = 2
Subtraction results:
1000 - 250 = 0
 
Addition results:
510 + 655 = 28674
Subtraction results:
1000 - 250 = 28672
 
Addition results:
510 + 655 = 28674
Subtraction results:
1000 - 250 = 28672
 
Addition results:
510 + 655 = 2
Subtraction results:
1000 - 250 = 0
 
^C
728x90
728x90

출처 : Raspberry Pi + Arduino + SPI - MitchTech | MitchTech

배선

소스 - Arduino (Slave)

// Written by Nick Gammon
// February 2011
/**
 * Send arbitrary number of bits at whatever clock rate (tested at 500 KHZ and 500 HZ).
 * This script will capture the SPI bytes, when a '\n' is recieved it will then output
 * the captured byte stream via the serial.
 */

#include <SPI.h>

char buf [100];
volatile byte pos;
volatile boolean process_it;

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

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
  
  // get ready for an interrupt 
  pos = 0;   // buffer empty
  process_it = false;

  // now turn on interrupts
  SPI.attachInterrupt();

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;  // grab byte from SPI Data Register
  
  // add to buffer if room
  if (pos < sizeof buf)
    {
    buf [pos++] = c;
    
    // example: newline means time to process buffer
    if (c == '\n')
      process_it = true;
      
    }  // end of room available
}  // end of interrupt routine SPI_STC_vect

// main loop - wait for flag set in interrupt routine
void loop (void)
{
  if (process_it)
    {
    buf [pos] = 0;  
    Serial.println (buf);
    pos = 0;
    process_it = false;
    }  // end of flag set
    
}  // end of loop

소스 - Raspberry PI (Master)

/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static void pabort(const char *s)
{
	perror(s);
	abort();
}

static const char *device = "/dev/spidev0.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;

static void transfer(int fd)
{
	int ret;
	uint8_t tx[] = {
        0x48, 0x45, 0x4C, 0x4C, 0x4F,
        0x20, 
        0x57, 0x4F, 0x52, 0x4C, 0x44,
        0x0A 
	};
	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = ARRAY_SIZE(tx),
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};

	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");

    /*
	for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
		if (!(ret % 6))
			puts("");
		printf("%.2X ", rx[ret]);
	}
	puts("");
    */
}

static void print_usage(const char *prog)
{
	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
	puts("  -D --device   device to use (default /dev/spidev1.1)\n"
	     "  -s --speed    max speed (Hz)\n"
	     "  -d --delay    delay (usec)\n"
	     "  -b --bpw      bits per word \n"
	     "  -l --loop     loopback\n"
	     "  -H --cpha     clock phase\n"
	     "  -O --cpol     clock polarity\n"
	     "  -L --lsb      least significant bit first\n"
	     "  -C --cs-high  chip select active high\n"
	     "  -3 --3wire    SI/SO signals shared\n");
	exit(1);
}

static void parse_opts(int argc, char *argv[])
{
	while (1) {
		static const struct option lopts[] = {
			{ "device",  1, 0, 'D' },
			{ "speed",   1, 0, 's' },
			{ "delay",   1, 0, 'd' },
			{ "bpw",     1, 0, 'b' },
			{ "loop",    0, 0, 'l' },
			{ "cpha",    0, 0, 'H' },
			{ "cpol",    0, 0, 'O' },
			{ "lsb",     0, 0, 'L' },
			{ "cs-high", 0, 0, 'C' },
			{ "3wire",   0, 0, '3' },
			{ "no-cs",   0, 0, 'N' },
			{ "ready",   0, 0, 'R' },
			{ NULL, 0, 0, 0 },
		};
		int c;

		c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);

		if (c == -1)
			break;

		switch (c) {
		case 'D':
			device = optarg;
			break;
		case 's':
			speed = atoi(optarg);
			break;
		case 'd':
			delay = atoi(optarg);
			break;
		case 'b':
			bits = atoi(optarg);
			break;
		case 'l':
			mode |= SPI_LOOP;
			break;
		case 'H':
			mode |= SPI_CPHA;
			break;
		case 'O':
			mode |= SPI_CPOL;
			break;
		case 'L':
			mode |= SPI_LSB_FIRST;
			break;
		case 'C':
			mode |= SPI_CS_HIGH;
			break;
		case '3':
			mode |= SPI_3WIRE;
			break;
		case 'N':
			mode |= SPI_NO_CS;
			break;
		case 'R':
			mode |= SPI_READY;
			break;
		default:
			print_usage(argv[0]);
			break;
		}
	}
}

int main(int argc, char *argv[])
{
	int ret = 0;
	int fd;

	parse_opts(argc, argv);

	fd = open(device, O_RDWR);
	if (fd < 0)
		pabort("can't open device");

	/*
	 * spi mode
	 */
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	/*
	 * bits per word
	 */
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	/*
	 * max speed hz
	 */
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");

	printf("spi mode: %d\n", mode);
	printf("bits per word: %d\n", bits);
	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

	transfer(fd);

	close(fd);

	return ret;
}

컴파일

$ gcc spidev_test.c -o spidev_test

실행

$ sudo ./spidev_test
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)

결과

728x90
728x90

출처 : Raspberry Pi SPI and I2C Tutorial
Use the Adafruit PCA9685 with a Raspberry PI, in Java Raspberry PI to drive up to 16 servos
JavaScript Robotics: Servo - PCA9685

I2C on Pi

$ sudo raspi-config

i2c device 활성화

$ sudo vi /etc/modules

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

i2c-bcm2708
i2c-dev

gpio commands

$ gpio -v
gpio version: 2.32
Copyright (c) 2012-2015 Gordon Henderson
This is free software with ABSOLUTELY NO WARRANTY.
For details type: gpio -warranty
 
Raspberry Pi Details:
  Type: Model B, Revision: 03, Memory: 512MB, Maker: Egoman 
  * Device tree is enabled.
  * This Raspberry Pi supports user-level GPIO access.
    -> See the man-page for more details
    -> ie. export WIRINGPI_GPIOMEM=1
$ gpio readall
 +-----+-----+---------+------+---+-Model B2-+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 | ALT0 | 1 |  3 || 4  |   |      | 5V      |     |     |
 |   3 |   9 |   SCL.1 | ALT0 | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | ALT0 | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT0 | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI | ALT0 | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO | ALT0 | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT  | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | OUT  | CE1     | 11  | 7   |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |  28 |  17 | GPIO.17 |   IN | 0 | 51 || 52 | 0 | IN   | GPIO.18 | 18  | 29  |
 |  30 |  19 | GPIO.19 |   IN | 0 | 53 || 54 | 0 | IN   | GPIO.20 | 20  | 31  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+-Model B2-+---+------+---------+-----+-----+

detect I2C chips

출처 : i2cdetect(8): detect I2C chips - Linux man page

$ ls /dev/*i2c*
/dev/i2c-1
$ sudo apt-get install -y i2c-tools
$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: 70 -- -- -- -- -- -- -- 

배선

PCA9685Gpio.java

출처 : wyliodrin-server-nodejs/libs/raspberrypi/java/pi4j/examples/PCA9685GpioExample.java

package com.bluexmas.arm;

import java.io.IOException;

/**
 * sudo java -cp .:pi4j-core.jar:pi4j-device.jar:pi4j-gpio-extension.jar:pi4j-service.jar com.bluexmas.arm.PCA9685Gpio
 */
import java.math.BigDecimal;

import com.pi4j.gpio.extension.pca.PCA9685GpioProvider;
import com.pi4j.gpio.extension.pca.PCA9685Pin;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinPwmOutput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CFactory;
import com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException;

public class PCA9685Gpio {
	
	private static final int SERVO_DURATION_MIN = 650;
	private static final int SERVO_DURATION_NEUTRAL = 1500;
	private static final int SERVO_DURATION_MAX = 2100;
	
	private static PCA9685Gpio instance = null;
	
	private PCA9685GpioProvider gpioProvider = null;
	
	private PCA9685Gpio() throws IOException, UnsupportedBusNumberException {		
		System.out.println("<--Pi4J--> PCA9685 PWM Example ... started.");
		// This would theoretically lead into a resolution of 5 microseconds per
		// step:
		// 4096 Steps (12 Bit)
		// T = 4096 * 0.000005s = 0.02048s
		// f = 1 / T = 48.828125
		BigDecimal frequency = new BigDecimal("48.828");
		// Correction factor: actualFreq / targetFreq
		// e.g. measured actual frequency is: 51.69 Hz
		// Calculate correction factor: 51.65 / 48.828 = 1.0578
		// --> To measure actual frequency set frequency without correction
		// factor(or set to 1)
		BigDecimal frequencyCorrectionFactor = new BigDecimal("1.0578");
		// Create custom PCA9685 GPIO provider
		I2CBus bus = I2CFactory.getInstance(I2CBus.BUS_1);
		gpioProvider = new PCA9685GpioProvider(bus, 0x40, frequency, frequencyCorrectionFactor);
		// Define outputs in use for this example
		GpioPinPwmOutput[] myOutputs = provisionPwmOutputs(gpioProvider);
		// Reset outputs
		gpioProvider.reset();
	}
	
	public static PCA9685Gpio getInstance() throws IOException, UnsupportedBusNumberException {
		if (instance==null) instance = new PCA9685Gpio();
		return instance;
	}
	
	public void setPwm(Pin pin, int duration) {
		gpioProvider.setPwm(pin, duration);
	}
	
	public void shutdown() {
		gpioProvider.shutdown();
	}
	
	private static GpioPinPwmOutput[] provisionPwmOutputs(final PCA9685GpioProvider gpioProvider) {
		GpioController gpio = GpioFactory.getInstance();
		GpioPinPwmOutput myOutputs[] = { 
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_00, "Pulse 00"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_01, "Pulse 01"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_02, "Pulse 02"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_03, "Pulse 03"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_04, "Pulse 04"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_05, "Pulse 05"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_06, "Pulse 06"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_07, "Pulse 07"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_08, "Pulse 08"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_09, "Pulse 09"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_10, "Always ON"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_11, "Always OFF"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_12, "Servo pulse MIN"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_13, "Servo pulse NEUTRAL"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_14, "Servo pulse MAX"),
				gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_15, "not used") };
		return myOutputs;
	}

	public static void main(String[] args) throws Exception {
		
		PCA9685Gpio test = PCA9685Gpio.getInstance();
		
		test.setPwm(PCA9685Pin.PWM_00, SERVO_DURATION_MIN);
		// Set 1.5ms pulse (R/C Servo neutral position)
		Thread.sleep(2000);
		test.setPwm(PCA9685Pin.PWM_00, SERVO_DURATION_NEUTRAL);
		// Set 2.1ms pulse (R/C Servo maximum position)
		Thread.sleep(2000);
		test.setPwm(PCA9685Pin.PWM_00, SERVO_DURATION_MAX);
		Thread.sleep(2000);
		test.setPwm(PCA9685Pin.PWM_00, SERVO_DURATION_MIN);
		Thread.sleep(2000);
		test.shutdown();
	}
	
}

실행

$ sudo java -cp .:pi4j-core.jar:pi4j-gpio-extension.jar com.bluexmas.arm.PCA9685Gpio
<--Pi4J--> PCA9685 PWM Example ... started.

728x90
728x90

출처 : java - read temperature from DHT11, using pi4j - Stack Overflow

pi4j 다운로드

$ mkdir pi4j
$ cd pi4j
$ wget http://get.pi4j.com/download/pi4j-1.0.zip
--2016-07-09 16:59:31--  http://get.pi4j.com/download/pi4j-1.0.zip
Resolving get.pi4j.com (get.pi4j.com)... 54.231.114.185
Connecting to get.pi4j.com (get.pi4j.com)|54.231.114.185|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3807428 (3.6M) [application/zip]
Saving to: ‘pi4j-1.0.zip.1’
 
pi4j-1.0.zip.1      100%[=====================>]   3.63M   544KB/s   in 6.4s   
 
2016-07-09 16:59:38 (581 KB/s) - ‘pi4j-1.0.zip.1’ saved [3807428/3807428]
 
$ unzip pi4j-1.0.zip 

핀 연결

   

DHT11.java

import java.util.List;
import java.util.ArrayList;

import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.GpioUtil;

public class DHT11 {
	private static final int MAXTIMINGS = 85;
	private int[] dht11_dat = { 0, 0, 0, 0, 0 };

	public DHT11() {

	    // setup wiringPi
	    if (Gpio.wiringPiSetup() == -1) {
	        System.out.println(" ==>> GPIO SETUP FAILED");
	        return;
	    }

	   GpioUtil.export(3, GpioUtil.DIRECTION_OUT);            
	}

	public void getTemperature() {
	   int laststate = Gpio.HIGH;
	   int j = 0;
	   dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;
	   StringBuilder value = new StringBuilder();

	   Gpio.pinMode(3, Gpio.OUTPUT);
	   Gpio.digitalWrite(3, Gpio.LOW);
	   Gpio.delay(18);

	   Gpio.digitalWrite(3, Gpio.HIGH);        
	   Gpio.pinMode(3, Gpio.INPUT);

	   for (int i = 0; i < MAXTIMINGS; i++) {
	      int counter = 0;
	      while (Gpio.digitalRead(3) == laststate) {
	          counter++;
	          Gpio.delayMicroseconds(1);
	          if (counter == 255) {
	              break;
	          }
	      }

	      laststate = Gpio.digitalRead(3);

	      if (counter == 255) {
	          break;
	      }

	      /* ignore first 3 transitions */
	      if ((i >= 4) && (i % 2 == 0)) {
	         /* shove each bit into the storage bytes */
	         dht11_dat[j / 8] <<= 1;
	         if (counter > 16) {
	             dht11_dat[j / 8] |= 1;
	         }
	         j++;
	       }
	    }
	    // check we read 40 bits (8bit x 5 ) + verify checksum in the last
	    // byte
	    if ((j >= 40) && checkParity()) {
	        float h = (float)((dht11_dat[0] << 8) + dht11_dat[1]) / 10;
	        if ( h > 100 )
	        {
	            h = dht11_dat[0];   // for DHT11
	        }
	        float c = (float)(((dht11_dat[2] & 0x7F) << 8) + dht11_dat[3]) / 10;
	        if ( c > 125 )
	        {
	            c = dht11_dat[2];   // for DHT11
	        }
	        if ( (dht11_dat[2] & 0x80) != 0 )
	        {
	            c = -c;
	        }
	        float f = c * 1.8f + 32;
	        System.out.println( "Humidity = " + h + " Temperature = " + c + "(" + f + "f)");
	    }else  {
	        System.out.println( "Data not good, skip" );
	    }

	}

	private boolean checkParity() {
	  return (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF));
	}



	public static void main (String ars[]) throws Exception {

	    DHT11 dht = new DHT11();

	    for (int i=0; i<10; i++) {
	       Thread.sleep(2000);
	       dht.getTemperature();
	    }

	    System.out.println("Done!!");

	}
}

컴파일

$ javac -cp pi4j-1.0/lib/pi4j-core.jar DHT11.java 

실행

$ sudo java -cp .:pi4j-1.0/lib/pi4j-core.jar DHT11 
Humidity = 56.0 Temperature = 32.0(89.6f)
Data not good, skip
Humidity = 53.0 Temperature = 31.0(87.8f)
Data not good, skip
Humidity = 52.0 Temperature = 31.0(87.8f)
Humidity = 52.0 Temperature = 31.0(87.8f)
Data not good, skip
Humidity = 51.0 Temperature = 31.0(87.8f)
Humidity = 51.0 Temperature = 31.0(87.8f)
Data not good, skip
Done!!

GPIO 핀 배열

728x90

+ Recent posts