久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 40343|回復: 66
打印 上一主題 下一主題
收起左側

STM32無刷電調全套開發資料(源碼、原理圖、PCB工程及說明文檔)

  [復制鏈接]
跳轉到指定樓層
樓主
ESC32硬件---PCB小結(第一版)
Altium Designer畫的原理圖和PCB圖如下:(51hei附件中可下載工程文件)

    經過一個星期的畫PCB,今天終于化了,整體看上去還比較滿意,具體的性能還得等后期制板、測試才知道。
這個電路屬于低頻功率型板,相對高頻板信號質量就要求不高了,所以也就不用考慮信號完整性等問題了。
    等完成原理圖的設計之后,我就請教了好幾個人,在布線的時候需要注意的事項,但是沒有得到什么有價值的答案,原因是他們不了解我,只是站在自己的去看待這件事了,所以對于他們就沒什么難度了。
    在原理圖的設計時,參照了“阿嘉”和“六哥”的方案,大體沒有太大的改動(六哥的已經商品化,相對有保證),只是完善了自己的接口和一些器件的選型。對于原理圖的分析請看前兩篇博客,有什么不對的地方歡迎指出。
    原理圖設計完成之后,接下來就是為各個器件添加封裝了。這個過程我檢查的還是比較仔細的,因為上次已經在這里出現過一次問題了。對于電阻,電容的封裝大體選用0603,對于個別選用0805。對于重要的器件,參考了數據手冊和IPC-7351進行選擇,應該不會有問題。
    接下來就是導入網表,開始布局。相對來說這個比較簡單所以布局也就比較隨意,基本原則就是按照功能模塊進行布局的。在布線的時候我更比較隨意了,也不想什么規則。當布到一半的時候,好多走線都無法完成了,連打過孔的機會都不給我了。我想肯定是出問題了,應該是布局的問題,大概看這個圖看了一天,光看不畫,看看哪里出問題了。于是就開始了第二版,有了第一次的不順利,第二次自然就順利了很多。大概用了不到一個星期就畫完了,這個圖我自己看上去很是滿意。
   前面這些跟流水賬似的,沒有什么實質性的意思。
   在畫之前我就找好了人幫我檢查這個圖了,周五我把圖發給我了相思谷(一個網友),把幫我之處了很多問題,下面就總結一下問題。
     1、線間距。
      這里應該遵循3W規則,所謂3W就是為了減少線間串擾,應保證線間距足夠大,當線中心不少于3倍線寬,則可 保持70%的電場不互相干擾。如要達到98%的電場不互相干擾,可使用10W的間距。——這是查閱華為PCB布線規則所得。
      這里我就沒有遵循這個原則,我的線間距大概只有1倍線寬。
     2、電源線過細。
      這里我查閱了華為PCB教程得到了下面一個表格。這里線寬跟所能承受最大電流的關系表
    3、電源環路。(用圖說明)

    高亮部分的GND形成了一個環路而且是一個嚴重的閉環。在看看VS電源線環路

   這是VS電源線沒有閉環,但是接近閉環了。

   這里我就困惑了,如果整體敷銅接地,那在敷銅層也是閉環的GND,而且整體敷銅可增強抗干擾的能力。
