10782|2

1234

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

CAN通信之STM32的实现 [复制链接]

本帖最后由 ywlzh 于 2017-9-15 11:47 编辑


这个帖子先在单片机stm32上实现CAN通信,如果你对CAN一点都不了解,建议先大概的了解下基本内容。
stm32,CAN通信例子多了去。我这就记录下ID过滤,中断处理远程帧和数据帧。

先说ID过滤吧
1.软处理
    跑过例程了,都应该知道,CAN接收都是放在主程序while(1),或者开个任务不断的查询对应FIFO是否有消息。
   
  1. CanRxMsg RxMessage;
  2.      CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
复制代码

   然后针对RxMessage去解析ID,发现ID不对,就不处理这一帧数据。
   这种处理有个弊端就是每一帧数据都接收,都处理,增加的CPU负载。
2.硬处理
   这个就得看CAN初始化程序了
  
  1. u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
  2. {

  3.           GPIO_InitTypeDef       GPIO_InitStructure;
  4.           CAN_InitTypeDef        CAN_InitStructure;
  5.            CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  6. #if CAN_RX0_INT_ENABLE
  7.            NVIC_InitTypeDef  NVIC_InitStructure;
  8. #endif

  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟                                                                                                                    

  10.           RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟        

  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽
  14.     GPIO_Init(GPIOA, &GPIO_InitStructure);                //初始化IO
  15.    
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
  18.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化IO
  19.          
  20.          //CAN单元设置
  21.           CAN_InitStructure.CAN_TTCM=DISABLE;                                                 //非时间触发通信模式  //
  22.            CAN_InitStructure.CAN_ABOM=DISABLE;                                                 //软件自动离线管理         //
  23.           CAN_InitStructure.CAN_AWUM=DISABLE;                                                 //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)//
  24.           CAN_InitStructure.CAN_NART=ENABLE;                                                         //禁止报文自动传送 //
  25.           CAN_InitStructure.CAN_RFLM=DISABLE;                                                 //报文不锁定,新的覆盖旧的 //
  26.           CAN_InitStructure.CAN_TXFP=DISABLE;                                                 //优先级由报文标识符决定 //
  27.           CAN_InitStructure.CAN_Mode= mode;                       //模式设置: mode:0,普通模式;1,回环模式; //
  28.           //设置波特率
  29.           CAN_InitStructure.CAN_SJW=tsjw;                                //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位  CAN_SJW_1tq         CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
  30.           CAN_InitStructure.CAN_BS1=tbs1; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
  31.           CAN_InitStructure.CAN_BS2=tbs2;//Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~        CAN_BS2_8tq
  32.           CAN_InitStructure.CAN_Prescaler=brp;            //分频系数(Fdiv)为brp+1        //
  33.           CAN_Init(CAN1, &CAN_InitStructure);            // 初始化CAN1

  34.            CAN_FilterInitStructure.CAN_FilterNumber=0;          //过滤器0
  35.            CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
  36.           CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
  37.           CAN_FilterInitStructure.CAN_FilterIdHigh=CAN_ID<<5;////32位ID
  38.           CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  39.           CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xffff;//32位MASK
  40.           CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xfff8;
  41.           CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
  42.            CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0

  43.           CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
  44. #if CAN_RX0_INT_ENABLE
  45.         
  46.           CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.               
  47.    
  48.                 NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  49.                
  50.           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1
  51.           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0
  52.           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  53.           NVIC_Init(&NVIC_InitStructure);
  54. #endif
  55.         return 0;
  56. }   
复制代码

这个程序是原子战舰板子CAN程序的例程,我对ID做了处理,原先例程就是用软处理ID过滤的,这不适合需求。在使用这个初始化前,要事先定义板子ID编号
#define CAN_ID   5   //板子ID为5 这个宏全局使用

重点介绍 ID过滤吧
CAN_FilterInitStructure.CAN_FilterIdHigh=CAN_ID<<5;////32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xffff;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xfff8;
再结合这本书 STM32CAN发送和接收过滤详解.pdf (252.93 KB, 下载次数: 254)
   
我这再给个例子说明一下,如果还不懂,那我也是没有办法让你懂了
例子: 我要设置自身ID为2,但我想接收ID为0x002和ID为0x402,那么就得这么设置
#define CAN_ID 2
CAN_FilterInitStructure.CAN_FilterIdHigh=CAN_ID<<5;////32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x7fff;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xfff8;
就可以了,不要被图中红色部分4个数字一组给搞糊涂了,因为上位机调试助手做了移位处理,在不使用扩展ID的情况下,ID的排序对应图片中的例子就为:
  011 0001 0111
  111 1111 1111
那么接收ID为0x002和ID为0x402,对应下来就是
  ID:     100 0000 0010  
  ID:     000 0000 0010
  过滤:011 1111 1111
也就是CAN_FilterMaskIdHigh为什么要为0x7fff了。
实验下发送数据帧看看

正确无误。图中让上位机向0x403发送,板子是不接收这个ID的数据,所以不接收数据。就没有往上回传数据了。

再强调一遍波特率的设置吧,传参数(x,y,z,e,mode);
计算波特率就为 36M/(((x+1)+(y+1)+(z+1))*e)
所以想要设定为500Kb的速度 就可以设置参数(0,0,6,8,0); //36M/72 = 500K
还不明白,再好好体会!

最后说一下CAN数据接收,我是不赞同额外开个任务去查询对应FIFO消息的,使用中断

  1. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0;
  2. CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.        

  3. NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
复制代码


至于使用FIFO0还是FIFO1,看你想法了,自己改好对应关系就可以了

再看看中断吧
  1. #if CAN_RX0_INT_ENABLE        //使能RX0中断
  2. //中断服务函数                           
  3. void USB_LP_CAN1_RX0_IRQHandler(void)
  4. {
  5.            CanRxMsg RxMessage;
  6.      CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
  7.            if(RxMessage.RTR == CAN_RTR_Remote){
  8.                          /* 远程帧  返回信息*/
  9.                          u8 Canbuf[8]={0};
  10.                          Can_Send_Msg(Canbuf,8);
  11.                  }
  12.                  else if(RxMessage.RTR == CAN_RTR_Data){
  13.                          /* 数据帧 */
  14.                          if((RxMessage.Data[0] == 0x01)&&(RxMessage.Data[1]==0x01)){
  15.                                  if(RxMessage.Data[2] == 0x01) Rate.Flag = 1;
  16.                                  else if(RxMessage.Data[2] == 0x00)  Rate.Flag = 0;
  17.                                  Can_Send_Msg(RxMessage.Data,8);
  18.                          }
  19.           }
  20.                          //for(i=0;i<8;i++)
  21.           //printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);
  22. }
  23. #endif
复制代码


就这么简单了,这个帖子目前就处理远程帧和数据帧。至于其他的帧,我还没开始实验,还有上位机的开发也没开始实验

敬请期待。




此内容由EEWORLD论坛网友ywlzh原创,如需转载或用于商业用途需征得作者同意并注明出处







此帖出自stm32/stm8论坛

最新回复

赞一个!!!  详情 回复 发表于 2017-9-15 14:25
点赞 关注(1)
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 

回复
举报

6107

帖子

4

TA的资源

版主

沙发
 
赞一个!!!
此帖出自stm32/stm8论坛
 
 

回复

1234

帖子

4

TA的资源

纯净的硅(高级)

板凳
 


上位机也写完了 ,感慨就是没什么技术含量,就是在合适的时候调对应的API,自己写个类和写一个线程来读取CAN数据就行。然后再解析数据。


此帖出自stm32/stm8论坛
 
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表