历史上的今天
返回首页

历史上的今天

今天是:2025年08月19日(星期二)

正在发生

2021年08月19日 | 利用CAN进行简单的数据发送

2021-08-19 来源:eefocus

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

在这里插入图片描述

本例通过用MC9S12XS128MAA来实现CAN标准帧的发送。


首先需要对CAN进行初始化配置,以下为本例所用到的寄存器介绍:

CANCTL0寄存器

在这里插入图片描述

RXFRM = 1 时,收到有效消息

= 0 时,未收到有效消息

RXACT = 1时,MSCAN正在接收消息

= 0时,MSCAN正在发送或空闲

CSWAI = 1 时,在等待模式下,模块停止计时

= 0时,等待模式期间模块不受影响

SYNCH = 1 时,MSCAN与CAN同步

= 0 时,MSCAN与CAN不同步

TIME = 1 时,启用内部 MSCAN计时器

= 0 时,禁用内部 MSCAN计时器

WUPE = 1 时,唤醒启用

= 0 时,唤醒禁用

SLPRQ = 1 时,CAN总线空闲时MSCAN进入休眠模式

= 0 时,MSCAN运行在正常模式

INITRQ = 1 时,MSCAN进入初始化模式

= 0 时,MSCAN运行在正常模式


CANCTL1寄存器

在这里插入图片描述

CANE = 1 时,MSCAN使能

= 0 时,MSCAN禁止

CLKSRC = 1 时,MSCAN时钟来源于总线

= 0 时,MSCAN时钟来源于晶振

LOOPB = 1 时,启用环回自检

= 0 时,禁用环回自检

LISTEN = 1 时,帧听模式开启

= 0 时,运行在正常模式

BORM = 1 时,根据用户请求总线断开恢复

= 0 时,自动总线断开恢复

MUPM = 1 时,只有当CAN总线上的主脉冲长度为t wup时,MSCAN才会唤醒

= 0 时,MSCAN任何时候都可唤醒

SLPAK = 1 时,睡眠模式激活

= 0 时,运行在正常模式

INITAK = 1 时,初始化模式激活

= 0 时,运行在正常模式


CANBTR0寄存器

在这里插入图片描述

SJW[1:0] :同步跳跃宽度

在这里插入图片描述

BRP[5:0] :波特率预分频

在这里插入图片描述

CANBTR1寄存器

在这里插入图片描述

SAMP = 1 时,每bit采样3次

= 0 时,每bit采样1次

TSEG2[2:0] :时间段2

在这里插入图片描述

TSEG1[3:0] :时间段1

在这里插入图片描述

通过以下公式计算bit time

在这里插入图片描述

CANIDMR0–CANIDMR7寄存器

在这里插入图片描述

AM[7:0]:接收屏蔽位

= 0 时,匹配接收码寄存器和标识符位

= 1 时,忽略相应接收码寄存器位


CANRIER寄存器

在这里插入图片描述

WUPIE = 1 时,唤醒事件导致唤醒中断请求

= 0 时,唤醒事件不生成中断请求

CSCIE = 1 时,CAN状态改变事件导致错误中断请求

= 0 时,CAN状态改变事件不生成中断请求

RSTATE[1:0] = 00 时,不生成由接收器状态变化引起的任何CSCIF中断

= 01 时,仅当接收器进入或离开“总线关闭”状态时生成CSCIF中断。丢弃其他接收器状态改变生成的CSCIF中断

= 10 时,只有当接收器进入或离开“RXERR”或“总线关闭”(2)状态时,才生成CSCIF中断。丢弃其他接收器状态改变生成的CSCIF中断

= 11 时,任何状态改变均生成CSCIF中断

TSTATE[1:0] = 00 时,不生成由发送器状态变化引起的任何CSCIF中断

= 01 时,仅当发送器进入或离开“总线关闭”状态时生成CSCIF中断。丢弃其他发送器状态改变生成的CSCIF中断

= 10 时,仅当发送器进入或离开“TXERR”或“总线关闭”状态时生成CSCIF中断。丢弃其他发送器状态改变生成的CSCIF中断

= 11 时,任何状态改变均生成CSCIF中断

OVRIE = 1 时,溢出事件导致错误中断请求

= 0 时,溢出事件不生成中断请求

RXFIE = 1 时,接收缓冲区满事件导致接收中断请求

= 0 时,接收缓冲区满事件不生成中断请求

CANTFLG寄存器

在这里插入图片描述

TXE[2:0] = 1 时,关联的消息缓冲区为空

= 0 时,关联的消息缓冲区已满

CANTBSEL寄存器

在这里插入图片描述

TX[2:0] = 1 时,如果最低编号置位,则选择相关的消息缓冲区