這個問題“相思谷”沒有給我解答清楚。他讓我查閱一下資料,我查閱了很多資料最終未果。于是翻看自己的QQ好友看看誰能幫助我,看后傻了,全是軟件的,硬件方面的就有貓大,還沒在線。這時候突然想起了流星趕月了,這是個大神。于是就翻看貓大的群就找他了,還不錯這人挺熱心。下面就看看他的問題吧。
   電源環路沒有問題,主要是低阻抗,電調的板子電流很多,不敷銅不合適。他又指出控制部分形成環路確實不好,線上分布電感明顯,應該盡量保證單面敷銅連續,就是盡量保證不出現死銅。我的電源環路最要是走線環路,沒有平面,是阻抗。

    聽完他說的我還沒懂,只是迷迷糊糊有個印象。在繼續深問就會顯得自己弱智了,我也含糊的問答了一下,想不太明白,我在看看。這個原因剩下的就是繼續查資料吧。
    在《電路設計技術與技巧》這本書中寫到:“地回路”會孕育一個低頻的電磁干擾。磁場在一個環形的、封閉的電路中,感應出一個感應電流。還有導線的低頻等效模型是一個電阻,由于高阻抗的作用,各個GND值就有會有壓差,而不是一個值了。這里指出了一個規則:永遠采用分社的電源地線,用不同的導線來分別承載由每個電源所提供的電源。如圖:
    與使用分開的地線的原因相同:使用一條公用的電源供給線,會在電源電壓上形成一個公共的串聯電壓降,只是這里被加入到了電源供給線上。
    我還問了他布線的技巧,讓他給我推薦一些資料。這個問題他給我的為回答是:整體鋪地,單點接地。雙層板要調整元件布局,使各個元件接地路勁最短,且地平面集中。泛泛看資料作用不大,很難推薦,布線技巧不是靠臨時看書就可以解決的,需要實際操練。
   他的回答很簡單,但是很受用,解決了我好多困惑。
   這些就是針對相思谷提出問題的理論補充了,看起來問題很是蠻多的,于是決定重新布局再畫一版。針對這次畫板,我打算請多個人檢查,初步打算有相思谷,華航申老師,貓大、流星。第一版的相思谷已經初驗了,還有工程已經發給申老師了還沒給我回復呢。第二版再去找貓大跟流星,針對他們提出的問題進行總結,然后修改。最后在拿去找老師檢查。估計周一申老師就會檢查完,到時候在把他提出的問題進行總結。
    總結:上面檢查的方式太局限了,但這是非常有效的方法。通過他們的檢查我可以充分補充理論知識,而且這些人尤其是貓大跟流星在硬件方面的造詣很深。結識他們就相當找到了一個柱子,順著他們向上爬吧。這種方法是我看于爭的視頻想到的方法。他們的經驗轉換化自己的經驗,相信通過這兩天電路板肯定幫我在低頻電路設計提升一個層次。同時在跟他們的交流過程中發現了一個問題,貓大跟流星的理論基礎太厚了,他們很說空經驗,他們的經驗全是有理論支撐的。這個正好符合了于爭視頻的快速積累經驗的理論。

  1. /*
  2.     This file is part of AutoQuad ESC32.

  3.     AutoQuad ESC32 is free software: you can redistribute it and/or modify
  4.     it under the terms of the GNU General Public License as published by
  5.     the Free Software Foundation, either version 3 of the License, or
  6.     (at your option) any later version.

  7.     AutoQuad ESC32 is distributed in the hope that it will be useful,
  8.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.     GNU General Public License for more details.
  11.     You should have received a copy of the GNU General Public License
  12.     along with AutoQuad ESC32.  If not, see

  13.     Copyright © 2011, 2012, 2013  Bill Nesbitt
  14. */

  15. #include "run.h"
  16. #include "main.h"
  17. #include "timer.h"
  18. #include "adc.h"
  19. #include "fet.h"
  20. #include "pwm.h"
  21. #include "cli.h"
  22. #include "binary.h"
  23. #include "config.h"
  24. #include "misc.h"
  25. #include "stm32f10x_exti.h"
  26. #include "stm32f10x_pwr.h"
  27. #include "stm32f10x_iwdg.h"
  28. #include "stm32f10x_dbgmcu.h"
  29. #include <math.h>

  30. uint32_t runMilis;   //systick中斷中自加.沒有什么控制用途
  31. static uint32_t oldIdleCounter;  //上次main函數中,死循環次數.
  32. float idlePercent;   //空閑時間百分比(在main循環里,什么事情也不做.main死循環運行的時間)
  33. float avgAmps, maxAmps; //平均電流, 最大電流
  34. float avgVolts;      //當前ADC采集轉換后的電池電壓(也就是12v)

  35. float rpm;           //當前轉速(1分鐘多少轉) 測量值 在runRpm函數中計算出來.在runThrotLim中還要繼續使用.
  36. float targetRpm;     //目標轉速 設定值(只在閉環 或 閉環推力模式下使用此變量)

  37. static float rpmI;
  38. static float runRPMFactor;
  39. static float maxCurrentSQRT;  //最大電流 平方根 后
  40. uint8_t disarmReason;//此變量沒啥作用.只用于給上位機顯示當前的 調試代碼(或者說停止電機的原因)
  41. uint8_t commandMode; //串口通訊的模式, cli是ascii模式, binary是二進制通訊模式
  42. static uint8_t runArmCount;
  43. volatile uint8_t runMode;//運行模式 (開環模式, RPM模式, 推力模式, 伺服模式)
  44. static float maxThrust;

  45. //執行看門狗喂狗
  46. void runFeedIWDG(void) {
  47. #ifdef RUN_ENABLE_IWDG
  48.     IWDG_ReloadCounter();
  49. #endif
  50. }

  51. // setup the hardware independent watchdog
  52. // 初始化并開啟獨立看門狗
  53. uint16_t runIWDGInit(int ms)
  54. {
  55. #ifndef RUN_ENABLE_IWDG
  56.     return 0;
  57. #else
  58.         uint16_t prevReloadVal;
  59.         int reloadVal;

  60.         IWDG_ReloadCounter();//喂狗

  61.         DBGMCU_Config(DBGMCU_IWDG_STOP, ENABLE);//當在jtag調試的時候.停止看門狗

  62.         // IWDG timeout equal to 10 ms (the timeout may varies due to LSI frequency dispersion)
  63.         // Enable write access to IWDG_PR and IWDG_RLR registers
  64.         IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//允許訪問IWDG_PR和IWDG_RLR寄存器

  65.         // IWDG counter clock: LSI/4
  66.         IWDG_SetPrescaler(IWDG_Prescaler_4);

  67.         // Set counter reload value to obtain 10ms IWDG TimeOut.
  68.         //  Counter Reload Value        = 10ms/IWDG counter clock period
  69.         //                                = 10ms / (RUN_LSI_FREQ/4)
  70.         //                                = 0.01s / (RUN_LSI_FREQ/4)
  71.         //                                = RUN_LSI_FREQ/(4 * 100)
  72.         //                                = RUN_LSI_FREQ/400
  73.         reloadVal = RUN_LSI_FREQ*ms/4000;

  74.         if (reloadVal < 1)
  75.                 reloadVal = 1;
  76.         else if (reloadVal > 0xfff)
  77.                 reloadVal = 0xfff;

  78.         prevReloadVal = IWDG->RLR;

  79.         IWDG_SetReload(reloadVal);

  80.         // Reload IWDG counter
  81.         IWDG_ReloadCounter();

  82.         // Enable IWDG (the LSI oscillator will be enabled by hardware)
  83.         IWDG_Enable();

  84.         return (prevReloadVal*4000/RUN_LSI_FREQ);
  85. #endif
  86. }

  87. //esc32 非正常停止運行 進入初始化
  88. void runDisarm(int reason) {
  89.         fetSetDutyCycle(0);  //fet占空比設置為0

  90.         timerCancelAlarm2();
  91.         state = ESC_STATE_DISARMED;
  92.         pwmIsrAllOn();

  93.         digitalHi(statusLed);   // turn off
  94.         digitalLo(errorLed);    // turn on
  95.         disarmReason = reason;  // 設置停機原因.給上位機查看狀態使用
  96. }

  97. //手動運行
  98. void runArm(void) {
  99.         int i;

  100.         fetSetDutyCycle(0);
  101.         timerCancelAlarm2();
  102.         digitalHi(errorLed);
  103.         digitalLo(statusLed);   // turn on

  104.         if (runMode == SERVO_MODE) {
  105.                 state = ESC_STATE_RUNNING;
  106.         }
  107.         else {
  108.                 state = ESC_STATE_STOPPED;
  109.                 if (inputMode == ESC_INPUT_UART)
  110.                         runMode = OPEN_LOOP;
  111.                 fetSetBraking(0);
  112.         }

  113.         // extra beeps signifying run mode
  114.         for (i = 0; i < runMode + 1; i++) {
  115.                 fetBeep(250, 600);
  116.                 timerDelay(10000);
  117.         }

  118. //        fetBeep(150, 800);
  119. }

  120. //電機開始運行
  121. void runStart(void) {
  122.         // reset integral bevore new motor startup
  123.         runRpmPIDReset();//先復位I值

  124.         if ((p[START_ALIGN_TIME] == 0) && (p[START_STEPS_NUM] == 0)) {
  125.                 state = ESC_STATE_STARTING;  //設置為準備啟動狀態
  126.                 fetStartCommutation(0);//換向啟動
  127.         }
  128.         else {
  129.                 motorStartSeqInit();//普通啟動
  130.         }
  131. }

  132. //電機停止運行
  133. void runStop(void) {
  134.     runMode = OPEN_LOOP;
  135.     fetSetDutyCycle(0);
  136. }

  137. //設置運行的占空比 duty = 0~100
  138. uint8_t runDuty(float duty) {
  139.     uint8_t ret = 0;

  140.     if (duty >= 0.0f || duty <= 100.0f) {
  141.                 runMode = OPEN_LOOP;
  142.                 fetSetBraking(0);
  143.                 fetSetDutyCycle((uint16_t)(fetPeriod*duty*0.01f));//最大周期 * 占空比(0~100) / 100
  144.                 ret = 1;
  145.     }

  146.     return ret;
  147. }

  148. //pwm.c中斷中調用  或  串口命令輸入調用
  149. void runNewInput(uint16_t setpoint) {
  150.         static uint16_t lastPwm;
  151.         static float filteredSetpoint = 0;

  152.         // Lowpass Input if configured
  153.         // TODO: Make lowpass independent from pwm update rate
  154.         if (p[PWM_LOWPASS]) {
  155.                 filteredSetpoint = (p[PWM_LOWPASS] * filteredSetpoint + (float)setpoint) / (1.0f + p[PWM_LOWPASS]);
  156.                 setpoint = filteredSetpoint;
  157.         }

  158.         if (state == ESC_STATE_RUNNING && setpoint != lastPwm)
  159.         {
  160.                 if (runMode == OPEN_LOOP)
  161.                 {
  162.                         //開環模式
  163.                         fetSetDutyCycle(fetPeriod * (int32_t)(setpoint-pwmLoValue) / (int32_t)(pwmHiValue - pwmLoValue));
  164.                 }
  165.                 else if (runMode == CLOSED_LOOP_RPM)
  166.                 {
  167.                         //閉環轉速模式
  168.                         float target = p[PWM_RPM_SCALE] * (setpoint-pwmLoValue) / (pwmHiValue - pwmLoValue);

  169.                         // limit to configured maximum
  170.                         targetRpm = (target > p[PWM_RPM_SCALE]) ? p[PWM_RPM_SCALE] : target;
  171.                 }
  172.                 // THRUST Mode
  173.                 else if (runMode == CLOSED_LOOP_THRUST)
  174.                 {
  175.                         //閉環推力模式
  176.                         float targetThrust;  // desired trust
  177.                         float target;        // target(rpm)

  178.                         // Calculate targetThrust based on input and MAX_THRUST
  179.                         targetThrust = maxThrust * (setpoint-pwmLoValue) / (pwmHiValue - pwmLoValue);

  180.                         // Workaraound: Negative targetThrust will screw up sqrtf() and create MAX_RPM on throttle min. Dangerous!
  181.                         if (targetThrust > 0.0f) {
  182.                                 // Calculate target(rpm) based on targetThrust
  183.                                 target = ((sqrtf(p[THR1TERM] * p[THR1TERM] + 4.0f * p[THR2TERM] * targetThrust) - p[THR1TERM] ) / ( 2.0f * p[THR2TERM] ));
  184.                         }
  185.                         // targetThrust is negative (pwm_in < pwmLoValue)
  186.                         else {
  187.                                 target = 0.0f;
  188.                         }

  189.                         // upper limit for targetRpm is configured maximum PWM_RPM_SCALE (which is MAX_RPM)
  190.                         targetRpm = (target > p[PWM_RPM_SCALE]) ? p[PWM_RPM_SCALE] : target;
  191.                 }
  192.                 else if (runMode == SERVO_MODE)
  193.                 {
  194.                         //伺服模式下
  195.                         fetSetAngleFromPwm(setpoint);
  196.                 }

  197.                 lastPwm = setpoint;
  198.         }
  199.         else if ((state == ESC_STATE_NOCOMM || state == ESC_STATE_STARTING) && setpoint <= pwmLoValue)
  200.         {
  201.                 fetSetDutyCycle(0);
  202.                 state = ESC_STATE_RUNNING;
  203.         }
  204.         else if (state == ESC_STATE_DISARMED && setpoint > pwmMinValue && setpoint <= pwmLoValue)
  205.         {
  206.                 runArmCount++;
  207.                 if (runArmCount > RUN_ARM_COUNT)
  208.                         runArm();
  209.         }
  210.         else {
  211.                 runArmCount = 0;
  212.         }

  213.         if (state == ESC_STATE_STOPPED && setpoint >= pwmMinStart) {
  214.                 //電機開始運行
  215.                 runStart();
  216.         }
  217. }

  218. //電調運行看門狗. 主要是判斷電調的當前一些狀態.做出停機等處理
  219. static void runWatchDog(void)
  220. {
  221.         register uint32_t t, d, p;

  222.         //__asm volatile ("cpsid i");
  223.         //CPSID_I();
  224.         __disable_irq();
  225.         t = timerMicros;      //當前的系統tick時間
  226.         d = detectedCrossing;
  227.         p = pwmValidMicros;   //在PWM輸入模式下.把timerMicros的時間賦值給此變量
  228.         //__asm volatile ("cpsie i");
  229.         //CPSIE_I();
  230.         __enable_irq();

  231.         if (state == ESC_STATE_STARTING && fetGoodDetects > fetStartDetects) //這里要檢測到fetStartDetects好的檢測,才允許切換電機狀態
  232.         {
  233.                 //是啟動狀態.切換到 運行狀態
  234.                 state = ESC_STATE_RUNNING;
  235.                 digitalHi(statusLed);   // turn off
  236.         }
  237.         else if (state >= ESC_STATE_STOPPED)
  238.         {
  239.                 //運行模式狀態下.會一直在這里檢測狀態.如果狀態不對出錯.會調用runDisarm函數停止

  240.                 // running or starting
  241.                 d = (t >= d) ? (t - d) : (TIMER_MASK - d + t);

  242.                 // timeout if PWM signal disappears
  243.                 if (inputMode == ESC_INPUT_PWM)
  244.                 {
  245.                         //PWM模式 判斷PWM輸入是否超時
  246.                         p = (t >= p) ? (t - p) : (TIMER_MASK - p + t);

  247.                         if (p > PWM_TIMEOUT)
  248.                                 runDisarm(REASON_PWM_TIMEOUT);//pwm輸入超時
  249.                 }

  250.                 if (state >= ESC_STATE_STARTING && d > ADC_CROSSING_TIMEOUT)
  251.                 {
  252.                         if (fetDutyCycle > 0) {
  253.                                 runDisarm(REASON_CROSSING_TIMEOUT);//錯誤停止
  254.                         }
  255.                         else
  256.                         {
  257.                                 runArm();//手動運行起來
  258.                                 pwmIsrRunOn();//PWM開啟輸入比較
  259.                         }
  260.                 }
  261.                 else if (state >= ESC_STATE_STARTING && fetBadDetects > fetDisarmDetects)  //運行狀態中  檢測到錯誤的個數后.進入這個判斷
  262.                 {
  263.                         //在運行過程中,出現錯誤.停止運行
  264.                         if (fetDutyCycle > 0)
  265.                                 runDisarm(REASON_BAD_DETECTS);//錯誤停止
  266.                 }
  267.                 else if (state == ESC_STATE_STOPPED)
  268.                 {
  269.                         //停止模式
  270.                         adcAmpsOffset = adcAvgAmps;        // record current amperage offset
  271.                 }
  272.         }
  273.         else if (state == ESC_STATE_DISARMED && !(runMilis % 100))
  274.         {
  275.                 //停止模式下
  276.                 adcAmpsOffset = adcAvgAmps;        // record current amperage offset
  277.                 digitalTogg(errorLed);
  278.         }
  279. }

  280. void runRpmPIDReset(void) {
  281.     rpmI = 0.0f;
  282. }

  283. //這個應該是計算PID
  284. //rpm:測量的轉速值
  285. //target:目標的轉速值
  286. static int32_t runRpmPID(float rpm, float target) {
  287.         float error;
  288.         float ff, rpmP;
  289.         float iTerm = rpmI;
  290.         float output;

  291.         // feed forward
  292.         ff = ((target*target* p[FF1TERM] + target*p[FF2TERM]) / avgVolts) * fetPeriod;

  293.         error = (target - rpm);//計算出偏差

  294.         if (error > 1000.0f)
  295.                 error = 1000.0f;

  296.         if (error > 0.0f) {
  297.                 rpmP = error * p[PTERM];  //P
  298.                 rpmI += error * p[ITERM]; //I
  299.         }
  300.         else {
  301.                 rpmP =  error * p[PTERM] * p[PNFAC];
  302.                 rpmI += error * p[ITERM] * p[INFAC];
  303.         }

  304.         if (fetBrakingEnabled)
  305.         {
  306.                 //開啟了制動模式
  307.                 if (rpm < 300.0f) {
  308.                         fetSetBraking(0);
  309.                 }
  310.                 else if (error <= -100.0f) {
  311.                         fetSetBraking(1);
  312.                 }
  313.                 else if (fetBraking && error > -25.0f){
  314.                         fetSetBraking(0);
  315.                 }
  316.         }

  317.         output = ff + (rpmP + rpmI) * (1.0f / 1500.0f) * fetPeriod;

  318.         // don't allow integral to continue to rise if at max output
  319.         if (output >= fetPeriod)
  320.                 rpmI = iTerm;

  321.         return output;
  322. }

  323. //計算出電機轉速,根據當前轉速計算出PID輸出值,設置占空比
  324. static uint8_t runRpm(void)
  325. {
  326.     if (state > ESC_STATE_STARTING)
  327.         {
  328.                 //電機處于運行狀態 計算出當前轉速rpm
  329.                 //        rpm = rpm * 0.90f + (runRPMFactor / (float)crossingPeriod) * 0.10f;
  330.                 //        rpm -= (rpm - (runRPMFactor / (float)crossingPeriod)) * 0.25f;
  331.                 //        rpm = (rpm + (runRPMFactor / (float)crossingPeriod)) * 0.5f;
  332.                 //        rpm = (rpm + ((32768.0f * runRPMFactor) / (float)adcCrossingPeriod)) * 0.5f; // increased resolution, fixed filter here
  333.                 rpm = p[RPM_MEAS_LP] * rpm + ((32768.0f * runRPMFactor) / (float)adcCrossingPeriod) * (1.0f - p[RPM_MEAS_LP]); // increased resolution, variable filter here

  334.                 // run closed loop control
  335.                 if (runMode == CLOSED_LOOP_RPM)
  336.                 {
  337.                         //運行在閉環模式下
  338.                         fetSetDutyCycle(runRpmPID(rpm, targetRpm));
  339.                         return 1;
  340.                 }
  341.                 // run closed loop control also for THRUST mode
  342.                 else if (runMode == CLOSED_LOOP_THRUST)
  343.                 {
  344.                         //運行在閉環推力模式
  345.                         fetSetDutyCycle(runRpmPID(rpm, targetRpm));
  346.                         return 1;
  347.                 }
  348.                 else
  349.                 {
  350.                         return 0;
  351.                 }
  352.         }
  353.         else
  354.         {
  355.                 //電機在停止狀態下
  356.                 rpm = 0.0f;
  357.                 return 0;
  358.     }
  359. }

  360. static void runSetupPVD(void) {
  361.     EXTI_InitTypeDef EXTI_InitStructure;
  362.     NVIC_InitTypeDef NVIC_InitStructure;

  363.     // Configure EXTI Line16(PVD Output) to generate an interrupt on rising and falling edges
  364.     EXTI_ClearITPendingBit(EXTI_Line16);
  365.     EXTI_InitStructure.EXTI_Line = EXTI_Line16;
  366.     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  367.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  368.     EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  369.     EXTI_Init(&EXTI_InitStructure);

  370.     // Enable the PVD Interrupt
  371.     NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;
  372.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  373.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  374.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  375.     NVIC_Init(&NVIC_InitStructure);

  376.     // Configure the PVD Level to 2.2V
  377.     PWR_PVDLevelConfig(PWR_PVDLevel_2V2);//配置pvd電壓等級.當電壓小于2.2V的時候產生中斷

  378.     // Enable the PVD Output
  379.     PWR_PVDCmd(ENABLE);
  380. }

  381. void runInit(void) {
  382.     runSetupPVD();
  383.     runSetConstants();
  384.     runMode = p[STARTUP_MODE];//啟動 運行模式

  385.         //系統tickcount時鐘
  386.     SysTick_Config(SystemCoreClock / 1000); // 1ms
  387.     NVIC_SetPriority(SysTick_IRQn, 2);            // lower priority

  388.     // setup hardware watchdog
  389.     runIWDGInit(20);
  390. }

  391. #define RUN_CURRENT_ITERM        1.0f
  392. #define RUN_CURRENT_PTERM        10.0f
  393. #define RUN_MAX_DUTY_INCREASE        1.0f

  394. float currentIState;

  395. //根據PID計算出PWM占空比的值
  396. static int32_t runCurrentPID(int32_t duty) {
  397.     float error;
  398.     float pTerm, iTerm;

  399.     error = avgAmps - p[MAX_CURRENT];

  400.     currentIState += error;
  401.     if (currentIState < 0.0f)
  402.                 currentIState = 0.0f;
  403.     iTerm = currentIState * RUN_CURRENT_ITERM;

  404.     pTerm = error * RUN_CURRENT_PTERM;
  405.     if (pTerm < 0.0f)
  406.                 pTerm = 0.0f;

  407.     duty = duty - iTerm - pTerm;

  408.     if (duty < 0)
  409.                 duty = 0;

  410.     return duty;
  411. }

  412. //計算得到實際的占空比fetActualDutyCycle
  413. //參數duty:實際上就是fetDutyCycle傳遞進來的.想要運行的周期
  414. static void runThrotLim(int32_t duty)
  415. {
  416.         float maxVolts; //最大的電壓
  417.         int32_t maxDuty;//最大的周期

  418.         // only if a limit is set
  419.         if (p[MAX_CURRENT] > 0.0f)
  420.         {
  421.                 //如果實際的占空比和設置的占空比不一樣.那么會實時改變CPU的PWM寄存器.

  422.                 // if current limiter is calibrated - best performance   使用電流限制器校準.性能最好
  423.                 if (p[CL1TERM] != 0.0f)
  424.                 {
  425.                         maxVolts = p[CL1TERM] + p[CL2TERM]*rpm + p[CL3TERM]*p[MAX_CURRENT] + p[CL4TERM]*rpm*maxCurrentSQRT + p[CL5TERM]*maxCurrentSQRT;
  426.                         maxDuty = maxVolts * (fetPeriod / avgVolts);

  427.                         if (duty > maxDuty)
  428.                                 fetActualDutyCycle = maxDuty;
  429.                         else
  430.                                 fetActualDutyCycle = duty;
  431.                 }
  432.                 // otherwise, use PID - less accurate, lower performance  使用PID來計算.不大準確.性能低
  433.                 else
  434.                 {
  435.                         fetActualDutyCycle += fetPeriod * (RUN_MAX_DUTY_INCREASE * 0.01f);
  436.                         if (fetActualDutyCycle > duty)
  437.                                 fetActualDutyCycle = duty;
  438.                         fetActualDutyCycle = runCurrentPID(fetActualDutyCycle);//用PID來計算出當前要運行的占空比
  439.                 }
  440.         }
  441.         else {
  442.                 fetActualDutyCycle = duty;
  443.         }

  444.         //設置到CPU寄存器里.算出來的實際PWM占空比
  445.         _fetSetDutyCycle(fetActualDutyCycle);
  446. }

  447. //系統tickcount中斷
  448. void SysTick_Handler(void) {
  449.     // reload the hardware watchdog
  450.     runFeedIWDG();


  451.     avgVolts = adcAvgVolts * ADC_TO_VOLTS;                     //轉換后的電池電壓(一般是12V) = ADC采集電壓原始值 * 電壓算法
  452.     avgAmps = (adcAvgAmps - adcAmpsOffset) * adcToAmps;        //平均電流 = (當前電流 - 停止時候的電流) * 轉換公式
  453.     maxAmps = (adcMaxAmps - adcAmpsOffset) * adcToAmps;        //最大電流 = (最大電流 - 停止時候的電流) * 轉換公式


  454.     if (runMode == SERVO_MODE)
  455.         {
  456.                 //伺服模式
  457.                 fetUpdateServo();
  458.     }
  459.     else
  460.         {
  461.                 runWatchDog();//檢測電調的狀態.做出相應的停機處理
  462.                 runRpm();     //計算RPM,計算PID,設置運行PWM占空比
  463.                 runThrotLim(fetDutyCycle);//計算得到實際PWM占空比.如果有偏差.那么在這里會實時改變PWM的占空比值
  464.     }


  465.         //計算空閑時間百分比 通過串口發送給上位機  沒什么用途
  466.     idlePercent = 100.0f * (idleCounter-oldIdleCounter) * minCycles / totalCycles;
  467. //  空閑時間百分比 = 100 * (本次循環次數 - 上次循環次數) * 最小周期 / 總共周期
  468.     oldIdleCounter = idleCounter;
  469.     totalCycles = 0;


  470.         //處理串口數據 和串口交互使用的
  471.     if (commandMode == CLI_MODE)
  472.                 cliCheck();    //ascii模式
  473.     else
  474.                 binaryCheck(); //二進制模式

  475.     runMilis++;
  476. }

  477. //低電壓中斷
  478. void PVD_IRQHandler(void) {
  479.     // voltage dropping too low
  480.     if (EXTI_GetITStatus(EXTI_Line16) != RESET) {
  481.                 // shut everything down
  482.                 runDisarm(REASON_LOW_VOLTAGE);

  483.                 // turn on both LEDs
  484.                 digitalLo(statusLed);
  485.                 digitalLo(errorLed);

  486.                 EXTI_ClearITPendingBit(EXTI_Line16);
  487.     }
  488. }

  489. void runSetConstants(void) {
  490.     int32_t startupMode = (int)p[STARTUP_MODE];
  491.     float maxCurrent = p[MAX_CURRENT];

  492.         //運行模式
  493.     if (startupMode < 0 || startupMode >= NUM_RUN_MODES)
  494.                 startupMode = 0;

  495.     if (maxCurrent > RUN_MAX_MAX_CURRENT)
  496.                 maxCurrent = RUN_MAX_MAX_CURRENT;
  497.     else if (maxCurrent < RUN_MIN_MAX_CURRENT)
  498.                 maxCurrent = RUN_MIN_MAX_CURRENT;

  499.     runRPMFactor = (1e6f * (float)TIMER_MULT * 120.0f) / (p[MOTOR_POLES] * 6.0f);
  500.     maxCurrentSQRT = sqrtf(maxCurrent);

  501.     p[MOTOR_POLES] = (int)p[MOTOR_POLES];
  502.     p[STARTUP_MODE] = startupMode;
  503.     p[MAX_CURRENT] = maxCurrent;

  504.     // Calculate MAX_THRUST from PWM_RPM_SCALE (which is MAX_RPM) and THRxTERMs
  505.     // Based on "thrust = rpm * a1 + rpm^2 * a2"
  506.     maxThrust = p[PWM_RPM_SCALE] * p[THR1TERM] + p[PWM_RPM_SCALE] * p[PWM_RPM_SCALE] * p[THR2TERM];
  507. }
