STM32F103的CAN
文章目录
21 STM32F103的CAN
在 STM32 互联型产品中,带有 2 个 CAN 控制器,而我们使用的STM32F103ZET6 属于增强型,不是互联型,只有 1 个 CAN 控制器.
21.1 双 CAN 的框图
两个 CAN 都分别拥有自己的发送邮箱和接收 FIFO,但是他们共用 28 个滤波器。
21.1.1 发送邮箱
发送邮箱共有3个
- 每个发送邮箱中包含有标识符寄存器 CAN_TIxR、数据长度控制寄存器 CAN_TDTxR及 2 个数据寄存器 CAN_TDLxR、 CAN_TDHxR。
要使用 CAN 外设发送报文时,把报文的各个段分解,按位置写入到这些寄存器中,并对标识符寄存器 CAN_TIxR 中的发送请求寄存器位 TMIDxR_TXRQ 置 1,即可把数据发送出去。
21.1.2 接收FIFO
具有 3 级深度的 2 个接收 FIFO
- 每个 FIFO 中有 3 个邮箱,即最多可以缓存 6 个接收到的报文。
- 每个接收 FIFO 中与发送邮箱一样,也包含有标识符寄存器 CAN_RIxR、数据长度控制寄存器CAN_RDTxR 及 2 个数据寄存器 CAN_RDLxR、 CAN_RDHxR
- 当接收到报文时, FIFO 的报文计数器会自增,而 STM32 内部读取 FIFO 数据之后,报文计数器会自减
- 通过中断或状态寄存器知道接收 FIFO 有数据后,我们再读取这些寄存器的值即可把接收到的报文加载到 STM32 的内存中。
通过主控制寄存器的 RFLM 位,可设置锁定模式
- 锁定模式下 FIFO 溢出时会丢弃新报文
- 非锁定模式下 FIFO 溢出时新报文会覆盖旧报文。
21.1.3 过滤器
CAN 总线上数据是以广播的形式发送的,所有连接在 CAN 总线的节点都会收到所有其它节点发出的有效数据,因而我们的 CAN 控制器大多具有根据 ID 过滤报文的功能,它可以控制自己只接收某些 ID的报文。减少了CPU处理CAN通信的开销。
STM32F103ZET6 只有 14 个(增强型)过滤器组。
- 每个滤波器组 x 由 2 个 32 为寄存器,CAN_FxR1 和 CAN_FxR2 组成。
STM32 每个过滤器组的位宽都可以独立配置
- 1 个 32 位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE 和 RTR 位
- 2 个 16 位过滤器,包括:STDID[10:0]、IDE、RTR 和 EXTID[17:15]位
过滤器可配置为,屏蔽位模式和标识符列表模式。
21.1.3.1 CAN_FMR 过滤器模式寄存器
该寄存器必须在过滤器处于初始化模式下(CAN_FMR 的 FINIT 位=1),才可以进行设置。
对 28 个滤波器组的工作模式,都可以通过该寄存器设置,对 STM32F103ZET6 来说,只有[13:0]这 14 个位有效。
- 应用程序不用的过滤器组,应该保持在禁用状态。
过滤器工作的两种模式
- 标识符列表模式
○ 它把要接收报文的 ID 列成一个表,要求报文 ID 与列表中的某一个标识符完全相同才可以接收,可以理解为白名单管理。
○ 为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。 - 掩码模式
○ 它把可接收报文 ID 的某几位作为列表,这几位被称为掩码,可以把它理解成关键字搜索,只要掩码(关键字)相同,就符合要求,报文就会被保存到接收 FIFO。
○ 为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。
21.1.3.2 CAN_FxR1 和 CAN_FxR2
用来存储要筛选的 ID 或掩码
x(CAN_FiRx)(互联产品中 i=0~27,其它产品中 i=0~13;x=1/2)
后两个模式是在互联型产品中的,F103不需要关注。
举个简单的例子,我们设置过滤器组 0 工作在:1 个 32 位过滤器-标识符屏蔽模式,然后设置 CAN_F0R1=0XFFFF0000,CAN_F0R2=0XFF00FF00。
- 存放到 CAN_F0R1 的值就是期望收到的 ID,即我们希望收到的映像(STID+EXTID+IDE+RTR)最好是:0XFFFF0000。
- 0XFF00FF00 就是设置我们需要必须关心的 ID,表示收到的映像,其位[31:24]和位[15:8]这 16个位的必须和 CAN_F0R1 中对应的位一模一样,而另外的 16 个位则不关心,都认为是正确的 ID,即收到的映像必须是 0XFFxx00xx,才算是正确的(x 表示不关心)。
21.2 CAN的配置
21.2.1 GPIO初始化
第一步就要使能 CAN 的时钟。其次要设置 CAN 的相关引脚为复用输出,设置 PA11 为上拉输入(CAN_RX 引脚)PA12 为复用输出(CAN_TX 引脚),并使能 PA 口的时钟。使能 CAN1 时钟的函数是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能 CAN1 时钟
具体函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能 PORTA 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能 CAN1 时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 IO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 IO
CAN是挂载在APB1之下的。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!