痞酷網_PIGOO

 找回密碼
 立即註冊
!!! [系統偵測到廣告阻擋軟體] !!!

如果您覺得痞酷網對您有些許幫助,或者您認同痞酷網的理想,

那麼希望您將痞酷網設定為白名單.

並請在上論壇的時候,動動您的手指,用行動支持我們.

謝謝!
查看: 6443|回復: 3

簡易型伺服機PWM輸出控制

[複製鏈接]
發表於 2016-6-13 22:37:11 | 顯示全部樓層 |閱讀模式
上次發文推動硬碟三相馬達雖然會轉,但是轉的非常"無力",信心也大受打擊,原來電動機的運轉是一個高深的學問,不是像我這樣甚麼都想玩的人可以勝任的!! 先進們提出許多驅動電路,也提供寶貴的 伺服機驅動模式PWM 1ms~2ms 50HZ ,還有 arduino 的pwm 電路和程式,所以就試著做看看這電路,發現電路好像不是那麼難,倒是程式比較複雜,還好書上有一些參考,所以,就這樣邊參考邊修改的把雛型給弄出來了...
選擇按鈕 選擇 PWM1 PWM2 PWM3 的輸出改變 並且由LED顯示,VR 1M歐姆調整電位輸入到 STM8 的 類比輸入 把0~5V 轉成 0~1023 並送給 TIM1 作為 PWM 的改變,1023 = 1.023ms 加上 1000的 offset 使得 PWM寬度為 1.0ms~2.023ms ...
  MODE 目前沒有作用,預計要給 數位式伺服機使用..



電路圖 因為找不到STM8S103K3的圖庫 所以用 32接腳取代
調整大小PWM線路.JPG

使用 QFP32轉版
調整大小PWMPCB.JPG

ARTCAM 電路板
調整大小PWM雕刻.JPG

ARTCAM 面板鑽孔標定
調整大小PWM面板雕刻.JPG

測試的波形 因為STM8S103裡面有腳有問題(內部短路?)所以波形有重複
IMG_20160611_233048.jpg

線上微調程式並且確認功能
IMG_20160611_233058.jpg

雕刻機的PCB 部分的線路需要雕刻2次位移0.05mm這樣再和接的時候才比較不會橋接
IMG_20160611_233120.jpg

