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
3 Y' M; G( A: t1 _2 s) D2 } 输入CPU型号:
, X6 ^, H' z9 N. q: \
: Q V; r6 R; m; @' e5 y4 I# { 在右下角双击CPU具体型号:! A/ |) @& H0 C: {! z6 x4 T( j
' c1 t9 {, r9 ]% M2 Z
稍等片刻会打开如下对话框:# C; b, ?* T- N% U4 G4 V' x
9 ~- k4 v! ] E% n8 _/ t+ S0 M; |
首先要配置系统的调试方式:我们选择SW方式,! O9 |* O8 [" Q8 y& M; f
8 y% T- @* Z. D
然后配置晶振源,这里选择的是外部晶振,8M,
+ V6 q9 ]# b7 x6 `6 q( `
7 R9 a+ c3 ^$ I7 R0 B- }% ]+ K& Q
使能看门狗,
" z# z. v4 n& @, u
! f# H' F, b7 x0 G) B3 t
使能CAN," c) b5 w+ `7 \0 z7 d) L
' n& S+ b9 J$ ^ Q
使能TIM2时钟源,采用内部时钟,4 N- V' p9 o- k
. M: N5 l2 D" N
配置完成后可以看到单片机管脚已经做了配置。
f5 Z6 D5 o1 q$ E6 |9 [$ \+ ?
5 I q7 W! p5 t% Y! u: W- {
切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M# q' _& c: h7 Q) C( U) {8 B
; M& [# K$ e2 A% t" |* H7 `" x 切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。) ]9 O1 D: h, ]$ ^( {! y8 X
! y) T3 T6 R: x0 P
配置接收中断。; h t4 i- \* \) p! u* P# w- _
# f5 y- t3 a! F5 Z 配置定时器如下为1ms定时器。
% i# g6 |/ M4 v9 Q5 {
0 `" @8 @; b* C# U7 d ~
配置定时器中断6 [! e" ?1 h7 I% I0 _: A8 _
( {# d8 w5 z @% f6 F' c
配置完成后点击保存,然后点击如下按钮,生成代码
3 O9 p) W4 t+ o3 g( ?8 J' g
% L5 \+ b0 n* D6 k$ t
填写工程名称,路径,编程软件等等0 V. |: J, R) R1 {. {
# p9 }( C8 U) ?* @: J" c 选择生成代码的方式
- W9 _- X& [3 m0 }; A( V. `
* Q# ~' ^0 m( f1 F6 p
等待……
. w5 d- H3 G2 c" @1 g* s0 U: p 之后点击打开项目。代码生成部分完成。' H* `, T, t1 w: w* R" c, |: f
$ {+ 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- void Can_Config(void): E: K0 ?" {" R$ x3 U' G' A" y
- {# |% c/ h( |; y; j& _* o4 ^ q
- hcan.pTxMsg = &TxMessage;
( j | ?& a& |6 m/ B2 a - hcan.pRxMsg = &RxMessage; [) L- `- X$ \- e
-
8 u# B$ c2 X' U& a, d - /*##-1- Configure CAN1 Transmission Massage #####################################*/) n4 C3 h {- k
- hcan.pTxMsg->StdId = 0x123;
$ P* F* m/ f. e# O; T) V- [ - hcan.pTxMsg->RTR = CAN_RTR_DATA;
0 m' H# q/ D: A - hcan.pTxMsg->IDE = CAN_ID_STD;
% L K, Q4 d* i; p - hcan.pTxMsg->DLC = 8;- w- W/ v- z8 V& r
- * u3 I* ?2 `) @7 S
- /*##-2- Configure the CAN1 Filter ###########################################*/6 z: R9 m8 s+ N) m! _# X) Q
- sFilterConfig.FilterNumber = 0;/ E5 ^# [3 v% n# K, f4 v
- sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
* f' n, ~" L. M: c7 D& e - sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
5 X2 C, x7 {1 m6 y1 p7 @; D. m! }0 t - sFilterConfig.FilterIdHigh = 0;
2 c* z& O. V$ J9 _ - sFilterConfig.FilterIdLow = 0; @7 O ~/ i6 F: F: j* ]" U
- sFilterConfig.FilterMaskIdHigh = 0;
H# ~: \) d' b7 U - sFilterConfig.FilterMaskIdLow = 0;
' b6 ]1 ?# @1 ]: I. K - sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;2 M& A6 ^, Q4 N
- sFilterConfig.FilterActivation = ENABLE;, T+ o' L ]' C5 ^1 d" D
- sFilterConfig.BankNumber = 14;
$ y7 c9 ^; V' X+ e$ F5 g - HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);" w( E2 a6 Z+ U
- }
复制代码
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
- 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) E8 \3 V1 s( f# F( c" ?% g6 U; P$ l! y
- ( V! n0 I- d: u" V; `
- HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);( r6 g& I8 W3 g3 k( s& P( x! Y9 \- @
- /* USER CODE BEGIN 2 */- [/ {3 A: R& k/ y) ^8 ?
-
& ^/ v% x* f7 u - Can_Config(); //Can配置信息
7 [7 J/ J4 [8 k5 S5 ~. z7 t) t/ x - HAL_TIM_Base_Start_IT(&htim2); //定时器启动
. n3 q( v6 e ^6 J( ?4 e: M) {: m - HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断
& Y% J; B$ a5 `7 q( F% p - * |& t# c" c( L7 F! l, g6 R
- /* 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- 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
, ~* @4 W0 y* R7 `( ~5 n( t( M) N- void USB_LP_CAN1_RX0_IRQHandler(void)! B; S/ q, V+ o6 n7 N7 i
- {
4 l8 \+ H% r: O1 H: D) \- z" K - /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */; A' {# F+ I) f7 Z) `8 |, P+ r: Q* D
-
/ i$ i9 n& E: W3 C6 D. z2 a - /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
9 E' r, j/ `( P" h* t/ Y - HAL_CAN_IRQHandler(&hcan);4 I; G2 G+ H& L2 J, m v; w
- /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */& \9 L$ r) V7 b1 K
- HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ7 P5 p4 L& \8 [3 L
- /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */& R" q: e# `3 m+ N) x% w5 v
- }
复制代码
6 {8 Z8 k) L7 o1 c; W7 {! Z, j7 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 ?: }, 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
- __weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
复制代码
* V/ D( [9 Q5 W8 `. [& J5 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
- 3 k5 [8 S# u9 i8 E0 L8 y& M
- void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)
# E* I" T* o6 Z+ D& W. B - {+ M5 W, |* H6 P6 B% ^
- unsigned short int speed;
$ b* S1 j3 e }) [4 `5 h" n - switch(hcan->pRxMsg->StdId)2 i) I" D( R2 K5 T# z) }, C+ U. C
- {//根据ID处理数据
" P* c; D! B* J) r5 X: P - case 0x123://
& s6 ~! A6 K. y/ B- i9 _" j& J7 T0 M - /*在此添加数据处理逻辑*/ K1 H8 p$ R/ @2 m3 H& m
- break;
, ~$ ^5 ]- }# l1 t - default:
( B' ^) ^8 B# c6 {+ |7 L, d - break;" L8 b. S) D5 t) ?7 Y5 B
- }
! D3 m3 C7 V3 |9 A- J0 c0 c" P; y - }
复制代码 # 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 {
- /* USER CODE BEGIN WHILE */- L! L% b! p4 T3 ?9 u) L
- while (1)' @- [5 P' q" |8 H2 k$ ^( n3 c
- {
J6 ^- M- l/ Q+ {% d - HAL_IWDG_Refresh(&hiwdg); //喂狗函数
8 X# S# X4 L6 h {8 }* S -
/ F: g: u8 r" L0 @8 } O - if(Can_Trans_Timer == 0)
x* F: `: c" Y/ {) B; p% f - {//每100ms发送一次数据7 W \" Z8 z9 \
- Can_Trans_Timer = 100;
& M! M" R7 y) O9 V( |/ a - * R6 s+ x7 W% k. G- ^8 i
- 6 h J- R% e2 P- b7 U) V
- hcan.pTxMsg->StdId = 0x123;
' d6 D: x4 V" N# r. ~$ R -
5 X" q" f& V9 A7 I - hcan.pTxMsg->Data[0] = 'C';- Z& h1 C( y4 y/ |
- hcan.pTxMsg->Data[1] = 'A';- B3 m' h$ u* Z- u5 Y+ \* o
- hcan.pTxMsg->Data[2] = 'N';# s9 H3 V$ M0 `* ]( ~8 Y$ F
- hcan.pTxMsg->Data[3] = ' ';
; @+ F$ f2 z+ z: R/ Y - hcan.pTxMsg->Data[4] = 'T';
. L6 L" d! E3 }2 B! o+ z4 D - hcan.pTxMsg->Data[5] = 'E';
0 ]: o; P2 T- r: a4 ^' h6 X' ^ } - hcan.pTxMsg->Data[6] = 'S';, h( a. l6 m% m0 ^1 w
- hcan.pTxMsg->Data[7] = 'T';# z6 N1 L+ ~* m# S
- 1 o2 W4 `/ y( V3 Z
- + I, p0 O1 m7 q) d1 q
- HAL_CAN_Transmit(&hcan, 200);//发送一帧数据
4 q+ Y8 Y+ E8 D1 X$ Y/ _7 [ - }
5 C5 G2 I% Y( D - }5 d8 \7 r a7 j1 f! C( r
- /* 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
- . q5 S" q" D4 D, U5 d
- void TIM2_IRQHandler(void)
! y0 W% b) \) E' | x. ~4 v( R - {7 f3 y: T2 ^" f/ \; \
- /* USER CODE BEGIN TIM2_IRQn 0 */
' q( r( r. a) v/ M - if(Can_Trans_Timer > 0) Can_Trans_Timer--;! l9 s7 C m7 @3 l2 m& `
- /* USER CODE END TIM2_IRQn 0 */$ G, J8 e8 e: t
- HAL_TIM_IRQHandler(&htim2);0 z& Q5 J) U8 w# u9 ?1 ]
- /* USER CODE BEGIN TIM2_IRQn 1 */; A+ p _) e' N$ W9 O
* S+ ?, o2 Q' j2 ?( o. @ ^
- @" U+ q( o0 V& m2 p: C9 z3 \: Q, P3 r) Q- /* USER CODE END TIM2_IRQn 1 */
^2 }) I# ~* J4 h - }
复制代码 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- ; i) J& X( p C. ?& A
- /* 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 @* |) F2 _ 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
|