W!o+ 的《小伶鼬工坊演義》︰ 一窺全豹之系統設計《實驗》

將要如何追查

若是考以不同『裝置組合』,為什麼『超聲波測距儀』 Ultrasonic Ranger 與『繼電器』 Relay 分接『三、七』可以!但是『二、八』卻不行的呢?

import time
import grovepi

relay = 8

ultrasonic_ranger = 2

grovepi.pinMode(relay,"OUTPUT")

time.sleep(0.1)

grovepi.digitalWrite(relay,1)

time.sleep(0.5)

while True:
    try:

# 因派生二、三『 print 』語法不同之相容寫法。
        print (grovepi.ultrasonicRead(ultrasonic_ranger))

        time.sleep(0.1)

    except IOError:
        print ("Error")

 

。一個簡單如此的程式!又怎麼會出錯的呢?既然是寫 W!o+ 的『小伶鼬工坊演義』,總該採納 Mrphs 是怎麼說的哩!!恍恍惚惚中,或是這麼講的吧︰ W!o+ 認為『單獨』與『共聚』物件情況,有很大的不同。縱使彼此可以排除『干擾性』,還有『同時性』和『共時性』的難題,這大部分發生於『資源性』之競奪領域。若是因『時序性』之問題引起,它在『通訊規範』的設計上尤其重要。大自然春暖花開固然花花無礙,社會上洛陽紙貴可就買不著的了。這些終究還是得用『實驗』來『確立』的事務。……

 

於是努力地嘗試改寫 GrovePi V1.2.5之 韌體,啟動 GrovePi 的Serial  通訊埠,

void setup()
{
# 打開序列通訊埠
    Serial.begin(9600);         // start serial for output
    Wire.begin(SLAVE_ADDRESS);

    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);
        attachInterrupt(0,readPulseDust,CHANGE);
}

    //Ultrasonic Read
    else if(cmd[0]==7)
    {
      pin=cmd[1];
      pinMode(pin, OUTPUT);
      digitalWrite(pin, LOW);
      delayMicroseconds(2);
      digitalWrite(pin, HIGH);
      delayMicroseconds(5);
      digitalWrite(pin,LOW);
      pinMode(pin,INPUT);
      dur = pulseIn(pin,HIGH);
      RangeCm = dur/29/2;
      b[1]=RangeCm/256;
      b[2]=RangeCm%256;
# 序列埠輸出傳回值
      Serial.print(b[1]);
      Serial.print(", ");
      Serial.print(b[2]);
      Serial.print(", ");
    }

void receiveData(int byteCount)
{
    while(Wire.available())
    {
      if(Wire.available()==4)
      {
        flag=0;
        index=0;
                run_once=1;
      }
        cmd[index++] = Wire.read();
    }
# 序列埠輸出當下指令
    Serial.print("Command ");
    Serial.println(cmd[0]);
}

 

,以備『實驗』、『探索』、『除錯』之所需。然後用『USB TTL RS232 轉換器』接回樹莓派︰

280_P_1399090698640
Adafruit USB Power Gauge Mini-Kit

139_P_1373091636963
USB TTL RS232 轉換器

後來作者發現 Adafruit 有一款 TTL RS232 界面之迷你的『 USB 埠傳輸功率量測』裝置,如果再加上『USB TTL RS232 轉換器』可以構成一套既便宜又好用的『功率量測』系統。假使輔之以『測試軟體』,可以『自動紀錄』任何一個『 USB 裝置』在各種『工作樣態』下的『功率消耗』。由於它的『量測範圍』可以及於『5V 2A』,因此即使一整個『樹莓派系統』的『消耗功率』大體也可以這麼度量。再者,這個裝置的『資料』輸出格式十分簡單易讀,也就很容易寫『程式』來作『量測數據』處理。在此列出兩種『 USB DVD 讀寫裝置』之『操作狀態』下的消耗功率︰

─── 摘自《音樂播放器之 CD 轉成 mp3《三》上

 

再用『已改寫』的 API 測試,初步之驗證結果如下︰

【在派生二解譯器中執行】

隨意連接五個派生命名裝置

Grove – Rotary Angle Sensorpotentiometer A0

Grove – LED Socket Kitled D5

Grove – Relayrelay D8

Grove – Relaypower D7

Grove – Ultrasonic Rangerultrasonic_ranger D4

