標(biāo)題: Nucleo + Scratch,給你孩子的編程玩具 [打印本頁]

作者: 51hei大小    時間: 2016-6-17 16:47
標(biāo)題: Nucleo + Scratch,給你孩子的編程玩具
    不知道大家有沒有聽說的Scratch: https://scratch.mit.edu/    是由麻省理工開發(fā)的一個軟件,幫助孩子們從零開始學(xué)習(xí)編程。圖形化的程序設(shè)計,萌萌噠的界面,想必能夠吸引住眾多孩子。不過這么好的軟件貌似在國內(nèi)知名度不高。

    后來,一個團隊開發(fā)了一個名為S4A(Scartch for Arduino)的軟件:http://s4a.cat/   將Scartch與Arduino連接起來。結(jié)合了Scartch的編程優(yōu)點,外加Arduino的眾多傳感器,一時間孩子們也能夠玩轉(zhuǎn)舵機,開關(guān),以及模擬量的傳感器了。S4A使用了Arduino的6路AD采集接口,3路PWM接口和3路舵機接口,方便小孩子連接傳感器,實現(xiàn)自己的設(shè)計。

    后來,我覺得S4A這個玩意挺好玩的,看了一下桌子上的Nucleo,決定來移植一下。經(jīng)過大約3天的緊張工作,終于成功完成了移植。期間出了一個小小的問題耗費了大約一天的時間。也就是Nucleo和S4A通訊的時候,S4A總是崩潰,一直未響應(yīng)。不知道是什么原因,期間一直在改動自己的代碼。一天無果。第二天無意間換了FT232作為串口通訊的工具。竟然奇跡般的好了。事后發(fā)現(xiàn),只要是Nucleo的串口,不出幾分鐘,S4A必然崩潰。不知道是Nucleo串口的原因還是S4A的原因。

    在移植完之后,我簡單的用S4A寫了一個呼吸燈的程序,突然發(fā)現(xiàn),用C很容易實現(xiàn)的東西,讓我來拖拽的時候竟然不知道如何去做了。。。
下面是程序截圖:


最后,給大家上傳一小段視頻看一下(由于社區(qū)限制,只能將視頻分成兩個壓縮包上傳),感興趣點個贊,不感興趣路過好了。


---------------------------------------------------------------------------------------------------------------------------------------------------------------------
Nucleo334的軟件包以上傳到社區(qū)。歡迎大家下載試用。
發(fā)帖的時候占用了3層樓。對這幾層的規(guī)劃:


---------------------------------------------------------------------------------------------------------------------------------------------------------------------
    軟件包已經(jīng)上傳,名為S4Nu.rar(Scartch for Nucleo)歡迎大家提前下載使用。另外需要特別注意的是:雖然Nucleo自帶了串口,但是在與S4A連接的時候不要使用這個串口。也不要使用USB連線將Nucleo與電腦相連。
    應(yīng)該對Nucleo使用外部供電。并使用USB轉(zhuǎn)串口工具,例如CP2102,F(xiàn)T232等連接電腦與Nucleo的串口。具體是什么原因暫時還未知。可能在接下來的幾天內(nèi)能夠解決這個問題,也可能解決不掉。下面就要說說如何設(shè)置Nucleo的硬件部分:




    因通訊的問題,給老外的技術(shù)支持發(fā)了一封郵件,幾天后,收到了一個回復(fù),大概意思說是他們的S4A只是為Arduino Uno和Duemienova定做的,并且在今后的升級中,會考慮兼容更多的板子。本以為這件事就這樣算了。

    沒想到,另一個人,猜測大概是S4A的開發(fā)人員,給回復(fù)了一封郵件。意思是他正在考慮讓S4A在LPC的ARM處理器上工作。讓我發(fā)送一下我的代碼,說不定他可以檢查到什么錯誤。好消息,給你吧。

    在發(fā)送完STM32的代碼之后,靜等了幾天,昨晚收到了郵件回復(fù):也沒看出是什么軟件的問題,大概是USB轉(zhuǎn)串口的問題吧。