= 0 时,忽略选择关联的消息缓冲区

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

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

CANTXDSR:用来存放数据

在这里插入图片描述

CANTXDLR:用来存放数据长度

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

CANTXTBPR:优先级设置,具有最低本地优先级字段的传输缓冲区获得优先级


在这里插入图片描述

以下为完整的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'做输出口



#define ID                  0x0001   

#define ID1                  0x0002    //发送标识符ID号

#define data_len_TX          8           //发送数据长度


unsigned char a;


unsigned char senddata[8] = {'A','d','o','k','e','n','T','o'};

unsigned char senddata1[8] = {'r','o','t','h','y','N','B','!'};     //发送的数据 AdokenTorothyNB!


struct can_msg     //定义发送报文的结构体

{

    unsigned int id;   //ID号

    Bool RTR;         //远程帧或数据帧标志位

    unsigned char data[8];  //存放数据

    unsigned char len;      //数据长度

    unsigned char prty;     //优先级

};


struct can_msg msg_send, msg_send1;   //定义结构体变量




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 = 0;          //禁止接收中断

}



Bool MSCAN0SendMsg(struct can_msg msg)     //CAN发送

{

  unsigned char send_buf, sp;

  

  

  if(msg.len > 8)

    return(FALSE);    // 检查数据长度


  

  if(CAN0CTL0_SYNCH==0)

    return(FALSE);        // 检查总线时钟是否同步


  send_buf = 0;

  do

  {

    

    CAN0TBSEL=CAN0TFLG;

    send_buf=CAN0TBSEL;

  }

  

  while(!send_buf);  // 寻找空闲的缓冲器

  

  

  CAN0TXIDR0 = (unsigned char)(msg.id>>3);

  CAN0TXIDR1 = (unsigned char)(msg.id<<5);   // 写入标识符

  

  if(msg.RTR)

    

    CAN0TXIDR1 |= 0x10;    //检测数据帧或标准帧

    

  

  for(sp = 0; sp < msg.len; sp++)

    *((&CAN0TXDSR0)+sp) = msg.data[sp];   // 写入数据

    

  

  CAN0TXDLR = msg.len;        // 写入数据长度

  

  

  CAN0TXTBPR = msg.prty;   // 写入优先级

  

  

  CAN0TFLG = send_buf;     // 清 TXx 标志 (缓冲器准备发送)

  

  return(TRUE);

  

}


