历史上的今天

今天是:2024年09月30日(星期一)

正在发生

2019年09月30日 | 利用CAN中断进行简单的数据接收

发布者:EternalSunset 来源: eefocus关键字:CAN  中断  数据接收 手机看文章 扫描二维码
随时随地手机看文章

CAN是控制器局域网络(Controller Area Network, CAN)的简称,是国际上应用最广泛的现场总线之一。 在北美和西欧,CAN总线协议已经成为汽车计算机控制系统和嵌入式工业控制局域网的标准总线,并且拥有以CAN为底层协议专为大型货车和重工机械车辆设计的J1939协议。

在这里插入图片描述

本例通过用MC9S12XS128MAA来实现CAN标准帧的接收。

以下为本例所用到的寄存器介绍(CAN初始化部分用到的寄存器此篇不再赘述,见“利用CAN进行简单的数据发送”)


CANRFLG寄存器

在这里插入图片描述

WUPIF (唤醒中断标志)= 1 时,MSCAN在CAN总线上检测到活动并请求唤醒

= 0 时,睡眠模式下未观察到唤醒活动

CSCIF(CAN状态改变中断标志) = 1 时, MSCAN更改了当前CAN总线状态

= 0 时,CAN总线状态未发生变化

RSTAT[1:0] (接收状态位)= 00 时,RxOK :0 ≤ 接收错误计数器 ≤ 96

= 01 时,RxWRN :96 < 接收错误计数器 ≤ 127

= 10 时,RxERR :127 < 接收错误计数器 ≤ 255

= 11 时,Bus-off : 传输错误计数器 > 255

TSTAT[1:0] (发送状态位) = 00 时,TxOK :0 ≤ 发送错误计数器 ≤ 96

= 01 时,TxWRN :96 < 发送错误计数器 ≤ 127

= 10 时,RxERR :127 < 发送错误计数器 ≤ 255

= 11 时,Bus-off : 传输错误计数器 > 255

OVRIF(溢出中断标志) = 1 时,数据溢出

= 0 时,没有溢出

RXF(接收缓冲区满标志) = 1 时,RxFG中有一条新消息

= 0 时,RxFG无可用新消息


CANRXIDR:用来存放CAN报文的ID、远程帧或数据帧状态、标准帧或扩展帧

在这里插入图片描述
在这里插入图片描述

CANRXDSR:用来存放数据长度用来存放数据(最多8个字节)

在这里插入图片描述

CAN0RXDLR:用来存放数据长度

在这里插入图片描述
在这里插入图片描述

以下为完整的CAN接收报文程序



#include            

#include "derivative.h"      

#define LED PORTB_PB0         //定义连接发光二级管的PORTB_PB0口数据寄存

                              //器为LED,写'0'亮,写'1' 灭

#define LED_dir DDRB_DDRB0    //定义连接发光二级管的PORTB_PB0口方向寄存器

                              //为LED_dir,写'0'做输入口,写'1'做输出口

                             



struct can_msg     //定义接收报文的结构体

{

    unsigned int id;    //报文的ID号

    Bool RTR;

    unsigned char data[8];  //报文的数据

    unsigned char len;      //数据长度

  

};




struct can_msg  msg_get;   //定义结构体变量




void INIT_PLL(void)     //初始化锁相环

{   

   

   CLKSEL_PLLSEL=0;     //内部总线时钟来源于晶振

           

   PLLCTL_PLLON=0;  //关闭PLL


   SYNR=0x40 | 0x03;

  

   REFDV=0x80 | 0x01; 

  

   POSTDIV=0x00;     //PLL为64MHz


   PLLCTL_PLLON=1;  //打开PLL


   _asm(nop);         

   _asm(nop);      //等待两个机器周期

   while(CRGFLG_LOCK==0); //根据CRGFLG寄存器的LOCK位,确定PLL是否稳定 LOCK==1 稳定,==0 不稳定  

   CLKSEL_PLLSEL =1;     //选择PLL作为时钟源        

}




void INIT_CAN0(void)         //初始化CAN0