復制代碼


全部資料51hei下載地址:
原理圖、PCB源文件及BOM.zip (533.82 KB, 下載次數: 932)
相關設計文檔.zip (7.71 MB, 下載次數: 643)
esc32_keil-master.rar (2.99 MB, 下載次數: 703)
ESC32 流程圖.rar (68.45 KB, 下載次數: 612)


評分

參與人數 1黑幣 +12 收起 理由
hzd530 + 12 贊一個!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏63 分享淘帖 頂9 踩
回復

使用道具 舉報

沙發
ID:89050 發表于 2018-7-26 16:54 | 只看該作者
66666666666666厲害了樓主
回復

使用道具 舉報

板凳
ID:303639 發表于 2018-8-26 22:48 來自手機 | 只看該作者
這個電調可以用在航模上嗎?非常不錯的資料
回復

使用道具 舉報

地板
ID:403112 發表于 2018-9-27 12:32 | 只看該作者
感謝 大神無私分享 資源
回復

使用道具 舉報

5#
ID:59980 發表于 2018-10-25 17:15 | 只看該作者
高手在民間啊!強烈支持!
回復

使用道具 舉報

6#
ID:512279 發表于 2019-4-14 23:14 | 只看該作者
感謝大神分享,學習了
回復

使用道具 舉報

