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

【经验分享】STM32实例-CAN通信④-程序编写

[复制链接]
STMCU小助手 发布时间:2022-6-26 17:47
硬件设计
    本实验使用到硬件资源如下:
(1)D1 指示灯
(2)K_UP 和 K_DOWN按键
(3)串口 1
(4)CAN 控制器
(5)CAN 收发器:TJA1040
    D1指示灯、K_UP 和 K_DOWN 按键、串口 1 电路在前面章节都介绍过,这里就不多说,至于 CAN 控制器它属于 STM32F1 芯片内部的资源,只要通过软件配置好即可使用,下面我们看下 STM32F1 的 CAN 与 TJA1040 的连接,如下图所示:
微信图片_20220626174723.png
6 r% Q' @: H( P/ N" d8 f0 v
微信图片_20220626174721.png
) G( O6 Y6 R  R2 C; H
微信图片_20220626174718.png

+ @) N/ X# n8 N7 H% r+ T
    从电路图中可以看到,TJA1040 芯片的 CAN_TX 和 CAN_RX 管脚连接在P16 排针上,因为 PA11 和 PA12 是 USB 和 CAN1 共用的管脚,所以使用 P16排针来做切换,本章实验我们使用的是 CAN1,所以将 P16 排针短接到CAN 端,PCB 板上P16插针短接图如下图所示:
; }- T* @" C4 z7 K
微信图片_20220626174714.png
' X# o0 v0 K9 W0 p+ g# D  M
    在TJA1040 的 CAN_H和CAN_L 管脚上连接了一个 120 欧的终端电阻, 如果我们的开发板不是作为 CAN 终端的话,需要把这个电阻去掉,以免影响通信。最后我们用两根导线将两块开发板上 CAN 收发器的 CAN_H 和 CAN_L 对应连接,不要交叉,否则通信错误。CAN_H 和 CAN_L 示意图如下图所示:
# e' T) `+ t; s; J
微信图片_20220626174711.png
6 o2 m1 L: I9 I1 q) V
    连接好后, 我们 STM32F1 的 CAN 控制器就可以通过 CAN 收发器 TJA1040与外部 CAN总线进行通信了。
    D1指示灯用来提示系统运行状态, K_UP 按键用来切换 CAN 工作模式, K_DOWN键用来发送数据,通过串口 1将切换的模式和发送与接收到的数据打印输出。
+ o7 k' a" T$ p; m$ ?) b0 o
函数编写
+ U* y+ A9 B4 _# q3 u) X0 W/ O
    本实例所要实现的功能是:通过 K_UP 键切换 CAN 通信模式,K_DOWN 键控制数据发送,将切换的 CAN 模式,发送和接收的数据通过串口打印输出,整个过程D1 指示灯不断闪烁,提示系统正常运行。本章我们使用的是 STM32F1 的 CAN1,程序框架如下:
(1)初始化 CAN1,包括工作模式、波特率、筛选器设置等
(2)编写 CAN1 的发送和接收函数
(3)编写主函数
    前面介绍 CAN 配置步骤时, 就已经讲解如何初始化 CAN。下面我们打开 “CAN 通信实验”工程,在 APP 工程组中添加can.c 文件(里面包含了 CAN 驱动程序),在 StdPeriph_Driver 工程组中添加stm32f10x_can.c 库文件。CAN 操作的库函数都放在 stm32f10x_can.c 和stm32f10x_can.h 文件中,所以使用到 CAN 就必须加入 stm32f10x_can.c文件,同时还要包含对应的头文件路径。
    这里我们分析几个重要函数,其他部分程序大家可以打开工程查看。
