你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32-CubeMX-实现CAN通讯

[复制链接]
STMCU-管管 发布时间:2020-10-19 13:07
STM32-CubeMX-实现CAN通讯
  Q0 c2 F& j9 ~0 }4 ~5 X9 {+ p
2 R; ?( [# r4 A! [4 N" l+ H
首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:; u. b# |( D: Y9 T# O! z# E2 Y( D
11.png % v# V! J) [3 N/ D" F/ _
    输入CPU型号:1 a. d/ N/ B. n6 ?
12.png ! i4 y! R. z  r
    在右下角双击CPU具体型号:4 J5 ]2 I9 p8 [3 l. k  S% s
13.png & S- `$ c* T$ h& L' w6 p5 A* r: W
    稍等片刻会打开如下对话框:
, U/ k$ A; j% q- U0 Z& B7 O: Q 14.png
3 d& B: G* F, s* a9 r* w    首先要配置系统的调试方式:我们选择SW方式,7 V$ F. S, {  `
15.png
6 }4 {1 |) k4 l9 @. V( N1 C    然后配置晶振源,这里选择的是外部晶振,8M,% ^$ D2 K. x& a
16.png 7 }' h. u7 y* u6 m( {/ C
    使能看门狗,
5 F! B! |2 i5 ], @7 O2 R; F 17.png ' I5 A7 D- y7 [. I6 C! n
    使能CAN,
* h% L3 a. x( z! z2 F, h 18.png ' N6 c. t1 M# N; B5 `
    使能TIM2时钟源,采用内部时钟,! A1 N! F3 c; Q+ U. Z/ V
19.png 7 D, k* ^( v3 V; y( H
    配置完成后可以看到单片机管脚已经做了配置。
4 V' E9 T# Y! C( `$ v% ~3 W& ^& Z2 w+ l 20.png 9 |! i. ~* |+ H  f; d
    切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M
0 D, N8 H2 O! @4 D! M1 W1 N 21.png 4 e. h. ]' ?) M6 u! w
    切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。
" ~) \  {; t/ u. q% ], ?: K8 k 22.png - W0 G# T5 S2 H6 a1 p, F5 B
    配置接收中断。4 ~) ^/ E9 y6 U) f
23.png * O: o9 d' E) ^3 H" D. I
    配置定时器如下为1ms定时器。! }$ u5 D- w% n) h6 n/ ~
24.png ; ]0 X1 d8 s8 f- A- ~' ^& R: Z! f+ h
    配置定时器中断
8 p: G) ^/ `' W. c0 h7 r+ h+ L' a 25.png
# H6 q9 Q& ^& U9 e: \    配置完成后点击保存,然后点击如下按钮,生成代码
7 o) p, Y% P* S3 r% ]2 U 26.png
. F% A3 e+ C  N4 B3 B    填写工程名称,路径,编程软件等等
; [1 \: E6 _3 a% A: P. `" A 27.png 6 z5 F% M5 Q$ z( R1 J  j
    选择生成代码的方式