S4Nu.rar (2.49 MB, 下載次數(shù): 21)

視頻.rar (14.65 MB, 下載次數(shù): 13)



----------------------------偶是分隔線----------------------------------------------------


Scartch的簡單編程

    如果你代碼下載完畢,串口連接完成,打開S4A之后,就可以看到6路AD模擬量和兩個開關(guān)的數(shù)字量的值了。圖中的COMx是你實際使用的串口。在我的電腦上,這個COM3是使用FT232轉(zhuǎn)換出來的。還要注意圖片中的旗幟的標(biāo)志和那個紅色的大圓點。旗幟代表運行我們使用S4A拖拽的程序,圓點代表停止。


    在S4A的左上角可以看到動作,控制,外觀,等等控件。里面有各種各樣的工具供我們使用。

    腳本這個位置就是我們寫程序的地方。只要將程序按照邏輯結(jié)構(gòu)放在這里就可以。一定要注意的是,開始的語句是一個“當(dāng)旗幟被點擊”的語句。這條語句類似于C語言中的main函數(shù),程序開始執(zhí)行的地方。下面就來簡單的寫一個閃燈的程序。



    這就是我們平時在單片機中常寫的Hello world程序。是不是很簡單呢?如果想修改延時的時間怎么辦?雙擊“等待1秒”中的1,然后填上你想要的時間并按回車。這個時間是小數(shù)的形式?梢允0.1 。

    我們平時在寫程序的時候,經(jīng)常會設(shè)置一個變量,用于存儲延時的時間。在S4A中,變量的設(shè)置也是支持的。在變量一欄中點擊“新建一個變量”,之后填上變量的名字,就出現(xiàn)很多關(guān)于這個變量操作的控件。比如設(shè)置變量的值,將變量增加一個數(shù)值等等?墒,為什么沒有減小變量的數(shù)值呢?其實只要將“將變量delayTime的值增加[]”中的空格處填寫一個負(fù)數(shù)就可以了。比如-10 ?墒切『⒆尤绻恢镭(fù)數(shù)怎么辦呢?


    在程序?qū)懲曛,點擊右上角圓點旁邊的旗幟圖標(biāo)就可以運行了。

   不知道你家孩子會不會喜歡上!


------------偶還是分隔線------------------------



S4A Arduino源代碼解析


準(zhǔn)備工具:



Arduino的函數(shù)
  1.     int main( void )
  2.     {
  3.             setup();
  4.             for (;;){
  5.                     loop();
  6.             }
  7.             return 0;
  8.     }
復(fù)制代碼

setup()和loop()是我們需要自己填充的。setup只會被調(diào)用一次,完成代碼的一些初始化工作。loop是需要一直循環(huán)執(zhí)行的。

Arduino控制IO引腳的幾個函數(shù)在arduino.h(SAM系列的在wiring_digital.h)中。

S4A的數(shù)據(jù)結(jié)構(gòu)
  1. typedef enum {
  2.   input, servomotor, pwm, digital }
  3. pinType;

  4. typedef struct pin {
  5.   pinType type;       //Type of pin
  6.   int state;         //State of an output
  7.   //byte value;       //Value of an input. Not used by now. TODO
  8. };  
復(fù)制代碼



上面的代碼在Arduino中確實能夠編譯。但是在C語言中確不能。不知道是不是C++中typedef的一個新特性,還是一個bug。我在移植的時候直接修改了這段:
  1. typedef struct pin {
  2.   pinType type;       //Type of pin
  3.   int state;         //State of an output
  4.   //byte value;       //Value of an input. Not used by now. TODO
  5. } pin ;
復(fù)制代碼

