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

STM32-CubeMX-实现CAN通讯

[复制链接]
STMCU-管管 发布时间:2020-10-19 13:07
STM32-CubeMX-实现CAN通讯

$ |2 }+ K1 n5 _: d: k5 i$ v
/ @  ^# }' W( G+ w. z" d( M" X
首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:
6 B; }  n/ P% L  s: U2 K$ Z* l 11.png : d# h+ N9 H, v3 Q. z; Y" ^
    输入CPU型号:0 b, f6 e5 s+ G7 j. F
12.png ; \: ~/ k$ c4 }
    在右下角双击CPU具体型号:
; m( Z4 W0 n/ T( Q 13.png
0 o8 k" s; A% o/ J) @8 I; @    稍等片刻会打开如下对话框:
+ G: i) Y& }; Q4 D, o9 M, `" S9 Q 14.png ( P- n4 O$ Z8 |) C
    首先要配置系统的调试方式:我们选择SW方式,
: A5 \6 p2 z' Z: {, { 15.png
6 S: g: I% A% l& s! j    然后配置晶振源,这里选择的是外部晶振,8M,* @9 X* P- ?4 v0 a% g
16.png : l: q% _; m6 M
    使能看门狗,
& }1 o: v# c% _# x+ S5 j( X 17.png
* Q0 T/ {4 Z) u9 j$ Z. c+ ?    使能CAN," q8 a; W8 k# d  ^* I5 A* _; ^4 g9 K% e' _
18.png 1 ^# q" M* Z- R
    使能TIM2时钟源,采用内部时钟,9 I8 e  Q, _; Y) F( Z. X. c
19.png - {. J- e: _; g) b! }/ c
    配置完成后可以看到单片机管脚已经做了配置。) a7 x, v5 ?' \) V+ m. I! `  u
20.png
# U$ `% O' I$ M  ^* N    切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M
# o) E( _& E: J9 s! k 21.png 3 ^: H8 Q9 W* a% ?7 L! R
    切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。* A6 ^2 G- y) j; R: n
22.png ! a! t9 t* d8 u+ T
    配置接收中断。
6 g3 q$ Q0 |1 z  j! } 23.png
7 W) `& J4 C3 }; b0 Q! w    配置定时器如下为1ms定时器。6 u* K% [3 S$ _2 G/ e) j% f0 B: `
24.png ; \% q$ v% n- Q0 |& p
    配置定时器中断( h- Z5 a) h3 x- V* l+ p1 i
25.png $ [4 t3 {$ f8 k" B& ?& O/ C
    配置完成后点击保存,然后点击如下按钮,生成代码2 W" D2 _+ D- g' P  w% Q+ y
26.png 7 H  M9 g3 ?- g' H( ~; M3 ^
    填写工程名称,路径,编程软件等等. q# B3 s0 y& U% y6 G) p
27.png ! x% G7 p2 a8 f  \( n' j2 I5 L
    选择生成代码的方式
( }6 F6 {3 z- b 28.png 1 r0 U. K+ L) t/ q, f/ d5 j
    等待……
- B4 }. W) W; E% c) M    之后点击打开项目。代码生成部分完成。
7 k. E3 T7 W" }8 O& N$ J 29.png
6 r0 U/ @$ P4 L: W7 ~' Y. p    添加一些特殊配置和逻辑代码,添加CAN的配置信息函数。# v! \; m3 |  @: L3 L6 A

