顯示具有 arduino 標籤的文章。 顯示所有文章
顯示具有 arduino 標籤的文章。 顯示所有文章

2018年9月14日 星期五

[Arduino]外部中斷

過去我們在偵測button有沒有按下時,我們會在loop() 中不斷的去檢查button狀態,

但這樣其實效能不佳,我們可以透過中斷,來處理Button按下的問題。

但記住一件事,傳統的button會有彈跳現像,這個我們之後再談。


2017年10月9日 星期一

[arduino] Arduino Nano 使用DFRobot LCD KeyPad Shield

首先介紹一下二個主角

  1. Arduino Nano
    1. 官方的說明 -->The Arduino Nano is a compact board similar to the UNO. (Arduino Nano是一塊類似於UNO的簡潔版)
      它的體型比較小,而且Analog Input有8支,比UNO多二支。

      資料及圖片來源:
      https://store.arduino.cc/usa/arduino-nano
  2. DFRobot LCD KeyPad Shield
    1. 這是一塊For UNO的擴充版,上面有一個1602LCD及幾個按鈕。
    2. 使用到的PIN如下表
      Analog 0是透過不同按鈕會輸出不同的電壓來分辨是那一個按鈕
       if (adc_key_in < 50)   return btnRIGHT;  
       if (adc_key_in < 250)  return btnUP; 
       if (adc_key_in < 450)  return btnDOWN; 
       if (adc_key_in < 650)  return btnLEFT; 
       if (adc_key_in < 850)  return btnSELECT;  
      Analog 0Button (select, up, right, down and left)
      Digital 4DB4
      Digital 5DB5
      Digital 6DB6
      Digital 7DB7
      Digital 8RS (Data or Signal Display Selection)
      Digital 9Enable
      Digital 10Backlit Control
              我們依照以上接腳定義,將其接上nano的D4~D10即可使用1602LCD的功能。

2017年9月30日 星期六

[Arduino]MCP4728 修改I2C Address

MCP4728簡介如下:
Features
• 12-Bit Voltage Output DAC with Four Buffered Outputs
• On-Board Nonvolatile Memory (EEPROM) for DAC Codes and I2C™ Address Bits
• Internal or External Voltage Reference Selection
• Output Voltage Range:
- Using Internal VREF (2.048V):
0.000V to 2.048V with Gain Setting = 1
0.000V to 4.096V with Gain Setting = 2
- Using External VREF (VDD):
0.000V to VDD • ±0.2 Least Significant Bit (LSB) Differential Nonlinearity (DNL) (typical)
• Fast Settling Time: 6 µs (typical)
• Normal or Power-Down Mode
• Low Power Consumption
• Single-Supply Operation: 2.7V to 5.5V
• I2C Interface: - Address bits: User Programmable to EEPROM
- Standard (100 kbps), Fast (400 kbps) and High Speed (HS) Mode (3.4 Mbps) • 10-Lead MSOP Package • Extended Temperature Range: -40°C to +125°C

資料來源:
http://ww1.microchip.com/downloads/en/DeviceDoc/22187E.pdf

它是一顆擁有四個類比輸出的DAC,透過I2C介面做控制。

12Bit 解析度,可以把輸出的電壓分成4096等份,例如輸出0~5V, 則可以將電壓的精準度

達到 0.001

可有以下幾種模式(透過指令即可變更):

使用外部參考電壓,例如5V 。

使用內部參考電壓  Gain =1
0.000V to 2.048V

使用內部參考電壓 Gain  =2
0.000V to 4.096V

如果要求精準,建議使用內部參考電壓 Gain =1  ,並透過穩壓IC供電給DAC。

如果要使用多組DAC在電路中,則需要改變MCP4728的I2C位置,我們先來看一下

datasheet中的說明


MCP4728預設的I2C位置為0x61 , 也就是1100001 ,也就是A2=0 , A1=0 ,A0=1

