|
首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:
( e1 H; k( ~% _3 X, q/ J, h; ~
: `9 J. G0 r/ h8 h- k 输入CPU型号: 9 Q \0 ]8 I4 x& B
" |7 v; m' K9 Z' ^
在右下角双击CPU具体型号:
/ F8 V9 M# Q/ I% A( n" G 4 a! a5 k4 @( a' X( }- o# D
稍等片刻会打开如下对话框: ' a! y! f5 Q7 e& ?1 N
7 Y) N# ^5 I2 V 首先要配置系统的调试方式:我们选择SW方式,
+ d! ^: }$ C/ v1 l; j( c
' y, P% v. ?+ m8 I+ j/ h3 t 然后配置晶振源,这里选择的是外部晶振,8M,
$ t% p! ^( d# K5 o9 k: |
; S3 H: Y2 i9 f3 @+ D( d' ` ^) @
使能看门狗, 8 q3 K4 S) E. B4 g
Q1 Q1 E4 y, G. A. ^& Z% [( e ^
使能CAN, % L$ h2 e$ k, B- L# g% s
$ d2 ^: T. k8 B a5 e; v 使能TIM2时钟源,采用内部时钟, : @8 {8 f3 A( c6 ?" a$ W6 _
' L7 H. u% M0 c% C6 } 配置完成后可以看到单片机管脚已经做了配置。
- F+ }5 T; h- J, F
% |6 |5 K( n3 y% z* B 切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M
" P3 A% Z& F' ^7 @
$ ^/ s; ^, p3 n+ o) E
" W5 V7 X( f! ~5 R) h# ]6 A 切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。( W/ n6 G& ^4 ]' b
/ K: s3 U" |- W0 L0 V- Y" _
+ n& |' G: b- @. ^6 s
配置接收中断。
' y. G5 W& b2 Q/ |7 @. M, i+ J ! ]7 Y( F) S$ p3 |5 r
) `- O& T* M) a8 F
配置定时器如下为1ms定时器。
0 b7 O1 o3 ~- K8 R/ d/ } 0 B% t( E& E5 w+ o" p
% n6 E2 I2 p2 N' v
配置定时器中断
$ ?# m8 @" |6 X# Q; i' I& ~6 n+ G/ b4 _- g
, R3 B- F7 Q1 b' @2 C 2 e3 y. [1 Z4 u. z; X1 N5 L5 @6 r
配置完成后点击保存,然后点击如下按钮,生成代码
$ ?8 G- I) L) h8 O) ^ H* T + t/ `$ b0 _. s! t; o
0 U6 b1 N: `3 R, m2 Q 填写工程名称,路径,编程软件等等5 k/ `) d; g# I% o; D* ^
' o5 }( s. E8 V% b ; z/ I5 J! v. Z3 L" t, J" c$ t
选择生成代码的方式4 g9 x, O- j8 @- X2 E* c
/ ]) u, B1 J- _+ [6 Q! K% L4 s
2 B N7 Q- t+ i! F9 S, d) |' [ 等待…… 之后点击打开项目。代码生成部分完成。
/ n1 R/ Q# n) s. X8 k6 [ & a! r. \; x, W5 @ N5 y2 C
添加一些特殊配置和逻辑代码,添加CAN的配置信息函数。 - void Can_Config(void)
# W7 t O% R8 o' a3 p - {
) X9 X& ]8 z, t1 U6 } - hcan.pTxMsg = &TxMessage;* M8 A# K, T+ `$ Z# }$ k
- hcan.pRxMsg = &RxMessage;# P3 w( `8 i0 y0 o# g
- : m1 y# _3 Z0 ?4 `1 X8 B6 n% ?
- /*##-1- Configure CAN1 Transmission Massage #####################################*/* g9 G4 l. O" f9 D2 r+ z7 Y9 `
- hcan.pTxMsg->StdId = 0x123;2 G' z# \7 F" P5 C8 [3 j3 g( d
- hcan.pTxMsg->RTR = CAN_RTR_DATA;
9 j8 x' x) @- L/ ?4 ]1 u - hcan.pTxMsg->IDE = CAN_ID_STD;6 i2 s+ V0 B7 X' n5 I' `. w
- hcan.pTxMsg->DLC = 8;* e2 t# i% r& n1 L' Z1 y
-
6 X9 @, s X# x) b0 p - /*##-2- Configure the CAN1 Filter ###########################################*/
* j: c2 H, J: J8 X2 `) ^9 @ - sFilterConfig.FilterNumber = 0;
$ t/ ?$ b j# Q - sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;! J% C0 r- O5 ]* ~4 h$ R
- sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
& s. ?+ b, K+ C( p; i Q - sFilterConfig.FilterIdHigh = 0;8 ] C s9 P3 N/ [! `
- sFilterConfig.FilterIdLow = 0;. x3 d7 _, ?! n1 K
- sFilterConfig.FilterMaskIdHigh = 0;4 H. ~- R% H Y, x n4 X2 g
- sFilterConfig.FilterMaskIdLow = 0;
4 N z. S; E! O6 V$ [ - sFilterConfig.FilterFIFOAssignment = CAN_FIFO0;
( n9 ~# v( w% L4 H" K8 _$ | - sFilterConfig.FilterActivation = ENABLE;
: h8 P0 P9 g2 Q' @! t - sFilterConfig.BankNumber = 14;$ Y1 _0 O2 e$ B7 z8 {
- HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);# Y! j% s. m7 x; D- k
- }
复制代码
s" R9 F+ N6 E& y) j
在Main函数中while(1)之前调用一下即可,添加定时器启动函数: - HAL_TIM_Base_Start_IT(&htim2);
复制代码 * ^/ }& l5 m, x
CAN接收中断启动函数:- HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);5 y/ d+ z K3 G4 ^. [/ P+ @5 Y
- /* USER CODE BEGIN 2 */) D. F* f) N' r% z
-
; g/ g( ^( g- f% f - Can_Config(); //Can配置信息/ }9 I) j9 T9 r
- HAL_TIM_Base_Start_IT(&htim2); //定时器启动
; C) v' O' S; _ - HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断
; _9 ?" x0 M4 p& a4 L) H - 0 ^1 @% J8 K2 L, J7 X' m, R% b
- /* USER CODE END 2 */
复制代码
& k$ [9 r, r' V5 @2 O- x3 g
打开stm32f1xx_it.c文件,找到如下函数,添加接收中断启动函数: - HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
复制代码 0 Y0 Q9 o' r5 i5 K) Z' |0 T
注意:接收中断启动函数使能一次只进一次中断,所以中断退出前要再次使能。 - void USB_LP_CAN1_RX0_IRQHandler(void)7 x# c4 ]9 r K3 i) m6 C/ \
- {' I" U- v* @4 S
- /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */( S m2 H6 Y" {8 S0 Y% V+ i
- ( w* Y; P; Y- A: p
- /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
0 x. x, Z, u1 ~# q, C: b/ p0 \ - HAL_CAN_IRQHandler(&hcan);
, u" V: i% Z: ~& |) v - /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */
: v3 t" E0 V9 T - HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ8 a' p$ E3 o$ s3 I! O" T
- /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */" Y. E0 {+ x+ \7 g* s/ T
- }
复制代码
- F. J$ q1 D. }- B8 r* X% X
添加CAN接收服务函数:
* i% l( S4 [$ K1 O$ A, X+ u) X; t 说明:该函数在stm32f1xx_hal_can.c文件中已经有定义,它的定义方式如下: - __weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
复制代码
; F- c9 ^$ s( b& N$ L8 w 函数前面的__weak关键字意思是如果有同样的定义,先执行没有__weak关键字的函数,所以当我们定义了HAL_CAN_RxCpltCallback函数后,编译器会先编译我们定义的函数,而忽略系统定义的该函数。当我们没有定义该函数时,系统会编译带有__weak关键字的函数。- void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)
* _* I3 y- [& j0 e* d) D - {
; b' H2 P2 y7 R) x m$ @5 { - unsigned short int speed;1 `3 q) \% {$ g, U1 y
- switch(hcan->pRxMsg->StdId)# j/ n/ X, w) V$ \1 a* U5 q- e
- {//根据ID处理数据' x% J, U- w2 L
- case 0x123://8 r( b! r9 b }0 E* [) v5 ~
- /*在此添加数据处理逻辑*/$ C( P! _* t/ v3 ?
- break;
. ^ S y9 K' P* m$ C - default:
8 ~+ Y& G' Y( C9 D - break;
/ V; j8 L0 l# _9 e - }- s6 G4 T+ Q0 s: l( r4 _
- }
复制代码
X1 t( n3 D# `9 w9 K+ r
添加CAN发送函数: - /* USER CODE BEGIN WHILE */
$ S9 j* b3 W0 b) j/ g% k) { - while (1)3 c$ u3 p2 L, a! c% N
- {
$ K7 f f$ q# i7 y N3 ^ - HAL_IWDG_Refresh(&hiwdg); //喂狗函数
" b2 V! U2 n9 I/ t1 I- l$ \ -
& o. a5 C7 q% {2 { - if(Can_Trans_Timer == 0)- j% Q7 K$ Z9 ]. Z
- {//每100ms发送一次数据! V3 T7 |- |* X: m. Y+ f
- Can_Trans_Timer = 100;
1 A, @: X/ O5 W; r, L( Q1 c4 O - ; s( N* O5 _ h6 j! b# c6 B
- 6 l, F1 c+ ^7 y8 A* ]' E, Y0 S9 S
- hcan.pTxMsg->StdId = 0x123;& `: Q3 u5 T- l; \. ]- S' U5 r) B6 g
- 3 c5 H ~+ W5 T5 {. Q3 k
- hcan.pTxMsg->Data[0] = 'C';
5 a& r( P+ V7 y4 `* W - hcan.pTxMsg->Data[1] = 'A';# c7 I! q* n$ R/ W" h7 q! N
- hcan.pTxMsg->Data[2] = 'N';
% x: J7 |7 ?; q - hcan.pTxMsg->Data[3] = ' ';
+ O- ?% A/ ]8 z3 r; Z L/ w( E - hcan.pTxMsg->Data[4] = 'T';
! F) m% g7 @ I) O1 M" P" `# E - hcan.pTxMsg->Data[5] = 'E';
" O5 C" P. i1 g4 ^2 K - hcan.pTxMsg->Data[6] = 'S';
8 c% N' V9 ~, u) i - hcan.pTxMsg->Data[7] = 'T';
6 N g% C6 M0 \6 T# E2 ], | - + F) c0 X' t: v+ ?2 \# Y
- 4 Y* c/ m2 O! T0 V' q# K5 b* v
- HAL_CAN_Transmit(&hcan, 200);//发送一帧数据* H# e8 n* J' U" u
- } B. h& t2 p0 E1 W
- }
* |/ @3 `" v6 ~! R# q3 t5 F' u( a - /* USER CODE END WHILE */
复制代码
5 d+ S& q3 Y3 b, O% Z2 u; @2 h! M
在定时器函数中添加定时器代码: - void TIM2_IRQHandler(void)
; P& W5 i6 _! v6 U - {( q* z: `* ]) y+ m2 y
- /* USER CODE BEGIN TIM2_IRQn 0 */4 u; _* ?( q1 H3 {% {
- if(Can_Trans_Timer > 0) Can_Trans_Timer--;5 G% g4 ]) ]0 }( B* ^/ A" X( r
- /* USER CODE END TIM2_IRQn 0 */
7 f8 q4 r% h0 k( H- y% {& y - HAL_TIM_IRQHandler(&htim2);
; m3 i- ~6 b) w: L - /* USER CODE BEGIN TIM2_IRQn 1 */" u- \" `# V8 j5 S( R
9 j, D# A( Q0 K1 e8 z" M1 }
% G3 f2 B! f9 y+ x; N, q. a- /* USER CODE END TIM2_IRQn 1 */
" t# I. b5 I. p( {2 C. i - }
复制代码
5 D3 N# X0 J( P& d8 i2 Z5 T; y. F2 I
说明:在往工程中添加代码时要注意,不要任意往里面添加代码,要在注释着USER CODE BEGIN的地方添加代码,这样在重新生成代码时才不至于将已经写好的代码覆盖掉,如下 - /* USER CODE BEGIN Includes */
复制代码
" f& K# I/ b9 ~* A. F |