CAN是控制器局域⽹络(Controller Area Network, CAN)的简称,是国际上应⽤最⼴泛的现场总线之⼀。 在北美和西欧,CAN总线协议已经成为汽车计算机控制系统和嵌⼊式⼯业控制局域⽹的标准总线,并且拥有以CAN为底层协议专为⼤型货车和重⼯机械车辆设计的 J1939协议。
本例通过⽤MC9S12XS128MAA来实现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 <hidef.h>
#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) //初始化锁相环
法兰加工设备
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; //返回⼀般模式运⾏
fpc焊接机
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; //允许打开所有中断pcti
湖水净化
for(;;)
{
{
}
}
注意:1.本例CAN初始化中 CAN0RIER_RXFIE ⼀定要赋值为1,打开接收中断,否则将⽆法接收到数据
2.中断向量可以通过查看Project -> Includes -> MC9S12XS128.h⽂件寻
3.由于本单⽚机只有⼀路CAN,所以⽆法实现⾃发⾃收,因⽽选择通过CANTest进⾏发送,通过指⽰灯闪烁来判断是否收到数据接线实物图见下⽅: