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

STM32-CubeMX-实现CAN通讯

[复制链接]
STMCU-管管 发布时间:2020-10-19 13:07
STM32-CubeMX-实现CAN通讯
' o$ U9 @7 x% {9 l- Q  ?; g4 r, X

  ~' P, X7 w5 \首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:
5 t( P  C  y! W* Y8 y: Z! C 11.png - g" E: G/ `: w( N4 H" r+ U
    输入CPU型号:
9 g. _  N4 f$ n! \ 12.png
, P5 @' n9 E- l. j    在右下角双击CPU具体型号:' Z" D3 u/ c0 C
13.png 2 @. }8 D8 ?1 K* Y- Q6 l
    稍等片刻会打开如下对话框:' ~7 B1 O& o5 h$ b: r& g
14.png
5 q( b/ t: p0 y1 c    首先要配置系统的调试方式:我们选择SW方式,
8 |; T4 W+ J* j6 d: x 15.png
8 n3 B  l2 a4 E" T$ `- d    然后配置晶振源,这里选择的是外部晶振,8M,
- r# }4 `: U) C& X 16.png . s: W9 ]& e  h* A
    使能看门狗,/ T" M% G& @0 f8 Y; {2 ~3 P
17.png
$ J! r% _% |9 V" F0 _! K, L    使能CAN,7 v# T( h! Z/ e0 Y
18.png : J! P; j$ A5 \7 a# [+ o& x
    使能TIM2时钟源,采用内部时钟,) U# H. u* k% S5 K8 F- s3 W8 P
19.png
& f) k+ Y0 D5 y! |/ `    配置完成后可以看到单片机管脚已经做了配置。
: o4 u4 e( A9 r3 U8 h: @. T 20.png . B6 M8 h5 f+ L: C$ j2 }
    切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M# L& k9 I3 Z) G
21.png
* u% U. p' V9 U' o  t1 w    切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。
* w, \2 i5 Q2 B( S5 \; T# p" r 22.png
% Z( a: ]! j. G( O. E8 G8 u3 y    配置接收中断。
0 f# Z' Y, H& p- O& c 23.png 3 X, I7 S* J- a3 {
    配置定时器如下为1ms定时器。  l" h/ G9 `; u8 R
