问题:用ATmega16 单片机控制SJA1000在PeliCAN模式下自收发不成功
调试方法:读取SJA1000内部各寄存器的值,通过串口电脑上显示数值,对比各寄存器状态
调试发现:1、在发送数据帧的时候SJA1000不能产生中断; 2、单片机强制中断进入中断函数,分别读取模式寄存器、状态寄存器发现模式寄存器进入了复位模式,状态寄存器总线离线、状态出错等;3、进一步检测发现,在发送数据帧子程序中,自接受请求命令前读取的各寄存器是正常的,而该句之后就出现了各种错误。
这个程序调了三天了,毫无头绪,恳请大神赐教,小弟不胜感激,程序如下
/*************************************************************************MCU:ATmega16MCLK:内部震荡8M熔丝位:低14高48CAN总线模块:独立可编程CAN芯片SJA1000CAN模块晶振:16M功能说明:自收发:按下key,1602第一行显示按下的次数,然后作为报文数据发送, 再由节点本身自己接收,并将接收的数据显示在第二行。接线说明:A0-A7口对应接SJA1000八位地址/数据线 C2-C7口接控制线 D2口接SJA1000INT0,D3口接外部按键key**************************************************************************/#include #include #include"yanshi.c"//提供ms和us延时函数#include"1602.c"//1602显示函数#define uchar unsigned char#define uint unsigned int#define mclk 8000000//8M晶振#pragma interrupt_handler can_rxd:2//外部中断INT0申明#pragma interrupt_handler key:3//外部中断INT1申明#pragma interrupt_handler usart_recieve:12//串口中断申明/*************************************************************************功能说明:SJA1000控制引脚定义**************************************************************************//*模块CANTest指示灯 PC2,高电平亮*/#define LED_H PORTC|=BIT(2)#define LED_L PORTC&=~BIT(2)/*SJA1000的RST信号线 PC3,低电平有效*/#define SJA_RST_H PORTC|=BIT(3)#define SJA_RST_L PORTC&=~BIT(3)/*SJA1000的WR信号线 PC4,低电平有效*/#define SJA_WR_H PORTC|=BIT(4)#define SJA_WR_L PORTC&=~BIT(4)/*SJA1000的RD信号线 PC5,低电平有效*/#define SJA_RD_H PORTC|=BIT(5)#define SJA_RD_L PORTC&=~BIT(5)/*SJA1000的CS信号线 PC6,低电平有效*/#define SJA_CS_H PORTC|=BIT(6)#define SJA_CS_L PORTC&=~BIT(6)/*SJA1000的ALE信号线 PC7,高电平有效*/#define SJA_ALE_H PORTC|=BIT(7)#define SJA_ALE_L PORTC&=~BIT(7)/*SJA1000的INT0信号线 PD2,外部中断INT0*/#define SJA_INT_H PORTD|=BIT(2)#define SJA_INT_L PORTD&=~BIT(2)/*SJA1000的KEY信号线 PD3,外部中断INT1*/#define SJA_KEY_H PORTD|=BIT(3)#define SJA_KEY_L PORTD&=~BIT(3)/*************************************************************************功能说明:SJA1000内部寄存器地址定义,各寄存器具体功能参阅SJA1000数据手册注意事项:不可随意修改模式:PeliCAN模式和扩展帧EFF模式描述符配置说明:BIT7:1,EFF:扩展帧格式 0,SFF:标准帧格式 BIT6:1,远程帧 0,数据帧 BIT3-0:数据长度代码**************************************************************************/#define MODR 0x00 //模式寄存器#define CMR 0x01 //命令寄存器#define SR 0x02 //状态寄存器#define IR 0x03 //中断寄存器#define IER 0x04 //中断使能寄存器#define BTR0 0x06 //总线定时寄存器0#define BTR1 0x07 //总线定时寄存器1#define OCR 0x08 //输出控制寄存器#define TEST 0x09 //测试寄存器#define ALC 0x0B //仲裁丢失捕捉#define ECC 0x0C //错误代码捕捉#define EWLR 0x0D //错误报警限额#define RXERR 0x0E //接收错误计数器#define TXERR 0x0F //发送错误计数器/*验收代码寄存器*/#define ACR0 0x10#define ACR1 0x11#define ACR2 0x12#define ACR3 0x13/*验收屏蔽寄存器*/#define AMR0 0x14#define AMR1 0x15#define AMR2 0x16#define AMR3 0x17/*发送缓冲区寄存器*/#define TBSR0 0x10 //TX描述符#define TBSR1 0x11 //TX标识符1#define TBSR2 0x12 //TX标识符2#define TBSR3 0x13 //TX标识符3#define TBSR4 0x14 //TX标识符4#define TBSR5 0x15 //TX数据1#define TBSR6 0x16 //TX数据2#define TBSR7 0x17 //TX数据3#define TBSR8 0x18 //TX数据4#define TBSR9 0x19 //TX数据5#define TBSR10 0x1A //TX数据6#define TBSR11 0x1B //TX数据7#define TBSR12 0x1C //TX数据8// 接收缓冲区寄存器#define RBSR 0x10 //RX描述符#define RBSR1 0x11 //RX标识符1#define RBSR2 0x12 //RX标识符2#define RBSR3 0x13 //RX标识符3#define RBSR4 0x14 //RX标识符4#define RBSR5 0x15 //RX数据1#define RBSR6 0x16 //RX数据2#define RBSR7 0x17 //RX数据3#define RBSR8 0x18 //RX数据4#define RBSR9 0x19 //RX数据5#define RBSR10 0x1A //RX数据6#define RBSR11 0x1B //RX数据7#define RBSR12 0x1C //RX数据8#define RMC 0x1D //RX报文计数器#define RBSA 0x1E //接收缓冲区起始地址#define CDR 0x1F //时钟分频寄存器/*************************************************************************功能说明:子函数定义**************************************************************************/void init_mcu(void);//MCU初始化函数void rxd_deal(void);//接收函数void txd_deal(void);//发送函数void can_txd(void);//发送扩展数据帧void init_INT(void);//外部中断初始化void SJA1000_WRITE(uchar ADDRESS,uchar A_DATA);//控制SJA1000写入一个数据uchar SJA1000_READ(uchar ADDRESS);//控制SJA1000读出一个数据void init_SJA1000_HardWare(void);//SJA1000硬件复位uchar init_SJA1000_Soft(void);//SJA1000软件复位void usart_init(uint baud);//串口初始化void usart_transmit(uchar data); //发送数据void usart_recieve(void); //接收数据/*************************************************************************功能说明:全局变量定义**************************************************************************/#define N_can 13//定义常数代表一帧字节uchar TXD_flag=0;//发送标志,置一时请求发送uchar RXD_flag=0;//接收标志,置一时有数据可以接收uchar TX_buffer[13];//发送数据缓冲区uchar RX_buffer[13];//接收数据缓冲区uchar Txd_data=0;//CAN总线要发送的数据uchar Rxd_data=0;//CAN总线要接收的数据uchar TempData;uchar rdata,flag=0;uchar num[]="0123456789ABCDEF";/*************************************************************************功能说明:MCU初始化**************************************************************************/void init_mcu(void){ DDRA=0XFF;//定义地址/数据线接口输出 DDRC=0XFF;//定义控制线输出 usart_init(9600);//串口初始化,波特率采用9600 init_INT();//外部中断INT0、INT1初始化}/*************************************************************************功能说明:串口初始化**************************************************************************/void usart_init(uint baud){ uint i; UCSRA=0X00; UCSRB=0X00; UCSRC=0X86;//1000 0110异步模式、一位停止位、8位字符 i=mclk/16/baud-2; UBRRL=i;//16为的数据只有低八位赋给了寄存器 UBRRH=i>>8; UCSRB=0X98;//1001 1000接收结束中断使能、接收和发送使能 SREG=BIT(7);//全局中断使能}/*************************************************************************功能说明:串口发送数据**************************************************************************/void usart_transmit(uchar data) //发送数据{ while(!(UCSRA&BIT(5)));//等待寄存器空 UDR=data;//写入UDR也就是发送TXB while(!(UCSRA&BIT(6)));//等待发送完毕 UCSRA|=BIT(6);//清空UDR}/*************************************************************************功能说明:串口接收数据**************************************************************************/void usart_recieve(void) //接收数据{ UCSRB&=~BIT(7);//关闭接收结束中断使能,防止干扰 rdata=UDR;//读UDR的值也就是是接收RXD flag=1; UCSRB|=BIT(7);//恢复接收结束中断使能}/*************************************************************************功能说明:外部中断初始化**************************************************************************/void init_INT(void){ MCUCR=0X0A;//下降沿产生中断 GICR=0XC0;//使能INT0、INT1 SREG|=BIT(7);//全局中断使能}/*************************************************************************功能说明:CPU中断接收服务程序(外部中断INT0)**************************************************************************/void can_rxd(void){ uchar state; GICR=0X00;//关闭INT0、INT1中断 state=SJA1000_READ(IR);//读sja1000中断寄存器 usart_transmit(state); delay(10); if(state&0x01) { RX_buffer[0]=SJA1000_READ(RBSR); delay(1); RX_buffer[1]=SJA1000_READ(RBSR1); delay(1); RX_buffer[2]=SJA1000_READ(RBSR2); delay(1); RX_buffer[3]=SJA1000_READ(RBSR3); delay(1); RX_buffer[4]=SJA1000_READ(RBSR4); delay(1); RX_buffer[5]=SJA1000_READ(RBSR5); delay(1); RX_buffer[6]=SJA1000_READ(RBSR6); delay(1); RX_buffer[7]=SJA1000_READ(RBSR7); delay(1); RX_buffer[8]=SJA1000_READ(RBSR8); delay(1); RX_buffer[9]=SJA1000_READ(RBSR9); delay(1); RX_buffer[10]=SJA1000_READ(RBSR10); delay(1); RX_buffer[11]=SJA1000_READ(RBSR11); delay(1); RX_buffer[12]=SJA1000_READ(RBSR12); delay(1); RXD_flag=1;//接收标志置位 SJA1000_WRITE(CMR,0X04);//释放接收缓冲器 state=SJA1000_READ(ALC); state=SJA1000_READ(ECC); } SJA1000_WRITE(IER,0X01);//接收中断使能 GICR=0XC0;//使能INT0、INT1}/*************************************************************************功能说明:按键外部中断INT1服务程序**************************************************************************/void key(void){ GICR=0X00;//关闭INT0、INT1中断 Txd_data++; TXD_flag=1; GICR=0XC0;//使能INT0、INT1}/*******************************************************************************函数名称: void SJA1000_WRITE(unsigned char ADDRESS,unsigned char A_DATA)功能说明: 该函数用于CAN控制器写入一个数据输入参数: unsigned char ADDRESS: 地址unsigned char A_DATA: 数据*******************************************************************************/void SJA1000_WRITE(uchar ADDRESS,uchar A_DATA){ delay_us(2); SJA_ALE_H;//ALE=1锁存地址 delay(10); DDRA=0XFF; //数据口为输出 PORTA=ADDRESS;//输出地址数据 delay(10); SJA_ALE_L;//地址锁存 SJA_CS_L;//低电平允许访问SJA1000 SJA_WR_L;//写入,低电平有效 delay(10); PORTA=A_DATA; //输出数据 delay(10); SJA_WR_H;//关闭写}/*****************************************************************************函数名称: unsigned char SJA1000_READ(unsigned char ADDRESS)功能说明: 该函数用于CAN控制器读出一个数据输入参数: unsigned char ADDRESS: 地址输出参数: 读出的数据*****************************************************************************/uchar SJA1000_READ(uchar ADDRESS){ uchar data; delay_us(2); SJA_ALE_H;//ALE=1 delay(10); DDRA=0XFF; //数据口为输出 PORTA=ADDRESS; //输出数据的地址 delay(10); SJA_ALE_L;//ALE=0 SJA_CS_L;//低电平允许访问SJA1000 SJA_RD_L;//读出,低电平有效 delay(10); DDRA=0X00; //数据口为输入 PORTA=0XFF; //上拉 delay(10); data=PINA; //获得数据 delay(10); SJA_RD_H;//关读取 return data;//将读到的数据返回}/******************************************************************************函数名称: void init_SJA1000_HardWare(void)功能说明: SJA1000硬件初始化系统******************************************************************************/void init_SJA1000_HardWare(void){ delay(100); SJA_RST_L; // SJA1000的RST信号线(低电平有效) delay(100); SJA_RST_H; // SJA1000的RST信号线(低电平有效) delay(100); // 复位延时,保证可靠复位}/****************************************************************************函数名称: void init_SJA1000_Soft(void)功能说明: SJA1000软件初始化系统****************************************************************************/uchar init_SJA1000_Soft(void){ do // SJA1000控制: 复位模式 { DDRC&=~BIT(3); SJA_RST_H; // SJA1000的RST信号线(低电平有效) delay(100); // 复位延时,保证可靠复位 SJA1000_WRITE(MODR,0X09);//MODR=0X00;控制寄存器 TempData = SJA1000_READ(MODR); } while((TempData&0X1F)!= 0x09); /*测试SJA1000的通信状态*/ SJA1000_WRITE(TEST,0X55); //访问测试寄存器写入测试值 TempData = SJA1000_READ(TEST); /*初始化时分控制器: PeilCAN模式、CLOCKOFF禁止*/ SJA1000_WRITE(CDR,0X88); // 时分控制寄存器 /*设置输出控制器*/ SJA1000_WRITE(OCR,0XAA); // 访问地址指向输出控制寄存器 /*波特率: bps = 10K*/ SJA1000_WRITE(BTR0,0X31); // 访问地址指向总线定时寄存器0 SJA1000_WRITE(BTR1,0X1C); // 访问地址指向总线定时寄存器 /*中断控制: 接收中断*/ SJA1000_WRITE(IER,0X01); // 访问中断使能控制 /*命令寄存器只写*/ SJA1000_WRITE(CMR,0X04); //释放接收缓冲区 delay(100); SJA1000_WRITE(CMR,0X08); //数据溢出清除命令 delay(100); /*设置滤波器,地址为本地的IP前29位,全无关*/ SJA1000_WRITE(ACR0,0X11); // 验收代码寄存器(ACR1) SJA1000_WRITE(ACR1,0X22); // 验收代码寄存器(ACR2) SJA1000_WRITE(ACR2,0X33); // 验收代码寄存器(ACR3) SJA1000_WRITE(ACR3,0X44); // 验收代码寄存器(ACR4) SJA1000_WRITE(AMR0,0X11); // 验收屏蔽寄存器 SJA1000_WRITE(AMR1,0X11); // 验收屏蔽寄存器 SJA1000_WRITE(AMR2,0X11); // 验收屏蔽寄存器 SJA1000_WRITE(AMR3,0X11); // 验收屏蔽寄存器 do { SJA1000_WRITE(MODR,0X0C); TempData = SJA1000_READ(MODR); DDRC|=BIT(3); SJA_RST_H; // SJA1000的RST信号线(低电平有效) delay(100); // 复位延时,保证可靠复位 } while(!(TempData&0x0C)); return 0;}/*************************************************************************功能说明:接收处理程序**************************************************************************/void rxd_deal(void){ if(RXD_flag) { GICR=0X00;//关闭INT0、INT1中断 RXD_flag=0; Rxd_data=RX_buffer[5]; GICR=0XC0;//使能INT0、INT1 }}/*************************************************************************功能说明:发送处理程序**************************************************************************/void txd_deal(void){ if(TXD_flag) { delay_us(10); TXD_flag=0; can_txd(); delay_us(10); }}/*************************************************************************功能说明:发送扩展数据帧**************************************************************************/void can_txd(void){ uchar state; TX_buffer[0]=0X81; TX_buffer[1]=0X11; TX_buffer[2]=0X22; TX_buffer[3]=0X33; TX_buffer[4]=0X44; TX_buffer[5]=Txd_data; TX_buffer[6]=0X22; TX_buffer[7]=0X33; TX_buffer[8]=0X44; TX_buffer[9]=0X55; TX_buffer[10]=0X66; TX_buffer[11]=0X77; TX_buffer[12]=0X88; GICR=0X00;//关闭INT0、INT1中断 do { state=SJA1000_READ(SR);//读状态寄存器 LED_H; } while((state&0x10)==0x10);//判断是否正在接收,正在接收等待 do { state=SJA1000_READ(SR); LED_H; } while(!(state&0x08));//发送请求未处理完等待 do { state=SJA1000_READ(SR); LED_H; } while(!(state&0x04)); LED_L; SJA1000_WRITE(TBSR0,TX_buffer[0]); delay(1); SJA1000_WRITE(TBSR1,TX_buffer[1]); delay(1); SJA1000_WRITE(TBSR2,TX_buffer[2]); delay(1); SJA1000_WRITE(TBSR3,TX_buffer[3]); delay(1); SJA1000_WRITE(TBSR4,TX_buffer[4]); delay(1); SJA1000_WRITE(TBSR5,Txd_data); delay(1); SJA1000_WRITE(TBSR6,TX_buffer[6]); delay(1); SJA1000_WRITE(TBSR7,TX_buffer[7]); delay(1); SJA1000_WRITE(TBSR8,TX_buffer[8]); delay(1); SJA1000_WRITE(TBSR9,TX_buffer[9]); delay(1); SJA1000_WRITE(TBSR10,TX_buffer[10]); delay(1); SJA1000_WRITE(TBSR11,TX_buffer[11]); delay(1); SJA1000_WRITE(TBSR12,TX_buffer[12]); delay(100); SJA1000_WRITE(CMR,0X10);//自接收请求 delay(100); GICR=0XC0;//使能INT0、INT1 }/*************************************************************************功能说明:主函数**************************************************************************/void main(void){ uchar i; init_mcu();//单片机自身初始化 delay(100); init_1602();//显示初始化 delay(100); init_SJA1000_HardWare();//SJA1000硬件初始化 delay(100); do { TempData = init_SJA1000_Soft(); // SJA1000软件初始化系统 } while(TempData!=0); usart_transmit(0x0b);//串口发送初始化完成标志 delay(10); while(1) { rxd_deal(); txd_deal(); first(0,num[Txd_data]);//1602第一行第一格显示要发送的报文 second(0,num[Rxd_data]);//1602第二行第一格显示接收的报文 if(Txd_data==16) Txd_data=0; if(Rxd_data==16) Rxd_data=0; } }
0
|
3个回答
|
|
|