struct pin是一個結(jié)構(gòu)體,里面存儲了引腳的信息,包括引腳的type和引腳的state。type是引腳的模式,可以是input,servomotors,pwm或者digital。state是引腳的值,有效取值從0到1023 。
S4A規(guī)定:

S4A的Arduino源代碼中定義了一個14個元素的數(shù)組,用來表示D0~D13的引腳的信息和狀態(tài):
pin arduinoPins[14]; //Array of struct holding 0-13 pins information
S4A對每一個引腳的功能都加以區(qū)分:
[原文]
Components have to be connected in a particular way. S4A allows for 6 analog inputs (analog pins), 2 digital inputs (digital pins 2 and 3), 3 analog outputs (digital pins 5, 6 and 9), 3 digital outputs (pins 10, 11 and 13) and 4 special outputs to connect Parallax continuous rotation servomotors (digital pins 4, 7, 8 and 12).



S4A的通信協(xié)議
根據(jù)S4A的通信協(xié)議(在附件中),每隔一段時間(20ms,在下文中會說明為什么是20ms),Arduino(或者Nucleo)應(yīng)該依次將A0~A5的模擬量,D2,D3的電平值依次上傳。共8組(一組數(shù)據(jù)由兩個字節(jié)組成)數(shù)據(jù)。每一組數(shù)據(jù)都有相應(yīng)的格式:
7 6 5 4 32
1 0
Byte1 1 N N N N R R R
Byte2 0 R R R R R R R

舉個例子:比如某一上傳時刻,采集到了A0~A5的電壓制為1023,D2為高電平,D3位低電平,那么應(yīng)該上傳:
B1_0000_111 B0_1111111 //A0,1023
B1_0001_111 B0_1111111 //A1,1023
B1_0010_111 B0_1111111 //A2,1023
B1_0011_111 B0_1111111 //A3,1023
B1_0100_111 B0_1111111 //A4,1023
B1_0101_111 B0_1111111 //A5,1023
B1_0110_111 B0_1111111 //D2,HIGH
B1_0111_000 B0_0000000 //D3,LOW

Arduino采集AD接口的信息的時候,一個AD接口采集了5次,取五次結(jié)果的中間值作為最后上傳的結(jié)果:
  1.     for (byte p = 0; p < 5; p++)
  2.             readings[p] = analogRead(sensorIndex);
  3.         insertionSort(readings, 5); //sort readings
  4.         sensorValues[sensorIndex] = readings[2]; //select median reading
復(fù)制代碼

insertionSort是插入排序,將5次結(jié)果排序,那么五次結(jié)果中的第二個一定是中間值。
索引
0 12
34
原始數(shù)據(jù)
1023 1018 1020 1019 1021

索引
0 1 2 3 4
排序之后
1018 1019 1020 1021 1023


在源代碼中,將數(shù)據(jù)打包上傳的代碼:(Serial.write發(fā)送8位無符號整數(shù))
  1.     void ScratchBoardSensorReport(byte sensor, int value) //PicoBoard protocol, 2 bytes per sensor
  2.     {
  3.       Serial.write( B10000000
  4.         | ((sensor & B1111)<<3)
  5.         | ((value>>7) & B111));
  6.       Serial.write( value & B1111111);
  7.     }
復(fù)制代碼

而每隔大約75ms,S4A會將D4~D13的值傳給Arduino。因為這個時間很短,為了保證數(shù)據(jù)的接受完整,在實際移植的時候,應(yīng)該建立RingBuffer緩沖區(qū),采用中斷接收的方式。

[原文]Protocol                        
S4A interacts with Arduino by sending the actuator states and receiving sensor states every 75 ms, therefore the pulse width needs to be greater than this time period. The data exchange follows the PicoBoard protocol and needs a specific program (firmware) to be installed in the board. Please refer to the Downloads section for further instructions on how to do so.