如果今天我要把它改成0x60 (1100000), New Address bit A2=0, A1=0 , A0=0 。 

把現有的位置和新的位置依照上面填空後,就是4個byte的指令,接下來要接上

LDAC這支Pin腳,它需要在第2個byte傳送到第8個bit時,將LDAC由HIGH轉LOW,

否則怎麼傳送指令都會失敗,注意必須在MCP4728回傳ACK 之前就要轉LOW,

所以用Arduino內建的Wire.Write會失敗,弄了2天,請教了Firmware朋友,得到的

答案建議自己去控制I2C通訊時的HIGH ,LOW ,才能在第八個bit時將LDAC轉LOW,

等到ACK回來就來不了。來看一下接線

Arduino UNO                MCP4728
VCC                             VDD
GND                             VSS
2                                 SCL
3                                 SDA
8                                  LDAC






















接下來是我去網路上找的一份程式碼,整理之後,確認可以成功。
將預設的0x61位置改成0x60


// R/W direction bit to OR with address for start or restart
#define I2C_READ 1
#define I2C_WRITE 0
#define SOFT_I2C_MASTER
#define I2C_DELAY_USEC 10
#define ldac_pin 8

uint8_t sclPin_;
uint8_t sdaPin_;

unsigned char OldAddr = 0x1;  //0x61 default I2C Address
unsigned char NewAddr = 0x0;  //0x60 new I2C Address

//I2C Init
void init(uint8_t sclPin, uint8_t sdaPin)
{
  sclPin_ = sclPin;
  sdaPin_ = sdaPin;
  pinMode(sclPin_, OUTPUT);
  digitalWrite(sdaPin_, HIGH); //Mark_H fix
  pinMode(sdaPin_, OUTPUT);
  digitalWrite(sclPin_, HIGH);
  digitalWrite(sdaPin_, HIGH);
}
//------------------------------------------------------------------------------
// read a byte and send Ack if last is false else Nak to terminate read
uint8_t read(uint8_t last)
{
  uint8_t b = 0;
  // make sure pullup enabled
  digitalWrite(sdaPin_, HIGH);
  pinMode(sdaPin_, INPUT);
  // read byte
  for (uint8_t i = 0; i < 8; i++) {
    // don't change this loop unless you verify the change with a scope
    b <<= 1;
    delayMicroseconds(I2C_DELAY_USEC);
    digitalWrite(sclPin_, HIGH);
    if (digitalRead(sdaPin_)) b |= 1;
    digitalWrite(sclPin_, LOW);
  }
  // send Ack or Nak
  digitalWrite(sdaPin_, HIGH); 
  pinMode(sdaPin_, OUTPUT);
  digitalWrite(sdaPin_, last);
  digitalWrite(sclPin_, HIGH);
  delayMicroseconds(I2C_DELAY_USEC);
  digitalWrite(sclPin_, LOW);
  digitalWrite(sdaPin_, HIGH);
  return b;
}
//------------------------------------------------------------------------------
// send new address and read/write without stop
uint8_t restart(uint8_t addressRW)
{
  digitalWrite(sclPin_, HIGH);
  return start(addressRW);
}
//------------------------------------------------------------------------------
// issue a start condition for i2c address with read/write bit
uint8_t start(uint8_t addressRW)
{
  digitalWrite(sdaPin_, LOW);
  delayMicroseconds(I2C_DELAY_USEC);
  digitalWrite(sclPin_, LOW);
  return write(addressRW);
}
//------------------------------------------------------------------------------
// issue a stop condition
void stop(void)
{
  digitalWrite(sdaPin_, LOW);
  delayMicroseconds(I2C_DELAY_USEC);
  digitalWrite(sclPin_, HIGH);
  delayMicroseconds(I2C_DELAY_USEC);
  digitalWrite(sdaPin_, HIGH);
  delayMicroseconds(I2C_DELAY_USEC);
}
//------------------------------------------------------------------------------
// write byte and return true for Ack or false for Nak
uint8_t write(uint8_t b)
{
  // write byte
  for (uint8_t m = 0X80; m != 0; m >>= 1) {
    digitalWrite(sdaPin_, m & b);
    digitalWrite(sclPin_, HIGH);
    delayMicroseconds(I2C_DELAY_USEC);
    digitalWrite(sclPin_, LOW);
  }
  // get Ack or Nak
  digitalWrite(sdaPin_, HIGH);
  pinMode(sdaPin_, INPUT);
  digitalWrite(sclPin_, HIGH);
  b = digitalRead(sdaPin_);
  digitalWrite(sclPin_, LOW);
  digitalWrite(sdaPin_, HIGH);
  pinMode(sdaPin_, OUTPUT);
  return b == 0;
}