外殼使用雕刻機定位出 4枝銅柱以及 三個LED 開關的位置,再使用鑽床開孔,因為對雕刻機還沒有信心,用鑽床比較快!!
IMG_20160613_214758.jpg


  1. // 20160613 for PWM out 3 channel
  2. #include "stm8s.h"
  3. #include "stm8s_tim1.h"
  4. #include "stm8s_clk.h"
  5. #include "stm8s_delay.h"
  6. #include "stm8s_adc1.h"
  7. #define VR_Channel ADC1_CHANNEL_0// stm8s103k3 pin 16
  8. u16 VR_data;
  9. u8 AD_read_count;//0~3 輪流read out AD count
  10. void AD_Data_Update(void);
  11. u16 ADCValue[10]={0};//電壓值平均用減少誤差雜訊
  12. u16 DataADC=0;//最後的電壓值
  13. u8 adc_update_flag;//ADC 更新1次的旗標
  14. u16 pwmwidth = 1;
  15. #define inputPORT GPIOA //PB1--mode, PB 2--select sw
  16. #define outputPORT GPIOC //led Pb5 Pb6 Pb7 11 10 9
  17. #define LED1 GPIO_PIN_5
  18. #define LED2 GPIO_PIN_6
  19. #define LED3 GPIO_PIN_7
  20. #define MODE_SW GPIO_PIN_1
  21. #define Select_SW GPIO_PIN_2
  22. u8 Select_SW_data = 0;
  23. u8 Key_pressed_flag = 0;
  24. u8 check_select_SW_count=0;
  25. u8 select_sw=0;


  26. void ADConvert(void)//轉換類比信號成為數位信號
  27. {
  28.         unsigned char ADCcount =0;
  29.         ADC1->CR1|=0x02;
  30.         ADC1_StartConversion();
  31.         while(ADCcount<10)
  32.         {
  33.                 while(ADC1_GetFlagStatus(ADC1_FLAG_EOC)==RESET);
  34.                 ADC1_ClearFlag(ADC1_FLAG_AWS0);
  35.                 ADCValue[ADCcount]=ADC1_GetConversionValue();
  36.                 ADCcount++;
  37.         }
  38.         ADC1->CR1 &= ~0x02;
  39. }

  40. void DigitalFiltering(void)//把類比信號的10組資料作中間的6組平均
  41. {
  42.         unsigned char i,j;
  43.         unsigned char cptemp;
  44.        
  45.         for(i=10;i>=1;i--)
  46.         {
  47.                 for(j-0;j<(i-1);j++)
  48.                 {
  49.                         if(ADCValue[j]>ADCValue[j+1])
  50.                         {
  51.                                 cptemp=ADCValue[j];
  52.                                 ADCValue[j]=ADCValue[j+1];
  53.                                 ADCValue[j+1]=cptemp;
  54.                         }
  55.                 }
  56.         }
  57.         DataADC=0;
  58.         for(i=2;i<=7;i++)
  59.         {
  60.                 DataADC +=ADCValue[i];
  61.         }
  62.         DataADC /=6;       
  63. }



  64. unsigned int ADC1Set(ADC1_Channel_TypeDef ADC_Channel)//讀取不同的AD通道經過類比轉成數位再經過10取6平均送出結果
  65. {
  66. u16 ADresult;
  67. {
  68. ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS,ADC_Channel,ADC1_PRESSEL_FCPU_D2,ADC1_EXTTRIG_TIM,DISABLE,ADC1_ALIGN_RIGHT,ADC1_SCHMITTTRIG_CHANNEL0,DISABLE);
  69. ADConvert();
  70. DigitalFiltering();
  71. ADresult=DataADC;
  72. DataADC=0;
  73. adc_update_flag=0;
  74. }
  75. return ADresult;
  76. }
  77. //---------------------------------------------------------------------
  78. void Read_select_SW(void)//每按下一次按鍵開關數加一以選擇 通道PWM設定用並且作為LED顯示
  79. //變數Select_SW_data Key_pressed_flag
  80. {
  81.         if(GPIO_ReadInputPin(inputPORT,Select_SW)==0)//Select sw be pressed
  82.         {
  83.                  //GPIO_WriteHigh(outputPORT,LED2);
  84.                         delay(500);
  85.                        
  86.                 if(GPIO_ReadInputPin(inputPORT,Select_SW)==0)
  87.                         {
  88.                         //        select_sw = GPIO_ReadInputPin(inputPORT,Select_SW);
  89.                                 while(GPIO_ReadInputPin(inputPORT,Select_SW)==0);
  90.                                
  91.                         //        check_select_SW_count++;
  92.                                 Select_SW_data++;
  93.                                 if(Select_SW_data > 2)
  94.                                         {
  95.                                                 Select_SW_data=0;
  96.                                         }
  97.                                 Key_pressed_flag = 1;
  98.                         }       
  99.   }       
  100. }

  101. void LED_OUT(u8 SW_data)//點亮相關led
  102. {
  103.          switch(SW_data)
  104.          {
  105.          case 0:
  106.          GPIO_WriteLow(outputPORT,LED1);
  107.          GPIO_WriteHigh(outputPORT,LED2);
  108.          GPIO_WriteHigh(outputPORT,LED3);
  109.          break;
  110.          
  111.          case 1:
  112.          GPIO_WriteHigh(outputPORT,LED1);
  113.          GPIO_WriteLow(outputPORT,LED2);
  114.          GPIO_WriteHigh(outputPORT,LED3);
  115.          break;

  116.          case 2:
  117.          GPIO_WriteHigh(outputPORT,LED1);
  118.          GPIO_WriteHigh(outputPORT,LED2);
  119.          GPIO_WriteLow(outputPORT,LED3);
  120.          break;
  121. }
  122.          
  123. }

  124. void GPIOinit(void)//basic i/o setting
  125.         {
  126.                 GPIO_Init(inputPORT,Select_SW,GPIO_MODE_IN_PU_NO_IT);//PA1 PA2
  127.                 GPIO_Init(outputPORT,(LED1|LED2|LED3),GPIO_MODE_OUT_OD_LOW_FAST);//PC5 PC6 PC7        
  128.         }
  129.        



  130. void update_TIM1_Config(u8 sw)
  131. {
  132.         switch(sw)
  133.         {
  134.         case 0:
  135.                 TIM1_OC1Init(TIM1_OCMODE_PWM2,TIM1_OUTPUTSTATE_ENABLE,TIM1_OUTPUTNSTATE_ENABLE,pwmwidth,TIM1_OCPOLARITY_LOW,TIM1_OCNPOLARITY_HIGH,TIM1_OCIDLESTATE_SET,TIM1_OCNIDLESTATE_RESET);
  136.         break;

  137.         case 1:
  138.                 TIM1_OC2Init(TIM1_OCMODE_PWM2,TIM1_OUTPUTSTATE_ENABLE,TIM1_OUTPUTNSTATE_ENABLE,pwmwidth,TIM1_OCPOLARITY_LOW,TIM1_OCNPOLARITY_HIGH,TIM1_OCIDLESTATE_SET,TIM1_OCNIDLESTATE_RESET);
  139.         break;

  140.         case 2:
  141.                 TIM1_OC3Init(TIM1_OCMODE_PWM2,TIM1_OUTPUTSTATE_ENABLE,TIM1_OUTPUTNSTATE_ENABLE,pwmwidth+20,TIM1_OCPOLARITY_LOW,TIM1_OCNPOLARITY_HIGH,TIM1_OCIDLESTATE_SET,TIM1_OCNIDLESTATE_RESET);
  142.         break;
  143.         }
  144.         TIM1_Cmd(ENABLE);
  145.         TIM1_CtrlPWMOutputs(ENABLE);
  146. }

  147. void CLK_Config(void)
  148. {
  149.         CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);
  150. }

  151. main()
  152. {
  153.         GPIOinit();
  154.         TIM1_DeInit();
  155.         TIM1_TimeBaseInit(1,TIM1_COUNTERMODE_UP,20000,0);        //20ms 1pulse 1us
  156.         CLK_Config();
  157.        
  158.         //test io
  159.          GPIO_WriteHigh(outputPORT,LED3);
  160.          GPIO_WriteLow(outputPORT,LED2);
  161.          GPIO_WriteLow(outputPORT,LED1);
  162.        
  163.         while (1)
  164.        
  165.         {
  166.                 Read_select_SW();//每按下一次按鍵開關數加一以選擇 通道PWM設定用並且作為LED顯示 Select_SW_data
  167.                
  168.                 if(Key_pressed_flag == 1)
  169.                 {               
  170.                 LED_OUT(Select_SW_data);//點亮相關led
  171.                 Key_pressed_flag = 0;
  172.           }
  173.                 //read PWM VR data
  174.                 VR_data = ADC1Set(VR_Channel);//channel 0 pin16                       
  175.                 //put to PWM pwmwidth parameter
  176.                 pwmwidth = VR_data+1000;
  177.                
  178.                 update_TIM1_Config(Select_SW_data);

  179.         }
  180. }

