关于通信波特率设置、初始化程序、发送程序、接收程序 1、波特率 CAN通讯属于 异步通讯,没有时钟信号线,所以所有节点之间要约定好使用相同的波特率来传输数据。波特率不同将无法进行通信 CAN总线是基于相同波特率通信的,所以设备接入前要知道总线上的波特率是多少。 波特率=(pclk1/((1+8+7)*9))=36MHz/16/9=250Kbits 在can.h文件中定义一些参数,用于计算波特率 2、数据数量 一次最多只能发送8个字节的数据,这是由CAN协议规定的。 多于8个的需要第二次再发送,或者做一个上层的连续多数据发送的函数。 1 0 逻辑电平 用逻辑电平组成数据 3、初始化程序 - u8 CAN1_Configuration(void){ //CAN初始化(返回0表示设置成功,返回其他表示失败) J) v- m; g. d6 h) B6 h
- GPIO_InitTypeDef GPIO_InitStructure; 7 K; I; ~+ y9 C& O; v" H
- CAN_InitTypeDef CAN_InitStructure;
3 l* N* @0 S+ u/ j - CAN_FilterInitTypeDef CAN_FilterInitStructure;
3 ?; `+ t! D; h5 a; a; L& x! l( d
+ @1 Q0 F. Q0 ?$ B2 W2 C( D2 R$ F- #if CAN_INT_ENABLE
" L, u6 k( b% ^9 }# B0 X& B - NVIC_InitTypeDef NVIC_InitStructure; 0 q, `; ^- ?0 u8 a* D
- #endif7 Q; L% [$ [# N
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //使能PORTD时钟 4 k/ d! {/ b) C- v. q, x0 F8 M
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //使能CAN1时钟 ) ` W3 z, J( B/ p; h) b V: h
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
$ u. W5 o V5 D. a# M - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
w( Q% ^* R" S3 n8 E8 T - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽7 r, R! w* M1 p( @4 e& Z
- GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO7 r3 ^' L5 ^! T$ o# P
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
* o: }! Z7 O) J8 X8 d( ~3 Z - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
/ Y' K% a* z3 p& ~/ [3 h - GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO2 c% m' r+ c- I# z1 k
- //CAN单元设置
2 {, W& c7 S) E( s$ \ F - CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式
/ C5 q! s3 _9 z; R" M3 O - CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理
L7 K X9 a3 A" E - CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位). V2 Q6 J/ s! K4 @. b7 i, Z
- CAN_InitStructure.CAN_NART=ENABLE; //禁止报文自动传送 ( i0 L; C; G1 f: t a2 g* r/ ]2 y9 r
- CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
: s# j+ I! Z0 \ - CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
: B5 l7 ^- n; B5 ~7 a9 h* t) P - CAN_InitStructure.CAN_Mode= CAN_Mode_Normal; //模式设置:CAN_Mode_Normal 普通模式,CAN_Mode_LoopBack 回环模式; / ?! R3 Q, `, S2 O6 }7 j* d
- //设置波特率 \2 @1 o6 ?1 Y8 c0 G
- CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
( V; F- B1 W: l$ \2 y" E - CAN_InitStructure.CAN_BS1=tbs1; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~ CAN_BS1_16tq# j% I8 F# T1 B# l. D- W m
- CAN_InitStructure.CAN_BS2=tbs2; //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq) A$ r) E* C1 M& r! p* [: u- i
- CAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1
' ^* c U6 n3 u4 T, k0 g - CAN_Init(CAN1, &CAN_InitStructure); //初始化CAN1 1 f3 p. q0 {$ J: X' m7 O) c
- //设置过滤器
8 p8 x6 i' P: N5 E6 X$ V+ m9 G - CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
) U; O# o+ ]% @/ M/ v. A - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //屏蔽位模式' U0 c+ a* b) ~4 I9 J
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位宽 - {# z+ x1 } Y# `$ C C) p
- CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //32位ID
. R, |& Y3 y% V0 q6 W& f* I/ z - CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
1 y6 s, h- Q- Y* f! o1 s! y - CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
; p8 a0 g$ _9 O+ j6 Y n3 {$ O- H5 b: S - CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
$ F! M! D2 o6 g2 q - CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
2 P9 u. N% Q9 c3 v, j- R, b - CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0: z* L% b' E7 n6 b
- CAN_FilterInit(&CAN_FilterInitStructure); //滤波器初始化
; }- C$ p4 T4 X& L M" m3 x+ x5 ]
5 ]7 O e1 Q' h X$ t. y: @- #if CAN_INT_ENABLE //以下是用于CAN中断方式接收的设置" b7 n, ~; `3 `& X7 j4 F r
- CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //FIFO0消息挂号中断允许. ! n/ w* n( k& d. t9 V5 A8 E$ ~
- NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
, k; Q8 |$ j6 U& H: o1 w - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1
5 i! E7 V$ |& y; s - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为0
3 v2 U7 r- d0 T) e - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;4 I9 t* ?& z' |0 P! Q
- NVIC_Init(&NVIC_InitStructure);
" J- e4 t+ V: X) P* E* f - #endif
3 m+ w: b3 P* l; t( N5 V - return 0; 5 j& P/ g+ |. \; Y5 \ ^5 T
- }
复制代码
0 s B& F" `5 i" l" r. A3、发送程序 - //CAN发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
8 T) z! r5 H. e6 i% R( v - //msg:数据指针,最大为8个字节,len:数据长度(最大为8) # @8 y6 e9 N0 |/ ~
- //返回值:0,成功; 其他,失败;2 P. L- t4 [# Y, e) y
- u8 CAN_Send_Msg(u8* msg,u8 len){
# {5 l6 C- z j - u8 mbox;" a& S, i$ _$ M* ~: [
- u16 i=0;: D G: x: s2 l, a; W
- CanTxMsg TxMessage;/ c j- C- E) e4 E. ?
- TxMessage.StdId=0x10; // 标准标识符
/ i4 q! Y- X$ O5 [ - TxMessage.ExtId=0x00; // 设置扩展标识符& Y9 m# v- e* x8 H
- TxMessage.IDE=CAN_Id_Standard; // 标准帧
8 x0 }& }" i1 G7 x - TxMessage.RTR=CAN_RTR_Data; // 数据帧 v) w# s8 F, B; x7 l4 G
- TxMessage.DLC=len; // 要发送的数据长度; \5 J7 Q+ {, i! j& r) h
- for(i=0;i<len;i++)7 F+ b3 b6 N5 M, @% y% n4 b, L& f
- TxMessage.Data[i]=msg[i]; //写入数据
3 T- _% ~& x; {4 [6 m - mbox= CAN_Transmit(CAN1,&TxMessage); - H0 A1 @9 T+ A& A
- i=0;
' g6 X$ @! s& J7 V" J7 p& ~ - while((CAN_TransmitStatus(CAN1,mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++; //等待发送结束
0 X8 R' S2 r9 @' Z - if(i>=0XFFF)return 1;: V# c% H9 L* }- ]
- return 0; ) x2 Y/ ]' `" R: _3 d/ P7 c
- }
复制代码
' k, T! M! @. \: y+ h) k4、接收程序 - //can口接收数据查询
d. e3 A1 u1 j, ]3 Z4 R1 ]( m - //buf:数据缓存区; + {$ k8 f' z6 M- C' t7 H D& w
- //返回值:0,无数据被收到,其他,接收的数据长度;3 {3 h4 ]/ Q* a9 v! M: s' X
- u8 CAN_Receive_Msg(u8 *buf){
2 t# e1 X8 W; F9 g% I - u32 i;
, r, J, v% U+ |! z - CanRxMsg RxMessage;) f$ N$ T$ @/ s9 I
- if(CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;//没有接收到数据,直接退出
3 H9 V: y" M2 _! d8 }, R - CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);//读取数据
# ~' c; @& o' B p1 S) a - for(i=0;i<8;i++) //把8个数据放入参数数组! E" |& a. N4 G4 r
- buf[i]=RxMessage.Data[i];
) K9 y% [" n9 X- z- K k1 j - return RxMessage.DLC; //返回数据数量
: g4 ]; M; _- L7 } - }
复制代码 8 \; q9 U* g- z: O. u8 W
STM32H7A3ZIQ作为主机、STM32F103C8T6作为从机。. W6 V* I9 s0 G1 F
主机通过CAN通信发送数据,从机接收数据,并显示在屏幕上。
& w9 @# L6 O$ S2 v( N o
) p7 s$ ^( \! |5 u2 y" B-------结果展示-------
, {2 I* J+ O. }5 S
|