//------------------------------------------------------------------------------
// write byte and return true for Ack or false for Nak
uint8_t ldacwrite(uint8_t b, uint8_t ldacpin)
{
  // write byte
  for (uint8_t m = 0X80; m != 0; m >>= 1) {
    // don't change this loop unless you verivy the change with a scope
    digitalWrite(sdaPin_, m & b);
    digitalWrite(sclPin_, HIGH);
    delayMicroseconds(I2C_DELAY_USEC);
    digitalWrite(sclPin_, LOW);
  }
  // get Ack or Nak
  digitalWrite(ldacpin, LOW);
  digitalWrite(sdaPin_, HIGH);
 
  pinMode(sdaPin_, INPUT);
  digitalWrite(sclPin_, HIGH);
//  digitalWrite(bsy_pin,LOW);
  b = digitalRead(sdaPin_);
  digitalWrite(sclPin_, LOW);
  digitalWrite(sdaPin_, HIGH); 
  pinMode(sdaPin_, OUTPUT);
  return b == 0;
}



void setup() {
Serial.begin(9600);
pinMode(ldac_pin,OUTPUT);
digitalWrite(ldac_pin,HIGH);
delay(10);
init (2,3);

uint8_t data1=(unsigned char)(0B11000000 | (OldAddr << 1));
uint8_t data2=(unsigned char)(0B01100001 | (OldAddr << 2));
uint8_t data3=(unsigned char)(0B01100010 | (NewAddr << 2));
uint8_t data4=(unsigned char)(0B01100011 | (NewAddr << 2));


uint8_t ack1=start(data1);
uint8_t ack2=ldacwrite(data2,ldac_pin);
uint8_t ack3=write(data3);
uint8_t ack4=write( data4);
stop();

Serial.println(data1);
Serial.println(data2);
Serial.println(data3);
Serial.println(data4);
 
Serial.println(ack1);
Serial.println(ack2);
Serial.println(ack3);
Serial.println(ack4);

delay(10);

Serial.println("FINISH");

}

void loop() {
  // put your main code here, to run repeatedly:

}
執行完畢後,請記得將Arduino 斷電,重新上電後用I2C Scanner 範例程式來確認是否有改成功。

參考來源:
https://forum.pjrc.com/threads/28424-Programming-the-I2C-address-of-a-MCP4728-4-channel-DAC-using-i2c_t3

https://github.com/TrippyLighting/SoftI2cMaster/blob/master/SoftI2cMaster.cpp

2017年9月16日 星期六

「LinkIt Samrt 7688][Arduino] 7688與Arduino Nano USB通訊

最近有一個需求,讓7688與Arduino透過USB通訊,想到的解法是Arduino本身的USB

預設為USB to Serial,只要能讓7688上的OpenWRT支援USB to Serial晶片驅動即可。

以下做了個簡單的Demo,附上Arduino及7688上python code做個Echo 測試。

檔案_000.jpeg




















這次用的是Arduino Nano,它使用的USB to Serial是 CH340  (我這塊不是原版的)

首先我需要安裝usbutils , 讓我可以使用lsusb來詢連接的USB裝置。(可以不裝)