{

  if(CAN0CTL0_INITRQ==0)      // 查询是否进入初始化状态   

    CAN0CTL0_INITRQ =1;        // 进入初始化状态


  while (CAN0CTL1_INITAK==0);  //初始化握手标志


  CAN0BTR0_SJW = 0;            //设置同步

  CAN0BTR0_BRP = 7;            //设置波特率  

  CAN0BTR1 = 0x1c;       //设置时段1和时段2的Tq个数 ,总线频率为250kb/s

  

  

  /*

      Bit Time = [(Prescaler value)*(1+TimeSegment1+TimeSegment2)]/fCANCLK

      f = 1 / Bit Time

      Prescaler value = 8

      TimeSegment1 = 13

      TimeSegment2 = 2

      fcanclk = 32MHz

      f = 250kb/s

  */


  CAN0IDMR0 = 0xFF;

  CAN0IDMR1 = 0xFF;

  CAN0IDMR2 = 0xFF;

  CAN0IDMR3 = 0xFF;

  CAN0IDMR4 = 0xFF;

  CAN0IDMR5 = 0xFF;

  CAN0IDMR6 = 0xFF;

  CAN0IDMR7 = 0xFF;     // 关闭滤波器                                  


  CAN0CTL1 = 0xC0;             //使能MSCAN模块,设置为一般运行模式、使用总线时钟源 


  CAN0CTL0 = 0x00;             //返回一般模式运行


  while(CAN0CTL1_INITAK);      //等待回到一般运行模式


  while(CAN0CTL0_SYNCH==0);    //等待总线时钟同步


  CAN0RIER_RXFIE = 1;          //打开接收中断

}




Bool MSCAN0GetMsg(struct can_msg *msg)     //CAN0接收函数

{

  unsigned char sp2;    


  

  if(!(CAN0RFLG_RXF))    // 检测接收标志    0没有新消息,1有新消息

    return(FALSE);

  

  

  if(CAN0RXIDR1_IDE)   // 检测 CAN协议报文模式 (标准帧/扩展帧) 0标准帧  1扩展帧

    return(FALSE);             

  

  msg->id = (unsigned int)(CAN0RXIDR0<<3) | 

            (unsigned char)(CAN0RXIDR1>>5);   //将ID通过移位放入相应的寄存器位置

  

  if(CAN0RXIDR1&0x10)

    msg->RTR = TRUE;

  else

    msg->RTR = FALSE;   // 读标识符    RTR0数据帧  1远程帧

  

  

  msg->len = CAN0RXDLR;   // 读取数据长度 

  

 

  for(sp2 = 0; sp2 < msg->len; sp2++)

    msg->data[sp2] = *((&CAN0RXDSR0)+sp2);    // 读取数据


  

  CAN0RFLG = 0x01;       // 清 RXF 标志位 (缓冲器准备接收)


  return(TRUE);

}




#pragma CODE_SEG __NEAR_SEG NON_BANKED          //中断接收函数

void interrupt VectorNumber_Vcan0rx CAN_receive(void)   //通过中断向量VectorNumber_Vcan0rx来定义中断接收函数

{

      if(MSCAN0GetMsg(&msg_get))    //判断是否有合法的标准帧收到

      {

        

                 LED = ~LED;     //接收到合法标准帧LED反相

                        

        

      }

      else             //错误进入死循环

      {

       for(;;);

      }

}




void main(void) {

  DisableInterrupts;           //禁止打开所有中断

  INIT_PLL();                  //初始化PLL模块,设置busclock=32Mhz

  INIT_CAN0();                 //初始化can0模块

  LED_dir=1;                   //LED接口PB0设置为输出口 

  LED=0;                       //初始化LED初始状态为亮

  EnableInterrupts;            //允许打开所有中断  



  for(;;) 

  {

  } 

}


注意:1.本例CAN初始化中 CAN0RIER_RXFIE 一定要赋值为1,打开接收中断,否则将无法接收到数据

2.中断向量可以通过查看Project -> Includes -> MC9S12XS128.h文件寻找

3.由于本单片机只有一路CAN,所以无法实现自发自收,因而选择通过CANTest进行发送,通过指示灯闪烁来判断是否收到数据


接线实物图见下方:

在这里插入图片描述

通过CANTest发送数据,数据内容可以通过下图粉色椭圆框起来的部分填写,点击发送就可以将所填写的信息发送出来了,此时开发板的指示灯将会由亮变暗或者由暗变亮

在这里插入图片描述

关键字:CAN  中断  数据接收 引用地址:利用CAN中断进行简单的数据接收

上一篇:stm32f103 学习笔记 —— 07 CAN通讯协议
下一篇:STM32F4 CAN2配置

推荐阅读

