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

STM32-CubeMX-实现CAN通讯

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

! Y- R# p  {) C, _/ r4 _" `
7 n; b- r7 x9 O+ \' _2 R0 U
首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:* E: ]4 M- S' y5 ]4 d5 H0 ^( Z
11.png
  F- C, ]& C" G0 M$ L. P" q    输入CPU型号:
2 d( a" B) c" C7 h1 ` 12.png
8 c, E+ P7 o" v    在右下角双击CPU具体型号:
1 d' Q. q- _% P# g+ I 13.png % W. @& ~) N; G# v  s7 m1 W# E3 @: w
    稍等片刻会打开如下对话框:7 [( x0 o* Y2 b9 [1 S
14.png 1 W2 I' B& t& j$ a
    首先要配置系统的调试方式:我们选择SW方式," j' h2 U' y0 d3 F; u* n/ J
15.png 3 k( V$ C% j) G4 g, [
    然后配置晶振源,这里选择的是外部晶振,8M,- t2 W0 P  {! p* Q/ s+ b
16.png . B! K- U  z5 e
    使能看门狗,
* q, L/ ]8 l8 O3 N 17.png
6 B4 q! M" d" [5 n. i; w; ~    使能CAN,
$ F8 D5 f. ^+ A/ c1 s3 f* ? 18.png 6 C0 \9 a/ A' v4 {6 S
    使能TIM2时钟源,采用内部时钟,6 q9 J# e8 l6 g: z; ]7 x) v4 q
19.png ' e! K) v) ]1 \+ Y6 X
    配置完成后可以看到单片机管脚已经做了配置。+ D7 }' s, @1 u& w
20.png
% m- i: k7 B  n5 Y  n4 X- d    切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M- Q8 `9 W0 L' p( x! H
21.png & U* H( p" o6 K  h
    切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。) L+ u; }1 O$ G) q8 t( K/ k5 I
22.png
6 |+ Y9 C9 V$ Q1 `6 Q9 _2 {    配置接收中断。
7 J/ m" k6 R8 m& ? 23.png
9 K- K' @0 o, H  O% e8 {: l) I    配置定时器如下为1ms定时器。
" W) W! C/ x4 f  B7 @' P2 m# |& {3 A, } 24.png
$ ?4 Y3 J% G' t" x0 G* U. \    配置定时器中断+ R+ i) G9 ]8 g: v$ ~- R( t
25.png
. C1 ~2 h" |& \9 T: G$ J# F    配置完成后点击保存,然后点击如下按钮,生成代码" |1 T5 s2 X( ~- J0 x9 @: D
26.png
0 u; I/ A6 }) w* y* l+ t( ~7 D    填写工程名称,路径,编程软件等等' J$ _8 q& P/ Q* r1 f# J
27.png 0 J: A2 c/ i- {" w$ o
    选择生成代码的方式
4 C/ u- s2 ?: U 28.png + d! M6 e6 l3 M' y! d& g
    等待……& S# b# X/ z3 l. s& u
    之后点击打开项目。代码生成部分完成。
3 Q2 Z: C9 Z( A9 _4 G4 o, C+ T7 Q 29.png " j- h+ r/ o% r/ s) K
    添加一些特殊配置和逻辑代码,添加CAN的配置信息函数。
( G  F2 p7 T/ J  A3 e  i
+ |, @; R! m8 c& E' K6 X5 }" D
2 W9 O* Z: s: e0 K7 E* c+ q
  1. void Can_Config(void)% A, a- Y5 h; h3 K
  2. {
    ! ~7 _7 t) K4 ]7 l+ u# l8 b9 C5 j
  3.   hcan.pTxMsg = &TxMessage;7 {3 z# b6 {1 b/ C5 p7 n9 e
  4.   hcan.pRxMsg = &RxMessage;5 L& D0 c7 j$ ~
  5. 2 f  {( Y" w: z, ?
  6.   /*##-1- Configure CAN1 Transmission Massage #####################################*/
    / |/ s' Z2 I3 w7 D) G) T9 w
  7.   hcan.pTxMsg->StdId = 0x123;, C' c/ O: W/ p3 x
  8.   hcan.pTxMsg->RTR = CAN_RTR_DATA;! O% w! ?1 h( x2 r5 H
  9.   hcan.pTxMsg->IDE = CAN_ID_STD;
    % Q& Q, `% S  H
  10.   hcan.pTxMsg->DLC = 8;) I" J. R% b: \% f
  11. % _4 o8 I- c8 J6 r' |3 M  n
  12.   /*##-2- Configure the CAN1 Filter ###########################################*/% ~: l; ~2 T; Z  S( _9 V5 p6 U" L
  13.   sFilterConfig.FilterNumber = 0;* n. P4 P* s$ Y9 s
  14.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;, A* s8 b6 t( q% ?, T& }
  15.   sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;! K5 @2 A% T. L
  16.   sFilterConfig.FilterIdHigh = 0;
    . r" M: E' z( g
  17.   sFilterConfig.FilterIdLow = 0;
    & i! Q4 F; V; Y  t/ Q1 Y
  18.   sFilterConfig.FilterMaskIdHigh = 0;
    + l& S* ?" M" {0 h- y) j
  19.   sFilterConfig.FilterMaskIdLow = 0;
    $ F/ `7 S3 J' K; m- ]
  20.   sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;
    3 {  t0 B4 T$ b* D/ c2 C
  21.   sFilterConfig.FilterActivation = ENABLE;
    $ P4 L1 Y( V' L2 |) F3 y
  22.   sFilterConfig.BankNumber = 14;& a- p  U: u% ]# {/ u( P
  23.   HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
    * I( l$ K1 J; _; e+ @) h3 @: \# I
  24. }
复制代码

* }; b+ \. l0 l% M0 |7 |4 N7 R

  ?( m: d7 ~( ~" d$ p7 L4 D) f+ K3 y7 H  r& l9 F, U9 N- b
2 y7 U9 N7 l; A
在Main函数中while(1)之前调用一下即可,添加定时器启动函数:
! ^+ v, g, }" x8 w' {+ B" V5 a# ]) ~

! P) N' C5 r8 r2 b
  1. HAL_TIM_Base_Start_IT(&htim2);
复制代码

' r* z! B( t6 a8 i7 |( ^

- o8 O: @* i5 G$ c: L7 u! fCAN接收中断启动函数:
2 {; r) a: j( o3 l
# w4 ?0 e& R; l

6 @4 C( b1 `9 j: h) g
  1. " i( i( _2 P! j& k1 Q
  2. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
    5 g. E* F) ~  P- W) A* N
  3. /* USER CODE BEGIN 2 */
    7 r0 _8 j; S- Z3 e3 L
  4. # a8 l0 ]8 Q2 d2 `6 p" H4 J/ N. g
  5. Can_Config();                        //Can配置信息  ?' H9 w# z9 D) J
  6. HAL_TIM_Base_Start_IT(&htim2);       //定时器启动6 K! ?& L2 [( @, G$ d. N! S
  7. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断
    ; E6 i3 o3 p' C9 y
  8. 4 X' P: V. k! o3 f6 I
  9.   /* USER CODE END 2 */
复制代码
' x9 A. S' R1 ?8 G6 H7 Y

& o# C! Y$ Y+ f" ?# _ 打开stm32f1xx_it.c文件,找到如下函数,添加接收中断启动函数:* l+ Z: k- D6 z! P( V0 q$ J, I/ g
9 X; ~+ ~$ S' P0 \& s* ^  _/ U2 e

5 Y+ S# e1 i( m1 S  J) S
  1. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
复制代码

4 v* u' p; {8 k  N
' D  R: m6 d# x, B. E
注意:接收中断启动函数使能一次只进一次中断,所以中断退出前要再次使能。1 W. `1 O% m4 H( {8 U; R- ?/ J
" A; y/ x% L" g( q
* G# s& G. C6 W, t* o
  1. 2 R( @8 C. M" U- N
  2. void USB_LP_CAN1_RX0_IRQHandler(void)7 C% H5 ]2 u9 V# _! E" i; _9 A
  3. {6 J* Y6 F1 t/ V, L8 B% E
  4.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */6 P' z  i2 m* ]0 Q

  5. * o2 s+ q+ d% K0 ^6 [% W! m
  6.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */5 K  W. X* [  R+ U2 R
  7.   HAL_CAN_IRQHandler(&hcan);% E+ s' m( ?; U, o) g6 w
  8.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */: D, @, v7 v1 Y3 j; N6 ?
  9.   HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ9 S5 z1 `, g2 c8 j$ X; H
  10.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */
    2 W* z& a9 C: E# p2 h9 F
  11. }
复制代码
, A3 _7 j' Z8 e- @  T* T& K6 X/ E

& `& q. r! r. x& v9 ^添加CAN接收服务函数:
, q  b/ \* l6 K2 A2 k2 e
! h& H( N; y8 y' y

' R8 |: [6 A9 l
  1. HAL_CAN_RxCpltCallback
复制代码
$ ^/ o1 V+ J3 A" J

2 U' d9 l: e+ c4 g- V6 a5 J3 l3 [  说明:该函数在stm32f1xx_hal_can.c文件中已经有定义,它的定义方式如下:3 C( V2 B- C0 R: E- o& m3 ]
4 }- S7 u% r* |* m7 B3 _9 j
5 t: j0 M- C; J8 y- {
  1. __weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
复制代码
; y+ s9 @/ J( X  ^' {0 k3 Y8 n
2 k/ u* u! U. B+ l/ W2 C6 i
函数前面的__weak关键字意思是如果有同样的定义,先执行没有__weak关键字的函数,所以当我们定义了HAL_CAN_RxCpltCallback函数后,编译器会先编译我们定义的函数,而忽略系统定义的该函数。当我们没有定义该函数时,系统会编译带有__weak关键字的函数。* s9 j5 z. \% D% U7 v- d7 w

0 ?! r+ u- H$ p; t- ^* G

" V1 I( G0 E2 B) V5 @+ H: o
  1. : y$ @( L% H6 W+ f% r
  2. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)) |7 Q+ V% c" i7 I1 o) a6 y5 c
  3. {" Y6 w1 T% X8 B
  4.     unsigned short int speed;2 O8 Z" S" u5 e4 F: t8 X
  5.     switch(hcan->pRxMsg->StdId)7 j7 q6 d9 Q% l
  6.     {//根据ID处理数据
    6 \& S6 M/ s& E
  7.         case 0x123://
    0 b9 e( Z/ Z' T- y( l8 \
  8.         /*在此添加数据处理逻辑*/, f3 V4 n1 T; W
  9.         break;5 g' N( t' B3 P$ X2 a9 k
  10.         default:% P$ f: g( W9 H
  11.         break;# x& G# R9 N' r( I/ s
  12.      }, i- L* H, j8 h+ W3 P
  13. }
复制代码

& a4 d5 x1 k: u
, y- U; y: S' u7 V
添加CAN发送函数:+ l. k9 l& y& N9 {
/ Z4 `7 P7 |( {3 i$ c' F0 s

* j3 H; j' V* R- n/ D( J& s2 i
  1. /* USER CODE BEGIN WHILE */
    5 p! a3 n1 G+ v, x; l( l
  2.   while (1)
    : z1 E# L* r4 W1 T8 Z3 j
  3.   {: u5 j0 ?6 @3 \% i; U( _
  4.         HAL_IWDG_Refresh(&hiwdg); //喂狗函数0 [0 J6 [% t% k& E
  5. 9 I: U$ |2 C+ b2 U& o& L# i
  6.         if(Can_Trans_Timer == 0)
    7 v- {0 t* {* P9 e6 o$ q5 c, p7 B: h
  7.         {//每100ms发送一次数据$ a+ C, ]# z& g
  8.             Can_Trans_Timer = 100;' m8 w! Y. d$ B* G9 ?# g+ t

  9. 5 U: \7 _9 E3 g& o

  10. $ W( m: m: V# S6 Q
  11.             hcan.pTxMsg->StdId = 0x123;
    $ B' ^4 t4 R. s  x7 |8 ]" K0 @6 C
  12. 8 J, w, W- J6 A, O* a
  13.             hcan.pTxMsg->Data[0] = 'C';
    / j" B+ S5 H7 c& b
  14.             hcan.pTxMsg->Data[1] = 'A';
    3 Z0 o4 P. R7 D) H& o- `
  15.             hcan.pTxMsg->Data[2] = 'N';
    ( o. o; Y7 W+ S7 U, A  c
  16.             hcan.pTxMsg->Data[3] = ' ';
    + v2 o! B3 ^% s. g, I
  17.             hcan.pTxMsg->Data[4] = 'T';
    ( @: Q- P4 L6 ~. L# X' S9 y, f
  18.             hcan.pTxMsg->Data[5] = 'E';
    9 N8 m9 `5 ?9 y% F  h. s4 ^
  19.             hcan.pTxMsg->Data[6] = 'S';
    - w9 J/ G) e. ]; g" W" Y8 g) w9 N
  20.             hcan.pTxMsg->Data[7] = 'T';5 s, g& g) K1 w% T! H0 Q( C. [

  21. ( v+ G5 S* C" J$ Y8 p. ]

  22. ' \9 v, }. C% W8 j* l  @0 M
  23.             HAL_CAN_Transmit(&hcan, 200);//发送一帧数据7 @) {* {( c; O4 c% K# j
  24.         }
    , `& ~3 b0 v) x" N3 J6 I
  25.     }
    ; T* t0 ]% A/ v% }1 w
  26.   /* USER CODE END WHILE */
复制代码
2 u: W. s: U; P- t; g
+ Z9 Y+ t" O# Q  ?. Y2 |- k9 F: v
在定时器函数中添加定时器代码:& J$ Z5 l$ o+ O: x0 i/ U& Z
) H8 [! v& D) u- b5 _& t% J
0 Y' f" A3 W1 S

  1. - [  f) x$ Y: g( c& u( m
  2. void TIM2_IRQHandler(void)# B' X2 y8 t  j! n9 q7 S$ d- F
  3. {* ]: E. ?) f- `5 z; g+ t8 J7 g
  4.   /* USER CODE BEGIN TIM2_IRQn 0 */% n+ i: B, O- R! G) ?6 Q) ^' f
  5.   if(Can_Trans_Timer > 0)          Can_Trans_Timer--;
    9 b) @# S% h) H% [, u4 l
  6.   /* USER CODE END TIM2_IRQn 0 *// n' s3 y3 l# i8 Z, P
  7.   HAL_TIM_IRQHandler(&htim2);
    % a: Q# {/ L1 }/ M4 H
  8.   /* USER CODE BEGIN TIM2_IRQn 1 */+ H5 s9 h. E$ Y; B2 t

  9. * i$ i6 C1 }& S) f3 g

  10. / m7 h! z# z7 g
  11.   /* USER CODE END TIM2_IRQn 1 */
      @# ?, D  z! w8 U+ U* l
  12. }