opkg install usbutils


接下來安裝CH340驅動程式

opkg install kmod-usb-serial-ch341


Arduino程式碼

一開始連通Serial Port時會輸出hello form Arduino

之後會回應所收到的值,做一個Echo


接下來是7688上的python程式碼

CH340裝置的名稱會是 /dev/ttyUSBx ,像我是/dev/ttyUSB0 ,換成自己裝置的名字。

一連Serial Port會傳送Hello from python ,之後會每隔一秒傳送目前時間,並印出收到的訊息。



執行結果

2017年8月1日 星期二

「Arduino] Mega 2650 外殻

颱風季節要到了,看到我的Mega 2560依然沒有衣服穿,看到禾樺有在賣就買一組。































拆開來,有螺絲及塑膠板































把保護的膠紙移除































組合完成,其實我只鎖四根外殻的螺絲

2017年7月31日 星期一

「Arduino」Digital HIGH /LOW 定義

HIGH: a voltage greater than 3.0V is present at the pin (5V boards);

Low:  voltage less than 1.5V is present at the pin (5V boards);


2017年6月8日 星期四

[Arduino]NTSC 4K7 量測溫度方法.

最近遇到一個溫度計,它只有2條線,Orz ,看起來不可能是1-Wire,

研究了一下發現是電阻式的溫度計,也就是熱敏電阻。

在25度西時大約是4.77K歐姆,在30度西時是38.8K歐姆,代表溫度上升阻值下降,

所以不可能是有名的PT100(0度西時阻值為100歐姆),去查了一下類似的數據,



接下來是該如何得到阻值變化 ----> 串聯一個固定阻值的電阻,就可以依電壓

變化的比例,知道目前溫度計的阻值,上面的4.7K表示溫度計的阻值,

下面量測的部份則是固定阻值的4.7K電阻。


2017年6月7日 星期三

[Arduino] I2C Scann

最近使用DAC時,看了很多文件和範例,都沒有反應,原因是I2C Address錯了,

當你使用I2C時,其實有一個方法可以掃描出正確的I2C Address

// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
 
#include <Wire.h>
 
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}

資料來源:

https://playground.arduino.cc/Main/I2cScanner

[Arduino] millis() 使用注意事項

最近在在Arduino上每隔五分鐘要用MQTT傳一次資料給SERVER,所以

millis() 這個函式來取得arduino執行程式到目前過了幾個milliseconds 

但這個值是用unsign long (32bit) 儲存的,所以大概在約50天左右就會overflow,

從0開始,但是如果程式寫法是如下,那就好笑了。


unsigned long start=millis();
int delaytime=3000;
void loop() {
  

while (millis()<start+delaytime)
{
    ;
}
sendData();

}


當五十天後,你就永遠不會傳送資料了,因為millis()可能會遠小於sendtime。等到大於sendtime時,差不多又overflow了。

但是以下的寫法是不會有問題的


unsigned long start=millis();
unsigned long delay=3000;
if (millis()-start>delay)
{
    sendData();
    start=millis();
}

我們先來了解一下unsigned long 到底可以放的下什麼

0 to 4,294,967,295 (2^32 - 1)


那如果overflow 後會發生什麼事

unsigned long number=4294967295;  
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);


  Serial.println("number is :"+String(number));
  number+=1;
  Serial.println("number+1 is :"+String(number));
}


輸出結果如下,當大於2^32 -1 後,就會歸零。

number is :4294967295
number is :0

我們來模擬一下overflow之後的運算


unsigned long number=4294967295; 
unsigned long testNumber=4294967295; 
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);


  Serial.println("number is :"+String(number));
  number+=1;
  Serial.println("number+1 is :"+String(number));
  Serial.println("number- 2^32-1 :"+String(number-testNumber));

}

number is :4294967295
number+1 is :0
number- 2^32-1 :1

所以0-(2^32-1) 會是1  ,