在几年前的智能机器人与系统国际会议上(IROS),哈佛研究生 chael Tolley 向我们介绍了一款依靠爆炸力进行弹跳的机器人。这款粉红色的柔软机器人有三条可以左右摇摆并负责定位的腿,不过这家伙的长相实在是太对不起观众了。现在,Tolley 在加州大学圣地亚哥分校已经有了自己的机器人实验室,该实验室的主要工作就是找到有效的制造软体机器人的方法...
初始化CAN模块void INIT_CAN0(void) { if(CAN0CTL0_INITRQ==0) // 查询是否进入初始化状态 CAN0CTL0_INITRQ =1; // 进入初始化状态 while (CAN0CTL1_INITAK==0); //等待进入初始化状态 CAN0BTR0_SJW = 0; //设置同步 CAN0BTR0_BRP = 7; //设置波特率 CAN0BTR1 =...
集微网9月29日报道近日,5G广播中国战略及前景展望研讨会在线上召开,高通中国区技术标准负责人李俨在研讨会上表示,5G广播具有非常大的应用潜力。李俨指出,数字经济发展中很重要的环节是信息数据的流通,5G广播使用户能够以更低的成本享受各种服务,将会改变人们的生活甚至生产的方式。就像3G、4G带动移动互联网的迅猛发展一样,5G广播的成熟,将再次调...
集微网消息,近段时间以来,包括原材料、设备,以及芯片制造及封装等半导体产业链服务价格持续上涨,终端厂商成本压力增大。鉴于这些原因,国内芯片制造商展锐也于近日发布了消费电子调价通知。展锐表示,因原材料价格上涨,且供应产能持续紧张,旗下相关产品的成本不断增加。为争取合理产能,稳定产品供应,更好地长期服务于客户,经公司慎重考虑决定,智...

史海拾趣

问答坊 | AI 解惑

AVR之学习资料篇

免费(芯币)资料大放送 来,快来,赶快来,AVR的彻底攻克誓师大会!!!!!!!! 哈哈 [ 本帖最后由 springvirus 于 2009-4-3 12:33 编辑 ]…

查看全部问答∨

一艘“绿色”游艇

 说到将游艇设计成绿色游艇可能你想到的就是将它的发动机设计成混杂动力型的,可设计师Christian Peetz不但采用太阳能供电的发动机而且游艇外壳也采用了绿色可再生材料设计。通过对世界上增长最快的天然资源-竹子深加工成竹胶合板,然后再采用类似 ...…

查看全部问答∨

欢迎自动控制技术爱好者来本qq群交流52581654

我们有很多经验也有很多不足之处,希望能结合论坛话题,在群里加强交流,共同进步。期盼您的加入。 QQ群号:52581654…

查看全部问答∨

winCE下,vs2005,C#,程序开始运行如何显示log画面和声音

log画面是用pictureBox控件吗?声音如何驱动?…

查看全部问答∨

EVC---关于ShellExecuteEx调用可执行文件的问题

在EVC下调用一个可执行文件A用 ShellExecuteEx(&A); 但是如果该文件A正在执行,如何切换至可执行A,而不让他再次执行一次。 如何实现?高手指教!!…

查看全部问答∨

单片机内部复位(不用外部复位电路)急!!!

ST7FILT15BF采用内部复位电路可靠吗?怎样实现不用外部复位电路,实现ST7FILT15BF单片机复位?需要设置什么?需要进行特殊功能寄存器设置或其它吗?复位脚如何处理?…

查看全部问答∨

stm32的奇怪SPI2问题?求解

现象:使用stm32的SPI2读写铁电FM25L512,软件IAR 5.4,仿真器JTAGE。 接上仿真器,使用硬件SPI2读写正常;把仿真器去掉开机,硬件SPI2读写错误,其它程序正常。 该用软件SPI2读写,带上仿真器正常,不带仿真器也正常。 附硬件SPI2初始化 ...…

查看全部问答∨

串口调试出问题了,高手进,分析一下情况

有一个比较大的程序,里面有显示屏和其他功能,现在需要将原来的串口程序改掉,在单步调试的过程中,一旦程序到了传输字节的程序部分,单片机就会自动往电脑里发数据,一次2024个0x00字节,在其它板子上感觉,到了单步运行的过程中,单片机不应该这 ...…

查看全部问答∨

求救啊,怎么用51的32个IO口直接驱动32x16的点阵屏(不许用其他的类似锁存的芯片)!

最近想做个点阵屏,网上游荡,无意中发现一个叫“杜洋工作室”的地方,杜老师的做的mini3216点阵时钟竟然不用串锁存或者行锁存芯片,直接用stc12c5as60的32个IO口控制32x16的点阵屏,而且还有多余的引脚接时钟温度等等IC,我百思不得其解,查阅了许 ...…

查看全部问答∨

LCD多层菜单的实现

       在前不久我发了《LCD单层菜单翻滚的实现》https://bbs.eeworld.com.cn/thread-314573-1-1.html,在此帖中实现了单层菜单的上下翻滚。此贴中实现的算法不能不说非常经典,而且此方法在我的一个手持机项目中也得 ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved