本帖最后由 RuiJack 于 2017-8-30 21:22 编辑
/ q2 r5 F9 t0 \% ~
, }4 {5 f2 @* {$ P+ u2 e( i 此次培训的视频和工具大家都差不多能介绍的都介绍了诶,我们还可以怎么玩玩?
1 E' y; E, { e3 r 好像之前一直想把四轴用的电调也做来玩玩,但又不会电机控制咧。这次好像可以捡个便宜,用ST的库来仿照做一个?7 {, J% v8 ~( R5 R, c
: b1 T* I; W, n1 O
那么,初步想法是这样的 -> 原来的工程 + PWM捕获 = 简易电调。$ J |! ^8 H: W6 _0 I
连工程都用原来的,可是懒到家了。1 d7 L& k( `& T; _" H
好了,首先来看看可用的资源。nucleo-F302的板子,电机驱动库SPN7的示例功工程中已经使用了TIM1,TIM2,TIM6,TIM16,额。为了保证尽可能少的改动,来看看还有哪个定时器可以用吧。
) h, j6 j/ _1 J* @: z8 z7 L" l; c9 L+ Y2 w, j+ d
好吧,至少还有两个定时器可供选择,TIM15,TIM17,但是板子上已经有很多已经都有用了,有些也被电机驱动库作为其他功能用了,对照数据手册和nucleo-F302板子的AD PCB功能,来寻找可用的GPIO,这里就省略耗时的过程。来看下其中一个可用的IO3 I( j9 D' w5 N- @: {
) o( |' F8 w( F1 C 是的,你没有看错,这还是UART2的RX引脚,已经被用了,好在可以暂时不用串口2来接收上位机数据,只用于向电脑发送调试数据。对应板子上的插针是# C1 `( q. T4 }
$ }' J3 y, v; ^( A
刚好还有个插针,后面再介绍下这还有个方便测试的好处。# O/ Z: A; j9 d2 f' U5 d* b
( c: A% I4 H4 M4 x 好了,继续正题。接下来开始初始化TIM15 CH2.之前还没有接触过HAL库,很多地方就参考库中的例程来了。
1 O7 t2 K2 [1 \3 Y 首先是GPIO初始化。之所以连这个也提出来,是因为一直在纳闷儿引脚要配置为复用上下拉模式,可能有段时间没用32的定时器捕获模式了,有点忘了。
; r) Q; W6 ]4 ?9 U2 ]4 F$ v# K8 C" O
- GPIO_InitStruct.Pin = GPIO_PIN_3; u8 e* {) U: L Q$ T
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;: K' o' L c2 H% Q% W8 e
- GPIO_InitStruct.Pull = GPIO_PULLDOWN;
, ^0 W0 y1 B8 e - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;. W0 S- l( M) E2 e8 U
- GPIO_InitStruct.Alternate = GPIO_AF9_TIM15;; d4 x$ {- n& o9 b5 q1 }! f
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
4 o# k9 i% a, t# G; Y
复制代码 然后是定时器基本参数的初始化。- htim15.Instance = TIM15;' \* U1 q }4 J9 u8 i3 ~' A6 O
- htim15.Init.Prescaler = 72 - 1;% f+ _" n9 _% d8 c; |( o
- htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
, b$ X0 \; ]) `) I. D* P; |, k* F' K - htim15.Init.Period = 0xFFFF;
q8 E0 k, s, V - htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
5 M5 }4 ^! \! M2 e4 l; @: y - htim15.Init.RepetitionCounter = 0;
M: C; X& u4 {( e - htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
; q. o! j$ U* H% o4 f - if(HAL_TIM_IC_Init(&htim15) != HAL_OK)1 \& S/ b, z, U
- {
3 S( F% Z' Z4 M - BSP_LED_On(LED2); 5 O( }' D& y/ K: P. A6 T
- }
* R8 P) E8 W; J
复制代码 接着是两个定时器通道的配置。这里直接使用了32定时器的PWM输入模式,以前在F1上就用得方便,这里也将两个内部输入通道连接到同一个输入引脚,CH2,通道1用作高电平脉宽采集,通道2用作PWM周期采集。两个通道的配置差异主要是采样边沿,和通道映射。
2 T+ M0 C( u7 |/ v! R7 T3 d' I! Q- sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
, W4 _+ N" O% D$ J# i - sConfigIC.ICFilter = 0;
2 L% n z8 V9 Z9 ?/ L6 v - % B; C; Z& z, e1 X5 f
- sConfigIC.ICPolarity = TIM_ICPOLARITY_FALLING;
$ s0 Z$ v0 Z" S: n/ y# ` - sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
5 s. Z' r+ n6 @; ] - if(HAL_TIM_IC_ConfigChannel(&htim15, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)% x& d6 W) Q0 Q
- {
/ Z! i4 r$ `& A( S - BSP_LED_On(LED2);' {" Z2 M( K7 J7 Y! ~
- }4 A" v2 a% S* }* H, P- D
- 1 p: J: ]4 l- @, M( d2 u
- sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING;7 P" h. {' T5 f( ~
- sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
$ @+ p0 _ M2 r, A+ q - if(HAL_TIM_IC_ConfigChannel(&htim15, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
4 C8 y# Y3 Q9 k, m; K# ^ - {
& B% z8 t5 K1 ], I. g" ^( E, |3 V - BSP_LED_On(LED2);* W, n+ B$ B, F
- }" X5 n' X) z0 y* Z' A
复制代码 这里有一段是输入捕获的配置,跟以前STD库有些区别,还没细看,直接从HAL库例程中拿过来先用着" G7 q4 B7 t# u5 g1 M+ v* y
- sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
' q; ~. a( R, v+ W1 D1 H3 ` - sSlaveConfig.InputTrigger = TIM_TS_TI2FP2;. z' {6 \7 p: t7 r
- sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED;
. g' B" f" u0 `4 x7 ] - sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
, X4 B# _+ A: _3 m; o- g - sSlaveConfig.TriggerFilter = 0;
* p/ {1 J: s% M' H& R - if(HAL_TIM_SlaveConfigSynchronization(&htim15, &sSlaveConfig) != HAL_OK)
X" S' w7 m' S5 H- D' a - {
7 N, M! x# e/ C' h6 K' o - BSP_LED_On(LED2);0 ]; N. a, Q# l! n0 M5 k
- }( ]% r0 q6 f; S; z9 e7 F
复制代码 还有两个通道输入捕获中断的使能
8 A; d: R" G4 G+ E. {6 f- if (HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_2) != HAL_OK)
& y- r3 M* g( M - {
- O) ^0 U) X5 v) X! B - BSP_LED_On(LED2);
" N/ q2 Z6 B8 K) e5 x( \ - Error_Handler();
( C2 B2 a4 M+ E, s% ^ - }
; q T8 W" ?4 T' T1 E1 v
: J( X9 D! x9 `5 ]5 @- if (HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_1) != HAL_OK)
. I4 Q% E' q$ I: [4 d: i - {) W/ t4 F0 {& U( V$ n; w
- BSP_LED_On(LED2);. |( N7 L- g5 {, m
- Error_Handler();
, Y3 F, \; q) g* T9 |9 ^7 d - }
! {3 V6 O" x; B- N0 Y* m2 G3 j
复制代码 我们在按顺序看中断部分,首先是中断向量的使能。这里需要注意的是TIM15的中断和TIM1 BREAK中断是用的同一个中断向量。" \7 I& t. e+ ?9 `+ y) X
- #define TIM15_IRQn TIM1_BRK_TIM15_IRQn9 L. `1 y- S/ ~, \, l) n% h
复制代码 所以最终我们还是得对原有工程进行修改,还是按顺序先来看中断服务函数
( V3 R% E) r* r, a- void TIM1_BRK_TIM15_IRQHandler(void)
( _6 a6 |; U9 ^% _ - {
! l* r! i: k9 @" \/ G9 g, G - / k% P5 S0 {; Z: H1 O. g$ P
- if(__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_BREAK) != RESET)
2 T4 t* x2 V. c& H* m - {
$ t i, s/ o6 `( ~ - MC_StopMotor(); # F+ b( g/ f' j$ x" l) c
- SIXSTEP_parameters.STATUS = OVERCURRENT;
3 w# u/ ]6 q! r3 z \: Z& ~& H - }
. W# E- R8 _5 k( ]- {( { - 7 P; g$ [# H7 S; \
- HAL_TIM_IRQHandler(&htim1);! z1 C- \5 F6 e [3 w5 w
- HAL_TIM_IRQHandler(&htim15);
1 \9 k% C( e4 n, E4 N - }0 V+ Z4 ^# m- q3 Q3 F
复制代码 最后一行就是添加的TIM15中断服务函数入口。3 i: t/ ]- l6 @1 m4 _# w
接下来继续刚才提到需要修改的两个地方,由于HAL库中将中断分类处理进行了封装,这里就不贴这个部分,直接来看需要修改的部分。
* y; }8 r1 l8 n# @/ u4 E 首先是TIM6的计数器溢出中断,这里改好的,对入口参数进行检查,确认是TIM6的溢出中断,才执行原来的函数。同时为TIM15添加溢出中断的回调函数。9 `* I% u t8 W, h& h: Y& N$ y* Q4 J
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
* q. M! c+ W# p+ ?6 @. T - {
2 ~; z& K4 ]7 d7 X# s8 q - if(htim->Instance == TIM6). w- O5 i" W+ l" ?8 m
- {
1 R, P0 u/ l' \* X! c8 n% o% y - MC_TIMx_SixStep_timebase();
4 x" G: d, x! h H" l - }
' B: k" {5 l$ E/ k" k - else if(htim->Instance == TIM15)5 e# @' _9 o/ w0 E3 i% H g; p
- {& P3 V* Z9 `9 x3 {! D: b- x* S% o
- TIM15_PeriodElapsedCallback();
5 A) o8 X% W) l) J - }& h! x3 Y/ u/ L
- 7 i2 ?2 S6 F" c0 J( U$ e5 _
- }
复制代码 话说写到这我突然忘了还有哪个地方的中断服务函数要改,敢信?唉,像我这样思路不清晰的,写代码真是个定时炸弹呀,指不定哪里留了个BUG还记不起来了。 大家待会儿直接对照看工程代码吧。, \* }7 |& @% e
TIM15用到了两个中断,一个是溢出中断,记录溢出次数,另一个是读取捕获到的高电平脉宽值和PWM周期值。前面将定时器时钟设置为1/72主频,这样捕获到的值的单位刚好就是us
$ _: p0 |! m$ G. F% s, o1 e% K- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)5 O' m( x0 N% a# ~" K- c& |
- { 0 \% o: C0 K7 o0 f- e& Y6 R
- if (htim->Instance == TIM15)9 j/ s) v1 Q3 z: f
- {
7 O4 L2 U+ R* K, e, o - if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
. S! ]3 O g U% {" ~1 I: p - {1 q3 ]: ^6 F5 M8 a1 j! h
- capCnt++;" J1 r/ p3 X9 q5 P$ h# O
- % ^4 p! x* v; o
- pulsePeriod = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) + periodCnt * 0xFFFF;' m) u- l0 \* f- H8 Q" X
- pulsePeriod += 1;
* k3 P- B' @8 }0 s* W - periodCnt = 0;
+ C" M. x7 x. c! L$ r. A$ Z- ~ F - pulseWidth = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
: A3 C3 b d0 x. [; g- X - pulseWidth += 1;* u/ w* _% T2 P
0 s1 [! E. [- V g8 I. j- if (pulsePeriod != 0)
3 N7 ~4 ^# ~; g4 Y4 `/ O. | - {
1 j2 Q1 o0 s. C. d {, U* d - uwDutyCycle = (pulseWidth * 100) / pulsePeriod;4 t5 s: ]* z: `) U4 Z
- uwFrequency = ulTmrClk / pulsePeriod;6 p7 X' ]. ?# v7 {# n7 s7 c
- }, H$ p# j% x& ]# L: r
- else
. Q$ n4 U% [2 c1 }' C - {$ Q% S$ v4 J' X3 D; B q
- uwDutyCycle = 0;7 p5 V/ g3 e% N @. q
- uwFrequency = 0;+ n3 h% T9 t7 Q# W* K+ [3 d
- pulsePeriod = 0;- v. F& R7 A" M% K
- pulseWidth = 0;
( k: S* g9 i6 @, y% a$ r' l, m' C - }
) ^# C) G5 t7 s6 J - }
" @7 h# b/ V0 E5 N" z5 ^/ z - }: Q; R* |* D- ^$ z3 i- I. q
- }
0 N3 T% P2 g( f9 Q X
复制代码 好了,主要的两个部分就这些,剩下的就是启动停止电机和设置速度。这部分就不贴吧,直接上传功臣压缩包。
1 E) ~" S& W, J/ _* |" t
' a4 j! V& T( r5 \, O' F 话说我还去移植6步换相的库,浪费的时间都可以熟悉HAL库,然后开始学习FOC库了6 b0 {* N- ^* i% w1 J# ^' r, h
! p" `& M) C8 S# E 今天先上传,改天有时间再来完善,大家看了一起讨论讨论。
) @9 m; c2 n1 o+ m3 x3 [2 l/-------------------------------------------------------------------------------------------------------------------/
, t4 W0 f4 w0 w- F+ @2 c 顺便把测试图片和视频上传了8 V. i) t% z/ v
( Y9 H& n+ g; K# y' M* o
测试视频,使用函数发生器给电调信号,周期20ms,油门对应的脉冲宽度1-2ms。% V, [6 e# `' M6 ^" g" \& o
0 U* ~* X v# ]
) s. M p: ^7 b! ~3 M
# I/ a1 `4 x8 `; w$ h9 L. i
|
http://www.st.com/content/st_com ... t5571_gl_bn_aug2017
9 U* q5 c; Z- K) i- O8 u
workbench界面有改动,电机硬件参数增加了诸如摩擦系数等,看起来速度环下以后PID不用用户改了。
1 ]+ f @2 `2 a0 `
ST其实是有几个版本的ESC的,还有一个是深圳ST做的基于STSPIN32F0的版本,另外说还有一个完整的无人机方案,包括姿态控制和ESC,说是开源的,可能还需要一些时间才能公开。
分享个链接学习下?
PCB工程应该是开源的吧