本帖最后由 MOPPLAYER 于 2016-9-22 14:30 编辑
前言:
繼上篇,將程式碼改寫為7.0版 ASF 3.31版,同樣的,小機械手臂共有4個Servo,利用按鈕做觸發改變手臂上各Servo的角度來夾起垃圾(衛生紙),並增加WINC1500模塊的使用,扮演著物聯網的重要接入模塊,使得可以透過WINC1500所搭載的TCP Server來驅動機械手臂,簡易的HTTP網頁可選擇觸發和收起手臂,和按鈕可同時執行
準備:
1. SAMD21 Xplained Pro 主板
2. MicroUSB傳輸線
3. 小機械手臂,買或者3D列印也可,本文使用4個Servo
4. 杜邦線數根和DC轉接頭
5. WINC1500模塊
6. 路由器
實作:
1. 首先,7.0版本的Atmel Studio所提供的ASF版本為3.31,因此WINC1500驅動也必須更新,但關鍵在於EDBG新版本有BUG,可參考之前小伙伴們所提供的解決方法,降回舊版本的EDBG驅動即可正確燒寫, https://bbs.elecfans.com/jishu_932943_1_1.html
2. 更新成功以後,以上一篇的Code為基礎來做修改,創建TCP Server Example範例專案工程
Fig. 1 TCP Server範例工程
3. 基本上範例已經可以做基本的TCP Server了,我們還必須將機械手臂的邏輯和HTML網頁加入,原始的Server會回傳MAIN_WIFI_M2M_PRODUCT_NAME的內容,我們可以藉著修改此字串來回傳HTML原始碼來顯示網頁,因此打開main.h檔案
- #define MAIN_WIFI_M2M_PRODUCT_NAME "
-
- <tiTLE>
- Smart Robotic ARM
-
-
-
-
- Please select:
-
-
-
- "///NMCTemp
复制代码
這就完成了簡單的選擇HTML網頁
4. 網頁設定好以後,別忘了更改您的連線到路由器的設定
- #define MAIN_WLAN_SSID /**< Destination SSID */
- #define MAIN_WLAN_AUTH M2M_WIFI_SEC_WPA_PSK /**< Security manner */
- #define MAIN_WLAN_PSK /**< Password for Destination SSID */
复制代码
共要更改這三項設定
5. 初始的Server設定並非走常見的HTML port,因此需要更改
- #define MAIN_WIFI_M2M_SERVER_PORT (80)
复制代码
以上就完成了網頁和連線部分的改寫
6. 接著我們要移植機械手臂的邏輯,首先打開ASF Wizard設定精靈,我們只需要保留TC和EINT driver即可
Fig. 2 您一定會問為什麼沒有加入EINT driver,實際上WIN1500模塊有使用到EINT driver,所以加不加都可,這裡只需要加入TC driver
7. 打開main21.c,這裡我們保留WIN1500的接口配置,但因為機械手臂中的2個Server是在EXT1接口上,有兩個辦法
- 1. 直接移往EXT3
- 2. 移往EXT2的GPIO,設置為PWM輸出
复制代码
實際上原始程式碼設定中,EXT3的PWM接口並沒有被啟用,所以1跟2的工作是一樣多的,但我們這裡簡化使用的EXT接口,直接在EXT2上使用4個Servo,即輸出4個PWM訊號
8. 增加以下程式碼在main21.c的頭部
- #define PWM1_MODULE EXT2_PWM_1_MODULE
- #define EXT2_PWM_1_MODULE TC7
- #define EXT2_PWM_2_CHANNEL 0
- #define EXT2_PWM_2_PIN PIN_PA20E_TC7_WO0
- #define EXT2_PWM_2_MUX MUX_PA20E_TC7_WO0
- #define EXT2_PWM_2_PINMUX PINMUX_PA20E_TC7_WO0
- #define EXT2_PWM_3_CHANNEL 1
- #define EXT2_PWM_3_PIN PIN_PA21E_TC7_WO1
- #define EXT2_PWM_3_MUX MUX_PA21E_TC7_WO1
- #define EXT2_PWM_3_PINMUX PINMUX_PA21E_TC7_WO1
- #define PWM2_MODULE EXT2_PWM_MODULE
- #define PWM20_OUT_PIN EXT2_PWM_0_PIN
- #define PWM20_OUT_MUX EXT2_PWM_0_MUX
- #define PWM21_OUT_PIN EXT2_PWM_1_PIN
- #define PWM21_OUT_MUX EXT2_PWM_1_MUX
- #define PWM22_OUT_PIN EXT2_PWM_2_PIN
- #define PWM22_OUT_MUX EXT2_PWM_2_MUX
- #define PWM23_OUT_PIN EXT2_PWM_3_PIN
- #define PWM23_OUT_MUX EXT2_PWM_3_MUX
复制代码
將原來機械手臂的PWM1_MODULE更改配置到EXT2接口的兩隻GPIO上,即PA20和PA21
9. 增加TC和TC Callback函數宣告,和PWM更改的delay數值
- void configure_tc(void);
- void configure_tc_callbacks(void);
- void tc_callback_to_change_duty_cycle_1(struct tc_module *const module_inst);
- void tc_callback_to_change_duty_cycle_2(struct tc_module *const module_inst);
- void tc_callback_to_change_duty_cycle_3(struct tc_module *const module_inst);
- void tc_callback_to_change_duty_cycle_4(struct tc_module *const module_inst);
- static uint32_t delay1 = 0, delay2 = 0, delay3 = 0, delay4 = 0;
- struct tc_module tc_instance1,tc_instance2;
复制代码
10. 增加所有的機械手臂相關的邏輯,即TC Callback的主要程式碼
- static void update_led_state(bool btn, bool pin_state)
- {
- if (btn)
- pin_state = port_pin_get_input_level(BUTTON_0_PIN);
- port_pin_set_output_level(LED_0_PIN, pin_state);
-
- if(pin_state==true)
- {
- delay1=20000;
- }
- else
- {
- delay1=60000;
- }
-
- if(pin_state==true)
- {
- delay2=11200;
- }
- else
- {
- delay2=11200;
- }
-
- if(pin_state==true)
- {
- delay3=30000;
- }
- else
- {
- delay3=65000;
- }
-
- if(pin_state==true)
- {
- delay4=11200;
- }
- else
- {
- delay4=11200;
- }
-
- }
- void tc_callback_to_change_duty_cycle_1(struct tc_module *const module_inst)
- {
- tc_set_compare_value(module_inst, TC_COMPARE_CAPTURE_CHANNEL_0, delay1 + 1);
- }
- void tc_callback_to_change_duty_cycle_2(struct tc_module *const module_inst)
- {
- tc_set_compare_value(module_inst, TC_COMPARE_CAPTURE_CHANNEL_1, delay2 + 1);
- }
- void tc_callback_to_change_duty_cycle_3(struct tc_module *const module_inst)
- {
- tc_set_compare_value(module_inst, TC_COMPARE_CAPTURE_CHANNEL_0, delay3 + 1);
- }
- void tc_callback_to_change_duty_cycle_4(struct tc_module *const module_inst)
- {
- tc_set_compare_value(module_inst, TC_COMPARE_CAPTURE_CHANNEL_1, delay4 + 1);
- }
- void configure_tc(void)
- {
- struct tc_config config_tc1, config_tc2;
- tc_get_config_defaults(&config_tc1);
- tc_get_config_defaults(&config_tc2);
-
- config_tc1.counter_size = TC_COUNTER_SIZE_16BIT;
- config_tc1.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
- config_tc1.counter_16_bit.compare_capture_channel[0] = 0xFFFF;
-
- config_tc1.pwm_channel[0].enabled =true;
- config_tc1.pwm_channel[0].pin_out = PWM22_OUT_PIN;
- config_tc1.pwm_channel[0].pin_mux = PWM22_OUT_MUX;
-
- config_tc1.counter_16_bit.compare_capture_channel[1] = 0xFFFF;
-
- config_tc1.pwm_channel[1].enabled =true;
- config_tc1.pwm_channel[1].pin_out = PWM23_OUT_PIN;
- config_tc1.pwm_channel[1].pin_mux = PWM23_OUT_MUX;
-
- config_tc2.counter_size = TC_COUNTER_SIZE_16BIT;
- config_tc2.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
- config_tc2.counter_16_bit.compare_capture_channel[0] = 0xFFFF;
-
- config_tc2.pwm_channel[0].enabled =true;
- config_tc2.pwm_channel[0].pin_out = PWM20_OUT_PIN;
- config_tc2.pwm_channel[0].pin_mux = PWM20_OUT_MUX;
-
- config_tc2.counter_16_bit.compare_capture_channel[1] = 0xFFFF;
-
- config_tc2.pwm_channel[1].enabled =true;
- config_tc2.pwm_channel[1].pin_out = PWM21_OUT_PIN;
- config_tc2.pwm_channel[1].pin_mux = PWM21_OUT_MUX;
-
- tc_init(&tc_instance1, PWM1_MODULE, &config_tc1);
- tc_init(&tc_instance2, PWM2_MODULE, &config_tc2);
-
- tc_enable(&tc_instance1);
- tc_enable(&tc_instance2);
- }
- void configure_tc_callbacks(void)
- {
- tc_register_callback(
- &tc_instance1,
- tc_callback_to_change_duty_cycle_1,
- TC_CALLBACK_CC_CHANNEL0);
-
- tc_register_callback(
- &tc_instance1,
- tc_callback_to_change_duty_cycle_2,
- TC_CALLBACK_CC_CHANNEL1);
- tc_register_callback(
- &tc_instance2,
- tc_callback_to_change_duty_cycle_3,
- TC_CALLBACK_CC_CHANNEL0);
-
- tc_register_callback(
- &tc_instance2,
- tc_callback_to_change_duty_cycle_4,
- TC_CALLBACK_CC_CHANNEL1);
-
- tc_enable_callback(&tc_instance1, TC_CALLBACK_CC_CHANNEL0);
-
- tc_enable_callback(&tc_instance1, TC_CALLBACK_CC_CHANNEL1);
- tc_enable_callback(&tc_instance2, TC_CALLBACK_CC_CHANNEL0);
-
- tc_enable_callback(&tc_instance2, TC_CALLBACK_CC_CHANNEL1);
- }
复制代码
其中delay值會有所不同,可能在於加入了WINC1500使得MCU負載增加,delay值需有所放大,經由Try and Error重新定義delay的數值,2和4號基本上不會轉動角度,可以不必調整,只調整1和3號Servo的delay值
11. 增加按鈕的觸發EINT相關程式碼
- static void extint_callback(void)
- {
- update_led_state(true, true);
- }
- static void configure_eic_callback(void)
- {
- extint_register_callback(extint_callback,
- BUTTON_0_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
- extint_chan_enable_callback(BUTTON_0_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
- }
- static void configure_extint(void)
- {
- struct extint_chan_conf eint_chan_conf;
- extint_chan_get_config_defaults(&eint_chan_conf);
- eint_chan_conf.gpio_pin = BUTTON_0_EIC_PIN;
- eint_chan_conf.gpio_pin_mux = BUTTON_0_EIC_MUX;
- eint_chan_conf.detection_criteria = EXTINT_DETECT_BOTH;
- eint_chan_conf.filter_input_signal = true;
- extint_chan_set_config(BUTTON_0_EIC_LINE, &eint_chan_conf);
- }
复制代码
12. 其中觸發處理的函式update_led_state(bool btn, bool pin_state),用來決定是否由按鈕來觸發
- btn= true <=> SW0按鈕觸發
- btn= false <=> HTML網頁觸發
复制代码
13. 修改TCP MSG的相關程式碼,讓TCP Client連線時,傳入URL參數用來判讀指令
- case SOCKET_MSG_RECV:
- {
- tstrSocketRecvMsg *pstrRecv = (tstrSocketRecvMsg *)pvMsg;
- if (pstrRecv && pstrRecv->s16BufferSize > 0) {
- printf("socket_cb: recv success!rn");
- printf("%srn",pstrRecv->pu8Buffer);
- if(strncmp((char*)pstrRecv->pu8Buffer,"GET /?SW=ON",11)==0)
- {
- printf("Switch-> ONrn");
- update_led_state(false,true);
- }
- else if(strncmp((char*)pstrRecv->pu8Buffer,"GET /?SW=OFF",12)==0)
- {
- printf("Switch-> OFFrn");
- update_led_state(false,false);
- }
- else
- printf("ERROR!rn");
- send(tcp_client_socket, &msg_wifi_product, sizeof(t_msg_wifi_product), 0);
- } else {
- printf("socket_cb: recv error!rn");
- close(tcp_server_socket);
- tcp_server_socket = -1;
- }
- }
复制代码
程式碼當由WINC1500傳入RECV MSG時候,會夾帶連線收到的封包,可用來解析URL的參數,封包的指標為pu8Buffer,藉由比較函式strncmp,來比較URL之後所帶入的指令參數,並且觸發update_led_state函式,來達到驅動機械手臂
Fig. 3 整個TCP Server模塊之間,函式的觸發原理,可藉由此張官方文檔圖表來說明
14. 最後要更改的部分,讓Server隨時可以監聽新的Client連線,因此修改以下這段程式碼
- case SOCKET_MSG_SEND:
- {
- printf("socket_cb: send success!rn");
- printf("TCP Server Test Complete!rn");
- printf("close socketn");
- close(tcp_client_socket);
- //close(tcp_server_socket);
- }
复制代码
取消關閉Server服務,讓之後Client可以建立新的連線
15. 修改完畢以後可以進行編譯和燒寫了,這裡就不再贅述,但須注意的是燒寫後,必須由腳位5.0V IN和GND進行供電,否則由USB Porte供電的話會造成電流不足,因為此USB供電口有限流(估計約1A),加上WINC1500模組已經不堪負荷
- 杜邦線連接 DC紅線 <=> POWER 5.0V IN
- 杜邦線連接 DC黑線 <=> POWER GND
- 機械手臂 1號Servo <=> EXT2 PA20
- 機械手臂 2號Servo <=> EXT2 PA21
- 機械手臂 3號Servo <=> EXT2 PB12
- 機械手臂 4號Servo <=> EXT2 PB13
- 機械手臂 Servo總紅線 <=> POWER 5.0V
- 機械手臂 Servo總黑線 <=> EXT2 GND
复制代码
以上是我設計的接線方法,DC轉接頭則連接5V 2A的電源即可
16. 打開Serial Console,這裡我使用SecureCRT,來驗證所有功能是否正確
Fig. 4 若顯示如圖表示TCP Server正確運作
17. 利用手機或者電腦打開網頁
Fig. 5 SAM D21上的簡易網頁
Fig. 6 同時Serial也顯示為ERROR!指令,因為後面不帶有指令參數
18. 選擇ON並按下Submit按鈕
Fig. 7 選擇ON
Fig. 8 同時Serial也顯示Switch-> ON的Debug訊息,觀看LED和機械手臂的動作
Fig. 9 同理,選擇OFF,按下按鈕後觀看,Serial輸出和LED,機械手臂的動作
19. 完成驗證,結束本試用應用設計,實體圖片可參考上一篇
2
|
|
|
|