复制代码
. q: E& ?! I6 ]1 a% _/ W" c9 d/ c

' y9 o! V6 O* F, C, F* z 说明:在往工程中添加代码时要注意,不要任意往里面添加代码,要在注释着USER CODE BEGIN的地方添加代码,这样在重新生成代码时才不至于将已经写好的代码覆盖掉,如下
1 l4 V! l# n; w0 l/ l( x' L' d  r
# y' D$ l! S0 C+ d" A1 R; Z( k& e; a

  1. 6 T! j( H4 E- d# L
  2. /* USER CODE BEGIN Includes */
复制代码
# B3 a, N: }. v, e" q- n8 q

& j9 V2 n7 _/ `+ c! F
9 a! ~9 h) z1 K& d0 q& ]" S; e# O( w$ E( K: h, g
; `' }5 ?. f5 F  E! H9 i
6 c* s# v6 C& x8 q, c$ W5 G7 L+ {

% U, ~9 M0 v' k* H# o- [: \" J% ]( B! }1 q+ f& W' m

7 g, S& k$ e' X3 n, z# Y7 K# R4 R) W! m  ]* @. Z

( ]# n( T$ E. I& m* _/ o. L6 x/ f7 `
# e  b( x$ D3 G+ G. y) w
; k3 X/ j/ s/ l0 ~+ E7 K) B
  l, L2 `# A3 K/ W
赞 收藏 3 评论1 发布时间:2020-10-19 13:07

举报

1个回答
g921002 回答时间:2020-10-20 22:50:40
新版的HAL已經不是這樣寫了。

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版