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

STM32-CubeMX-实现CAN通讯

[复制链接]
STMCU-管管 发布时间:2020-10-19 13:07
STM32-CubeMX-实现CAN通讯
+ I  u- u6 \1 w" m' \- _/ B, \
% X; I4 {0 X' O$ v2 J
首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:
/ J6 C: K1 y  W$ E3 x$ F% B 11.png
3 Y' M; G( A: t1 _2 s) D2 }    输入CPU型号:
, X6 ^, H' z9 N. q: \ 12.png
: Q  V; r6 R; m; @' e5 y4 I# {    在右下角双击CPU具体型号:! A/ |) @& H0 C: {! z6 x4 T( j
13.png ' c1 t9 {, r9 ]% M2 Z
    稍等片刻会打开如下对话框:# C; b, ?* T- N% U4 G4 V' x
14.png 9 ~- k4 v! ]  E% n8 _/ t+ S0 M; |
    首先要配置系统的调试方式:我们选择SW方式,! O9 |* O8 [" Q8 y& M; f
15.png 8 y% T- @* Z. D
    然后配置晶振源,这里选择的是外部晶振,8M,
+ V6 q9 ]# b7 x6 `6 q( ` 16.png 7 R9 a+ c3 ^$ I7 R0 B- }% ]+ K& Q
    使能看门狗,
" z# z. v4 n& @, u 17.png ! f# H' F, b7 x0 G) B3 t
    使能CAN," c) b5 w+ `7 \0 z7 d) L
18.png ' n& S+ b9 J$ ^  Q
    使能TIM2时钟源,采用内部时钟,4 N- V' p9 o- k
