找回密码
 注册
关于网站域名变更的通知

STM32|CAN总线实战

2023-8-16 14:19| 查看: 95| 评论: 0

摘要: 其实CAN还是比较复杂的,如果不明白没有关系,我们可以先从软件层面上来学习怎么使用 CAN,然后再回过头看这些理论知识,这样学习 CAN 应该会比较轻松。 使能 CAN 时钟,将对应引脚复用映射为 CAN 功能 RCC_APB1Pe ...
其实CAN还是比较复杂的,如果不明白没有关系,我们可以先从软件层面上来学习怎么使用 CAN,然后再回过头看这些理论知识,这样学习 CAN 应该会比较轻松。

使能 CAN 时钟,将对应引脚复用映射为 CAN 功能

RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //打开CAN1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//PA端口时钟打开  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;    //PA11     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入模式GPIO_Init(GPIOA, &GPIO_InitStructure);  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;    //PA12     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //IO口速度为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);
设置 CAN 工作模式、波特率等
CAN_InitStructure.CAN_TTCM=DISABLE;  //非时间触发通信模式   CAN_InitStructure.CAN_ABOM=DISABLE;  //软件自动离线管理    CAN_InitStructure.CAN_AWUM=DISABLE;  //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)CAN_InitStructure.CAN_NART=ENABLE;   //使用报文自动传送 CAN_InitStructure.CAN_RFLM=DISABLE;  //报文不锁定,新的覆盖旧的  CAN_InitStructure.CAN_TXFP=DISABLE;  //优先级由报文标识符决定 CAN_InitStructure.CAN_Mode= mode;    //模式设置 CAN_InitStructure.CAN_SJW=tsjw;      //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tqCAN_InitStructure.CAN_BS1=tbs1;      //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tqCAN_InitStructure.CAN_BS2=tbs2;      //Tbs2范围CAN_BS2_1tq ~  CAN_BS2_8tqCAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1  CAN_Init(CAN1, &CAN_InitStructure);  // 初始化CAN1
设置 CAN 筛选器
CAN_FilterInitStructure.CAN_FilterNumber=0;    //过滤器0CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;////32位IDCAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASKCAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
can.c文件

#include "can.h"#include "usart.h"
//CAN初始化//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq//tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;//tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq//brp :波特率分频器.范围:1~1024;  tq=(brp)*tpclk1//波特率=Fpclk1/((tbs1+tbs2+1)*brp);//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//则波特率为:36M/((8+9+1)*4)=500Kbps//返回值:0,初始化OK;//    其他,初始化失败;void 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;#endif    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //打开CAN1时钟  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //PA端口时钟打开    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;    //PA11       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    //上拉输入模式  GPIO_Init(GPIOA, &GPIO_InitStructure);  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;    //PA12       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //IO口速度为50MHz  GPIO_Init(GPIOA, &GPIO_InitStructure);    //CAN单元设置     CAN_InitStructure.CAN_TTCM=DISABLE;  //非时间触发通信模式       CAN_InitStructure.CAN_ABOM=DISABLE;  //软件自动离线管理        CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)    CAN_InitStructure.CAN_NART=ENABLE;  //使用报文自动传送     CAN_InitStructure.CAN_RFLM=DISABLE;  //报文不锁定,新的覆盖旧的      CAN_InitStructure.CAN_TXFP=DISABLE;  //优先级由报文标识符决定     CAN_InitStructure.CAN_Mode= mode;   //模式设置     CAN_InitStructure.CAN_SJW=tsjw;  //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq    CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq    CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~  CAN_BS2_8tq    CAN_InitStructure.CAN_Prescaler=brp;  //分频系数(Fdiv)为brp+1      CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1    //配置过滤器   CAN_FilterInitStructure.CAN_FilterNumber=0;    //过滤器0    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;////32位ID    CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;    CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK    CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0    CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0    CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化  #if CAN_RX0_INT_ENABLE   CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);        //FIFO0消息挂号中断允许.        
  NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);#endif}
#if CAN_RX0_INT_ENABLE  //使能RX0中断//中断服务函数          void USB_LP_CAN1_RX0_IRQHandler(void){    CanRxMsg RxMessage;  int i=0;    CAN_Receive(CAN1, 0, &RxMessage);  for(i=0;i<8;i++)  printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data);}#endif
//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)  //len:数据长度(最大为8)             //msg:数据指针,最大为8个字节.//返回值:0,成功;//     其他,失败;u8 CAN_Send_Msg(u8* msg,u8 len){    u8 mbox;  u16 i=0;  CanTxMsg TxMessage;  TxMessage.StdId=0x12;   // 标准标识符为0  TxMessage.ExtId=0x12;   // 设置扩展标示符(29位)  TxMessage.IDE=0;      // 使用扩展标识符  TxMessage.RTR=0;      // 消息类型为数据帧,一帧8位  TxMessage.DLC=len;               // 发送两帧信息  for(i=0;i<len;i++)    TxMessage.Data=msg;         // 第一帧信息            mbox= CAN_Transmit(CAN1, &TxMessage);     i=0;  while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;  //等待发送结束  if(i>=0XFFF)return 1;  return 0;    }
//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(i=0;i<RxMessage.DLC;i++)    buf=RxMessage.Data;    return RxMessage.DLC;  }

can.h

#ifndef _can_H#define _can_H
#include "system.h"                  
#define CAN_RX0_INT_ENABLE 0   //不使用中断
void CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode);//CAN初始化 u8 CAN_Send_Msg(u8* msg,u8 len);            //发送数据
u8 CAN_Receive_Msg(u8 *buf);              //接收数据

#endif

main.c


#include "system.h"#include "SysTick.h"#include "led.h"#include "usart.h"#include "key.h"#include "can.h"

/******************************************************************************** 函 数 名         : main* 函数功能       : 主函数* 输    入         : 无* 输    出         : 无*******************************************************************************/int main(){  u8 i=0,j=0;  u8 key;  u8 mode=0;  u8 res;  u8 tbuf[8],char_buf[8];  u8 rbuf[8];
  SysTick_Init(72);  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组  LED_Init();  USART1_Init(9600);  KEY_Init();  CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_Normal);//500Kbps波特率    while(1)  {    key=KEY_Scan(0);    if(key==KEY_UP)  //模式切换    {      mode=!mode;      CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);      if(mode==0)      {        printf("Normal Mode\r\n");      }      else      {        printf("LoopBack Mode\r\n");      }      }    if(key==KEY_DOWN)  //发送数据    {      for(j=0;j<8;j++)      {        tbuf[j]=j;        char_buf[j]=tbuf[j]+0x30;      }      res=CAN_Send_Msg(tbuf,8);      if(res)      {        printf("Send Failed!\r\n");      }      else      {        printf("发送数据:%s\r\n",char_buf);      }          }    res=CAN_Receive_Msg(rbuf);    if(res)    {      for(j=0;j<res;j++)      {        char_buf[j]=rbuf[j]+0x30;      }      printf("接收数据:%s\r\n",char_buf);    }        i++;    if(i%20==0)    {      led1=!led1;    }        delay_ms(10);  }}[backcolor=rgba(0, 0, 0, 0.03)]

本站资讯文章系编辑转载,转载目的在于传递更多信息,并不代表本站赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与本站联系,我们将在第一时间删除内容!
[声明]本站文章版权归原作者所有 内容为作者个人观点 本站只提供参考并不构成任何投资及应用建议。
本站拥有对此声明的最终解释权。
收藏 邀请
关闭

推荐内容上一条 /1 下一条

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-9-22 10:17 , Processed in 0.125000 second(s), 27 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

返回顶部