7#
ID:58454 發表于 2019-4-15 13:15 | 只看該作者
完整的資料
回復

使用道具 舉報

8#
ID:512855 發表于 2019-4-15 17:08 | 只看該作者
程序很好
回復

使用道具 舉報

9#
ID:343391 發表于 2019-4-17 15:03 | 只看該作者
非常不錯,謝謝分享!!!
回復

使用道具 舉報

10#
ID:523092 發表于 2019-4-27 17:34 | 只看該作者
多謝樓主分享
回復

使用道具 舉報

11#
ID:547404 發表于 2019-5-26 10:56 | 只看該作者
樓主厲害了,這個程序是在什么環境下開發的?
回復

使用道具 舉報

12#
ID:241073 發表于 2019-6-5 13:41 | 只看該作者
下臂MOS接地線如此細   8mil??? 這是在開玩笑嘛!!可靠性未知呀!  
回復

使用道具 舉報

13#
ID:559757 發表于 2019-6-13 18:17 | 只看該作者
精華帖啊,值得收藏
回復

使用道具 舉報

14#
ID:97068 發表于 2019-6-14 10:23 | 只看該作者
真是好資料,新人學習下
回復

使用道具 舉報

15#
ID:302850 發表于 2019-6-16 07:22 來自手機 | 只看該作者
標記下,很棒的資料
回復

使用道具 舉報

16#
ID:171874 發表于 2019-6-21 01:26 | 只看該作者
很好的貼子 學習一下
回復

使用道具 舉報

17#
ID:282095 發表于 2019-6-21 03:54 | 只看該作者
直流無刷電機的資源不錯
回復

使用道具 舉報

18#
ID:416869 發表于 2019-6-24 16:53 | 只看該作者
mark
回復

使用道具 舉報

19#
ID:363244 發表于 2019-6-27 00:02 來自手機 | 只看該作者
大佬大佬,多謝分享
回復

使用道具 舉報

20#
ID:499701 發表于 2019-7-2 08:42 | 只看該作者
樓主厲害了~~~~~
回復

使用道具 舉報

21#
ID:584488 發表于 2019-7-23 16:34 | 只看該作者
大神。真的大神,厲害
回復

使用道具 舉報

22#
ID:318452 發表于 2019-7-23 21:52 | 只看該作者
剛好工作用到
回復

使用道具 舉報

23#
ID:314147 發表于 2019-8-11 10:07 | 只看該作者
好東西
回復

使用道具 舉報

24#
ID:314147 發表于 2019-8-11 10:07 | 只看該作者
很好。板子比較規范。!!!!!!!!!!
回復

使用道具 舉報

25#
ID:259981 發表于 2019-8-12 12:40 | 只看該作者
非常不錯,謝謝分享!!!
回復