% M2 S+ T0 S8 I 28.png
+ r* }0 J5 N" ?) Y! q    等待……
+ M. t9 R3 E. C0 X* l. D* X7 {    之后点击打开项目。代码生成部分完成。6 }& `6 |9 f3 P5 a1 ~
29.png + d2 X8 h' p6 V2 ~$ K, B
    添加一些特殊配置和逻辑代码,添加CAN的配置信息函数。
( R% j3 O9 y, e
% s3 v3 l0 }" ^% ~0 f1 G
. y$ K/ A1 P8 c) e7 Y( X7 k7 |( U
  1. void Can_Config(void)
    * k! O$ p/ r8 U7 }8 G2 W
  2. {
    ! J  R- k' Z7 a9 o
  3.   hcan.pTxMsg = &TxMessage;
    " x" N# _9 U4 i/ w# D5 H2 @. A. X+ g" i
  4.   hcan.pRxMsg = &RxMessage;
    & Y  U! Z3 V9 A9 ?# ^, U
  5. 6 `+ {/ z7 l) A# l' a4 N% `( @; P  @
  6.   /*##-1- Configure CAN1 Transmission Massage #####################################*/
    ' |5 R* y' z+ \) I+ ]5 `
  7.   hcan.pTxMsg->StdId = 0x123;, N( I6 E" j& v; C3 o
  8.   hcan.pTxMsg->RTR = CAN_RTR_DATA;1 Q: n/ P1 X, f/ Z6 s
  9.   hcan.pTxMsg->IDE = CAN_ID_STD;9 i5 _& ?( q+ `  C5 E4 y+ x% C- c
  10.   hcan.pTxMsg->DLC = 8;8 S# J% t# J$ |, ~7 Q* Q
  11. 1 L0 f4 e5 L7 p7 f+ n5 ?
  12.   /*##-2- Configure the CAN1 Filter ###########################################*/
    5 [/ r, W8 L1 `9 x1 D
  13.   sFilterConfig.FilterNumber = 0;
    ( P+ U  X/ \/ G% C! a
  14.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;9 P8 c- d/ `$ E3 N  s* A5 [
  15.   sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;/ S) @3 o4 O$ s' k+ @- K9 a3 I" ]2 h
  16.   sFilterConfig.FilterIdHigh = 0;  w" k* {, }! S' M) e, c; v( a( S5 t, D
  17.   sFilterConfig.FilterIdLow = 0;/ e8 r: [* g  y3 G3 D
  18.   sFilterConfig.FilterMaskIdHigh = 0;
    5 y5 ?1 z* H. M( y5 P9 \5 \
  19.   sFilterConfig.FilterMaskIdLow = 0;
    0 I3 `. c, I) u1 d7 Z" m' C
  20.   sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;+ ]9 ?" W  F1 E) q5 A, K. p
  21.   sFilterConfig.FilterActivation = ENABLE;- B" ?& ^6 A' f' u# g
  22.   sFilterConfig.BankNumber = 14;. K! b# k) e. J3 i# T
  23.   HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
    ! T" ]  H# S1 I& X$ S
  24. }
复制代码
, d. k0 }! ?& g- \
' e/ s% c' P/ |: v

( d% W! W1 {% Y
- r3 y$ f0 v0 D% m, z
在Main函数中while(1)之前调用一下即可,添加定时器启动函数:
! z4 |+ [" h: Y% Y1 ]. ^5 y- x" }; B9 f/ D7 w
3 r& v5 ~. K4 V+ x
  1. HAL_TIM_Base_Start_IT(&htim2);
复制代码

& x9 W" O6 m4 P3 @* j, g) X
2 q$ @2 c* v2 K! k
CAN接收中断启动函数:/ `" d8 p1 J% }+ |+ v0 F7 a
/ l- l, E2 Z& v/ O+ R5 n

) u& u8 e( }" ~& F: J

  1. 1 z1 C3 P& R/ r( I  }. a
  2. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
    * I. o1 e: E: ]& i5 X/ `3 c
  3. /* USER CODE BEGIN 2 */7 t/ G8 Z% v, K. E1 {" X
  4. 9 w, h  f. h- k$ w# Q" \
  5. Can_Config();                        //Can配置信息
    9 h9 @2 j3 ?4 T8 O( u+ \
  6. HAL_TIM_Base_Start_IT(&htim2);       //定时器启动
    3 g! N( r5 @$ B5 b0 W/ k5 R
  7. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断
    8 ]( d" ]8 e4 o9 w( ]7 u0 S

  8. 6 d: F. s* u1 B* Q8 C( J
  9.   /* USER CODE END 2 */
复制代码
5 C* l$ H2 w" T( k

) J: o4 L/ X8 Q8 W, |1 @* w 打开stm32f1xx_it.c文件,找到如下函数,添加接收中断启动函数:3 z% W& V: b7 v2 D; b

& Z' z6 B  O: c& q+ O+ D: M6 _

- l; ^3 R; `; t" C* o: D
  1. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
复制代码
# s9 S( L& y. {8 a% z% f% @/ h

% c% P3 C$ ~4 C1 x5 e 注意:接收中断启动函数使能一次只进一次中断,所以中断退出前要再次使能。
: P4 D, v6 \$ V/ }2 R, G' R, I. U  L+ U# f6 n2 v% Z  E

