打印
[应用相关]

STM32的CAN现场总线应用总结

[复制链接]
1147|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gejigeji521|  楼主 | 2016-1-6 19:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
CAN现场总线的应用最重要的就是其接口端口映射、初始化及数据的发送、接收。
1.接口映射
STM32中的CAN物理引脚可以设置成三种:默认模式、重定义地址1模式、重定义地址2模式。
CAN信号可以被映射到端口A、端口B或端口D上,如下表所示,对于端口D,在36、48和64脚的封装上没有重映射功能。
表1:CAN复用功能重映射
  
复用功能
  
CAN_REMAP[1:0]="00"
CAN_REMAP[1:0]="10"
CAN_REMAP[1:0]="11"
CAN_RX
PA11
PB8
PD0
CAN_TX
PA12
PB9
PD1
重映射不适用于36脚的封装
当PD0和PD1没有被重映射到OSC_IN和OSC_OUT时,重映射功能只适用于100脚和144脚的封装上
----------------------------------------------------------------------------------------------------------------------
默认模式
/* ConfigureCAN pin: RX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIO_CAN_Key,&GPIO_InitStructure);
  
  /* Configure CAN pin: TX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
----------------------------------------------------------------------------------------------------------------------
重定义地址1模式
  /* Configure CAN pin: RX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIO_CAN_Key,&GPIO_InitStructure);
  
  /* Configure CAN pin: TX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;
  GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);
  
  /*Configure CAN Remap 重映射 */
  GPIO_PinRemapConfig(GPIO_Remap1_CAN,ENABLE);
----------------------------------------------------------------------------------------------------------------------
/* ConfigureCAN pin: RX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIO_CAN_Key,&GPIO_InitStructure);
  
/* ConfigureCAN pin: TX */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;
  GPIO_Init(GPIO_CAN_Key,&GPIO_InitStructure);
  
  /*Configure CAN Remap 重映射 */
  GPIO_PinRemapConfig(GPIO_Remap2_CAN,ENABLE);