19.png . M: N5 l2 D" N
    配置完成后可以看到单片机管脚已经做了配置。
  f5 Z6 D5 o1 q$ E6 |9 [$ \+ ? 20.png 5 I  q7 W! p5 t% Y! u: W- {
    切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M# q' _& c: h7 Q) C( U) {8 B
21.png
; M& [# K$ e2 A% t" |* H7 `" x    切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。) ]9 O1 D: h, ]$ ^( {! y8 X
22.png ! y) T3 T6 R: x0 P
    配置接收中断。; h  t4 i- \* \) p! u* P# w- _
23.png
# f5 y- t3 a! F5 Z    配置定时器如下为1ms定时器。
% i# g6 |/ M4 v9 Q5 { 24.png 0 `" @8 @; b* C# U7 d  ~
    配置定时器中断6 [! e" ?1 h7 I% I0 _: A8 _
25.png ( {# d8 w5 z  @% f6 F' c
    配置完成后点击保存,然后点击如下按钮,生成代码
3 O9 p) W4 t+ o3 g( ?8 J' g 26.png % L5 \+ b0 n* D6 k$ t
    填写工程名称,路径,编程软件等等0 V. |: J, R) R1 {. {
27.png
# p9 }( C8 U) ?* @: J" c    选择生成代码的方式
- W9 _- X& [3 m0 }; A( V. ` 28.png * Q# ~' ^0 m( f1 F6 p
    等待……
. w5 d- H3 G2 c" @1 g* s0 U: p    之后点击打开项目。代码生成部分完成。' H* `, T, t1 w: w* R" c, |: f
29.png
$ {+ Q; [8 n, d5 C: v. W    添加一些特殊配置和逻辑代码,添加CAN的配置信息函数。  J  D: ]5 j  G7 q
- ]& O* y4 e. k- [

2 A& j9 Q- a+ a+ H+ k' R% N6 A
  1. void Can_Config(void): E: K0 ?" {" R$ x3 U' G' A" y
  2. {# |% c/ h( |; y; j& _* o4 ^  q
  3.   hcan.pTxMsg = &TxMessage;
    ( j  |  ?& a& |6 m/ B2 a
  4.   hcan.pRxMsg = &RxMessage;  [) L- `- X$ \- e

  5. 8 u# B$ c2 X' U& a, d
  6.   /*##-1- Configure CAN1 Transmission Massage #####################################*/) n4 C3 h  {- k
  7.   hcan.pTxMsg->StdId = 0x123;
    $ P* F* m/ f. e# O; T) V- [
  8.   hcan.pTxMsg->RTR = CAN_RTR_DATA;
    0 m' H# q/ D: A
  9.   hcan.pTxMsg->IDE = CAN_ID_STD;
    % L  K, Q4 d* i; p
  10.   hcan.pTxMsg->DLC = 8;- w- W/ v- z8 V& r
  11. * u3 I* ?2 `) @7 S
  12.   /*##-2- Configure the CAN1 Filter ###########################################*/6 z: R9 m8 s+ N) m! _# X) Q
  13.   sFilterConfig.FilterNumber = 0;/ E5 ^# [3 v% n# K, f4 v
  14.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    * f' n, ~" L. M: c7 D& e
  15.   sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
    5 X2 C, x7 {1 m6 y1 p7 @; D. m! }0 t
  16.   sFilterConfig.FilterIdHigh = 0;
    2 c* z& O. V$ J9 _
  17.   sFilterConfig.FilterIdLow = 0;  @7 O  ~/ i6 F: F: j* ]" U
  18.   sFilterConfig.FilterMaskIdHigh = 0;
      H# ~: \) d' b7 U
  19.   sFilterConfig.FilterMaskIdLow = 0;
    ' b6 ]1 ?# @1 ]: I. K
  20.   sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;2 M& A6 ^, Q4 N
  21.   sFilterConfig.FilterActivation = ENABLE;, T+ o' L  ]' C5 ^1 d" D
  22.   sFilterConfig.BankNumber = 14;
    $ y7 c9 ^; V' X+ e$ F5 g
  23.   HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);" w( E2 a6 Z+ U
  24. }
复制代码

8 D4 W9 g5 d" e

* ^  n& J1 P( {$ Y( G
% S" [/ c. J3 b7 `

5 Z) I, P- A2 S! J0 t% x1 J在Main函数中while(1)之前调用一下即可,添加定时器启动函数:
' ^5 d% i3 T4 n
4 o! i6 g/ U. A( `
' F+ N  @& H2 t2 N$ ~: V7 O4 o: ?. Y
  1. HAL_TIM_Base_Start_IT(&htim2);
复制代码

+ ~- ^& d. d, Z/ _$ V7 N

; s/ x% s" R2 y( F3 yCAN接收中断启动函数:7 Z! r& Y% L2 I0 c$ O) A

; X$ ?  C6 N; k0 F) E
8 \3 V1 s( f# F( c" ?% g6 U; P$ l! y
  1. ( V! n0 I- d: u" V; `
  2. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);( r6 g& I8 W3 g3 k( s& P( x! Y9 \- @
  3. /* USER CODE BEGIN 2 */- [/ {3 A: R& k/ y) ^8 ?

  4. & ^/ v% x* f7 u
  5. Can_Config();                        //Can配置信息
    7 [7 J/ J4 [8 k5 S5 ~. z7 t) t/ x
  6. HAL_TIM_Base_Start_IT(&htim2);       //定时器启动
    . n3 q( v6 e  ^6 J( ?4 e: M) {: m
  7. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断
    & Y% J; B$ a5 `7 q( F% p
  8. * |& t# c" c( L7 F! l, g6 R
  9.   /* USER CODE END 2 */
复制代码

" ?5 D- c9 [( C/ W( {

4 H- P6 I) ^% q* P4 R 打开stm32f1xx_it.c文件,找到如下函数,添加接收中断启动函数:
: }% M" V" s3 R: B; Q8 s
! f+ L( f/ [$ s! M7 _: T  t

  {/ q- r, H2 X, p- ^8 N) p. v
  1. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
复制代码
* k4 R/ V) e" u/ X
6 k0 }4 q$ i! T$ s
注意:接收中断启动函数使能一次只进一次中断,所以中断退出前要再次使能。
8 n$ ]1 z8 K; m& c- _2 }( q; U* a2 i% e& N; ^
+ T* E  A4 X% ?/ H

  1. , ~* @4 W0 y* R7 `( ~5 n( t( M) N
  2. void USB_LP_CAN1_RX0_IRQHandler(void)! B; S/ q, V+ o6 n7 N7 i
  3. {
    4 l8 \+ H% r: O1 H: D) \- z" K
  4.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */; A' {# F+ I) f7 Z) `8 |, P+ r: Q* D

  5. / i$ i9 n& E: W3 C6 D. z2 a
  6.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
    9 E' r, j/ `( P" h* t/ Y
  7.   HAL_CAN_IRQHandler(&hcan);4 I; G2 G+ H& L2 J, m  v; w
  8.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */& \9 L$ r) V7 b1 K
  9.   HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ7 P5 p4 L& \8 [3 L
  10.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */& R" q: e# `3 m+ N) x% w5 v
  11. }
复制代码

6 {8 Z8 k) L7 o1 c; W7 {! Z, j
7 C  Y* i0 O; G, u& T
添加CAN接收服务函数:8 C- \; C0 i7 C% ~6 j( y

  i: x9 G2 F$ v% D0 w+ ]9 C

0 N; A) y0 [5 q3 f3 ?
  1. HAL_CAN_RxCpltCallback
复制代码
: }, x+ D# E/ @/ `7 {* W, d

. H7 n/ b! R0 I  说明:该函数在stm32f1xx_hal_can.c文件中已经有定义,它的定义方式如下:& }) Y% ^- m: Q0 a+ X' [) f
1 I; E# _) R6 X' C) J( P
0 V; g5 x8 L1 U: x7 p
  1. __weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
复制代码

* V/ D( [9 Q5 W8 `. [& J
5 h5 p, W9 _7 q) B5 _( U
函数前面的__weak关键字意思是如果有同样的定义,先执行没有__weak关键字的函数,所以当我们定义了HAL_CAN_RxCpltCallback函数后,编译器会先编译我们定义的函数,而忽略系统定义的该函数。当我们没有定义该函数时,系统会编译带有__weak关键字的函数。, x2 T% o2 ?0 p9 s% E% x+ y, C

7 g, B! t5 p8 c; C2 L0 D
: z& Y1 o  v# o' A: {" j
  1. 3 k5 [8 S# u9 i8 E0 L8 y& M
  2. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)
    # E* I" T* o6 Z+ D& W. B
  3. {+ M5 W, |* H6 P6 B% ^
  4.     unsigned short int speed;
    $ b* S1 j3 e  }) [4 `5 h" n
  5.     switch(hcan->pRxMsg->StdId)2 i) I" D( R2 K5 T# z) }, C+ U. C
  6.     {//根据ID处理数据
    " P* c; D! B* J) r5 X: P
  7.         case 0x123://
    & s6 ~! A6 K. y/ B- i9 _" j& J7 T0 M
  8.         /*在此添加数据处理逻辑*/  K1 H8 p$ R/ @2 m3 H& m
  9.         break;
    , ~$ ^5 ]- }# l1 t
  10.         default:
    ( B' ^) ^8 B# c6 {+ |7 L, d
  11.         break;" L8 b. S) D5 t) ?7 Y5 B
  12.      }
    ! D3 m3 C7 V3 |9 A- J0 c0 c" P; y
  13. }
复制代码
# s- P; V# {  E
9 C* h8 k  k2 X* U, M
添加CAN发送函数:9 n3 ^# C0 o0 _9 u

6 A1 S9 Z5 u9 g+ \% i
  e7 k" E" n$ w1 V2 M, w5 ?8 {
  1. /* USER CODE BEGIN WHILE */- L! L% b! p4 T3 ?9 u) L
  2.   while (1)' @- [5 P' q" |8 H2 k$ ^( n3 c
  3.   {
      J6 ^- M- l/ Q+ {% d
  4.         HAL_IWDG_Refresh(&hiwdg); //喂狗函数
    8 X# S# X4 L6 h  {8 }* S

  5. / F: g: u8 r" L0 @8 }  O
  6.         if(Can_Trans_Timer == 0)
      x* F: `: c" Y/ {) B; p% f
  7.         {//每100ms发送一次数据7 W  \" Z8 z9 \
  8.             Can_Trans_Timer = 100;
    & M! M" R7 y) O9 V( |/ a
  9. * R6 s+ x7 W% k. G- ^8 i
  10. 6 h  J- R% e2 P- b7 U) V
  11.             hcan.pTxMsg->StdId = 0x123;
    ' d6 D: x4 V" N# r. ~$ R

  12. 5 X" q" f& V9 A7 I
  13.             hcan.pTxMsg->Data[0] = 'C';- Z& h1 C( y4 y/ |
  14.             hcan.pTxMsg->Data[1] = 'A';- B3 m' h$ u* Z- u5 Y+ \* o
  15.             hcan.pTxMsg->Data[2] = 'N';# s9 H3 V$ M0 `* ]( ~8 Y$ F
  16.             hcan.pTxMsg->Data[3] = ' ';
    ; @+ F$ f2 z+ z: R/ Y
  17.             hcan.pTxMsg->Data[4] = 'T';
    . L6 L" d! E3 }2 B! o+ z4 D
  18.             hcan.pTxMsg->Data[5] = 'E';
    0 ]: o; P2 T- r: a4 ^' h6 X' ^  }
  19.             hcan.pTxMsg->Data[6] = 'S';, h( a. l6 m% m0 ^1 w
  20.             hcan.pTxMsg->Data[7] = 'T';# z6 N1 L+ ~* m# S
  21. 1 o2 W4 `/ y( V3 Z
  22. + I, p0 O1 m7 q) d1 q
  23.             HAL_CAN_Transmit(&hcan, 200);//发送一帧数据
    4 q+ Y8 Y+ E8 D1 X$ Y/ _7 [
  24.         }
    5 C5 G2 I% Y( D
  25.     }5 d8 \7 r  a7 j1 f! C( r
  26.   /* USER CODE END WHILE */
复制代码
- S, F1 ]7 `, T3 [. c" B3 u
* T' K: _% g9 Q+ V1 G# ~7 j
在定时器函数中添加定时器代码:7 V- f  ^0 ~& m$ E- T+ Y
+ @7 A7 e9 O0 |, q, T! T5 e1 h* K
( z2 ~+ m& }0 s; A7 O
  1. . q5 S" q" D4 D, U5 d
  2. void TIM2_IRQHandler(void)
    ! y0 W% b) \) E' |  x. ~4 v( R
  3. {7 f3 y: T2 ^" f/ \; \
  4.   /* USER CODE BEGIN TIM2_IRQn 0 */
    ' q( r( r. a) v/ M
  5.   if(Can_Trans_Timer > 0)          Can_Trans_Timer--;! l9 s7 C  m7 @3 l2 m& `
  6.   /* USER CODE END TIM2_IRQn 0 */$ G, J8 e8 e: t
  7.   HAL_TIM_IRQHandler(&htim2);0 z& Q5 J) U8 w# u9 ?1 ]
  8.   /* USER CODE BEGIN TIM2_IRQn 1 */; A+ p  _) e' N$ W9 O

  9. * S+ ?, o2 Q' j2 ?( o. @  ^

  10. - @" U+ q( o0 V& m2 p: C9 z3 \: Q, P3 r) Q
  11.   /* USER CODE END TIM2_IRQn 1 */
      ^2 }) I# ~* J4 h
  12. }
复制代码
  r$ Z1 A( J, B( q" U9 Q' U
6 X0 S5 e+ C% s  n7 Z& g- K
说明:在往工程中添加代码时要注意,不要任意往里面添加代码,要在注释着USER CODE BEGIN的地方添加代码,这样在重新生成代码时才不至于将已经写好的代码覆盖掉,如下
/ m5 l6 O, L, q& _2 X6 L. E. e$ z- {8 {* T6 v. E0 X

4 l8 I. y" G. D" Y
  1. ; i) J& X( p  C. ?& A
  2. /* USER CODE BEGIN Includes */
复制代码

1 E+ f7 {. `# @( `9 N; r# |

  g0 L, t8 S, @0 C
4 n, N  j5 d4 [% i( J/ }, K, i* d1 ~. `7 x% W- ^
: l, a4 q( |: c$ p' {- c- D

  j1 l3 m  F  @* |) F
2 _  a" p7 F4 ^% b2 ]' K! ^0 C
* e/ @  P* H7 ~) a

. Z- ^5 S7 D' d- k1 _: m0 L' V+ w1 q, o1 Z2 i
7 i7 L. m. g6 T! L
% C4 A- q( K, r: ]" {

1 y$ \; C3 ?4 A+ W: M* T9 n# x  [9 O/ w: R
收藏 3 评论1 发布时间:2020-10-19 13:07

举报

1个回答
g921002 回答时间:2020-10-20 22:50:40
新版的HAL已經不是這樣寫了。
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版