硬件:18F2680,CAN收发芯片MCP2551
1.自测形式
//* ****************************************************************
//** 功用描绘: CAN自测试收发编程,CAN发送邮箱0以必定的时刻距离发送数据,接纳到数据后,将接纳数据加1作为下一次的发送数据
//***************************************************************
#include”pic18.h” //PIC18系列的头文件 */
charCAN_Adress_H,CAN_Adress_L;// CAN标识符凹凸字节 */
charCAN_Adress_EH,CAN_Adress_EL;// CAN扩展标识符凹凸字节 */
int CAN_FLAG;// =1接纳到CAN 数据,=0未接纳到数据 */
unsignedintCAN_Delay_count=0;// 距离必定时刻发送CAN数据 */
// ****************************************************************
//** 函 数 名: initial()
//** 功用描绘: 体系初始化子程序,放在程序首部
//*************************************************************** */
voidinitial()
{
SWDTEN=0; //关看门狗
INTCON=0x00;// bit7-bit0:关总中止 */
ADCON1=0X07;// 设置数字输入输出口 */
PIE1=0; // PIE1 的中止不使能 */
PIE2=0;// PIE2 的中止不使能 */
PIE3=0;// PIE3 的中止不使能 */
TRISB7=0; // RB7为输出端口
RB7=0;
}
//********************************************
//延时函数
//********************************************
void delay(unsigned int asd)
{
unsigned int i;
for(i=0;i {}
}
//* ****************************************************************
//** 函 数 名: initcan()
//** 功用描绘: CAN初始化子程序,选用规范标识符,自测试形式
//*************************************************************** */
voidinitcan()
{
// ************设置对CAN进行装备*************** */
TRISB=(TRISB|0X08)&0XFB;//设置CANRX/RB3输入,CANTX/RB2输出*/
CANCON=0X80;// CANCON,bit7-5:1XX恳求装备 */
while((CANSTAT&0X80)==0)// CAN状况寄存器。bit7-5:100装备方法 */
{
;
}// 等候进入CAN装备形式OPMODE=100 */
// ***********波特率设置 ************************** */
BRGCON1=0X01;// Sync_Seg(bit7-6)=1TQ,BRP(bit5-0)=1,
//则TQ=((2*(BRP+1))/Fosc=4/4M=1us */
BRGCON2=0X90;//bit7=1自在编程,bit6=0总线在采样点采样1
//次;Phase_Seg1(bit5-3)=3TQ;Prog_Seg(bit2-0)=1TQ*/
BRGCON3=0X42;// 设置Phase_Seg2(bit2-0)=3TQ */
// 标称位时刻=TQ*(Sync_Seg+ Prop_Seg+ Phase_seg1+ Phase_seg2)
//=(1+1+3+3)TQ=8TQ, 位率=1/(8*1U)=0.125MHz */
// ******设置发送邮标识符号和初始发送的数据***** */
TXB0CON=0X03;// bit1-0:发送优先级,设置TXB0为最高优先级3 */
TXB0SIDL=CAN_Adress_L&0xe0;// bit3=0规范标识符,bit7-5:规范标识符2-0位 */
TXB0SIDH=CAN_Adress_H;// 规范标识符的10-3位 */
TXB0DLC=0X08;// 设置数据长度为8个字节 */
TXB0D0=0X00;// 写发送缓冲器数据区数据初值 */
TXB0D1=0X01;// 写发送缓冲器数据区数据初值 */
TXB0D2=0X02;
TXB0D3=0X03;
TXB0D4=0X04;
TXB0D5=0X05;
TXB0D6=0X06;
TXB0D7=0X07;
// *******设置接纳邮箱0的标识符和初始化数据********** */
RXB0SIDL=CAN_Adress_L&0xe0;// bit3=0规范标识符,bit7-5:规范标识符2-0位*/
RXB0SIDH=CAN_Adress_H;// 规范标识符的10-3位 */
RXB0CON=0X20;// bit6-5=01只接纳有用的规范标识符信息 */
RXB0DLC=0X08;// 设置接纳缓冲器0的数据区长度8个字节 */
RXB0D0=0X02;// 初始化接纳缓冲器0的数据区数据 */
RXB0D1=0X03;// 初始化接纳缓冲器0的数据区数据 */
RXB0D2=0X04;
RXB0D3=0X05;
RXB0D4=0X00;
RXB0D5=0X00;
RXB0D6=0X00;
RXB0D7=0X00;
// *******初始化接纳滤波器0和接纳屏蔽**************** */
RXF0SIDH=CAN_Adress_H;
RXF0SIDL=CAN_Adress_L;// 本字节高3位为标识符低3位,低5位是装备 */
RXM0SIDH=0Xff;
RXM0SIDL=0Xe0;// 11个1表明接纳11位标识符进行滤波,标识符
//不同不接纳;若全为0,若正确信息,悉数接纳*/
// *******设置CAN作业形式**************************** */
CANCON=0X40;// bit6:=1进入自测试形式;=0,正常操作形式 */
while((CANSTAT&0X40)!=0)// 检测CAN装备完结 */
{
;
}
// 初始化CAN的中止,PIR3为CAN的外围中止标志寄存器 */
PIR3=0X00;// 清一切CAN中止标志 */
PIE3=PIE3|0X01;// 使能接纳缓冲器0的接纳中止 */
IPR3=IPR3|0X01;// 接纳缓冲器0的接纳中止为最高优先级 */
}
/* **************************************************************
**函 数 名: CAN_deal()
**功 能:CAN接纳数据后处理子程序:接纳数据加1为下次发送的数据
****************************************************************** */
voidCAN_deal()
{
RB7=1;
delay(1000);
CAN_FLAG=0;// 清接纳到标志 */
TXB0CON=TXB0CON&0xf7;// TXB0REQ=0,制止发送恳求 */
TXB0D0=RXB0D0+1;// 用接纳数据加1来更新发送数据 */
TXB0D1=RXB0D1+1;
TXB0D2=RXB0D2+1;
TXB0D3=RXB0D3+1;
TXB0D4=RXB0D4+1;
TXB0D5=RXB0D5+1;
TXB0D6=RXB0D6+1;
TXB0D7=RXB0D7+1;
}
/* ****************************************************************
** 函 数 名: interruptHI_ISR()
** 功用描绘: 高优先级中止子程序:RXB0接纳邮箱0接纳中止子程序
*************************************************************** */
voidinterrupt HI_ISR()
{
if(RXB0IF==1)// RXB0接纳邮箱0接纳中止 */
{
CAN_FLAG=1;// 置接纳到 CAN 数据 */
RXB0IF=0;/// 清接纳中止标志 */
RXB0FUL=0;//bit7=0翻开接纳缓冲器接纳新信息 */
}
}
main()
{
initial();// 体系初始化子程序 */
CAN_Adress_H=0x33;// CAN高地址为33,低地址为3 */
CAN_Adress_L=0xe0;// 接纳和发送邮箱标识符:00110011111=0x019F*/
initcan();// CAN设置初始化 */
IPEN=1;// 使能中止凹凸优先级 */
INTCON=INTCON|0xc0;// 开总中止、开外围接口中止 */
while(1)
{
if(CAN_FLAG==1)CAN_deal();// 接纳到CAN信息,处理 */
elseif(CAN_Delay_count>0x2fe)// 距离必定时刻发送CAN数据 */
{
RB7=0;
delay(65535);
TXB0CON=TXB0CON|0x08;// bit3(TXREQ)=1,恳求发送 */
while(TXB0REQ) //等候发送结束退出!!
{
; //等候发送结束
}
CAN_Delay_count=0;// 距离必定时刻发送CAN数据计时器清0 */
}
elseCAN_Delay_count++;// 不到CAN距离发送时刻,持续延时 */
}
}
2.正常通讯形式
界说:CANsend.c 接纳上位机发送的八个数据后,经过CAN发送到另一个节点,CANslave.c接纳CAN数据后进行+1操作后把数据经过CAN发送出去,CANsend.c 接纳数据再送到上位机!
CANsend.c
*
CAN总线程序(包含发送使命和接纳使命)
程序: CANsend.c
版本号:V1.0
功用: 可以接纳上位机发送的串口数据
一起把接纳的上位机程序经过CAN总线发送出去
发送数据到CAN上后间听总线,预备接纳另一个CAN节点发送数据,并把数据回来上位机
MCU: PIC18F2680
公司: RESUN
编译器:Hi-tech PICC 18 v9.50PL3
*/
#include
unsigned char CAN_TX_Adress_L; //CAN发送低地址寄存器
unsigned char CAN_RX_Adress_H; //CAN接纳高地址寄存器
unsigned char CAN_RX_Adress_L; //CAN接纳低地址寄存器
unsigned char Counter; //计数器
unsigned char UartFlage; //串口数据接纳标志
unsigned char CanrecFlage; //CAN数据接纳标志
unsigned char Uartdata[8]; //接纳数据,PC-MCU
unsigned char Senddata[8]; //发送数据,MCU-PC
//———–函数界说————-
void uartint(void);
void picint(void);
void canint(void);
void Work1(void);
void Work2(void);
void Delay(unsigned int asd);
//********************************
//单片机初始化
//********************************
void picint() //PIC初始化!
{
INTCON=0; //制止总中止
ADCON1=0x07; //AD端口设置为通用IO口
PIE1=0; //制止外设中止
PIE2=0;
PIE3=0;
TRISB7=0; //RB7输出引脚,用于调试程序
RB7=0; //输出0
UartFlage=0;
CanrecFlage=0;
Counter=0; //计数器清0
}
//********************************
//串口初始化程序(与PC通讯)
//********************************
void uartint()
{
SPBRG=25; //设置波特率为9600
TXSTA=0x04; //高速波特率4M晶振
RCSTA=0x80; //USART串口使能
TRISC6=1; //设置UART端口,RC6是数据发送,RC7是数据接纳
TRISC7=1;
RCIP=0; //串口接纳设置为低优先级中止
RCIE=1; //答应接纳中止
TXIE=0; //制止发送中止
CREN=1; //答应串口接纳数据
}
//********************************
//延时函数
//********************************
void Delay(unsigned int asd)
{
unsigned int i;
for(i=0;i {}
}
//********************************
//CAN接口初始化
//********************************
void canint() //CAN接口初始化
{
// ************设置对CAN进行装备***************
TRISB=(TRISB|0X08)&0XFB;//设置CANRX/RB3输入,CANTX/RB2输出
CANCON=0X80;// CANCON,bit7-5:1XX恳求装备
while((CANSTAT&0X80)==0)// CA
// ****************************************************************
//** 函 数 名: initcan()
//** 功用描绘: CAN初始化子程序,选用规范标识符N状况寄存器。bit7-5:100装备方法
{
;
}// 等候进入CAN装备形式OPMODE=100
// ************设置对CAN进行装备***************
// ***********波特率设置 **************************
BRGCON1=0X01;// Sync_Seg(bit7-6)=1TQ,BRP(bit5-0)=1,
//则TQ=((2*(BRP+1))/Fosc=4/4M=1us
BRGCON2=0X90;//bit7=1自在编程,bit6=0总线在采样点采样1
//次;phase_Seg1(bit5-3)=3TQ;Prog_Seg(bit2-0)=1TQ
BRGCON3=0X42;// 设置Phase_Seg2(bit2-0)=3TQ
// 标称位时刻=TQ*(Sync_Seg+ Prop_Seg+ Phase_seg1+ Phase_seg2)
//=(1+1+3+3)TQ=8TQ, 位率=1/(8*1U)=0.125MHz */
// 设置发送邮箱0标识符 :00110011111=0x019F */
CAN_TX_Adress_H=0x33; //CAN高地址标识符,应与接纳方标识符相同
CAN_TX_Adress_L=0xe0; //CAN低地址标识符
CAN_TX_Adress_L=CAN_TX_Adress_L&0xe0;
// 设置接纳邮箱0标识符 :10011001010=0x04CA */
CAN_RX_Adress_H=0x99; //CAN高地址标识符
CAN_RX_Adress_L=0x55; //CAN低地址标识符,应与发送方标识符相同
CAN_RX_Adress_L=CAN_RX_Adress_L&0xe0;
// ******设置发送邮箱0和初始发送的数据***** */
TXB0CON=0X03;// bit1-0:发送优先级,设置TXB0为最高优先级3 */
TXB0SIDL=CAN_TX_Adress_L&0xe0; // bit3=0规范标识符,bit7-5:规范标识符2-0位*/
TXB0SIDH=CAN_TX_Adress_H; // 规范标识符的10-3位*/
TXB0DLC=0X08;// 设置数据长度为8个字节 */
TXB0D0=0X00;// 写发送缓冲器数据区数据初值 */
TXB0D1=0X01;// 写发送缓冲器数据区数据初值 */
TXB0D2=0X02;
TXB0D3=0X03;
TXB0D4=0X04;
TXB0D5=0X05;
TXB0D6=0X06;
TXB0D7=0X07;
RXB0SIDL=CAN_RX_Adress_L&0xe0; // bit3=0规范标识符,bit7-5:规范标识符2-0位*/
RXB0SIDH=CAN_RX_Adress_H; // 规范标识符的10-3位 */
RXB0CON=0X20;// bit6-5=01只接纳带有规范标识符的有用报文 */
RXB0DLC=0X08;// 设置接纳缓冲器0数据区长度8个字节 */
RXB0D0=0X02;// 初始化接纳缓冲器0的数据区数据 */
RXB0D1=0X03;// 初始化接纳缓冲器0的数据区数据 */
RXB0D2=0X04;
RXB0D3=0X05;
RXB0D4=0X00;
RXB0D5=0X00;
RXB0D6=0X00;
RXB0D7=0X00;
// *******初始化接纳滤波器0和接纳屏蔽**************** */
RXF0SIDH=CAN_RX_Adress_H;
RXF0SIDL=CAN_RX_Adress_L&0xe0;//高3位为标识符低3位,低5位是装备 */
RXM0SIDH=0Xff;
RXM0SIDL=0Xe0; // 11个1表明接纳11位标识符进行滤波,标识符
//不同不接纳;若全为0,若正确信息,悉数接纳*/
// *******设置CAN作业形式**************************** */
CANCON=0X00;//=0X40,进入自测试形式;=0x00,正常操作形式
while((CANSTAT&0XE0)!=0)// 检测CAN装备完结 */
{
;
}
// 初始化CAN的中止,PIR3为CAN的外围中止标志寄存器 */
PIR3=0X00;// 清一切CAN中止标志*/
PIE3=PIE3|0X01;// 使能接纳缓冲器0的接纳中止 */
IPR3=IPR3|0X01;// 接纳缓冲器0的接纳中止为最高优先级 */
}
//*********************************
//高优先级中止程序
//*********************************
void interruptHI_ISR()
{
if(RXB0IF==1) //接纳缓冲器1接纳到新数据
{
RB7=1;
CanrecFlage=1;// 置接纳到 CAN 数据 */
RXB0IF=0;// 清接纳中止标志 */
RXB0FUL=0;// bit7=0,翻开接纳缓冲器接纳新信息 */
}
}
//*********************************
//低优先级中止程序
//*********************************
void interrupt low_priority LOW_ISR()
{
if(RCIF==1) //判别是不是串口中止
{
Uartdata[Counter]=RCREG;
Counter++;
if(Counter>7)
{
Counter=0;
UartFlage=1; //有串行数据接纳
}
}
}
//*********************************
//处理函数1
//*********************************
void Work1()
{
TXB0CON=TXB0CON&0xf7; //bit3:TXREQ=0, 关恳求发送
UartFlage=0; //清标志
TXB0D0=Uartdata[0]; //CAN发送数据更新(用串口接纳来的数据)
TXB0D1=Uartdata[1];
TXB0D2=Uartdata[2];
TXB0D3=Uartdata[3];
TXB0D4=Uartdata[4];
TXB0D5=Uartdata[5];
TXB0D6=Uartdata[6];
TXB0D7=Uartdata[7];
TXB0CON=TXB0CON|0x08; //恳求发送,bit3:TXREQ=1
// RB7=1;
while(TXB0REQ) //等候发送结束
{
;
}
Delay(10000);
}
//*********************************
//处理函数2
//*********************************
void Work2() //接纳数据回来PC机
{
unsigned char i;
Senddata[0]=RXB0D0;
Senddata[1]=RXB0D1;
Senddata[2]=RXB0D2;
Senddata[3]=RXB0D3;
Senddata[4]=RXB0D4;
Senddata[5]=RXB0D5;
Senddata[6]=RXB0D6;
Senddata[7]=RXB0D7;
//RCEN=0; //接纳制止
TXEN=1; //使能串口发送
for(i=0;i<8;i++) //串口数据发送
{
TXREG=Senddata[i];
while(1)
{
if(TXIF==1) break;
}
Delay(100);
}
//RCEN=1; //接纳使能
TXEN=0; //制止数据发送
}
//*********************************
//主程序
//*********************************
void main()
{
SWDTEN=0; //软件封闭看门狗
picint();
canint();
uartint();
IPEN=1; //使能凹凸中止优先级
INTCON=INTCON|0xc0; //开总中止、开外围接口中止
TXB0REQ=0; //制止CAN发送
while(1) //主循环
{
if(UartFlage) //接纳到串口数据
{
UartFlage=0;
Work1();
//RB7=0;
}
if(CanrecFlage) //接纳到CAN总线数据
{
CanrecFlage=0;
Work2();
}
}
}
CANslave.c
/*
CAN总线程序(包含发送使命和接纳使命)
程序: CANslave.c
版本号:V1.0
功用:
一起把接纳的CAN数据经过CAN总线发送出去
供其他节点进行接纳
MCU: PIC18F2680
公司: RESUN
编译器:Hi-tech PICC 18 v9.50PL3
*/
#include
unsigned char CAN_TX_Adress_L; //CAN发送低地址寄存器
unsigned char CAN_RX_Adress_H; //CAN接纳高地址寄存器
unsigned char CAN_RX_Adress_L; //CAN接纳低地址寄存器
unsigned char CAN_FLAG;
//————函数界说————
void picint(void);
void canint(void);
void delay(unsigned int asd);
//************************************
//延时函数
//************************************
void delay(unsigned int asd)
{
unsigned int i;
for(i=0;i {}
}
//************************************
//单片机初始化函数
//************************************
void picint()
{
INTCON=0; //制止总中止
ADCON1=0x07; //AD端口设置为通用IO口
PIE1=0; //制止外设中止
PIE2=0;
PIE3=0;
TRISB7=0; //RB7输出引脚,用于调试程序
RB7=0; //输出0
}
//************************************
//CAN总线初始化函数
//************************************
void canint()
{
// 设置发送邮箱0标识符 :10011001010=0x04CA */
CAN_TX_Adress_L=0x55;//CAN低地址标识符
CAN_TX_Adress_L=CAN_TX_Adress_L&0xe0;
CAN_TX_Adress_H=0x99;//CAN高地址标识符,应与发送方标识符相同
// 设置接纳邮箱0标识符 :00110011111=0x019F */
CAN_RX_Adress_H=0x33;//CAN高地址标识符
CAN_RX_Adress_L=0xe0;//CAN低地址标识符,应与发送方标识符相同
CAN_RX_Adress_L=CAN_RX_Adress_L&0xe0;
// ************设置对CAN进行装备*************** */
TRISB=(TRISB|0X08)&0XFB;// 设置CANRX/RB3输入,CANTX/RB2输出 */
CANCON=0X80;// CANCON,bit7-5:1XX恳求装备 */
while((CANSTAT&0X80)==0)// CAN状况寄存器。bit7-5:100装备方法 */
{
;
}// 等候进入CAN装备形式OPMODE=100 */
// ***********波特率设置 ************************** */
BRGCON1=0X01;/* Sync_Seg(bit7-6)=1TQ,BRP(bit5-0)=1,
则TQ=((2*(BRP+1))/Fosc=4/4M=1us */
BRGCON2=0X90;/*bit7=1自在编程,bit6=0总线在采样点采样1
次;phase_Seg1(bit5-3)=3TQ;Prog_Seg(bit2-0)=1TQ*/
BRGCON3=0X42;/* 设置Phase_Seg2(bit2-0)=3TQ */
// 标称位时刻=TQ*(Sync_Seg+ Prop_Seg+ Phase_seg1+ Phase_seg2)
//=(1+1+3+3)TQ=8TQ, 位率=1/(8*1U)=0.125MHz */
// ******设置发送邮箱0和初始发送的数据***** */
TXB0CON=0X03;// bit1-0:发送优先级,设置TXB0为最高优先级3 */
TXB0SIDL=CAN_TX_Adress_L&0xe0; //bit3=0规范标识符,bit7-5:规范标识符2-0位*/
TXB0SIDH=CAN_TX_Adress_H;// 规范标识符的10-3位*/
TXB0DLC=0X08;// 设置数据长度为8个字节 */
TXB0D0=0X00;// 写发送缓冲器数据区数据初值 */
TXB0D1=0X01;// 写发送缓冲器数据区数据初值 */
TXB0D2=0X02;
TXB0D3=0X03;
TXB0D4=0X04;
TXB0D5=0X05;
TXB0D6=0X06;
TXB0D7=0X07;
RXB0SIDL=CAN_RX_Adress_L&0xe0; //bit3=0规范标识符,bit7-5:规范标识符2-0位*/
RXB0SIDH=CAN_RX_Adress_H;// 规范标识符的10-3位 */
RXB0CON=0X20;// bit6-5=01只接纳有用的规范标识符信息 */
RXB0DLC=0X08;// 设置接纳缓冲器0数据区长度8个字节 */
RXB0D0=0X02;// 初始化接纳缓冲器0的数据区数据 */
RXB0D1=0X03;// 初始化接纳缓冲器0的数据区数据 */
RXB0D2=0X04;
RXB0D3=0X05;
RXB0D4=0X00;
RXB0D5=0X00;
RXB0D6=0X00;
RXB0D7=0X00;
// *******初始化接纳滤波器0和接纳屏蔽**************** */
RXF0SIDH=CAN_RX_Adress_H;
RXF0SIDL=CAN_RX_Adress_L&0xe0;//高3位为标识符低3位,低5位是装备 */
RXM0SIDH=0Xff;
RXM0SIDL=0Xe0;// 11个1表明接纳11位标识符进行滤波,标识符
//不同不接纳;若全为0,若正确信息,悉数接纳*/
// *******设置CAN作业形式**************************** */
CANCON=0X00;//=0X40,进入自测试形式;=0x00,正常操作形式
while((CANSTAT&0XE0)!=0)// 检测CAN装备完结 */
{
;
}
// 初始化CAN的中止,PIR3为CAN的外围中止标志寄存器 */
PIR3=0X00; // 清一切CAN中止标志 */
PIE3=PIE3|0X01; // 使能接纳缓冲器0的接纳中止 */
IPR3=IPR3|0X01; // 接纳缓冲器0的接纳中止为最高优先级 */
}
//************************************
//中止函数
//************************************
void interruptHI_ISR()
{
if(RXB0IF==1)
{
CAN_FLAG=1;// 置接纳到 CAN 数据 */
RXB0IF=0;// 清接纳中止标志 */
RXB0FUL=0;// bit7=0翻开接纳缓冲器接纳新信息 */
}
}
//************************************
//主函数
//************************************
void main()
{
SWDTEN=0; //软件封闭看门狗
picint();
canint();
IPEN=1;// 使能中止凹凸优先级 */
INTCON=INTCON|0xc0;// 开总中止、开外围接口中止 */
TXB0REQ=0;// 关发送,TXB0REQ=0; */
while(1)
{
if(CAN_FLAG==1)
{
RB7=!RB7;
CAN_FLAG=0;// 清接纳到标志 */
TXB0CON=TXB0CON&0xf7;// TXB0REQ=0关发送 */
TXB0D0=RXB0D0+1;// 用接纳数据加1来更新发送数据 */
TXB0D1=RXB0D1+1;
TXB0D2=RXB0D2+1;
TXB0D3=RXB0D3+1;
TXB0D4=RXB0D4+1;
TXB0D5=RXB0D5+1;
TXB0D6=RXB0D6+1;
TXB0D7=RXB0D7+1;
TXB0CON=TXB0CON|0x08;// bit3(TXREQ)=1恳求发送 */
while(TXB0REQ) //等候发送结束
{
;
}
delay(10000);
RB7=0;
}
}
}