24.png
$ R) E: y4 D# o% z2 R    配置定时器中断$ C# O: A0 I5 x2 v4 {
25.png
3 h! M3 j( c9 O0 B, @# ~( |    配置完成后点击保存,然后点击如下按钮,生成代码
. [# `* @) F. _5 g# b 26.png 6 R: X! s1 Q. Y5 ]+ T2 l
    填写工程名称,路径,编程软件等等
; K9 m5 S) W) L1 o4 b2 i0 F7 f3 \1 f 27.png - @' H+ Y, v# d: o, c6 z
    选择生成代码的方式( y2 R6 r6 n+ |# f+ R$ S
28.png ; h5 `) z2 z! t- G7 p, ^
    等待……
5 u1 p+ B0 J5 c+ M% p    之后点击打开项目。代码生成部分完成。, w1 i  y; c8 `: @* i
29.png $ Z% y% Y6 [+ c+ D3 c  b( V$ g
    添加一些特殊配置和逻辑代码,添加CAN的配置信息函数。
5 x: g5 C5 b  ?2 q, N7 m' |' X4 P6 c8 K& }5 E
* O. z% t( R6 K# p5 f* r- V$ [
  1. void Can_Config(void)1 k( @2 g6 n8 G5 X8 `$ C' B, X: y
  2. {: o( K  d3 l5 `. R* s
  3.   hcan.pTxMsg = &TxMessage;
    5 Z6 F* v9 K, {
  4.   hcan.pRxMsg = &RxMessage;3 Q' U$ B) N  }6 Z9 t, \

  5. . O" ~+ x0 `6 T6 B
  6.   /*##-1- Configure CAN1 Transmission Massage #####################################*/5 m+ B( k$ Z- p# |
  7.   hcan.pTxMsg->StdId = 0x123;5 k* y) U) V; G4 F8 v  i* B8 u9 s! I
  8.   hcan.pTxMsg->RTR = CAN_RTR_DATA;
    0 E; k  f. d& Z3 u# U
  9.   hcan.pTxMsg->IDE = CAN_ID_STD;
    & `+ L2 o, ]# m
  10.   hcan.pTxMsg->DLC = 8;
    2 v  J& F# }8 W* r+ h8 b

  11. 2 a" C) E) q) e! j; E  \4 q- D
  12.   /*##-2- Configure the CAN1 Filter ###########################################*/
    " f1 `- e$ e  W% X- b
  13.   sFilterConfig.FilterNumber = 0;
    0 I# h; G. m) X9 V6 j0 g& l% q) ?
  14.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    1 i8 b# P3 @1 e' F, j# i
  15.   sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;$ a0 i7 i& @( ]: i
  16.   sFilterConfig.FilterIdHigh = 0;/ o0 x3 z! b7 w/ |9 n  H& G
  17.   sFilterConfig.FilterIdLow = 0;
    2 H) s% I2 q# a, E- M
  18.   sFilterConfig.FilterMaskIdHigh = 0;
      Z2 E" b+ A! Y4 W" N) `) [, @9 g2 E
  19.   sFilterConfig.FilterMaskIdLow = 0;( T2 D) k  ?* j& y3 {0 y2 H8 k
  20.   sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;6 |# C" i! q+ Q6 a3 i
  21.   sFilterConfig.FilterActivation = ENABLE;
    ; L' Z4 X6 ]3 e3 L% N* V4 |
  22.   sFilterConfig.BankNumber = 14;0 Q0 ~" y' B7 v
  23.   HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
    + }  S' A$ o7 d' N0 Z  c
  24. }
复制代码

. W3 i5 V2 I( ^# ~
" ^. }; H6 H$ @
/ z1 |) f0 r# b4 r1 h$ ?5 Z
, s/ |4 y. n9 G0 A' K4 X% r
在Main函数中while(1)之前调用一下即可,添加定时器启动函数:3 M4 n; w" J" w4 T3 P9 X0 e3 I2 O  D
+ Q( x, h4 N* W# q5 d

# E; ]+ I" p; g2 j: H
  1. HAL_TIM_Base_Start_IT(&htim2);
复制代码

$ w4 |( u9 y' c0 m* S

% z4 l* ~& P- N. J' o2 W; ?CAN接收中断启动函数:
# k/ ^% N5 l; U2 V1 Q3 n( E. s5 \
* u, F/ q8 T% Q3 @. h/ i

  1. 7 G' g! M4 }4 ~1 ]4 ?; |& K0 w
  2. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
    3 \4 O+ Z/ i  L3 ?- t2 D9 J1 Q$ O  O
  3. /* USER CODE BEGIN 2 */  \8 B) O# D7 T' }- S

  4. , W: F6 U4 {7 [3 Q
  5. Can_Config();                        //Can配置信息
    " t, l6 z# K& k. C5 @
  6. HAL_TIM_Base_Start_IT(&htim2);       //定时器启动( L3 t. L. |/ h; ?  x
  7. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断7 D; }2 Z) V" w1 g; R- y
  8. ) B2 o8 w/ c) y, o
  9.   /* USER CODE END 2 */
复制代码
- X) d( d1 p$ T

" |. e# B% x/ w# S+ U8 k/ n 打开stm32f1xx_it.c文件,找到如下函数,添加接收中断启动函数:
5 ~; I* o8 ]& W, d5 I% O" c/ {( o, N# u' w/ C0 P+ [

- m- l: y& \; A* l# V, R
  1. HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
复制代码

, V) V9 i7 b$ Y" M1 i
  E8 `1 G6 ^) l. C
注意:接收中断启动函数使能一次只进一次中断,所以中断退出前要再次使能。
/ o* v8 U9 d* Z1 t" J1 I; k
$ [# p0 P5 B  V; T6 z$ E
+ C0 t5 E+ `( A3 }2 x+ m9 R# P

  1. 7 v" b3 S8 m6 F  H
  2. void USB_LP_CAN1_RX0_IRQHandler(void)/ q  w$ }8 w  ]- e7 }6 D5 \
  3. {
    5 J& R* v7 m( e" k, M8 I& x8 }9 E
  4.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */$ K' M& E9 ~! ~% z* g# J

  5. 7 ?- E9 u: ?5 S3 J$ U" C0 f
  6.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
    6 ^  U+ j2 t6 J! f3 C& Y, C' Q
  7.   HAL_CAN_IRQHandler(&hcan);/ ^  v4 W8 J  C& w' u' r+ a
  8.   /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */
    ( {5 E! J4 ]0 ^0 A# Y1 t2 M9 K+ A
  9.   HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ  V% U: W  ]+ t5 U! s
  10.   /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */% v: S6 k! p8 |. h3 S$ ?  E4 Z
  11. }
复制代码

- J5 O& y" u% x; w/ y8 ^! I- O
2 `5 W! w6 _$ p+ q
添加CAN接收服务函数:
5 F7 j* {: U& Z+ Q9 f  ~2 X. E5 o7 c; b# \) T0 h# Q4 l7 y, b/ Q) f0 ~# A; L
4 g7 y% e+ }6 h3 h; O
  1. HAL_CAN_RxCpltCallback
复制代码

1 {( G3 w, T0 o/ o* D& Q9 E
* [$ p, j: H" O2 Z" a, T$ Z
  说明:该函数在stm32f1xx_hal_can.c文件中已经有定义,它的定义方式如下:# K9 X# N$ G$ i1 `
  c. H! Q6 c9 W* _

1 ~; I  G& f& A/ l
  1. __weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
复制代码
% |9 D% D1 T* W7 D
' V  O8 y1 t. s2 ]! g- N1 B) c
函数前面的__weak关键字意思是如果有同样的定义,先执行没有__weak关键字的函数,所以当我们定义了HAL_CAN_RxCpltCallback函数后,编译器会先编译我们定义的函数,而忽略系统定义的该函数。当我们没有定义该函数时,系统会编译带有__weak关键字的函数。
5 d) w; m6 ^( b) B3 g, b- H7 D  ^4 J6 z5 r, X
! f4 a! d) _0 s' S& ~
  1. * T- z$ K( d5 y' Y& s, P, s/ W
  2. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)5 n! M5 R4 F: s! }1 p, ~+ h
  3. {$ `/ Q% _% s' u% p  M  F; B. J1 @
  4.     unsigned short int speed;
    2 {9 M. l* D- `. |! ]
  5.     switch(hcan->pRxMsg->StdId)
    : d  s9 u# o& d- L0 `1 F
  6.     {//根据ID处理数据$ O, u( e% L- e  }. T9 e& \
  7.         case 0x123://4 C4 Q: O' v7 h" `
  8.         /*在此添加数据处理逻辑*/
    / A! a$ I0 s% ^- I
  9.         break;, N# G/ [9 C, O* H4 J; j
  10.         default:5 V9 {3 W% s. n! l: H
  11.         break;
    # H9 J8 L' d+ `/ m- l
  12.      }
    6 _, n, E, I- L. Q6 d: ?
  13. }
复制代码

( ^7 h0 @; I! y  m  s9 s+ z' z

% `* p. I. I) v/ Q4 u+ m# L, b: g 添加CAN发送函数:) R9 w$ c! D4 q+ e" i

# m( M* F& Z  t3 m) V; z

9 n& I$ p; Q( X7 r& ?
  1. /* USER CODE BEGIN WHILE */+ E9 R$ u5 Y7 B0 B9 v' [/ t9 q
  2.   while (1)% O# _9 r. w; _9 W
  3.   {
    0 y5 U4 C: S( Z( Y: W& }/ {0 S
  4.         HAL_IWDG_Refresh(&hiwdg); //喂狗函数4 Y& t! ^  \3 F8 N1 @" y

  5. 3 Z' G7 v2 a. D: s6 i
  6.         if(Can_Trans_Timer == 0)
    ! p6 g7 S- `- p
  7.         {//每100ms发送一次数据7 t0 i- a2 g6 |1 ?0 T( K  P
  8.             Can_Trans_Timer = 100;
      r" u/ F" g1 a& X

  9. 3 I0 w4 `, o0 }# E9 |7 `" ?

  10. ; L2 I# m6 w- [. w7 c
  11.             hcan.pTxMsg->StdId = 0x123;( |/ p* g- ]6 @5 }0 v1 c1 `
  12. 7 g0 J; v" o' p' a! A
  13.             hcan.pTxMsg->Data[0] = 'C';" n$ b7 G* X8 I& H
  14.             hcan.pTxMsg->Data[1] = 'A';
    5 m- c  @! a& M. ]5 G0 Q' W
  15.             hcan.pTxMsg->Data[2] = 'N';6 Q* h" F7 e$ `$ e5 q% \! W8 |, I
  16.             hcan.pTxMsg->Data[3] = ' ';7 i  Z6 C0 T/ Y- T
  17.             hcan.pTxMsg->Data[4] = 'T';2 f, Z# H6 n5 v, Y6 X4 P* ?4 m: J
  18.             hcan.pTxMsg->Data[5] = 'E';
    ) a, W) t* u2 N# o5 z/ m
  19.             hcan.pTxMsg->Data[6] = 'S';9 Q& C" u0 e) C3 k$ n
  20.             hcan.pTxMsg->Data[7] = 'T';
    8 {! e% O' [4 z  Z1 m* l& H8 ?! Z( F

  21. . `7 S4 E3 S2 |! I6 b. y' V

  22. ' Y( e  T6 g7 L0 K9 u1 ?
  23.             HAL_CAN_Transmit(&hcan, 200);//发送一帧数据/ ?' P  _8 j; O5 G& B+ ]
  24.         }( W% t$ c9 \9 N& k( I
  25.     }
    " a3 @* ^  j* I0 M4 N  |
  26.   /* USER CODE END WHILE */
复制代码

4 D4 n  l5 N; G$ c8 x
3 I/ J* F5 J! ?  ?  H
在定时器函数中添加定时器代码:
1 q6 F# Y% K; A5 L
5 B# N% m- S* N% }1 Y

0 l3 [# L% E. }* W% R! }
  1. % g" z. K3 ]+ c
  2. void TIM2_IRQHandler(void)' W5 @$ D! E& J; s* D0 k
  3. {, R' n/ [% d, x/ L# v% I
  4.   /* USER CODE BEGIN TIM2_IRQn 0 */
    + j7 s# R& q0 K8 ~: `" o
  5.   if(Can_Trans_Timer > 0)          Can_Trans_Timer--;! A, h& x$ I9 a8 I: K$ k" M( x% W
  6.   /* USER CODE END TIM2_IRQn 0 */. X, b, y. G7 s8 l
  7.   HAL_TIM_IRQHandler(&htim2);* f' V6 Y) c6 ]- }% e* W% n3 Y
  8.   /* USER CODE BEGIN TIM2_IRQn 1 */- S2 U, \" D% e0 s" w

  9. ; c/ L, H- W, ?+ v
  10. " {! E( k9 z4 K% ^
  11.   /* USER CODE END TIM2_IRQn 1 */2 N. |0 E& P0 a! p0 x2 u9 C, H
  12. }
复制代码

$ \6 A  l5 |$ E

- J) C" {# T1 |" ^ 说明:在往工程中添加代码时要注意,不要任意往里面添加代码,要在注释着USER CODE BEGIN的地方添加代码,这样在重新生成代码时才不至于将已经写好的代码覆盖掉,如下. W' G% N  j- r  |% o: f& A

5 A! K% \! T5 x
: Q* B' X/ l7 `. B
  1. % G% X" b1 b/ y: e% `4 ^3 U+ ^
  2. /* USER CODE BEGIN Includes */
复制代码

; x1 w2 l% X( c0 E
: h9 X# _2 k9 J4 M% P2 j
  z# j: l+ G3 @0 S" Q/ ]4 V- k

& C, k3 g3 v# _6 L, }6 L

2 ~; z' e3 W7 r9 z$ ^, l8 H1 J$ a5 o2 E4 b4 X/ J

1 w: A% _' G( R  m2 K8 e# I! {5 K! X6 A) p7 k% L

5 @* `) f7 I# J6 U( i" `' Z
7 Z# w3 A% o- _7 v0 X( ]. |8 K

, l$ C6 F0 I% l7 w
# S0 n$ g) g$ s3 d2 E: X

1 _, A7 }% j: A3 f/ i7 K4 H
" o$ V9 c: P+ l/ d- M3 j( f
收藏 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 手机版