# |" d( s! @8 z, D- ~+ M5 F$ Q) H
CAN1 初始化函数
    要使用 STM32F1 的 CAN1,我们必须先对它进行配置。初始化代码如下:
  1. //CAN 初始化
    * S' J& v) g, T5 P
  2. //tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq+ n5 J, q1 a! A9 c; k
  3. //tbs2:时间段 2 的时间单元. 范围:CAN_BS2_1tq~CAN_BS2_8tq;. A& N' @) R/ W& E1 |
  4. //tbs1:时间段 1 的时间单元. 范围:CAN_BS1_1tq ~CAN_BS1_16tq- S) E6 u; w. s! f
  5. //brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1) X# y2 n* P8 E8 L9 P' w
  6. //波特率=Fpclk1/((tbs1+tbs2+1)*brp);
    5 W* {. \3 ?1 H8 R: w3 d. }
  7. //mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
    8 b5 K  j5 X8 n; k& ~9 }" S9 j
  8. //Fpclk1 的 时 钟 在 初 始 化 的 时 候 设 置 为 36M, 如 果 设 置
    - P4 t: ?9 e8 v8 ^7 M: l- C
  9. CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);5 y' U) I0 G* d  ^' ~& X
  10. //则波特率为:36M/((8+9+1)*4)=500Kbps
    3 j( o0 n# x4 ^7 N8 ^
  11. //返回值:0,初始化 OK;
    ; g4 R0 h- D) C6 l4 ~8 E. L) l
  12. // 其他,初始化失败;- E* E  g; f- \9 c  c* l, V1 b* x
  13. void CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
    + }* u# }! L; M, P; e4 G- q
  14. {3 s$ c5 i- ]( I  L& L
  15. GPIO_InitTypeDef GPIO_InitStructure;  z" a' b8 r# w( P' I8 l! L7 M
  16. CAN_InitTypeDef CAN_InitStructure;* C* x9 l* m( \' _/ `' T. h
  17. CAN_FilterInitTypeDef CAN_FilterInitStructure;
    ( a* ]' E/ U4 n$ M0 W% h! L& a
  18. #if CAN_RX0_INT_ENABLE
    " o+ j' k  K7 G4 M' m# m( ]
  19. NVIC_InitTypeDef NVIC_InitStructure;
    0 {! ^7 P" D% N3 u3 n
  20. #endif
    & |  `. R0 \6 R
  21. RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); // 打 开CAN1时钟1 w) Q  J, @5 z# _7 v, d2 K( g' p
  22. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //PA 端口时钟打开
    & v/ @* i4 T* K& u$ G
  23. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PA115 b0 P" g9 s% w% |# j& a# Y
  24. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入模式& w/ b, G2 a8 ^, n
  25. GPIO_Init(GPIOA, &GPIO_InitStructure);& r4 H& S+ L! Z, |
  26. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PA12
    ) J: L1 Y" Y4 X+ E1 Z% W
  27. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出& j$ z8 j& [2 s+ N1 G
  28. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度为 50MHz! u% O& a0 L  a  U3 A' x! C2 I
  29. GPIO_Init(GPIOA, &GPIO_InitStructure);
    5 l4 f( @  k! W1 n- y) [$ u
  30. //CAN 单元设置
    * V7 b( A/ w  _+ W1 j# [
  31. CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式) Q- H; |/ i6 T! `( }, v
  32. CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理
    8 a9 ?  }. I$ W  O0 h$ p
  33. CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR 的 SLEEP 位)/ J7 K+ L! j( |" X
  34. CAN_InitStructure.CAN_NART=ENABLE; //使用报文自动传送
    3 N3 `: t5 r/ w% ~. }# A5 d; N3 d
  35. CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
    & l8 [2 G4 R4 e; ~; k) ^
  36. CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
    + a5 T4 b# O5 O! [
  37. CAN_InitStructure.CAN_Mode= mode; //模式设置( E1 }, k- h6 }/ K4 R7 J! X- X' e
  38. CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq. L' x" h" Q' F6 ]6 U
  39. CAN_InitStructure.CAN_BS1=tbs1; //Tbs1 范 围 CAN_BS1_1tq~CAN_BS1_16tq0 A& f) z) q  b# Y; L0 Q$ g
  40. CAN_InitStructure.CAN_BS2=tbs2;//Tbs2 范 围 CAN_BS2_1tq ~CAN_BS2_8tq
    " j+ {0 O6 h2 v: u+ a
  41. CAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为 brp+1  {& P! L5 o/ j8 m
  42. CAN_Init(CAN1, &CAN_InitStructure); // 初始化 CAN1) n0 Y6 s' k: _) s3 @7 Q: L
  43. //配置过滤器$ R' D! E3 T* ~9 C4 ^, K8 h2 U8 j
  44. CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
    ) v: z6 W. s' P, }" D
  45. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;# _1 J! x0 I; G5 ?( p3 y$ H8 J  w
  46. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
    ; `& ?) l* f8 L# Q8 V
  47. //32位9 P  u' f! f0 r
  48. CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;////32 位ID8 d1 n# W  Q. G* b9 U8 k- G0 ^
  49. CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
    % |2 I  X) Y; c7 b' m; ^$ T
  50. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32 位MASK/ G4 `" Y+ x% {/ T" p" t& p
  51. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
    9 |$ ^5 M  |1 l9 K9 \! X
  52. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;% Z1 `! n8 p6 g9 E$ M- ^& ?4 d: V
  53. //过滤器 0 关联到 FIFO0
    7 L6 U! `7 m% e/ }
  54. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器 0$ u8 W+ A) I0 p/ Z  Q. t
  55. CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
    : T& K4 {- ]0 [) S6 K7 m
  56. #if CAN_RX0_INT_ENABLE
    : k$ s: R5 b4 ?
  57. CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //FIFO0 消 息挂号中断允许.
    9 K+ m1 X2 w5 T/ L5 W& Q# ^# s9 h
  58. NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;) r; i1 Q- j  J- T1 J) j& ?
  59. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    ' U1 n+ \) g" i& i4 c0 U
  60. // 主优先级为 11 a; x8 L! F" J9 M& ^/ S% v6 f
  61. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;& K6 \. D3 M9 D
  62. // 次优先级为 0
    4 `. ~5 m6 {8 ?* y
  63. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  s4 a1 k) t: s/ ]
  64. NVIC_Init(&NVIC_InitStructure);. N, a) L9 _" Y
  65. #endif1 ]& n: ]" D9 t( I4 F
  66. }
复制代码

5 C  q. L9 `" f3 @# }
    在CAN1_Mode_Init()函数中,首先使能 CAN1 和 GPIOA 时钟,并将管脚配置为复用功能。然后配置 CAN的工作模式、波特率及筛选器等参数。这一过程在前面步骤介绍中已经提了。CAN1_Mode_Init()函数有 4个参数,用来设置 CAN1 的波特率和工作模式,方便大家修改 CAN 的波特率和工作模式。参数的具体意义在函数开始处已注释。
; [" f) s# t8 a1 \2 g7 m# I- Y
CAN1 发送与接收函数
    初始化了 CAN1 后,我们就可以编写它的发送和接收函数,具体代码如下:
  1. //can 发送一组数据(固定格式:ID 为 0X12,标准帧,数据帧)
    2 e  b4 U; K, ^
  2. //len:数据长度(最大为8)
    : u6 b. y( N# r3 ?4 G
  3. //msg:数据指针,最大为8个字节.& x7 s- u0 r7 j  q* K
  4. //返回值:0,成功;
    , k/ l7 L: J% G5 B$ c; Z$ g! Q
  5. // 其他,失败;
    1 l! W$ v4 m) ~( `& P8 @5 h
  6. u8 CAN1_Send_Msg(u8* msg,u8 len)
    - C8 F% A- z3 G
  7. {: O# c" i$ s2 S. e+ K# K8 @
  8. u8 mbox;% `. y  k  O6 t0 d6 Y, f
  9. u16 i=0;, F) K, x7 G4 R- `6 w9 b
  10. CanTxMsg TxMessage;( O7 B) s; {: k! q9 z6 o+ Q
  11. TxMessage.StdId=0x12; // 标准标识符为 0
    5 u% E: e# q0 t6 u
  12. TxMessage.ExtId=0x12; // 设置扩展标示符(29 位)& m2 ?1 c3 m' c* u" C4 W5 u4 k4 W
  13. TxMessage.IDE=0; // 使用扩展标识符; X3 V- o6 s! y% M/ R3 {# e4 g" N
  14. TxMessage.RTR=0; // 消息类型为数据帧,一帧 8位
    : z* P5 R. d! Z
  15. TxMessage.DLC=len; // 发送两帧信息1 y# M, ]" X* {: j& t1 q
  16. for(i=0;i<len;i++)7 Z" ~3 [! E1 G, O3 p$ v7 Y
  17. TxMessage.Data[i]=msg[i]; // 第一帧信息
    + u. q7 M4 e0 c+ B: D' D
  18. mbox= CAN_Transmit(CAN1, &TxMessage);
    3 X* I; _  _9 j# a. Z6 z  c+ V
  19. i=0;6 v2 I& |  I5 d! F
  20. while((CAN_TransmitStatus(CAN1,
    8 u( o) l' ^# ^& l3 L. }0 K# e
  21. mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++; //等待发送结束6 q) F0 ~- f7 r3 T  V
  22. if(i>=0XFFF)return 1;  l% a& v# R1 N' }
  23. return 0;  X9 P: Z2 K& R  m
  24. }
    / i8 V& n# d# q4 K+ j) e
  25. //can 口接收数据查询: X/ q0 E" e/ n
  26. //buf:数据缓存区;5 p/ @2 x8 R1 H4 k5 v" y
  27. //返回值:0,无数据被收到;1 m: I9 G0 g; v$ I. S# S( ]
  28. // 其他,接收的数据长度;0 Y1 E+ b4 P, G) C9 ^
  29. u8 CAN1_Receive_Msg(u8 *buf)! Q  K  |. N( [  Y
  30. {
    - R; |; a1 \) W; e7 ?+ g( m
  31. u32 i;
    5 o3 O- S, f; z# ?: r, v
  32. CanRxMsg RxMessage;( \) e( w2 q& [: e, R* d
  33. if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0; //没有接收到数据,直接退出% x: ?; ~8 j% q1 U( A9 k3 }+ N* c+ m) b
  34. CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据
    % L- P# u! V  x4 u) W
  35. for(i=0;i<RxMessage.DLC;i++)$ ]( ?9 ]+ {5 g' I$ v
  36. buf[i]=RxMessage.Data[i];  p/ f# P- \4 P7 Q5 G* `
  37. return RxMessage.DLC;8 [2 E7 n0 c* S7 D3 N# S! D7 |
  38. }
复制代码

0 B2 m5 C0 g- y' S! q/ p
    CAN1_Send_Msg 函数为发送函数,用于 CAN 报文的发送,主要是设置标识符 ID等信息,写入数据长度和数据,并请求发送,实现一次报文的发送。CAN1_Receive_Msg 函数为接收函数,用于接受报文数据并且将接受到的数据存放到 buf 数组内。

5 m6 a0 a! v4 y; r2 u
主函数
    编写好 CAN1 初始化和发送接收函数后,接下来就可以编写主函数了,代码如下:
  1. /****************************************************************" U; Y4 [' A4 Z9 D4 l$ H% p4 Z8 c
  2. * 函 数 名 : main
    % k" s+ g- [+ {
  3. * 函数功能 : 主函数
    , C! q$ ^1 F+ ^
  4. * 输 入 : 无- C( [/ Z/ z; w- d* U
  5. * 输 出 : 无
    3 z  [" s  T8 p
  6. *****************************************************************/
    : q) H0 P3 G4 m! ~8 Y* y3 [
  7. int main()# F# L6 M0 ]' |
  8. {( T! o* Z0 V+ [6 g
  9. u8 i=0,j=0;
    7 V8 z+ r, w9 S. n
  10. u8 key;! G# M$ i) R( k& f2 C, a7 L8 N4 M- S+ {
  11. u8 mode=0;# U3 g( ?& ~3 E. I( l; z
  12. u8 res;
    8 h" \; z6 H- u6 T) K! k% _2 i
  13. u8 tbuf[8],char_buf[8];  h/ g2 A  {* R, R
  14. u8 rbuf[8];
    6 E1 G9 |1 H* ~2 E0 A1 E
  15. SysTick_Init(72);* ~& E2 O- S# F/ O; o$ P# M: F
  16. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2 组
    2 Y2 g3 y6 K. c% L4 Z" m
  17. LED_Init();
    * l: P. b9 p$ W( e
  18. USART1_Init(9600);
    & u% E" ]1 A! o6 J# x; M9 {& P  a
  19. KEY_Init();+ P! s* q9 W' }2 G2 P9 d- P
  20. CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_Normal);//500Kbps 波特率
    2 i9 v; Y3 C+ V1 u
  21. while(1)& d3 n0 ^$ z" A1 {
  22. {9 M: b" t' C- i8 M3 M0 c
  23. key=KEY_Scan(0);8 w$ {/ c" z' i% I9 _. F
  24. if(key==KEY_UP) //模式切换9 o0 F' r: K5 n% E; U8 s1 o0 R& E$ Z
  25. {
    + ~& y$ K8 |5 z9 Z$ m8 M4 p
  26. mode=!mode;6 P2 J4 s/ }" Q+ R
  27. CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);
    6 E, X, T9 T% z, j2 s3 [; M) O
  28. if(mode==0)
    + v  Z; G2 S7 e
  29. {0 K$ @9 Z2 ]1 N! U9 u' }+ `: s
  30. printf("Normal Mode\r\n");8 R1 K/ ?$ l# }- A
  31. }6 p( j: g- {1 W& Y' [
  32. else& d5 u4 |! \3 R* L
  33. {
    1 z' m3 R# [6 O8 T
  34. printf("LoopBack Mode\r\n");, w" x1 f3 T8 p. B8 V
  35. }
    ' K% L% N+ Y1 T+ y4 T; y2 |' B+ v
  36. }
    , }7 l: k# q" P
  37. if(key==KEY_DOWN) //发送数据$ j+ `4 N9 z( j; ]
  38. {
    & u& S  d. Z+ x) g
  39. for(j=0;j<8;j++)8 @- k) }0 T9 g- e/ f5 N) b
  40. {4 Y( f% y$ D+ O# D# U; [7 D
  41. tbuf[j]=j;' h: h# E" p# d" l% H
  42. char_buf[j]=tbuf[j]+0x30;
    4 T" Z' s7 j  x4 U
  43. }
    + g3 ^" Q0 S4 e7 i' ^" x' b
  44. res=CAN_Send_Msg(tbuf,8);
    7 o# N) _" G- F8 t+ m
  45. if(res)
    / x, m9 G* e8 t* R! \
  46. {  g1 J( T( O' p& [( v0 c8 ~
  47. printf("Send Failed!\r\n");
    : b: d% u, \8 M9 A( d" R: ]% K
  48. }
    * ?6 U" P8 k) [2 {$ _; n" _
  49. else6 }0 T8 \( q5 u* {; G
  50. {
    ) s, t7 {1 Z; ~) M8 H, d9 Q
  51. printf("发送数据:%s\r\n",char_buf);
    " N: A- Y+ F: l9 E; U  C! L" M
  52. }
      C. F; J" Y( J' a
  53. }' k% I+ T: |$ Z/ |$ L  V
  54. res=CAN_Receive_Msg(rbuf);
    3 T6 Q: U% s, Q: D' N
  55. if(res)( X$ ]2 @. r4 v' Q8 u; {1 K/ G
  56. {
    & w4 C) N2 T( j* E3 k/ f
  57. for(j=0;j<res;j++)
    / ]; G. P0 F% P- b6 m6 y* p# W
  58. {
    0 V+ p1 i: y: E7 C! [7 B
  59. char_buf[j]=rbuf[j]+0x30;
    1 c# Z& c% ~1 j$ A+ q
  60. }
    & Y  e/ J- L- E! j  g& X
  61. printf("接收数据:%s\r\n",char_buf);( W) V. S' R# i6 u# r0 {" J
  62. }3 O4 v& M, @& n1 x; o, T
  63. i++;
    8 V- ~4 l+ b/ Q8 s1 h0 O( u2 l
  64. if(i%20==0)' A3 [8 |4 `" `; r9 x1 C4 ~/ r/ g( ]
  65. {
    5 t) l! y6 ]" l' Q+ |
  66. led1=!led1;
    1 K& _# Z# `9 H& n6 B& w( {6 X
  67. }
    % [* m" w& g  l) N/ B: \1 p, b
  68. delay_ms(10);
    : K& e' C( \, z# |- L, q
  69. }
    ' x: ]+ g$ S6 p1 v' w1 l
  70. }
复制代码
4 b& Y: P# _: H
    主函数实现的功能很简单,首先调用之前编写好的硬件初始化函数,包括SysTick 系统时钟,中断分组,LED 初始化等。然后调用我们前面编写的CAN1_Mode_Init 函数,我们将 CAN1 波特率设置为 500Kbps(波特率计算可参考前面内容),工作模式为正常模式 CAN_Mode_Normal。最后进入 while 循环,循环检测K_UP 和 K_DOWN 按键是否按下。如果 K_UP 键按下,通过 mode 值变化实现CAN1的工作模式的切换(正常/环回模式),并将切换的工作模式提示信息打印输出。如果 K_DOWN 键按下,调用 CAN1_Send_Msg 函数将数据发送出去,并将发送的数据内容打印输出,同时调用 CAN1_Receive_Msg 函数将发送的数据内容保存在 rbuf 数组内,通过串口打印输出。整个过程 D1 指示灯会间隔200ms闪烁,提示系统正常运行。
    将工程程序编译后下载到开发板内,可以看到 D1 指示灯不断闪烁,表示程序正常运行。默认我们设置的是正常模式,所以需要连接 2 块 STM32F1 开发板的CAN 接口才能互发数据(前提是两块开发板都下载了这个程序),当按下任意一块开发板上的 K_DOWN 键后,通过串口就可以查看它们的收发数据。如果想在串口调试助手上看到输出信息,可以打开“串口调试助手”,首先勾选下标号 1 DTR 框,然后再取消勾选。这是因为此串口助手启动时会把系统复位住,通过 DTR 状态切换下即可。然后设置好波特率等参数后,串口助手上即会收到串口发送过来的信息。(前提一定要用短接片将P16排针短接到 CAN 端,串口助手上先勾选下标号 1 DTR 框,然后再取消勾选)如下图所示:
微信图片_20220626174701.png

0 u* Q! C! T1 W( H8 Z3 q
赞 收藏 评论0 发布时间:2022-6-26 17:47

举报

0个回答

所属标签

相似技术帖

官网相关资源

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