5 J% H, @) L1 D1 ~/ ^
$ w( p0 R. K% m1 F1 m( [4 p
  1. void Can_Config(void)
    : E: f8 r( J( Q+ I: r! [
  2. {
    . y( f+ w+ _, i: t" F
  3.   hcan.pTxMsg = &TxMessage;" w  f  |) b8 h4 A7 A+ N' X
  4.   hcan.pRxMsg = &RxMessage;
    ' Z% E8 M3 D6 J1 r2 Z

  5. , s9 P) M  e( ^
  6.   /*##-1- Configure CAN1 Transmission Massage #####################################*/
    : S! `* u$ c2 `
  7.   hcan.pTxMsg->StdId = 0x123;& l' `" ~2 L2 ]; P: ?& [3 Y
  8.   hcan.pTxMsg->RTR = CAN_RTR_DATA;
    + r4 S* H% t! L4 P: R
  9.   hcan.pTxMsg->IDE = CAN_ID_STD;9 a2 k% Y" r' h. ^+ q9 h- g
  10.   hcan.pTxMsg->DLC = 8;  I! w+ |1 X! D1 w

  11. ( q5 R3 d  L9 D4 j
  12.   /*##-2- Configure the CAN1 Filter ###########################################*/# F5 c1 p! I0 d& _2 p: |
  13.   sFilterConfig.FilterNumber = 0;
    9 Z& E( V5 E( B4 I$ I
  14.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;; O' _8 Z9 U# _3 L; Y
  15.   sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
    . ^0 B- a9 y! S: u: Q4 i
  16.   sFilterConfig.FilterIdHigh = 0;
    + _% l' ], \. P4 N' d
  17.   sFilterConfig.FilterIdLow = 0;
    ( @/ p  d$ e/ n1 [
  18.   sFilterConfig.FilterMaskIdHigh = 0;
    ) F% k- i/ b+ d9 ?- S0 p
  19.   sFilterConfig.FilterMaskIdLow = 0;* \1 f4 n& M: \" d, Y
  20.   sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;
    & d3 ]) _9 H; q$ K( y" O8 Z
  21.   sFilterConfig.FilterActivation = ENABLE;0 s; g4 c  C8 A( g$ W: N$ E
  22.   sFilterConfig.BankNumber = 14;
    ! j0 h  |- p) D1 T& r$ w
  23.   HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);2 ]3 _* k* J2 Q+ v. p
  24. }
复制代码

! V! ~2 P+ e4 R/ _4 `$ G8 n

+ T  B# g$ W, }  C3 e/ T" w* p  X0 J- Q. T& o9 ^

% o3 |2 h( F& _在Main函数中while(1)之前调用一下即可,添加定时器启动函数:
  \8 N: R/ z! d. l1 h" _0 f! t% f+ u: h+ a3 A7 u8 v
% x) E6 N' [5 P3 P, G
  1. HAL_TIM_Base_Start_IT(&htim2);
复制代码

7 E0 d& {7 J0 K  N; }! y

" N8 J, R8 Y# j5 I/ ICAN接收中断启动函数:6 K9 k' t0 g( ]. O

: _3 c6 V( E! ?3 h: L8 w* W
$ J. c3 `  H# N* s1 P! Z7 I0 l& _
  1. 2 B; \) [& k6 k( L% O' K! V2 c
  2. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);; y. S$ R/ Q% j# N" b  l$ F2 j- t8 `# U
  3. /* USER CODE BEGIN 2 */% g* _6 g& N' ^# e8 a
  4. 9 L# x& B3 T6 i0 Y; R6 W
  5. Can_Config();                        //Can配置信息
    8 E, H- C3 c3 H4 G
  6. HAL_TIM_Base_Start_IT(&htim2);       //定时器启动
    $ b- J) r% z6 T& L
  7. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断! k  C7 |" O3 I4 w- A/ F$ M2 Y% x
  8. 6 ?3 I% R1 b+ ?2 q
  9.   /* USER CODE END 2 */
复制代码
* i$ J  H8 M8 W- P" X# m
8 y; A4 U& {5 ]
打开stm32f1xx_it.c文件,找到如下函数,添加接收中断启动函数:- n9 y, L# x1 W% |3 c$ _

! U: y9 G) b0 B6 b7 O

( B7 {! k7 w; Q  R& S8 h4 y5 w3 j
  1. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
复制代码

* k4 q0 v! ?! K$ P0 Q/ f9 Q

2 H$ ~/ o) n3 i2 m" `+ I6 g 注意:接收中断启动函数使能一次只进一次中断,所以中断退出前要再次使能。
' ]# `* T# c5 ^" l1 i" [. G! z
2 V7 Y7 N& m+ c2 T6 n: \

* ~9 b* s- b9 q) A# H

  1. ' \; k* Q8 K  [: h
  2. void USB_LP_CAN1_RX0_IRQHandler(void)
    2 d+ |6 ?2 r. m6 Q& N
  3. {
    - Z6 p* L+ U, n) z* z! `
  4.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */# l. n; a* b) f3 v9 b) y

  5. 1 n  L2 R" S, z. a# K
  6.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
    " e3 {% y. t9 D7 g0 B$ S' R
  7.   HAL_CAN_IRQHandler(&hcan);4 z* f3 t! m# L, {0 Z
  8.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */
    8 a6 o& L0 T0 N7 ^0 d
  9.   HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ4 P* ~( q) n2 j
  10.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */. _$ q. S8 o' I( N# Z% O+ M- w9 m7 E  f
  11. }
复制代码
, z! W( B5 H' L
1 G5 Y- P& ~' M8 q  B9 u
添加CAN接收服务函数:0 ?0 k: n- n  j  t+ ~* E
; f9 O' k3 c9 K* y  x
9 S3 _0 I2 e& ^, m# r' U& X2 O, Z
  1. HAL_CAN_RxCpltCallback
复制代码

, v: V! C1 b% u/ H; w
! i6 s# E+ Z. V0 H
  说明:该函数在stm32f1xx_hal_can.c文件中已经有定义,它的定义方式如下:
: a7 r( b- h3 ]$ ?4 j& o1 F1 P' }

7 `0 y3 _: Q6 {; c) _
  1. __weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
复制代码
, Y9 h! r$ p/ r( \9 p+ ^
5 }% v! N6 h& w4 ]8 V
函数前面的__weak关键字意思是如果有同样的定义,先执行没有__weak关键字的函数,所以当我们定义了HAL_CAN_RxCpltCallback函数后,编译器会先编译我们定义的函数,而忽略系统定义的该函数。当我们没有定义该函数时,系统会编译带有__weak关键字的函数。( d' R1 R: z) |8 ?) h
- Z& l+ B' }1 S# d0 O, s
1 W6 N( y1 G; o: m5 X5 v6 o
  1. 8 @: e+ d, o0 G/ e+ d
  2. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)' t0 F4 z$ p; k# T9 T- ?; A
  3. {
    ( e5 O9 i; X5 z1 C% ]% @8 X2 }
  4.     unsigned short int speed;0 r$ i1 Q5 f( R2 a) v4 ~6 N1 u
  5.     switch(hcan->pRxMsg->StdId)* }' T, b: b- ?- Y+ P3 `
  6.     {//根据ID处理数据
    2 F9 d2 o, c$ s8 X
  7.         case 0x123://# u1 _: s) E  z( C& b/ n( X4 L
  8.         /*在此添加数据处理逻辑*/( m# Q! q" X0 K, L  d
  9.         break;
    / l3 Y: `+ j- A; F( Z6 d/ i
  10.         default:. b2 O. n% \4 X2 h% ]+ q; z8 B
  11.         break;6 Y& k8 I$ [+ ]6 \
  12.      }7 M' k0 {! C" v. A; `
  13. }
复制代码
, }) J" c# E' V. k. q& j, N" l
& M& d+ O) t7 Z& ?0 G- L, ]: Q2 {
添加CAN发送函数:
1 S" G, x+ |8 Q. h- L
' i" V' c( j4 M  b& M: z- F
4 y6 N1 W' D; {+ `6 x
  1. /* USER CODE BEGIN WHILE */, m+ W* a7 F! W' Y2 G$ c' b; h
  2.   while (1)
    $ U, T3 Z9 X" e+ i4 k! e4 v& ]3 c- ]+ m
  3.   {# ]. [; L) d# G1 [2 R* @7 h
  4.         HAL_IWDG_Refresh(&hiwdg); //喂狗函数
    : _* k0 `. V4 V1 ]: X8 C

  5. + Q: R" y  V$ ~% ~
  6.         if(Can_Trans_Timer == 0); U- V6 `5 Q+ C5 k  F# [0 Q
  7.         {//每100ms发送一次数据
    8 N' u  [- E$ c- {4 t
  8.             Can_Trans_Timer = 100;; y+ a' Z- l* G+ X  I* {

  9. 8 L8 e$ M4 ?8 P' k  ?$ |$ X7 p- c

  10. * ?$ Y: M% ]7 R8 m- j: e
  11.             hcan.pTxMsg->StdId = 0x123;
    ( p5 @; ^9 v3 P2 U: c

  12. / c" l! _" t: g. Y1 X
  13.             hcan.pTxMsg->Data[0] = 'C';
    * x# i" {. ?7 i
  14.             hcan.pTxMsg->Data[1] = 'A';' l3 Y+ A1 e5 c8 n7 m5 g4 f' c
  15.             hcan.pTxMsg->Data[2] = 'N';
    6 n; h1 F! g3 K1 V4 a! _
  16.             hcan.pTxMsg->Data[3] = ' ';8 S& P9 q& d! j; g( k: e
  17.             hcan.pTxMsg->Data[4] = 'T';
    + M" P# o: q0 t4 H
  18.             hcan.pTxMsg->Data[5] = 'E';
    , W7 K# e4 F6 P" V6 c4 \
  19.             hcan.pTxMsg->Data[6] = 'S';
    * p/ [1 h, \+ D2 g" `6 |
  20.             hcan.pTxMsg->Data[7] = 'T';# F# ]: e# a* s* }8 ?
  21. ' F8 ^2 J) A& U2 e
  22. # ~& A! A  ?. O* q4 J- \; }
  23.             HAL_CAN_Transmit(&hcan, 200);//发送一帧数据5 J6 z1 b+ H, ~- X6 [
  24.         }
      E8 ~, C; b% i- [1 k' M/ G1 Z
  25.     }) [& F* }; h! U# z: e
  26.   /* USER CODE END WHILE */
复制代码

& l7 r& c1 S- P* N4 K, }

0 M- T4 k; u2 Y9 }在定时器函数中添加定时器代码:2 m! v1 W  w. H" V
2 g; i% P5 O9 y. X+ j8 X4 _/ o

& n% r0 q* }* D

  1. ) B' A0 w, f% D6 |" n, u
  2. void TIM2_IRQHandler(void)
    4 l8 C& |& z4 a
  3. {
    $ d3 W5 }' T8 ?' ^
  4.   /* USER CODE BEGIN TIM2_IRQn 0 */; p" E2 T: f  k* j
  5.   if(Can_Trans_Timer > 0)          Can_Trans_Timer--;
    5 I6 I. N% R# b* q  z
  6.   /* USER CODE END TIM2_IRQn 0 */, h9 C/ i! }0 [& H2 q
  7.   HAL_TIM_IRQHandler(&htim2);
    $ Z$ z. o1 S3 d# H5 Q7 @, H! b( i
  8.   /* USER CODE BEGIN TIM2_IRQn 1 */8 k# v; b2 F$ y4 J  Z( X

  9. 0 Y0 Z; V6 b6 x# n) j6 h$ j, @$ S8 h
  10.   D! Q2 t" v3 l3 p. i5 h
  11.   /* USER CODE END TIM2_IRQn 1 */3 I) }3 C8 c* o( n& G" |
  12. }