void main(void) {

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

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

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

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

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

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


//填写报文内容

  msg_send.id = ID;   //填写报头ID

  for(a=0;a  {

     msg_send.data[a] = senddata[a];

  }

  msg_send.len = data_len_TX;       //设置报文长度

  msg_send.RTR = FALSE;       //设置为标志帧

  msg_send.prty = 0;          //优先级设置为0

  

  msg_send1.id = ID1;   //填写报头ID

  for(a=0;a  {

     msg_send1.data[a] = senddata1[a];

  }

  msg_send1.len = data_len_TX;       //设置报文长度

  msg_send1.RTR = FALSE;     //设置为标志帧

  msg_send1.prty = 0;        //优先级设置为0


  for(;;) 

  {

      if(!MSCAN0SendMsg(msg_send)||!MSCAN0SendMsg(msg_send1)) //发送过程出现错误

      {

          for(;;);

      }

  } 

}


**注意:**ID号我们需要通过移位处理放入CANTXIDR寄存器相应的位置,另外还需将相应的RTR和IDE数据放入相应位置


本例我们通过用ZLG-USBCAN来查看CAN发送出来的数据,具体接线实物图如下所示

然后通过CANTest可以看到循环接收到的CAN数据,如下图所示(数据是ASCII码表示的,和我们程序中所要发送的两个数组是一致的)

推荐阅读

史海拾趣

DIPTRONICS MANUFACTURING INC公司的发展小趣事

为了降低成本、提高生产效率,圜达实业不断进行垂直整合。公司自主设计和生产自动组装机、模具和工具等生产设备,实现了从原材料采购到成品供应的全程控制。这种垂直整合的模式使公司在保证产品品质的同时,也降低了生产成本,提高了市场竞争力。

德欣(COV)公司的发展小趣事

作为一家有社会责任感的企业,德欣公司始终关注环境保护和可持续发展。公司积极推广绿色生产技术和资源循环利用方案,减少生产过程中的能源消耗和废弃物排放。同时,德欣公司还积极参与社会公益活动,为社区和环境贡献自己的力量。这些举措不仅体现了德欣公司的社会责任担当,也为其赢得了更多客户和合作伙伴的信任和支持。

Fairchild公司的发展小趣事

近年来,Fairchild公司在全球范围内与众多知名企业建立了合作关系。其中,与华为的合作尤为引人注目。华为作为全球领先的通信设备制造商,对供应商的要求极为严格。然而,Fairchild公司凭借其出色的产品质量、客户支持和公司间的成功合作,从众多供应商中脱颖而出,成为华为的核心合作伙伴之一。华为对Fairchild公司的认可不仅体现在订单量的增加上,还体现在对其产品和服务的高度评价上。

AMICC [AMIC TECHNOLOGY]公司的发展小趣事

近年来,电子行业面临着技术升级、市场变革等多重挑战。AMICC积极应对这些挑战,不断调整战略和业务模式。公司加大了对新兴技术的研发投入,加快了产品更新换代的速度。同时,AMICC还加强了与产业链上下游企业的合作,共同应对市场变化。这些措施使AMICC在行业中保持了领先地位,实现了持续稳健的发展。

Antenova公司的发展小趣事

Antenova公司积极寻求与其他行业领导者的战略合作,以推动公司的成长和发展。通过与全球知名的芯片制造商、设备生产商等建立合作关系,Antenova得以将其天线产品集成到更广泛的电子产品中,从而进一步扩大了市场份额。这些战略合作不仅提升了Antenova的品牌知名度,还为公司的长期发展提供了有力支持。

以上是关于Antenova公司发展起来的五个相关故事,这些故事展示了公司在技术创新、市场拓展、产品推出、专业服务以及战略合作等方面的努力和成就。这些成就为Antenova在电子行业中的成功奠定了坚实基础,并为公司未来的持续发展提供了有力保障。

Heatron公司的发展小趣事

随着市场对个性化需求的增加,Heatron公司敏锐地捕捉到了这一趋势。公司成立了专门的定制化服务团队,致力于为客户提供从设计到生产的全方位解决方案。无论是特殊尺寸的加热器,还是具有特定功能的电加热元件,Heatron都能根据客户需求快速响应并高效完成。这种以客户为中心的服务模式,帮助Heatron在竞争激烈的市场中脱颖而出,赢得了众多知名企业的青睐。

问答坊 | AI 解惑

汽车仪表

型号,产品简介、技术参数、应用领域 瑞士intersema产品说明: 瑞士intersema传感器是硅压阻式的压力传感器,采用了微型的设计结构,最大的也只有9mm*9mm(MS5536PJU/MS5536NJU除外,为12.14MM*10.4MM)。产品以其高精度,高灵敏性适用于气象,水 ...…

查看全部问答>

什么是电容的ESR?相关概念解释

虽然是个简单的概念,不过一写成洋文,就变得不容易理解了。 ESR,是Equivalent Series Resistance三个单词的缩写,翻译过来就是“等效串连电阻”。 理论上,一个完美的电容,自身不会产生任何能量损失,但是实际上,因为制造电容的材料有电阻, ...…

查看全部问答>

请赐教关于LCD12232显示的问题

请赐教,我要怎么修改源程序,才能让“京”字显示在  “南”字的右下方?                                  &nb ...…

查看全部问答>

ICCAVR教程

初学AVR,下了ICCAVR教程,上传与大家共享。…

查看全部问答>

2812板子频繁重启

2812控制电机,电压加到240V以上  板子频繁重启  ,会是什么原因?…

查看全部问答>

wince和linux启动时间

这两个系统的启动时间怎么样,我购买的开发板wince启动时间有1分钟左右,太慢了,可不可以缩短启动时间。启动时间对我们的项目不适用。…

查看全部问答>

wince开机内存占用问题?

如上图,红色指示区域是wince进入桌面后程序内存的使用量。有9M多呢 这样子正常吗?启动应用都没运行呢! 哪位兄台解答一下啊? …

查看全部问答>

单片机入门了后再学点什么好了呢

大家好,我学单片机一个多月了,用买来的板子做了很多试验,不过都是书上的,因为我知道是做高级语言编程的,所以学单片机器语言上没有什么困难,这个月我感觉单片机主要对外围编程,用程序控制外围硬件显示或者不显示,运作或者不运作,现在书也看 ...…

查看全部问答>

pxa270的电源管理

小弟最近在研究pxa270的电源管理,用的BSP是BVDMAIN,进入WINCE后,点击开始中的“挂起”后,在执行完所有驱动的POWEROFF函数后,开始执行OEMPowerOff(),执行到XllpPmEnterSleep()时发生异常,我查了一下,这个函数是内容都是汇编语言,发生异常 ...…

查看全部问答>

交换机上怎么防御ddos攻击和机器狗病毒啊

交换机上怎么防御ddos攻击和机器狗病毒啊?在网上搜索过很多资料,都没有什么好的办法。刚进公司就被分配了这个任务,再不做出来就要被开了。有没有哪位大虾帮一下啊?在下万分感谢啊。…

查看全部问答>