複製代碼

評分

7

查看全部評分

發表於 2016-6-16 00:03:14 | 顯示全部樓層
本文章最後由 xiaolaba 於 2016-6-16 12:12 AM 編輯

呂大玩得不亦樂乎..
這雕雞機確實好物, 解決了很多DIY原型時焊線的工作量, 可以專心寫程序.
如果你的 adcvalue 是8BIT 或者10BIT, 試試看用簡單的一階 LPF, 當16BIT計算, 計算速度可以移動平均法快20倍以上, 效果也好, 如果要再高級, 就用卡曼濾波, 快狠準.
 樓主| 發表於 2016-6-16 13:57:11 | 顯示全部樓層
xiaolaba 發表於 2016-6-16 12:03 AM
呂大玩得不亦樂乎..
這雕雞機確實好物, 解決了很多DIY原型時焊線的工作量, 可以專心寫程序.
如果你的 adcva ...

xiaolaba 大:
   感謝!! 其實我不是寫程式的料,所有的 數學運算我都很痛苦,我只會簡單的IO 玩玩!!  這些建議 我上網看看有沒有可以"抄"的,不但不會錯又省事,再次感謝!!
  雕刻機 真的很方便,尤其是做第二個第三個...
發表於 2016-6-16 22:55:13 | 顯示全部樓層
本文章最後由 xiaolaba 於 2016-6-16 11:01 PM 編輯
antlu 發表於 2016-6-16 01:57 PM
xiaolaba 大:
   感謝!! 其實我不是寫程式的料,所有的 數學運算我都很痛苦,我只會簡單的IO 玩玩!!  這些 ...


試試看這樣

int temp=0; //16bit
char adcvalue, filter_output; //8bit

void main () {

do {
temp = temp - (temp / 4) + adcvalue;
filter_output = temp / 4;
} while (1)

}


驗證效果可以這樣看, excel 做的, simple8bit_LPF.rar (11.73 KB, 下載次數: 1, 售價: 2 個酷幣)

常數k選4的話 SIGMA = 1 - 1/4 =0.75, 濾波輸出也很快速逼近adcvalue, 一般都夠用, 除非你的取樣率需要很高. 假設adcvalue就是100, 5次取樣後達到 63%, 12次取樣後達到95%, 是不是和電容充電的曲線很像呢, 電容的一大功用就是 [濾波]. 如果加大常數K, 等於加大濾波電容量, 不過實際還要兼顧取樣率和需要, 不能任意.
simple8bit_LPF.JPG
您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

關閉

站長小叮嚀上一條 /1 下一條

禁閉室|手機版|連繫我們|痞酷網電子技術論壇

GMT+8, 2024-11-22 01:21 AM , Processed in 0.160008 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.