复制代码
' O) @2 x% k, B, @9 |) x( M3 M- n2 z

# D7 x/ o- M' \2 G% J" }/ q 说明:在往工程中添加代码时要注意,不要任意往里面添加代码,要在注释着USER CODE BEGIN的地方添加代码,这样在重新生成代码时才不至于将已经写好的代码覆盖掉,如下
/ d" {& t% H9 k3 W' h9 r5 J! _9 }5 n0 {9 ^' K
+ e6 y6 Q( q0 O

  1. 6 g! y" k' k! b& {/ t4 V. i: K; y8 h
  2. /* USER CODE BEGIN Includes */
复制代码
8 Z, l1 w  y# a4 ?2 {: X

9 L& Y7 {& ?4 o# J+ Q6 J2 G2 j  F- A2 U9 P/ I) h1 Z4 n

! Y- N0 s8 d. V
, P% ^/ ~- p7 l) V2 i, s

0 w9 v3 v4 q  Y4 E, P) k; c/ p
* n! J6 d9 B% z3 ?8 D

0 r" |& r- N. y* m& L
5 u0 N  n4 O" d4 a3 L5 o2 _# @, `
0 i( N% c9 S& k! A& A- L* o
6 [& R4 e7 v* S

7 C& F- d4 S3 c+ u

: F* w; @, Y& @6 ^
7 Y8 W* \% G* i" u5 t
收藏 3 评论1 发布时间:2020-10-19 13:07

举报

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