8 ?6 B1 |. S, s& H2 N
  1. 0 W  _  k+ ~5 R( X* u
  2. void USB_LP_CAN1_RX0_IRQHandler(void)/ I# ^, l3 N) o9 `" H
  3. {2 M* X3 @& M# r" S6 W
  4.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */% T4 L% }) s+ q. Z  H4 P# w
  5. 1 i& l) }# c  {
  6.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
    2 ?! b+ h8 f8 d6 f4 q+ u: x
  7.   HAL_CAN_IRQHandler(&hcan);
    - o$ y( y4 I" m+ y8 e# l, z' m
  8.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */
    * g( N6 f% R/ a
  9.   HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ
    7 @3 j" `# ]0 @3 k, j  s
  10.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */6 ]: e3 F6 _6 s
  11. }
复制代码

- R3 S: K/ K: h( \
9 Z5 x6 \+ a6 A' ?# u8 N5 `* x
添加CAN接收服务函数:
9 k+ w( U( K; V0 c: L+ V" p* R' A# Z( Q
& W( d9 A% j+ i/ B+ d9 Y; h, ~
  1. HAL_CAN_RxCpltCallback
复制代码
2 c9 T. z3 v! d/ X+ y
" Q8 t% c3 N$ [9 t- B0 N
  说明:该函数在stm32f1xx_hal_can.c文件中已经有定义,它的定义方式如下:  z4 V* g" `8 k
7 {/ V& Z6 U: O+ }, r, w

; f. K, F' s( f0 P
  1. __weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
复制代码

. }3 q/ N; `! N/ e! }* M' K

# @9 C  v% P3 R函数前面的__weak关键字意思是如果有同样的定义,先执行没有__weak关键字的函数,所以当我们定义了HAL_CAN_RxCpltCallback函数后,编译器会先编译我们定义的函数,而忽略系统定义的该函数。当我们没有定义该函数时,系统会编译带有__weak关键字的函数。; Y- V! r/ b! u5 R3 f

" g: q1 H. ~" ^/ e$ D: z
9 r$ _: e  D! G

  1. $ n3 {, F4 P2 g1 s
  2. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)$ [2 ?7 c7 ^6 f1 K3 O3 z/ m
  3. {
    & `4 t" X  K- A
  4.     unsigned short int speed;! s  D3 e# S- D, q5 r, h/ M0 l
  5.     switch(hcan->pRxMsg->StdId)" C6 [9 `1 F7 {2 H$ n, a- `
  6.     {//根据ID处理数据3 h5 N8 o, K9 F+ \0 z; Q+ Y
  7.         case 0x123://
    % q6 w* _$ p, M8 u# S  a# M) W9 A
  8.         /*在此添加数据处理逻辑*/, q/ q7 M2 K0 I' ~. `* v! ?' n4 @
  9.         break;. }* Q6 f( O1 l/ H0 }  m3 `% f
  10.         default:. f2 ^6 d- o! o/ ^3 Q
  11.         break;) `3 R: g* |; `) m
  12.      }' v' ~6 D# R0 O3 K" U! q2 L' S
  13. }
复制代码
* Y' t, `1 R8 T$ q$ A& ?
0 E5 Q- c6 g% R8 f. e' s& _
添加CAN发送函数:
( d/ r" j6 q: j# d5 W
7 J! Q; W8 Z6 D1 b! i
& ^4 @" o& H4 V0 d4 J6 X; d5 }
  1. /* USER CODE BEGIN WHILE */& S& _2 A3 y  c6 D
  2.   while (1)
    & N, S+ C, ~1 {/ t+ Y! y
  3.   {( d- y3 V! @, r3 H( z' q0 Q/ j8 i
  4.         HAL_IWDG_Refresh(&hiwdg); //喂狗函数/ L+ w; `/ R7 \! h4 {/ @

  5. $ Z! w( U$ o% B: o" C: a
  6.         if(Can_Trans_Timer == 0)2 m. O1 f; h) Z1 S( I; o
  7.         {//每100ms发送一次数据0 W- c5 ~3 p4 w" I3 e6 u# M
  8.             Can_Trans_Timer = 100;
    ( e) \. K+ v* G) a+ i% f
  9. % @( ], b6 E- W( }& J) f% O
  10. % M7 }5 S% V, N6 o; n( j( I9 v+ u
  11.             hcan.pTxMsg->StdId = 0x123;; v- q3 G/ }- N8 U  u' y
  12. . T% p. A6 t' b9 ~9 Z; ~1 v
  13.             hcan.pTxMsg->Data[0] = 'C';, T- k4 n. {4 L4 k8 a& r" A9 n+ O- c" w
  14.             hcan.pTxMsg->Data[1] = 'A';' `% {/ o3 n( d0 X1 i5 l
  15.             hcan.pTxMsg->Data[2] = 'N';& `4 ~# E2 S8 v& z: e. _
  16.             hcan.pTxMsg->Data[3] = ' ';
    ( V, ]* c% q& }4 n# l
  17.             hcan.pTxMsg->Data[4] = 'T';
    7 Q0 X! K: ?6 N
  18.             hcan.pTxMsg->Data[5] = 'E';0 ^/ P7 X* V, g: U" m% i. J" X
  19.             hcan.pTxMsg->Data[6] = 'S';
    7 g9 d$ L5 r" m0 T
  20.             hcan.pTxMsg->Data[7] = 'T';5 Q& ~; y$ \: E7 |, V  C/ L- p% ?4 L

  21. : j! w, y9 P# {( _
  22. 1 i+ F" p. x# ~' R5 i! J- F; f
  23.             HAL_CAN_Transmit(&hcan, 200);//发送一帧数据6 d' T- T7 s8 @2 M6 D
  24.         }. x; n: ~- E) g4 O; s
  25.     }/ ?6 i2 n1 s7 [
  26.   /* USER CODE END WHILE */
复制代码

1 f# w7 M& a" W: I; S

$ [7 X9 D3 l$ z8 ?! C4 S' r& U在定时器函数中添加定时器代码:8 ]& g# \- \" F, C0 U

* v' z: y. h2 V9 q$ w( E4 m2 B1 {; Z
- q2 g) s3 H1 v+ U8 K8 ^4 B; ~

  1. 6 f- b, A$ t6 [- ]! J' ^, H
  2. void TIM2_IRQHandler(void)
    * d/ d; ?% s3 D4 L( ~6 v8 n
  3. {& k$ b8 ~! ~+ m, A( I* U6 h
  4.   /* USER CODE BEGIN TIM2_IRQn 0 */+ ?( N; W! a; `! L; N- X3 U
  5.   if(Can_Trans_Timer > 0)          Can_Trans_Timer--;
    : R% l; J( N* h
  6.   /* USER CODE END TIM2_IRQn 0 */
    4 k' \; T! j2 C2 a% c% i$ R* u* h
  7.   HAL_TIM_IRQHandler(&htim2);
    $ l1 ~8 \% e' x
  8.   /* USER CODE BEGIN TIM2_IRQn 1 */
    8 D* M- }$ }4 Z& z

  9. % k: U: |- O; X( l9 S

  10. / a6 V) ]2 Q7 Y7 i# u) e# @6 N
  11.   /* USER CODE END TIM2_IRQn 1 */2 a! T" ?( x6 R0 A3 G; d
  12. }
复制代码

6 z% V/ f2 c( {1 _5 L2 s

9 v6 G5 L- O! F5 e0 P8 ] 说明:在往工程中添加代码时要注意,不要任意往里面添加代码,要在注释着USER CODE BEGIN的地方添加代码,这样在重新生成代码时才不至于将已经写好的代码覆盖掉,如下( w$ C$ ]7 E& \; N
' ^$ _( ], Y% }# o' T, x! C

0 N' i& n' o/ M5 s5 A+ \
  1. 3 c, Z6 H& P5 D! o: S: R' z
  2. /* USER CODE BEGIN Includes */
复制代码

1 N7 ?2 `2 ?$ H6 ?* ?/ n3 z

( E( S# m, |# k) ^+ T$ k9 n: t" B3 z, a0 x. q

" v" ?4 ~. H: s6 R3 Y

3 y' W1 H5 ?5 P, j" O; G( S: W. M; h9 L% |0 h

2 c# j0 s/ p$ Y& C- Y2 \8 {: [; F1 I( v# u: ?+ ?
; A2 l# p% E' }5 z( C
$ D5 J% [7 I- a

+ h: r0 L: v/ E1 ?. s$ o5 v" ^: r) @: I: Y* b7 F1 G" x9 A
7 M( x3 b4 Q7 I9 x2 N+ A

3 D# I6 C- P( m
收藏 3 评论1 发布时间:2020-10-19 13:07

举报

1个回答
g921002 回答时间:2020-10-20 22:50:40
新版的HAL已經不是這樣寫了。
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版