使用道具 舉報

26#
ID:343391 發表于 2019-8-14 10:47 | 只看該作者
厲害,謝謝分享!!
回復

使用道具 舉報

27#
ID:441868 發表于 2019-8-14 15:30 | 只看該作者
這個厲害了,期待
回復

使用道具 舉報

28#
ID:482834 發表于 2019-8-14 21:01 | 只看該作者
很強大,感謝分享~~
回復

使用道具 舉報

29#
ID:99177 發表于 2019-8-15 12:07 | 只看該作者
感謝樓主的分享,非常不錯的資料
回復

使用道具 舉報

30#
ID:96079 發表于 2019-8-15 21:27 | 只看該作者
貌似不錯,下載了
回復

使用道具 舉報

31#
ID:76408 發表于 2019-8-30 07:52 | 只看該作者
沒有下載完成,過幾天再下,謝謝樓主
回復

使用道具 舉報

32#
ID:605217 發表于 2019-8-30 09:32 | 只看該作者
STM32無刷電調全套開發資料 支持
回復

使用道具 舉報

33#
ID:607221 發表于 2019-9-4 09:49 | 只看該作者
這個可以刷BL Heli 32 的固件嗎
回復

使用道具 舉報

34#
ID:20672 發表于 2019-9-14 16:23 | 只看該作者
謝謝分享~~~
回復

使用道具 舉報

35#
ID:13282 發表于 2019-9-17 19:36 | 只看該作者
圖文并茂,好料!
回復

使用道具 舉報

36#
ID:625214 發表于 2019-10-16 19:08 | 只看該作者
感謝分享,非常好的資料。就差點幣
回復

使用道具 舉報

37#
ID:96935 發表于 2019-11-28 21:41 | 只看該作者
8往事隨風001 發表于 2019-6-5 13:41
下臂MOS接地線如此細   8mil??? 這是在開玩笑嘛!!可靠性未知呀!

負片處理了
回復

使用道具 舉報

38#
ID:302850 發表于 2019-11-29 00:24 來自手機 | 只看該作者
很棒,mark一下,感覺會用到
回復

使用道具 舉報

39#
ID:414387 發表于 2020-1-2 16:07 | 只看該作者
樓主,單片機程序驗證過沒有啊
回復

使用道具 舉報

40#
ID:123837 發表于 2020-3-7 10:40 | 只看該作者
很不錯,學習了。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美国产日韩一区 | 日韩视频二区 | 久久精品国产亚洲 | 久久久tv | 日韩在线观看网站 | 超碰在线免费av | 丁香六月伊人 | 国产精品久久久久久久久久久免费看 | 精品99久久久久久 | 亚洲国产精品久久久久婷婷老年 | 日韩中文字幕在线视频 | 狠狠干狠狠插 | 午夜成人在线视频 | 欧美三级免费观看 | 97久久久久久久久 | 日韩一区精品 | 亚洲国产成人精品女人久久久野战 | 欧美成年人 | 国产在线小视频 | 能看的av | 一级免费在线视频 | 久久久一二三区 | 成人精品一区 | 色精品视频 | 97国产一区二区精品久久呦 | 操操日| 久夜精品| 九九热精品在线视频 | 91在线影院 | 精品九九 | 91网在线播放| 色视频www在线播放国产人成 | 韩日一区二区三区 | 在线播放一区二区三区 | 日韩中文字幕视频 | 秋霞在线一区 | 国产精品一区一区三区 | 日韩免费一区二区 | 98成人网 | 成年人黄色一级毛片 | 成人久久网 |