以此類推,當overflow後,即使millis()比較小,相滅之後仍然會是正值。

number is :4294967295
number+10000 is :9999
number- 2^32-1 :10000

我們來測試一下,若是millis()比較小時做相減會怎樣

number is :0
number+10000 is :10000
number- 2^32-1 :10001

所以2數運算時要考慮到unsigned long 能裝的下的空間,unsigned long 面對運算結果負值也會出現問題。

number is :0
number+10000 is :10000
number-10001 :4294967295



參考資料:

millis() 溢出(overflow)歸零(rollover)有沒問題?(教程)定时器相關http://www.arduino.cn/thread-12506-1-1.html

「Arduino」MQTT踩到一個坑

紀錄一下使用MQTT時採到的一個坑,在爬回平地前先來

看看Pubsubclient lib裡面一個基本的範例 ,不可否認的,這範例寫的很清楚。

我的MQTT Broker是mosquitto 1.4.x 版


#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);

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++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

EthernetClient ethClient;
PubSubClient client(ethClient);

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("arduinoClient")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic","hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } 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(57600);

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

  Ethernet.begin(mac, ip);
  // Allow the hardware to sort itself out
  delay(1500);
}

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

單一台裝置運作時,非常順利,但是同樣的程式碼,在二個arduino上執行時會出現

漏訊息,而且拼命和MQTT Broker Reconnect問題。

查詢了一下錯誤代碼,rc=-4表示 Connection Timeout , 在MQTT中,client與server之間會

有一個keepalive的參數,這個lib預設是15秒,也就是在15內,client有義務和server保持連

接,當超過keepalive所設定的秒數內沒有傳送資料,client必須發送一個心跳訊號,而server

在收到心跳訊號後,必須回覆,這個client才能確認與server是保持連通的。


後來確認後發現是這一行程式碼導致的問題

if (client.connect("arduinoClient"))

一眼瞄過去我也不覺得那裡有異,直到去查詢後才發現"arduinoClient" 其實是

ClientID  , 所以不應該重覆,否則Server會無法正確識別與client連線狀態,導致Client

可能沒有正確收到Server response 的keepalive回覆,誤以為斷線。

2017年5月11日 星期四

[Arduino] Arduino Nano + ENC28J60 LED問題

最近使用Arduino Nano V3 搭配ENC28J60 Ethernet Shield Network Module

For Arduino Nano 時遇到Pin 13 LED 沒反應問題。



 + 



研究後發現,在Ethernet.begin(mac);後, Pin 13 LED就失去反應了。

上網爬文後,得到解答,我使用UIPEthernet Library  , ENC28J60使用SPI協定與

Arduino溝通,SPI使用的腳位分別是D10~D13,所以13 Pin除了是LED之外,也作為SCK

用途,被佔用了,當然LED就不會亮囉。



Pin nameETHER_28J60EthercardUIPEthernetMy eBay Module
 SS 10 (!) 10 10
 MOSI (SI) 11 11 11 11
 MISO (SO) 12 12 12 12
 SCK 13 13 13 13
表格來源:





[Arduino] Linkit ONE 小筆記

最近在公司接觸到Linkit ONE,碰到一些小問題,筆記一下。

1. Linkit ONE只有二支腳支援PWM(D3及D9),而不像Arduino一樣有六支。
 
2. Linkit ONE在接上電腦後會有二個Comport。只有一個可以顯示Serial.print的內容。

3 .Linkit ONE 的PWM是13 bit的解析度,範圍由0~8191,電壓為0~3.3V。

4. LinkIt ONE在連上WI-FI後要稍等一下,讓它有時間取得IP,不要一連線就急著連網。

2017年3月26日 星期日

[Arduino]RS485 初嘗

買了一塊WaveShare 的UART轉RS485(5V)板子來玩玩看。

先簡介一下RS485:

EIA-485(過去叫做RS-485或者RS485])是隸屬於OSI模型實體層的電氣特性規定為2線,半雙工,多點通訊的標準。它的電氣特性和RS-232不大一樣。用纜線兩端的電壓差值來表示傳遞訊號,1極的電壓標識為邏輯1,另一段標識為邏輯0。兩端的電壓差最小為0.2V以上時有效,任何不大於12V或者不小於-7V的差值對接受端都被認為是正確的。

EIA-485僅僅規定了接受端和傳送端的電氣特性。它沒有規定或推薦任何資料協定。EIA-485可以應用於配置便宜的廣域網路和採用單機傳送,多機接受通訊連結。它提供高速的資料通訊速率(10m時35Mbit/s;1200m時100kbit/s)。EIA-485和EIA-422一樣使用雙絞線進行高電壓差分平衡傳輸,它可以進行大面積長距離傳輸(超過4000英尺,1200公尺)。
EIA-485經常和常用裝置UART一起使用來實現在飛機上的低速率資料傳輸,舉個例子,一些乘客控制單元採用這種裝置,從而只需要很少的線纜就可以實現幾端子共享線纜,從而減輕整個裝置的重量。

                                                          所以RS485上會常見到一些協定,例如Modbus,BacNet and Profibus  。

當然RS485 也可以利用2組A/B來達成全雙工(一對專送,一對專收)

以上資料來源:

EIA-485 WIKI


簡單來說,RS485並沒有規定使用任何界面,只要電氣特性相符即可。

最左邊是接UART , 你可以看到它提供3種介面的RS485 A/B ,除了杜邦線之外就是2P端子 ,以及一個
































腳立說明如下,資料來源:



























主要特點為RSE這一支腳,它控制了資料流的方向,當RSE為HIGH時,代表要送資料,

RSE為LOW時表示要接收資料,所以一開始Master會預設為發送,remote會預設為接收。


由於RS485是半雙工的通訊方式,所以每一個裝都只能是傳送或是接收其中一種狀態。

參考了以下網址的範例。

https://arduino-info.wikispaces.com/SoftwareSerialRS485Example

這個範例master每次只能傳送一個byte,然候就會切換到接收模式直到Serial有再次輸入,就會切回去發送模式(此時remote傳再多它也收不到了),而remote在接收到資料後會切換成傳送模式把資料發送回去,10ms後就會再回到接收模式。


接腳如下:

arduino              RS485
10                        RX
11                        TX
3                         RSE
5V                       VCC
GND                    GDN 

二塊板子之間的A接A,B接B。















































之後燒錄程式,一邊為Master,一邊為remote


Master端程式如下:

/* YourDuino SoftwareSerialExample1
   - Connect to another Arduino running "YD_SoftwareSerialExampleRS485_1Remote"
   - Connect this unit Pins 10, 11, Gnd
   - Pin 3 used for RS485 direction control
   - To other unit Pins 11,10, Gnd  (Cross over)
   - Open Serial Monitor, type in top window. 
   - Should see same characters echoed back from remote Arduino

   Questions: terry@yourduino.com 
*/

/*-----( Import needed libraries )-----*/
#include <SoftwareSerial.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX        10  //Serial Receive pin
#define SSerialTX        11  //Serial Transmit pin

#define SSerialTxControl 3   //RS485 Direction control

#define RS485Transmit    HIGH
#define RS485Receive     LOW

#define Pin13LED         13

/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX

/*-----( Declare Variables )-----*/
int byteReceived;
int byteSend;

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // Start the built-in serial port, probably to Serial Monitor
  Serial.begin(9600);
  Serial.println("YourDuino.com SoftwareSerial remote loop example");
  Serial.println("Use Serial Monitor, type in upper window, ENTER");
  
  pinMode(Pin13LED, OUTPUT);   
  pinMode(SSerialTxControl, OUTPUT);    
  
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver   
  
  // Start the software serial port, to another device
  RS485Serial.begin(4800);   // set the data rate 

}//--(end setup )---


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  digitalWrite(Pin13LED, HIGH);  // Show activity
  if (Serial.available())
  {
    byteSend = Serial.read();
    digitalWrite(SSerialTxControl, RS485Transmit);  // Enable RS485 Transmit   
    RS485Serial.write(byteSend);          // Send byte to Remote Arduino
    digitalWrite(Pin13LED, LOW);  // Show activity    
    delay(10);
    digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit       
   
  }
    
  if (RS485Serial.available())  //Look for data from other Arduino
   {
    digitalWrite(Pin13LED, HIGH);  // Show activity
    byteReceived = RS485Serial.read();    // Read received byte
    if (byteReceived!=0 && byteReceived!=10 && byteReceived!=13)
     {
        Serial.print("receive:");        // Show on Serial Monitor
        Serial.write(byteReceived);
        Serial.println();
     }
     
    delay(10);
    digitalWrite(Pin13LED, LOW);  // Show activity   
   }  

}//--(end main loop )---

/*-----( Declare User-written Functions )-----*/

//NONE
//*********( THE END )***********

remote端如下

/* YourDuino SoftwareSerialExample1Remote
   - Used with YD_SoftwareSerialExampleRS485_1 on another Arduino
   - Remote: Receive data, loop it back...
   - Connect this unit Pins 10, 11, Gnd
   - To other unit Pins 11,10, Gnd  (Cross over)
   - Pin 3 used for RS485 direction control   
   - Pin 13 LED blinks when data is received  
   
   Questions: terry@yourduino.com 
*/

/*-----( Import needed libraries )-----*/
#include <SoftwareSerial.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX        10  //Serial Receive pin
#define SSerialTX        11  //Serial Transmit pin

#define SSerialTxControl 3   //RS485 Direction control
#define RS485Transmit    HIGH
#define RS485Receive     LOW

#define Pin13LED         13

/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX

/*-----( Declare Variables )-----*/
int byteReceived;
int byteSend;

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // Start the built-in serial port, probably to Serial Monitor
  Serial.begin(9600);
  Serial.println("SerialRemote");  // Can be ignored
  
  pinMode(Pin13LED, OUTPUT);   
  pinMode(SSerialTxControl, OUTPUT);  
  
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver
  
  // Start the software serial port, to another device
  RS485Serial.begin(4800);   // set the data rate 
}//--(end setup )---


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  //Copy input data to output  
  if (RS485Serial.available()) 
  {
    byteSend = RS485Serial.read();   // Read the byte 
    digitalWrite(Pin13LED, HIGH);  // Show activity
    delay(10);              
    digitalWrite(Pin13LED, LOW);   
    Serial.write(byteSend);
    digitalWrite(SSerialTxControl, RS485Transmit);  // Enable RS485 Transmit    
    if (byteSend!=0 && byteSend!=10 && byteSend!=13)
        RS485Serial.write(byteSend); // Send the byte back
    delay(10);   
    digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit      
//    delay(100);
  }// End If RS485SerialAvailable
  
}//--(end main loop )---

/*-----( Declare User-written Functions )-----*/
//NONE

//*********( THE END )***********

程式碼來源:(我有稍微做一點修改)
https://arduino-info.wikispaces.com/SoftwareSerialRS485Example

master執行畫面(記得選擇為沒有結尾)




remote執行畫面(使用CoolTerm)
記得先修改一下傳送的結尾模式



























由master傳送一個字元a,會收到一個相同回應

















remote端也會將收到的字元顯示並回傳給Master
















如果一次輸入一堆字傳送,可能就會出現問題,例如我輸入1234567890abcdefg

















remote端收到的也是不正確的字元









所以使用rs485做傳輸時,一定要注意收和送的時間點,建議使用現有的協定,例如ModBus,因為在收和送之間需要切換,這個如果沒有搭配好,會出現異常的資料。