本帖最后由 MOPPLAYER 于 2016-9-11 15:36 编辑
前言:
本分享是基於範例D21 Xplained的LED toggle (6.2版 ASF 3.22版)範例修改後而成,小機械手臂共有4個Servo,利用按鈕做觸發改變手臂上各Servo的角度來夾起垃圾(衛生紙),新版本的Atmel Studio(7.0版)的一樣可做編譯和燒寫,因為實質上並無差異,所以小伙伴們也可直接測試程式碼
準備:
1. SAMD21 Xplained Pro 主板
2. MicroUSB傳輸線
3. 小機械手臂,買或者3D列印也可,本文使用4個Servo
實作:
1. Atmel Studio提供完整的編譯和燒錄工具,和USB驅動,可至官網來下載http://www.atmel.com/tools/atmelstudio.aspx
Fig. 1 Atmel Studio,現行版本為7.0
2. 下載離線安裝包或者在線安裝執行檔即可,這裡選擇在線安裝較省空間
Fig. 2 已安裝後的維護程式
3. 打開IDE,更新版子的Firmware,當插上開發板時會自動偵測板子種類和Firmware的版本
Fig. 3 Firmware主要是幫助您在線Debug時候非常有用的工具
4. 創建LED Toggle範例程式,將以此為修改,注意6.2版本還是有些和7.0版本程式碼不同,但架構上並無差異,以下針對6.2版本升級後的來講解
5. 對ASF增加必要的驅動,ASF主要是針對各個外設模組化,當需要時候加入該模組即可使用相關的驅動和功能
Fig. 4 當然主要是增加tc模組, timer主要是用來產生中斷,產生指定佔空比的PWM訊號,用來驅動Servo
6. LED toggle由開發板上的SW0按鈕偵測是否被按下的高低電位變化,產生interrupt給MCU在執行LED的亮滅,除此之外就是額外增加了在更新LED狀態時,同時也變更了小機械手臂各servo的狀態
7. 在static void update_led_state(void)加入
- if(pin_state==true)
- {
- delay1=3500;
- }
- else
- {
- delay1=10000;
- }
复制代码
其中delay1是用來決定第一個PWM輸出的duty cycle值給Servo,之後的delay2決定第二個Servo,以此類推,其中delay值大小需try and error,來決定Servo轉角
8. 並加入tc driver用以產生PWM訊號,定義PWM1 即EXT1擴充腳位群組上的PWM,而PWM10即PWM(+),PWM11即PWM(-)
- #define PWM1_MODULE EXT1_PWM_MODULE
- #define PWM10_OUT_PIN EXT1_PWM_0_PIN
- #define PWM10_OUT_MUX EXT1_PWM_0_MUX
- #define PWM11_OUT_PIN EXT1_PWM_1_PIN
- #define PWM11_OUT_MUX EXT1_PWM_1_MUX
复制代码
9. tc初始化所需要的參數設定,其中tc1給第一個跟第二個servo,tc2給第三個跟第四個servo,每個instance各有channel0跟channel1兩個PWM頻道,並觸發callback時產生duty cycle的變化給Servo改變機械手臂的狀態:
- 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 = PWM10_OUT_PIN;
- config_tc1.pwm_channel[0].pin_mux = PWM10_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 = PWM11_OUT_PIN;
- config_tc1.pwm_channel[1].pin_mux = PWM11_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);
- }
-
- 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);
- }
复制代码
將Timer設定好後就可以周期的產生PWM訊號,由config_tc1和config_tc2來決定,設置好PWM參數和channel和使能,並註冊callback函式,用來隨著按下按鈕改變duty cycle來達到變更Servo角度,使得機械手臂可以抓取物品
10. 最後在main()中放入啟動副程式
- system_init();
- delay_init();
- struct port_config Port_con;
- port_get_config_defaults(&Port_con);
- Port_con.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
- Port_con.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
- port_pin_set_config(EXT1_PIN_GPIO_0,&Port_con);
- configure_tc();
- configure_tc_callbacks();
复制代码
11. 成品實體圖
Fig. 5 完整圖,其中底板我拿其他開發板當作支撐底板,鎖上銅柱和螺帽,並放上夾起實驗物體-衛生紙
Fig. 6 按下SW0按鈕時,可看見LED和機械手臂轉角變化,展現出打開來抓取的姿勢
Fig. 7 鬆開按鈕,衛生紙也成功被夾起
12. 完成本篇簡單複合式應用
2
|
|
|
|
|
|