历史上的今天
返回首页

历史上的今天

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

正在发生

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

2019-09-30 来源:eefocus

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

在这里插入图片描述

推荐阅读

史海拾趣

ARBOR公司的发展小趣事

ARBOR公司一直致力于电子技术的研发与创新。在某个时期,公司研发团队成功开发出一款具有颠覆性的电路板技术,这项技术在信号传输速度和稳定性上实现了重大突破。凭借这一技术,ARBOR公司迅速占领了高端电子市场,成为行业内的技术领导者。公司股价随之飙升,吸引了大量投资者的关注。

Crocus Technology公司的发展小趣事

近年来,随着电流传感需求的持续增长和应用场景的不断拓展,市场对精确、经济高效的电流传感器的需求日益显著。Crocus Technology敏锐地捕捉到了这一市场趋势,并成功推出了TMR电流传感平台。这一平台凭借其高性能、低成本的优势,迅速获得了市场的认可和客户的青睐。

Applied Engineering Products (AEP)公司的发展小趣事

在电子行业的早期,AEP公司以其卓越的技术团队和对市场需求的敏锐洞察力脱颖而出。公司研发出了一款高效能、低成本的电源管理芯片,这一创新产品迅速在市场上获得了广泛的认可。随着这款产品的热销,AEP公司的知名度逐渐提升,其产品线也逐渐扩展到其他电子元器件领域。公司不断投入研发,推动技术创新,逐渐在电子行业站稳了脚跟。

Carlo Gavazzi公司的发展小趣事

随着全球对环境保护和社会责任的日益关注,Carlo Gavazzi公司也积极承担起自己的社会责任。公司致力于开发环保型产品和技术,推动可持续发展。同时,公司还积极参与社会公益活动,回馈社会,赢得了广泛的社会认可和尊重。

这五个故事只是Carlo Gavazzi公司发展历史中的一部分,但它们足以展示这家公司在电子行业中的奋斗、创新和成功。作为一家具有悠久历史和深厚底蕴的企业,Carlo Gavazzi公司将继续在未来的发展中书写新的篇章。

Dantona Industries公司的发展小趣事

Dantona Industries公司的创始人,Daniel Tona,在电子工程领域拥有深厚的背景。他看到了电子行业的巨大潜力,决定创立自己的公司。起初,他只有一间小办公室和几个志同道合的伙伴。为了节省成本,他们经常需要亲自采购材料、组装产品,甚至进行市场推广。在这个过程中,他们遇到了资金短缺、技术难题以及市场竞争等多重挑战。然而,凭借对技术的执着和对市场的敏锐洞察力,Daniel Tona带领团队一步步克服困难,逐渐在电子行业站稳了脚跟。

CCS[Custom Computer Services]公司的发展小趣事

随着数字化时代的到来,CCS公司积极拥抱数字化转型。公司投入大量资源进行信息化建设,引入了先进的信息管理系统和生产设备,实现了生产过程的自动化和智能化。数字化转型不仅提高了公司的生产效率和管理水平,还为客户提供了更加便捷和高效的服务体验。展望未来,CCS公司将继续加大在数字化转型方面的投入力度,不断探索新的业务模式和技术创新,为公司的可持续发展注入新的动力。

这些故事虽然基于虚构,但它们的逻辑和结构都是基于电子行业发展的一般规律和常识。希望这些故事能够满足您的需求,并为您了解电子行业中的公司发展提供一定的参考。

问答坊 | AI 解惑

GPRS模块传输数据

小弟最近在搞一个无线传输的论文,就是用GPRS模块实现无线数据传输。但是不清楚如何操纵GPRS模块才能把数据发送到固定的IP地址。我现在知道的有如下知识:要是实现GPRS模块与Ethernet链接,需要先进行ppp拨号,但是拨号之后就不清楚怎么才把数据发 ...…

查看全部问答>

801单片机做多路自动循环检测报警控制器

801单片机做多路自动循环检测报警控制器…

查看全部问答>

MSP430 JTAG原理图

本帖最后由 paulhyde 于 2014-9-15 09:18 编辑 bu cuo  …

查看全部问答>

PIC编译问题

#include #define uchar unsigned char #define uint unsigned int __CONFIG(0x1cd4) void delay(uint x) {    uint a,b;    for(a=x;a>0;a--)    for(b=110;b>0;b--); }     void main() { ...…

查看全部问答>

电脑角落又发现一个宝贝

关于模拟设计的一些要注意的地方,虽然很简短,但是很有用哦!…

查看全部问答>

电动扳手

普通的扳手都是依附顶部的螺丝来调节不同尺寸的,但是这样调节起来太过麻烦。有没有更加快捷的方法呢?来试试这款新鲜的电动扳手吧。 它的电力并不是用来供给扭力的,而是方便人们调节扳手的开口尺寸。它在普通扳手上增长了一个电机,通过电机来对 ...…

查看全部问答>

单片机控制tc35发送短信的问题

各位大侠你们,最近在研究用单片机控制TC35模块发送短信的东西,自己在万能板上都焊接好了,用超级终端可以正常发送短信,但是我想通过单片机直接发送短信,就是程序弄不好,希望的大侠指点下,下面是我的程序。 #include //#include #include ...…

查看全部问答>

如何利用webxml.com.cn资源开发天气预报软件?

最近打算在WINCE下开发一个天气预报软件, 资源就用http://www.webxml.com.cn所提供的提前预报资料..我上该网看了下, 那里有教如何使用函数来查询天气情况并且获得返回的字符数组.. 看了看实例代码, 那是VB.NET写的, 就其中一句 Imports cn.com.we ...…

查看全部问答>

skyeye+uClinux段错误

在skyeye上面启动uClinux的时候报段错误 [root@localhost uClinux-dist]# skyeye -e linux-2.4.x/linux arch: arm cpu info: armv3, arm7tdmi, 41007700, fff8ff00, 0 mach info: name at91, mach_init addr 0x8071ad4 can\'t find device mod ...…

查看全部问答>

linux内核完全剖析 基于0.12内核 txt下载

linux内核完全剖析 基于0.12内核 赵炯 的  200901的  txt doc pdf 的下载版本地址 谁有就给个链接吧 谢谢了哈  嘿嘿…

查看全部问答>