----------------------------------------------------------------------------------------------------------------------
设置完CAN的引脚之后还需要打开CAN的时钟:
  /* CAN Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN,ENABLE);

沙发
gejigeji521|  楼主 | 2016-1-6 20:00 | 只看该作者
2. 初始化
2.1.1 CAN单元初始化
CAN单元初始化最重要的就是波特率的设置,原理如下:
file:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image001.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image002.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image003.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image003.png                                                                 位时间
  
同步段
  
时间段1(BS1)
时间段2(BS2)
file:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image004.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image005.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image006.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image007.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image008.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image009.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image010.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image010.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image010.pngfile:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image010.png      1×tq            tBS1=(TS1[3:0]+1×tq                      tBS2=(TS2[2:0]+1)×tq
file:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image011.png

波特率=1/位时间
位时间 = (1 + tBS1+ tBS2)× tq
file:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image012.pngtq = (BRP[9:0] + 1× tPCLK
tPCLK =APB1
例如现有一STM32系统时钟为72MHz,关于CAN波特率有以下设置:
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq; //时间段1为8个时间单位
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq; //时间段2为7个时间单位
CAN_InitStructure.CAN_Prescaler = 45; //设定了一个时间单位的长度为45
则其CAN的波特率为1÷[(1+8+7)×45÷(36×106)]=50KHz

file:///C:/Users/mint/AppData/Local/Temp/msohtmlclip1/01/clip_image013.png


    CAN单元的初始化,除了波特率的设置
以外还包括以下设置:
CAN_InitTypeDef        CAN_InitStructure; //定义一个CAN单元
CAN_InitStructure.CAN_TTCM= DISABLE; //设置时间触发通信模式(失能)
CAN_InitStructure.CAN_ABOM = DISABLE;// 使/失能自动离线管理(失能)
CAN_InitStructure.CAN_AWUM = DISABLE;// 使/失能自动唤醒模式(失能)
CAN_InitStructure.CAN_NART = DISABLE; //使/失能非自动重传输模式(失能)
CAN_InitStructure.CAN_RFLM = DISABLE;// 使/失能接收FIFO锁定模式(失能)
CAN_InitStructure.CAN_TXFP = DISABLE; //使/失能发送FIFO优先级(失能)
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;//设置CAN工作模式(正常模式)
2.1.2 CAN报文过滤器初始化
STM32共有14组过滤器,每组过滤器包括了2个可配置的32位寄存器:CAN_FxR0和CAN_FxR1。
可以将过滤器组配置成屏蔽位模式,这样CAN_FxR0中保存的就是标识符匹配值,CAN_FxR1中保存的是屏蔽码,即CAN_FxR1中如果某一位为1,则CAN_FxR0中相应的位必须与收到的帧的标志符中的相应位吻合才能通过过滤器;CAN_FxR1中为0的位表示CAN_FxR0中的相应位可不必与收到的帧进行匹配。
还可以将过滤器组配置成标识符列表模式,此时CAN_FxR0和CAN_FxR1中的都是要匹配的标识符,收到的帧的标识符必须与其中的一个吻合才能通过过滤。
对CAN报文过滤器的初始化实际上就是对接收FIFO邮箱标识符寄存器(CAN_RixR)(x=0,1)的设置。这些寄存器如下图所示:
  
31
  
  
30
  
  
29
  
  
28
  
  
27
  
  
26
  
  
25
  
  
24
  
  
23
  
  
22
  
  
21
  
  
20
  
  
19
  
  
18
  
  
17
  
  
16
  
  
STID[10:0]
  
EXID[17:13]
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
15
  
  
14
  
  
13
  
  
12
  
  
11
  
  
10
  
  
9
  
  
8
  
  
7
  
  
6
  
  
5
  
  
4
  
  
3
  
  
2
  
  
1
  
  
0
  
  
EXID[12:0]
  
IDE
RTR
Res.
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
CAN_RIxR寄存器各位域定义:
  
  
定义
31:21
   STID[10:0]:标准标识符 标识符的标准部分
20:3
   EXID[17:0]: 扩展标识符 标识符的扩展部分(如果使用了扩展标识符)
2
  IDE:标识符选择   0:标准标识符;1:扩展标识符
1
  RTR:远程发送请求 0:数据帧;1:远程帧
0
  保留位
注意:CAN_FilterIdHigh是指高16位,CAN_FilterIdLow是低16位,应该将需要得到的帧和过滤器的设置值坐对齐起。
采用stm32f10x标准外设库时过滤器的完整设置如下:
CAN_FilterInitTypeDef  CAN_FilterInitStructure;   //定义一个过滤器
CAN_FilterInitStructure.CAN_FilterNumber=0;     //选定第一组过滤器     
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;     //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=(0x0010 << 5); //接收ID为10的消息,11位标准帧因此左移5位
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;      //第一组过滤器指向FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);

使用特权

评论回复
板凳
gejigeji521|  楼主 | 2016-1-6 20:01 | 只看该作者
3.数据发送
CAN_Transmit()函数的操作包括:
1. [选择一个空的发送邮箱]
2. [设置Id]*
3. [设置DLC待传输消息的帧长度]
4. [请求发送]
请求发送语句:
CAN->sTxMailBox[TransmitMailbox].TIR|= TMIDxR_TXRQ;//对CAN_TIxR寄存器的TXRQ位置1,来请求发送
采用stm32f10x标准外设库时CAN发送的完整方法如下:
CanTxMsg TxMessage; //定义发送信息
TxMessage.StdId = 0x0110;   //设定标识符(采用标准标识符时,硬件会自动把数据左移5位)
TxMessage.ExtId=0x0000;    //设定扩展标识符(非必须,采用标准标识符时可不设定)
TxMessage.RTR = CAN_RTR_DATA;   //设定待传输消息的帧类型
TxMessage.IDE = CAN_ID_STD; //设定消息标识符的类型
TxMessage.DLC = X;    //设定待传输消息的帧的长度
TxMessage.Data[0] = 0xXX; //写入要传送的数据,最多可写8个字节
                            .
                            .
TxMessage.Data[7] = 0xXX;
CAN_Transmit(CAN1, &TxMessage);  //开始一个消息的传输
4.数据接收
CAN数据的接收可以放在一个中断中,以下为一完整中断接收程序:
void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
  RxMessage.StdId=0x0004;
  RxMessage.IDE=0;
  RxMessage.DLC=2;
  RxMessage.FMI=0;
  RxMessage.Data[0]=0x00;
  RxMessage.Data[1]=0x00;
CAN_Receive(CAN1, CAN_FIFO0,&RxMessage);
CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);  
}

使用特权

评论回复
地板
gejigeji521|  楼主 | 2016-1-6 20:02 | 只看该作者
在word里做的东西,有的贴上来变化不见了。我做成PDF再发上来。 STM32的CAN现场总线应用总结.pdf (163.51 KB)



使用特权

评论回复
5
sackfc| | 2016-1-10 14:33 | 只看该作者
好东西,谢谢了

使用特权

评论回复
6
armxu| | 2016-1-10 14:54 | 只看该作者
谢谢分享!

使用特权

评论回复
7
米尔豪斯| | 2016-1-10 16:33 | 只看该作者
CAN_Receive(CAN1, CAN_FIFO0,&RxMessage)怎么定义的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

177

主题

2224

帖子

8

粉丝