# 關閉電源,重新開機。確定 Arduino 在 Hard Reset 狀態。
pi@raspberrypi ~/example python Python 2.7.9 (default, Mar  8 2015, 00:52:26)  [GCC 4.9.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import grovepi >>> addr = 0x05  # 韌體 Wire 程式庫,如何處理『未下指令』之 I2C 『讀取』  # 位元組讀取 >>> grovepi.read_i2c_byte(addr) 0 # 區塊讀取 >>> grovepi.read_i2c_block(addr) [11, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] # 長度 32 ? >>> len(grovepi.read_i2c_block(addr)) 32  # Grove - Rotary Angle Sensor 測試。命令 3 >>> potentiometer = 0 # 設定 pinMode 為輸入。命令 5 >>> grovepi.pinMode(potentiometer,"INPUT") 1 # 讀取值 >>> sensor_value = grovepi.analogRead(potentiometer) 0 [11, 2, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] # 傳回值 >>> sensor_value 703  # Grove - Ultrasonic Ranger 測試。命令 7 >>> ultrasonic_ranger = 4 # 讀取值。命令 3 >>> print grovepi.ultrasonicRead(ultrasonic_ranger) 0 [11, 1, 196, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  452  # 交叉指令 # 命令 3 >>> grovepi.analogRead(potentiometer) 0 [11, 2, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  703 # 命令 3 >>> grovepi.analogRead(potentiometer) 0 [11, 2, 190, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  702 # 命令 7 >>> grovepi.ultrasonicRead(ultrasonic_ranger) 0 [11, 0, 198, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  198 # 命令 7 >>> grovepi.ultrasonicRead(ultrasonic_ranger) 0 [11, 0, 197, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  197 # 命令 3 >>> sensor_value = grovepi.analogRead(potentiometer) 0 [11, 2, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] >>> sensor_value 703  # Grove - Relay ︰ relay 測試。命令 2 >>> relay=8 # 未設定 pinMode 。輸出無效。命令 2 >>> grovepi.digitalWrite(relay,1) 1 # 設定 pinMode 為輸出。命令 5 >>> grovepi.pinMode(relay,"OUTPUT") 1 # 數位輸出。開。命令 2 >>> grovepi.digitalWrite(relay,1) 1 # 數位輸出。關。命令 2 >>> grovepi.digitalWrite(relay,0) 1  # Grove - LED Socket Kit 測試。PWM 。命令 4 >>> led=5 # 設定 pinMode 為輸出。命令 5 >>> grovepi.pinMode(led,"OUTPUT") 1 # 類比輸出。128。命令 4 >>> grovepi.analogWrite(led,128) 1  # 再次『未下指令』之 I2C 『讀取』 # 位元組讀取 >>> grovepi.read_i2c_byte(addr) 0 # 區塊讀取 >>> grovepi.read_i2c_block(addr) [11, 2, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  # 命令 3 >>> grovepi.analogRead(potentiometer) 0 [11, 2, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  703 # 命令 7 >>> grovepi.ultrasonicRead(ultrasonic_ranger) 0 [11, 0, 198, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  198  # Grove - Relay ︰ power 測試。命令 2 >>> power=7 # 設定 pinMode 為輸出。命令 5 >>> grovepi.pinMode(power,"OUTPUT") 1 # 數位輸出。開。命令 2 >>> grovepi.digitalWrite(power,1) 1 # 命令 7 >>> grovepi.ultrasonicRead(ultrasonic_ranger) 0 [11, 0, 197, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]  197 # 數位輸出。關。命令 2 >>> grovepi.digitalWrite(power,0) 1 >>>  </pre>    <strong><span style="color: #808080;">【與之對應通訊埠的輸出】</span></strong> <pre class="lang:default decode:true">pi@raspberrypi ~ cat /dev/ttyUSB0 
Command 7

0, 198, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, Command 7

1, 194, Command 3

Command 3

Command 3

Command 3

Command 7

0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 197, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, Command 7

0, 194, Command 7

0, 197, 0, 198, 0, 198, 0, 197, 0, 197, 0, 198, 0, 198, 0, 198, 0, 197, 0, 198, 0, 198, 0, 198, 0, 198, 0, 197, Command 7

0, 194, Command 3

Command 3

Command 2

Command 5

Command 2

Command 2

Command 5

Command 4

Command 4

Command 3

Command 3

Command 7

0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, 0, 198, Command 7

0, 194, Command 5

Command 2

Command 7

0, 197, 0, 197, 0, 197, 0, 197, 0, 198, 0, 198, 0, 197, 0, 197, 0, 197, 0, 198, 0, 198, 0, 197, 0, 197, 0, 197, Command 7

0, 194, Command 2


 

 

 

 

 

 

 

 

 

 

 

 

 

 

W!o+ 的《小伶鼬工坊演義》︰ 一窺全豹之系統設計《童子問》

易童子問第一

乾,元亨利貞

童子問曰:「乾,元亨利貞」何謂也?

曰:眾辭淆亂,質諸聖。《彖》者,聖人之言也。

童子曰:然則《乾》無四德,而《文言》非聖人書乎?

曰:是魯穆姜之言也,在襄公之九年。

 

假使思考歐陽修為什麼寫《易童子問》?

歐陽修(1007年-1072年),字永叔,號醉翁、六一居士,諡文忠,北宋吉州廬陵(今屬江西省永豐縣)人。(歐陽修生平請參考維基百科

所著《易童子問》三卷,收錄於《歐陽文忠公集》(或簡稱《文忠集》)第七十六至七十八卷,以問答的方式表達其對於《易經》的一些見解。每個問題都以「童子問」做為開始。

文忠公是第一位對於《十翼》以及諸如「四元德」等傳統見解提出質疑與抨擊的大儒,而這些見解也影響了後世許多學者,甚至得到近現代許多學者考證的支持。

除了較為知名的《易童子問》三卷之外,易學網另外也收錄《文忠集》中其他與《易經》相關的論述,以完整呈現歐陽修對《易經》所提出的見解。

,難到不因懷疑也!『聖人』也是『人』??果能『全知』乎!!

今想 GrovePi 之『軟體架構』,當真『奇怪』耶︰

 

【為什麼需要 Dummy Byte ?】

dataformat

 

因為 SMBus 的

I2C Access Functions

long[] read_i2c_block_data( int addr, char cmd )
Block Read transaction.

write_i2c_block_data(int addr, char cmd,  long vals[])
Block Write transaction.

 

,需要『 char cmd 』參數!所以

【 API 】

# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino

# Write I2C block
def write_i2c_block(address, block):
        try:
                return bus.write_i2c_block_data(address, 1, block)
        except IOError:
                if debug:
                        print ("IOError")
                return -1

# Read I2C byte
def read_i2c_byte(address):
        try:
                return bus.read_byte(address)
        except IOError:
                if debug:
                        print ("IOError")
                return -1


# Read I2C block
def read_i2c_block(address):
        try:
                return bus.read_i2c_block_data(address, 1)
        except IOError:
                if debug:
                        print ("IOError")
                return -1

 

【韌體】

void receiveData(int byteCount)
{
    while(Wire.available())
    {
    if(Wire.available()==4)
    {
      flag=0;
      index=0;
              run_once=1;
    }
      cmd[index++] = Wire.read();
    }
}

 

配合著寫,或可 I2C 通訊校核?且有其他用途的哩??

 

【為什麼傳回值也有 Dummy Read ?】

def analogRead(pin):
bus.write_i2c_block_data(address, 1, aRead_cmd + [pin, unused, unused])
time.sleep(.1)
bus.read_byte(address)
number = bus.read_i2c_block_data(address, 1)
time.sleep(.1)
return number[1] * 256 + number[2]

 

因為『統整』一與多之故。考之以韌體『流程』︰

// callback for sending data
void sendData()
{
  if(cmd[0] == 1)
    Wire.write(val);
  if(cmd[0] == 3 || cmd[0] == 7 || cmd[0] == 56)
    Wire.write(b, 3);
  if(cmd[0] == 8 || cmd[0] == 20)
    Wire.write(b, 4);
  if(cmd[0] == 30)
    Wire.write(b, 9);
  if(cmd[0] == 40)
    Wire.write(dht_b, 9);
  if(cmd[0]==21)
  {
    Wire.write(b,21);
    b[0]=0;
  }
  if(cmd[0]==dust_sensor_read_cmd)
  {
    Wire.write(b,4);
    dust_latest=0;
    cmd[0]=0;
  }
  if(cmd[0]==encoder_read_cmd)
  {
    Wire.write(enc_val,2);
    enc_val[0]=0;
    cmd[0]=0;
  }
  if(cmd[0]==flow_read_cmd)
  {
    Wire.write(flow_val,3);
    flow_val[0]=0;
    cmd[0]=0;
  }
}

 

,察之以 API 『改寫』︰

# Read analog value from Pin
def analogRead(pin):
        bus.write_i2c_block_data(address, 1, aRead_cmd + [pin, unused, unused])
        time.sleep(.1)
        temp = bus.read_byte(address)
        print (temp)
        number = bus.read_i2c_block_data(address, 1)
        print (number)
        time.sleep(.1)
        return number[1] * 256 + number[2]

# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
        write_i2c_block(address, uRead_cmd + [pin, unused, unused])
        time.sleep(.2)
        temp = read_i2c_byte(address)
        print (temp)
        number = read_i2c_block(address)
        print (number)
        return (number[1] * 256 + number[2])

 

證之以『實務』結果︰

Python 2.7.9 (default, Mar  8 2015, 00:52:26) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import grovepi
>>> potentiometer = 0
>>> grovepi.pinMode(potentiometer,"INPUT")
1
>>> sensor_value = grovepi.analogRead(potentiometer)
0
[0, 2, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
>>> sensor_value
703
>>> ultrasonic_ranger = 4
>>> print grovepi.ultrasonicRead(ultrasonic_ranger)
0
[0, 0, 198, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
198
>>> 

 

那麼下文又將怎麼說的呢?

# Arduino Digital Read
def digitalRead(pin):
        write_i2c_block(address, dRead_cmd + [pin, unused, unused])
        time.sleep(.1)
        n = read_i2c_byte(address)
        return n

def dustSensorRead():
        write_i2c_block(address, dus_sensor_read_cmd + [unused, unused, unused])
        time.sleep(.2)
        #read_i2c_byte(address)
        #number = read_i2c_block(address)
        #return (number[1] * 256 + number[2])
        data_back= bus.read_i2c_block_data(address, 1)[0:4]
        #print data_back[:4]
        if data_back[0]!=255:
                lowpulseoccupancy=(data_back[3]*256*256+data_back[2]*256+data_b$
                #print [data_back[0],lowpulseoccupancy]
                return [data_back[0],lowpulseoccupancy]
        else:
                return [-1,-1]
        print data_back

 

,難不成還有『未公開』 undocumented 之事嘛!

 

【為什麼新舊韌體所得不一?裝置組合結果不同??】

請參考

Ultrasonic Ranger 1.0 Broken ?

討論。然後測之以其法

# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
        write_i2c_block(address, uRead_cmd + [pin, unused, unused])
        time.sleep(.2)
        read_i2c_byte(address)
        number = read_i2c_block(address)
        if type(number) is list : return (number[1] * 256 + number[2])
        else: return -1

 

似乎較好。若是考以不同『裝置組合』,為什麼『超聲波測距儀』 Ultrasonic Ranger 與『繼電器』 Relay 分接『三、七』可以!但是『二、八』卻不行的呢?

再三設想那個韌體程式︰

    //Ultrasonic Read
    else if(cmd[0]==7)
    {
      pin=cmd[1];
      pinMode(pin, OUTPUT);
      digitalWrite(pin, LOW);
      delayMicroseconds(2);
      digitalWrite(pin, HIGH);
      delayMicroseconds(5);
      digitalWrite(pin,LOW);
      pinMode(pin,INPUT);
      dur = pulseIn(pin,HIGH);
      RangeCm = dur/29/2;
      b[1]=RangeCm/256;
      b[2]=RangeCm%256;
      //Serial.println(b[1]);
      //Serial.println(b[2]);
    }

 

,雖然不知

Grove – Ultrasonic Ranger

之『電路原理』,這個

『 dur = pulseIn(pin,HIGH); 』

,真的不會『出錯』嗎?!或許某些『答案』只得回到『故紙堆』中找耶??!!

 

【 Arduino Wire 程式庫】

:: Wire Library, Explored

An indepth reference to the Arduino Wire library.

Introduction

Greetings, fellow Arduinoid! GreyGnome here. The Arduino Wire library documentation is notoriously stingy in details. Nowhere does it explain its relationship to the twi library of the avr-lib, and worse, to the TWI hardware in the ATmega chips. This reference attempts to fill in the gaps and give the Wire library the documentation it needs and deserves.

Throughout the exploration of the code and the design of this document, this author has used the Arduino Duemilanove, based on the ATmega328 datasheet. See the ATmega328 datasheet for more information. It is an invaluable reference for understanding the TWI hardware and the ATmega‘s I2C communication methodology.

………

 

【 ATmega CPU DataSheet 】

ATmega48A/PA/88A/PA/168A/PA/328/P

 

 

 

 

 

 

 

 

 

 

 

 

W!o+ 的《小伶鼬工坊演義》︰ 一窺全豹之系統設計《解讀》

事實上 GrovePi 的『應用軟體界面』 API

GrovePi/Software/Python/grovepi.py

# 【所需程式庫】
44 import smbus
45 import time
46 import math
47 import RPi.GPIO as GPIO
48 import struct
49 import sys
50

# 【除錯模式】
51 debug =0
52

# 【派生版本】
53 if sys.version_info<(3,0):
54         p_version=2
55 else:
56         p_version=3
57

# 【 GPIO 版本/樹莓派版本】
58 rev = GPIO.RPI_REVISION
59 if rev == 2 or rev == 3:
60         bus = smbus.SMBus(1)
61 else:
62         bus = smbus.SMBus(0)
63

# 【 Arduino I2C 地址】
64 # I2C Address of Arduino
65 address = 0x04

# 【 Arduino 提供之命令】
67 # Command Format

# 【 主從 I2C 通訊】
158 # Function declarations of the various functions used for encoding and sending
159 # data from RPi to Arduino

# 【應用程式界面 API 】
190 # Arduino Digital Read
191 def digitalRead(pin):
192 write_i2c_block(address, dRead_cmd + [pin, unused, unused])
193 time.sleep(.1)
194 n = read_i2c_byte(address)
195 return n
196
197 # Arduino Digital Write
198 def digitalWrite(pin, value):
199 write_i2c_block(address, dWrite_cmd + [pin, value, unused])
200 return 1
201
202
203 # Setting Up Pin mode on Arduino
204 def pinMode(pin, mode):
205 if mode == "OUTPUT":
206 write_i2c_block(address, pMode_cmd + [pin, 1, unused])
207 elif mode == "INPUT":
208 write_i2c_block(address, pMode_cmd + [pin, 0, unused])
209 return 1
210
211
212 # Read analog value from Pin
213 def analogRead(pin):
214 bus.write_i2c_block_data(address, 1, aRead_cmd + [pin, unused, unused])
215 time.sleep(.1)
216 bus.read_byte(address)
217 number = bus.read_i2c_block_data(address, 1)
218 time.sleep(.1)
219 return number[1] * 256 + number[2]

 

,與之『韌體』

GrovePi/Firmware/Source/v1.2/grove_pi_v1_2_5/grove_pi_v1_2_5.ino

# 【對應的 Arduino 之指令】
101 //Digital Read
102 else if(cmd[0]==1)
103   val=digitalRead(cmd[1]);
104
105 //Digital Write
106 else if(cmd[0]==2)
107   digitalWrite(cmd[1],cmd[2]);
108
109 //Analog Read
110 else if(cmd[0]==3)
111 {
112   aRead=analogRead(cmd[1]);
113   b[1]=aRead/256;
114   b[2]=aRead%256;
115 }
116
117 //Set up Analog Write
118 else if(cmd[0]==4)
119   analogWrite(cmd[1],cmd[2]);
120
121 //Set up pinMode
122 else if(cmd[0]==5)
123   pinMode(cmd[1],cmd[2]);

 

,都是平鋪直敘,沒有太多疑惑之處。但想深入『解讀』者,或許需要先了解

Linux/Documentation/i2c/

Back Parent directory
Folder busses/
Folder muxes/
File dev-interface 8885 bytes
File fault-codes 5042 bytes
File functionality 6119 bytes
File i2c-protocol 3041 bytes
File i2c-stub 2323 bytes
File instantiating-devices 9755 bytes
File old-module-parameters 1899 bytes
File slave-eeprom-backend 474 bytes
File slave-interface 7087 bytes
File smbus-protocol 9176 bytes
File summary 1920 bytes
File ten-bit-addresses 1260 bytes
File upgrading-clients 6954 bytes
File writing-clients 15331 bytes

 

相關文件。此處僅列出『 I2C 』和『 SMBus 』摘要︰

Linux/Documentation/i2c/summary

I2C and SMBus
=============

I2C (pronounce: I squared C) is a protocol developed by Philips. It is a
slow two-wire protocol (variable speed, up to 400 kHz), with a high speed extension (3.4 MHz). It provides an inexpensive bus for connecting many types of devices with infrequent or low bandwidth communications needs. I2C is widely used with embedded systems. Some systems use variants that don’t meet branding requirements, and so are not advertised as being I2C.

SMBus (System Management Bus) is based on the I2C protocol, and is mostly a subset of I2C protocols and signaling. Many I2C devices will work on an SMBus, but some SMBus protocols add semantics beyond what is required to achieve I2C branding. Modern PC mainboards rely on SMBus. The most common devices connected through SMBus are RAM modules configured using I2C EEPROMs,
and hardware monitoring chips.

Because the SMBus is mostly a subset of the generalized I2C bus, we can use its protocols on many I2C systems. However, there are systems that don’t meet both SMBus and I2C electrical constraints; and others which can’t implement all the common SMBus protocol semantics or messages.

Terminology
===========

When we talk about I2C, we use the following terms:
Bus -> Algorithm
Adapter
Device -> Driver
Client

An Algorithm driver contains general code that can be used for a whole class of I2C adapters. Each specific adapter driver either depends on one algorithm driver, or includes its own implementation.

A Driver driver (yes, this sounds ridiculous, sorry) contains the general code to access some type of device. Each detected device gets its own data in the Client structure. Usually, Driver and Client are more closely integrated than Algorithm and Adapter.

For a given configuration, you will need a driver for your I2C bus, and
drivers for your I2C devices (usually one driver for each device).

 

至於『 python-smbus 』的說明簡介,也許讀者可以參考

Using the I2C Interface

。然而為何如此的規劃『架構』??作者亦莫宰羊的耶!!

 

 

 

 

 

 

 

 

 

 

 

 

 

W!o+ 的《小伶鼬工坊演義》︰ 一窺全豹之系統設計《地圖》

既已渡河,若是缺少地圖,怕會走許多冤枉路。在此略作整理 GrovePi 的官方文件,以為嚮導︰

【程式篇】

 

【派生 API 界面篇】

Python Library Documentation

The python library (Available at github) for grove pi has three types of functions:

  1. Basic Arduino Functions
  2. Grove Specific Functions
  3. Private Functions for Communication

………

 

【韌體 I2C 通訊篇】

GrovePi Protocol and Adding Custom Sensors

tl;dr- For each operation that you want to do on the GrovePi, the Raspberry Pi sends a command via I2C to the GrovePi and waits for a response for the command from the GrovePi. When it receives the response, it interprets the data and returns the desired output.

Explanation in depth

We will look into how the working of the GrovePi with an example of the Ultrasonic Ranger. The Ultrasonic ranger connects to a digital port and gives out the range in cm.

working_python1

If you look at the above code, the function ultrasonicRead(pin), is repeatedly called to print the distance measured by the ranger.

The ultrasonicRead() is defined in GrovePi.py and is called every time. The Raspberry Pi sends the command to the GrovePi, waits for some time and requests the data back.

In the main python library, the RaspberryPi writes a block of data to the GrovePi whose address is 0x04 and the block which is sent has the following format(5 bytes).

dataformat

For a new sensor, you can create a new unique id and send the required data to the Grove Pi.

working_python1

In the main loop of the GrovePi, there is a case for each of the unique id. When a unique id is received the relevant code is executed and the data is stores in the b[] buffer(b[0] is dummy and should not be used). The Raspberry Pi then asks for the data to be returned back and the Grove Pi sends the bytes depending on the last command executed.

The processing and interpretation of the data is performed by the Python code on the Raspberry Pi and the output is returned back to the calling function.

………

 

初步瀏覽比對,發現『 GrovePi.py 』當是『 grovepi.py』。若思『範例』能講的清楚明白,或應補足

GrovePi/Software/Python/grovepi.py

程式主架構說明︰

# grovepi 主架構

# 命令碼
67 # Command Format
68 # digitalRead() command format header
69 dRead_cmd = [1]
70 # digitalWrite() command format header
71 dWrite_cmd = [2]
72 # analogRead() command format header
73 aRead_cmd = [3]
74 # analogWrite() command format header
75 aWrite_cmd = [4]
76 # pinMode() command format header
77 pMode_cmd = [5]
78 # Ultrasonic read
79 uRead_cmd = [7]

# 與 Arduino 韌體 I2C 讀寫通訊
162 # Write I2C block
163 def write_i2c_block(address, block):
164         try:
165                 return bus.write_i2c_block_data(address, 1, block)
166         except IOError:
167                 if debug:
168                         print ("IOError")
169                 return -1
170
171 # Read I2C byte
172 def read_i2c_byte(address):
173         try:
174                 return bus.read_byte(address)
175         except IOError:
176                 if debug:
177                         print ("IOError")
178                 return -1
179
180
181 # Read I2C block
182 def read_i2c_block(address):
183         try:
184                 return bus.read_i2c_block_data(address, 1)
185         except IOError:
186                 if debug:
187                         print ("IOError")
188                 return -1

# 派生 API 界面
243 # Read value from Grove Ultrasonic
244 def ultrasonicRead(pin):
245         write_i2c_block(address, uRead_cmd + [pin, unused, unused])
246         time.sleep(.2)
247         read_i2c_byte(address)
248         number = read_i2c_block(address)
249         return (number[1] * 256 + number[2])

 

欲創寫新裝置驅動者,務須知『韌體端』之對應面︰

# GrovePi V1.2.5 韌體

125  //Ultrasonic Read
126  else if(cmd[0]==7)
127  {
128    pin=cmd[1];
129    pinMode(pin, OUTPUT);
130    digitalWrite(pin, LOW);
131    delayMicroseconds(2);
132    digitalWrite(pin, HIGH);
133    delayMicroseconds(5);
134    digitalWrite(pin,LOW);
135    pinMode(pin,INPUT);
136    dur = pulseIn(pin,HIGH);
137    RangeCm = dur/29/2;
138    b[1]=RangeCm/256;
139    b[2]=RangeCm%256;
140    //Serial.println(b[1]);
141    //Serial.println(b[2]);
142  }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

W!o+ 的《小伶鼬工坊演義》︰ 一窺全豹之系統設計《關鍵》

固然我們現今可以閱讀 GrovePi 韌體的原始碼,

# GrovePi V1.2.5 韌體 I2C 讀寫流程骨幹

33 int cmd[5];
34 int index=0;
35 int flag=0;

68 void setup()
69 {
70     // Serial.begin(38400); // start serial for output
71     Wire.begin(SLAVE_ADDRESS);
72
73     Wire.onReceive(receiveData);
74     Wire.onRequest(sendData);
75         attachInterrupt(0,readPulseDust,CHANGE);
76 }

79 void loop()
80 {
81   long dur,RangeCm;
82   if(index==4)
83 {
84   flag=1;
85   //IR reciever pin set command
86   if(cmd[0]==22)
87      IR.Init(cmd[1]);
88
89   //Grove IR recieve command
90   else if(cmd[0]==21)
91   {
92      if(IR.IsDta())
93       {
94          int length= IR.Recv(dta);
95          b[0]=1;
96          for(i=0;i<20;i++)
97              b[i+1]=dta[i];
98       }
99   }
100
101 //Digital Read
102 else if(cmd[0]==1)
103   val=digitalRead(cmd[1]);
104 //Digital Write
105 else if(cmd[0]==2)
106   digitalWrite(cmd[1],cmd[2]);

646 void receiveData(int byteCount)
647 {
648     while(Wire.available())
649      {
650       if(Wire.available()==4)
651        {
652         flag=0;
653         index=0;
654                 run_once=1;
655        }
656         cmd[index++] = Wire.read();
657       }
658 }

660 // callback for sending data
661 void sendData()
662 {
663   if(cmd[0] == 1)
664     Wire.write(val);
665   if(cmd[0] == 3 || cmd[0] == 7 || cmd[0] == 56)
666     Wire.write(b, 3);
667   if(cmd[0] == 8 || cmd[0] == 20)
668     Wire.write(b, 4);
669   if(cmd[0] == 30)
670     Wire.write(b, 9);
671   if(cmd[0] == 40)
672     Wire.write(dht_b, 9);
673
674   if(cmd[0]==21)
675    {
676     Wire.write(b,21);
677     b[0]=0;
678    }
679   if(cmd[0]==dust_sensor_read_cmd)
680    {
681     Wire.write(b,4);
682         dust_latest=0;
683         cmd[0]=0;
684    }
685   if(cmd[0]==encoder_read_cmd)
686    {
687     Wire.write(enc_val,2);
688     enc_val[0]=0;
689         cmd[0]=0;
690    }
691   if(cmd[0]==flow_read_cmd)
692    {
693     Wire.write(flow_val,3);
694     flow_val[0]=0;
695         cmd[0]=0;
696    }
697
698 }


 

,追跡其上裝置的驅動始末,甚至可以創寫新的可連接設備。但思『架構拼圖』時,『全貌』是『關鍵』,一時過細恐泥。況且通常『應用軟體界面』 API ,實有多種多層

中介軟體

中介軟體英語Middleware)是提供系統軟體應用軟體之間連線的軟體,以便於軟體各部件之間的溝通,特別是應用軟體對於系統軟體的集中的邏輯,在現代資訊科技應用框架如Web服務面向服務的體系結構等中應用比較廣泛。如資料庫、Apache的Tomcat,IBM公司的WebSphere,BEA公司的WebLogic應用伺服器,東方通公司的Tong系列中介軟體,以及Kingdee公司的等都屬於中介軟體。

嚴格來講,中介軟體技術已經不局限於應用伺服器、資料庫伺服器。圍繞中介軟體,Apache組織、IBM、Oracle(BEA)、微軟各自發展出了較為完整的軟體產品體系。(Microsoft Servers是 微軟公司的伺服器產品介紹)。中介軟體技術建立在對應用軟體部分常用功能的抽象上,將常用且重要的過程呼叫、分散式元件、訊息佇列、事務、安全、連結器、 商業流程、網路並行、HTTP伺服器、Web Service等功能集於一身或者分別在不同品牌的不同產品中分別完成。一般認為在商業中介軟體及資訊化市場主要存在微軟陣營、Java陣營、開源陣營。陣營的區分主要體現在對下層作業系統的選擇以及對上層元件標準的制訂。目前主流商業作業系統主要來自Unix蘋果公司Linux的系統以及微軟視窗系列。微軟陣營的主要技術提供商來自微軟及其商業夥伴,Java陣營則來自IBMSun(已被Oracle收購)、OracleBEA(已被Oracle收購)、金蝶(Kingdee Apusic)及其合作夥伴,開源陣營則主要來自諸如Apache,SourceForge等組織的共享代碼。

中介軟體技術的蓬勃發展離不開標準化,標準的建立有助於融合不同陣營的系統。越來越多的標準被三大陣營共同接受並推廣發展。 中介軟體技術的發展方向朝著更廣闊範圍的標準化,功能的層次化 ,產品的系列化方面發展。

基於中介軟體技術構建的商業資訊軟體廣泛的應用於能源、電信、金融、銀行、醫療、教育等行業軟體,降低了面向行業的軟體的開發成本。

 

Linux_kernel_and_gaming_input-output_latency.svg

Anything between the kernel and user applications is considered middleware. Functionality such as gesture recognition or speech recognition is usually processed by some middleware, and the results are transmitted to user applications.

 

Middleware_Schema.svg

Software architecture: Middleware

───

 

居處其間。何妨此刻『渡河彼岸』,從樹莓派這一端來看 GrovePi 上之裝置存取的呢?!

雖說這也可能只是一種『整體』 與『部份』理解之『錯覺』,

 

□ A 和 B 的顏色其實是一樣的

360px-Grey_square_optical_illusion

360px-Same_color_illusion_proof2

泰戈爾‧錯覺

河的此岸暗自歎息:『我相信,一切歡樂都在對岸。』

河的彼岸一聲長嘆:『唉,也许,幸福盡在對岸。』

知識到底是什麼?真理果真能追求??

或是
凡所有相,皆是虛妄 ── 金剛經 ──

還是
一切只是『幻覺』,如墬『虛擬實境』中!!

─── 摘自《知識是什麼?

 

,不過問題是我們如何能夠知道自己

是否是活在柏拉圖之『洞穴』

裡的耶??!!