网站设计 英文,wordpress ip 地址修改密码,凡网站创建,站长做旅游网站STM32 CAN 文章目录 STM32 CAN前言一、CAN外设1.主控制寄存器CAN_MCR2.位时序寄存器CAN_BTR3.CAN的发送邮箱4.CAN的接收FIFO5.验收筛选器 二、代码配置1.初始化2.发送数据3.接收数据4.main.c 前言
前面学习了CAN的一些理论知识#xff0c;他在我们的STM32里面是怎么用的呢 前…STM32 CAN 文章目录 STM32 CAN前言一、CAN外设1.主控制寄存器CAN_MCR2.位时序寄存器CAN_BTR3.CAN的发送邮箱4.CAN的接收FIFO5.验收筛选器 二、代码配置1.初始化2.发送数据3.接收数据4.main.c 前言
前面学习了CAN的一些理论知识他在我们的STM32里面是怎么用的呢 前面讲了一些can的知识在STM32里是什么样的呢
一、CAN外设
1.主控制寄存器CAN_MCR
DBF调试冻结处于程序调试模式才使用。可以设置CAN处于工作模式还是禁止收发状态禁止收发时仍可以访问接受FIFO中的数据。 TTCM时间触发模式设置CAN的时间触发通信模式。在此模式下CAN使用它内部定时器产生时间戳并把它保存在CAN_RDTxR,CAN_TDTxR寄存器中。可以利用它实现标准分时同步通信功能。 ABOM自动离线管理当节点检测到他发送错误或者接受错误超过一定值时会自动离线管理。离线状态下不能接收或者发送。 AWUM自动唤醒在使用软件进入睡眠后如果使用自动唤醒在检测到总线活动时会自动唤醒。 NART自动重传当报文发送失败会自动重传直到成功为止。 RFLM锁定模式锁定接收FIFO。锁定之后当接收FIFO溢出时会丢弃下一个接收的报文。若不锁定则会覆盖掉之前的报文。 TXFP报文发送优先级的判定方法当邮箱中有多个报文需要发送时控制它是根据报文的ID优先级还是报文存进邮箱的顺序来发送。
2.位时序寄存器CAN_BTR
SILM为0正常模式为1静默模式 LBKM为1允许回环模式为0禁止回环模式 CAN有四种工作模式。由位时序寄存器的SILM和LBKM组合控制。 • 正常模式 正常模式下就是一个正常的 CAN 节点可以向总线发送数据和接收数据。 • 静默模式 静默模式下它自己的输出端的逻辑 0 数据会直接传输到它自己的输入端逻辑 1 可以被发送到总线所以它不能向总线发送显性位 (逻辑 0)只能发送隐性位 (逻辑 1)。输入端可以从总线接收内容。由于它只可发送的隐性位不会强制影响总线的状态所以把它称为静默模式。这种模式一般用于监测它可以用于分析总线上的流量但又不会因为发送显性位而影响总线。 • 回环模式 回环模式下它自己的输出端的所有内容都直接传输到自己的输入端输出端的内容同时也会被传输到总线上即也可使用总线监测它的发送内容。输入端只接收自己发送端的内容不接收来自总线上的内容。使用回环模式可以进行自检。 • 回环静默模式 回环静默模式是以上两种模式的结合自己的输出端的所有内容都直接传输到自己的输入端并且不会向总线发送显性位影响总线不能通过总线监测它的发送内容。输入端只接收自己发送端的内容不接收来自总线上的内容。这种方式可以在“热自检”时使用即自我检查的时候不会干扰总线。
在STM32中的位时序
SYNC_SEG,BS1,BS2三段采样点位于BS1和BS2交界处。SYNC_SEG的固定长度是1Tq.BS1和BS2的长度SJW可以在位时序寄存器中配置。
波特率
STM32的CAN1和CAN2挂载在APB1上。APB1总线的最大频率是36MHz。在使用CAN2时必须打开CAN1的时钟。波特率设置 举两个例子 500bps
CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN,波特率500Kbps 这个是怎么计算的呢根据前面提到4分频 4/36M *189500Kbps 那么1M应该怎么配置呢
CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_5tq,CAN_BS1_3tq,4,CAN_Mode_LoopBack);//CAN 1Mbps4/36*1531M
3.CAN的发送邮箱
CAN外设有三个发送邮箱即最多可以缓存3个待发送报文。 每个发送邮箱中包含有四个寄存器。
标识符寄存器CAN_TIxR存储待发送报文的ID扩展IDIDE位及RTR位 数据长度控制寄存器CAN_TDTxR存储待发送报文的DLC段 低位数据寄存器CAN_TDLxR存储数据段的低四个字节内容 高位数据寄存器CAN_TDHxR存储高四字节的内容 发送邮箱的工作过程当需要发送报文时把报文分解成各个段存储到不同的寄存器中并对标识符寄存器的发送请求位置1即可把数据发送出去。
4.CAN的接收FIFO
CAN外设有2个接收FIFO每个FIFO中有3个邮箱即最多可以缓存6个接收报文。当接收到报文时FIFO报文计数器会自增当报文被读取之后计数器会自减。和发送邮箱类似FIFO有四个寄存器。 标识符寄存器CAN_RIxR存储接收报文的ID扩展IDIDE位及RTR位 数据长度控制寄存器CAN_RDTxR存储接收报文的DLC段 低位数据寄存器CAN_RDLxR存储数据段的低四个字节内容 高位数据寄存器CAN_RDHxR存储高四字节的内容
5.验收筛选器
STM32F103的CAN外设有14个筛选器组每组有两个寄存器。CAN1和CAN2共用筛选器。筛选器的作用下节点只接受需要的报文到自己的FIFO中。筛选器可以调整筛选ID的长度和过滤模式
1根据筛选ID长度分类
32位STDID[10:0],EXTID[17:0],IDE,RTR 16位STDID[10:0],EXTID[17:15],IDE,RTR 2根据过滤方式分为
标识符列表模式要求报文与列表中的ID的每一个标识符相同才接收。 掩码模式只要报文ID中规定的某些位相同就会被接收。 筛选尺度寄存器CAN_FS1R的FSCx位可以设置工作在32位还是16位筛选模式寄存器CAN_FM1R的FBMx位可以设置工作在标识符列表模式还是掩码模式。每组筛选器有2个32位寄存器分别为CAN_FxR1,CAN_FxR2,用来存储要筛选的ID或者掩码。
二、代码配置
1.初始化
备注比正点的例程或者野火的都要详细
/**
* brief CAN 初始化
* param tsjw : 重新同步跳跃时间单元.范围: 1~3;
* param tbs2 : 时间段 2 的时间单元.范围: 1~8;
* param tbs1 : 时间段 1 的时间单元.范围: 1~16;
* param brp : 波特率分频器.范围: 1~1024;
* note 以上 4 个参数, 在函数内部会减 1, 所以, 任何一个参数都不能等于 0
* CAN 挂在 APB1 上面, 其输入时钟频率为 Fpclk1 PCLK1 36Mhz
* tq brp * tpclk1;
* 波特率 Fpclk1 / ((tbs1 tbs2 1) * brp);
* 我们设置 can_init(1, 8, 9, 4, 1), 则 CAN 波特率为:
* 36M / ((8 9 1) * 4) 500Kbps
* param mode : CAN_MODE_NORMAL, 普通模式;CAN_MODE_LOOPBACK,回环模式;
* retval 0, 初始化成功; 其他, 初始化失败;
* */
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{GPIO_InitTypeDef GPIO_InitStructure; CAN_InitTypeDef CAN_InitStructure;CAN_FilterInitTypeDef CAN_FilterInitStructure;
#if CAN_RX0_INT_ENABLE NVIC_InitTypeDef NVIC_InitStructure;
#endifRCC_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); //初始化IOGPIO_InitStructure.GPIO_Pin GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU;//上拉输入GPIO_Init(GPIOA, GPIO_InitStructure);//初始化IO//CAN单元设置CAN_InitStructure.CAN_TTCMDISABLE;//非时间触发通信模式 //CAN_InitStructure.CAN_ABOMDISABLE;//软件自动离线管理 //CAN_InitStructure.CAN_AWUMDISABLE;//睡眠模式通过软件唤醒(清除CAN-MCR的SLEEP位)//CAN_InitStructure.CAN_NARTENABLE;//禁止报文自动传送 //CAN_InitStructure.CAN_RFLMDISABLE; //报文不锁定,新的覆盖旧的 // CAN_InitStructure.CAN_TXFPDISABLE; //优先级由报文标识符决定 //CAN_InitStructure.CAN_Mode mode;//模式设置 mode:0,普通模式;1,回环模式; ////设置波特率CAN_InitStructure.CAN_SJWtsjw; //重新同步跳跃宽度(Tsjw)为tsjw1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tqCAN_InitStructure.CAN_BS1tbs1; //Tbs1tbs11个时间单位CAN_BS1_1tq ~CAN_BS1_16tqCAN_InitStructure.CAN_BS2tbs2;//Tbs2tbs21个时间单位CAN_BS2_1tq ~ CAN_BS2_8tqCAN_InitStructure.CAN_Prescalerbrp; //分频系数CAN_Init(CAN1, CAN_InitStructure); // 初始化CAN1 CAN_FilterInitStructure.CAN_FilterNumber0;//过滤器0CAN_FilterInitStructure.CAN_FilterModeCAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScaleCAN_FilterScale_32bit; //32位 CAN_FilterInitStructure.CAN_FilterIdHigh0x0000;设置过滤器的标识符高位32位IDCAN_FilterInitStructure.CAN_FilterIdLow0x0000;//设置过滤器的标识符低位CAN_FilterInitStructure.CAN_FilterMaskIdHigh0x0000;//设置过滤器的掩码高位32位MASKCAN_FilterInitStructure.CAN_FilterMaskIdLow0x0000;//设置过滤器的掩码低位CAN_FilterInitStructure.CAN_FilterFIFOAssignmentCAN_Filter_FIFO0;//过滤器0关联到FIFO0表示匹配的数据帧将进入FIFO0缓冲区。CAN_FilterInitStructure.CAN_FilterActivationENABLE; //激活过滤器0CAN_FilterInit(CAN_FilterInitStructure);//滤波器初始化
#if CAN_RX0_INT_ENABLECAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许. NVIC_InitStructure.NVIC_IRQChannel USB_LP_CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; // 主优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; // 次优先级为0NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);
#endifreturn 0;
} CAN_FilterMode_IdMask宏指定过滤模式为标识符/掩码模式。在这种模式下过滤器将使用标识符和掩码来匹配数据帧。标识符是数据帧的标识符而掩码用于指定哪些位需要匹配。如果标识符和掩码的匹配条件满足数据帧就会被允许通过过滤器。
CAN_FilterMode_IdList宏指定过滤模式为标识符列表模式。在这种模式下过滤器将使用一个预定义的标识符列表来匹配数据帧。如果数据帧的标识符与列表中的任何一个匹配数据帧就会被允许通过过滤器。
2.发送数据
//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//len:数据长度(最大为8)
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
// 其他,失败;
u8 Can_Send_Msg(u8* msg,u8 len)
{ u8 mbox;u16 i0;CanTxMsg TxMessage;TxMessage.StdId0x12; // 标准标识符 TxMessage.ExtId0x12; // 设置扩展标示符 TxMessage.IDECAN_Id_Standard; // 标准帧TxMessage.RTRCAN_RTR_Data; // 数据帧TxMessage.DLClen; // 要发送的数据长度for(i0;ilen;i)TxMessage.Data[i]msg[i]; mbox CAN_Transmit(CAN1, TxMessage); i0;while((CAN_TransmitStatus(CAN1, mbox)CAN_TxStatus_Failed)(i0XFFF))i; //等待发送结束if(i0XFFF)return 1;return 0; }首先定义了一个CanTxMsg类型的变量TxMessage用于存储要发送的数据帧的相关信息包括标识符、帧类型、数据长度和数据内容等。 然后根据输入参数msg和len将要发送的数据存储到TxMessage.Data数组中。 调用CAN_Transmit函数发送数据帧并返回发送邮箱mbox的编号。 等待发送结束直到CAN_TransmitStatus返回CAN_TxStatus_Failed或者经过一定的时间限制才退出等待循环。 如果发送成功则返回0否则返回1。
3.接收数据
//can口接收数据查询
//buf:数据缓存区;
//返回值:0,无数据被收到;
// 其他,接收的数据长度;
u8 Can_Receive_Msg(u8 *buf)
{ u32 i;CanRxMsg RxMessage;if( CAN_MessagePending(CAN1,CAN_FIFO0)0)return 0; //没有接收到数据,直接退出 CAN_Receive(CAN1, CAN_FIFO0, RxMessage);//读取数据 for(i0;i8;i)buf[i]RxMessage.Data[i]; return RxMessage.DLC;
}
首先定义了一个CanRxMsg类型的变量RxMessage用于存储接收到的数据帧的相关信息包括标识符、帧类型、数据长度和数据内容等。 使用CAN_MessagePending函数检查CAN1的FIFO0中是否有待接收的数据帧。如果没有数据帧待接收则直接退出函数并返回0。 调用CAN_Receive函数从CAN1的FIFO0中读取接收到的数据帧并将其存储到RxMessage变量中。 将接收到的数据存储到输入参数buf指向的缓冲区中。 返回接收到的数据帧的数据长度RxMessage.DLC。
4.main.c CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN初始化环回模式,波特率500Kbps while(1){keyKEY_Scan(0);if(keyKEY0_PRES)//KEY0按下,发送一次数据{for(i0;i8;i){canbuf[i]i;//填充发送缓冲区printf(发送%d\r\n,canbuf[i]);}resCan_Send_Msg(canbuf,8);//发送8个字节 if(res)printf(发送失败\r\n); //提示发送失败else printf(发送\r\n); //提示发送成功 }else if(keyWKUP_PRES)//WK_UP按下改变CAN的工作模式{ mode!mode;CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);//CAN普通模式初始化, 波特率500Kbps if(mode0)//普通模式需要2个开发板{printf(正常模式\r\n);}else //回环模式,一个开发板就可以测试了.{printf(回环模式\r\n);}} keyCan_Receive_Msg(canbuf);if(key)//接收到有数据{ for(i0;ikey;i){ printf(接收到%d\r\n,canbuf[i]);}}t; delay_ms(10);if(t20){LED0!LED0;//提示系统正在运行 t0;} }
}初始化CAN模式为回环模式波特率为500Kbps。 进入循环不断检测按键状态。 如果KEY0按键按下将canbuf数组填充为0-7的连续数值并调用Can_Send_Msg函数发送8个字节的数据帧。如果发送失败打印发送失败如果发送成功打印发送。 如果WK_UP按键按下切换CAN的工作模式。如果当前为普通模式将其切换为回环模式并打印回环模式如果当前为回环模式将其切换为普通模式并打印正常模式。 调用Can_Receive_Msg函数接收数据帧并将接收到的数据打印出来。 按下KEY0之后