當(dāng)Arduino接收到S4A傳來的數(shù)據(jù)之后,會對數(shù)據(jù)解碼,獲取N編號和R的值:
  1.     pin = ((actuatorHighByte >> 3) & 0x0F);
  2.     newVal = ((actuatorHighByte & 0x07) << 7) | (actuatorLowByte & 0x7F);
復(fù)制代碼
如果R值需要更新:
  1.     if(arduinoPins[pin].state != newVal)
  2.     {
  3.         arduinoPins[pin].state = newVal;
  4.         updateActuator(pin);
  5.     }
復(fù)制代碼
而查閱updateActuator的代碼,發(fā)現(xiàn)并沒有更新舵機的代碼(具體什么原因,會和上文提到的20ms一起解釋)。
  1.     void updateActuator(byte pinNumber)
  2.     {
  3.       if (arduinoPins[pinNumber].type==digital) digitalWrite(pinNumber, arduinoPins[pinNumber].state);
  4.       else if (arduinoPins[pinNumber].type==pwm) analogWrite(pinNumber, arduinoPins[pinNumber].state);
  5.     }
復(fù)制代碼
20ms?
loop函數(shù)是整個調(diào)用過程:
  1.     void loop()
  2.     {
  3.       static unsigned long timerCheckUpdate = millis();

  4.       if (millis()-timerCheckUpdate>=20)
  5.       {
  6.         sendUpdateServomotors();
  7.         sendSensorValues();
  8.         timerCheckUpdate=millis();
  9.       }

  10.       readSerialPort();
  11.     }
復(fù)制代碼

由于C和C++的原因,上述代碼在C中并不能成功編譯。因此我修改為:
  1.     void loop()
  2.     {
  3.       static unsigned long timerCheckUpdate = 0;
  4.       //...
  5.     }
復(fù)制代碼

   millis()是Arduino中用于獲取自CPU啟動以來經(jīng)歷的ms數(shù)。將timerCheckUpdate改為0,只不過第一次執(zhí)行的時候if中的語句也能夠執(zhí)行罷了。在這20ms中,更新了舵機的數(shù)值,上傳了A0~A5,D2,D3的狀態(tài)。在最后更新了timerCheckUpdate時間戳,保證下一次執(zhí)行是在20ms之后。如果這時候串口的接受緩沖區(qū)中存在數(shù)據(jù),讀出來,并解析。
    先科普一下舵機的知識:舵機的轉(zhuǎn)動角度是0~180度,轉(zhuǎn)動角度的大小是由pwm的占空比決定的。pwm的周期必須為20ms。pwm波形中高電平的時間大約在500us~2500us之間。500us代表0度,2500us代表180度。
  1.     void sendUpdateServomotors()
  2.     {
  3.       for (byte p = 0; p < 10; p++)
  4.         if (arduinoPins[p].type == servomotor) servo(p, arduinoPins[p].state);
  5.     }

  6.     void servo (byte pinNumber, byte angle)
  7.     {
  8.       if (angle != 255)
  9.         pulse(pinNumber, (angle * 10) + 600);
  10.     }

  11.     void pulse (byte pinNumber, unsigned int pulseWidth)
  12.     {
  13.       digitalWrite(pinNumber, HIGH);
  14.       delayMicroseconds(pulseWidth);
  15.       digitalWrite(pinNumber, LOW);
  16.     }
復(fù)制代碼
servo這個函數(shù)將S4A發(fā)送來的舵機的轉(zhuǎn)動角度(0~180)轉(zhuǎn)換成為實際的高電平時間。然后通過延時來產(chǎn)生一定時間的高電平。為了保證舵機能夠正常運轉(zhuǎn)。在移植的時候必須提供一個精度較高的delayMicroseconds函數(shù)。

S4A的Arduino函數(shù)解析就這么多,希望大家都能夠移植到自己的單片機中。
Have Fun!

S4AFirmware16.rar (2.61 KB, 下載次數(shù): 16)

s4a-protocol.pdf (74.33 KB, 下載次數(shù): 19)






歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1