sja1000 can 驱动程序演示实验
- 格式:doc
- 大小:35.50 KB
- 文档页数:9
我的CAN总线SJA1000调试经历展开全文我的 CAN总线 SJA1000调试经历前几天学校实验室赶活,调试了SJA1000的CAN总线驱动,我所做的平台是在Intel PXA270的ARM处理器上面进行控制的,通过读写总线的方式进行控制的,期间对着SJA1000的databook查找了很多,期间调试时也走了不少的弯路,现在把调试心得一些经验在这里讲讲。
由于以前对CAN的驱动接触比较少,只是了解过它的物理特性和用途,所以下手点就是从databook这块着手的,于是先调试CAN的初始化配置,首先是通过CPU能够读写SJA1000的寄存器了,然后我从网上下了一个基于Linux内核的CAN驱动代码,往里一直添加,但最后发现这套代码写得太复杂了,可能本身自己对SJA1000的寄存器设置也不是很了解,没办法,看了大半天的databook,终于有些头绪想清楚该是怎样去控制了,从ZLG网站中下了一个BASIC模式下的参考例程,我看了一下,然后SJA的寄存器详细看了看(由于开始的时候比较忙,所以直到这个时候才算是仔细看了看SJA的内部,至于CAN 的基础协议我是根本没有看,这给我后面带来了极大的麻烦)。
然后就参考ZLG的程序开始写SJA的测试程序,那个程序写的很大,也比较完整,因为我想快点把CAN打通,于是弄了一个一千多行的程序,以前我的调试程序一般都很小的。
写好程序之后就开始测试,首先测试的是测试寄存器,然后一步步测试下去,在BASIC模式下所有的寄存器都正常,但是在发送的时候是总是不正常,启动发送之后就一直在发送,状态寄存器的标志位一直处在发送的状态下,然后就是报总线错误,不知道是怎么会事情,很郁闷,上网上的BBS看了一下。
其他人告诉我单个CAN节点发送是成功不了的,如果没有收到接受CAN 节点的应答,发送节点就会一直发送,直到超出错误计数器的允许值使得总线关闭。
这下我终于明白是怎么回事了,同时在精华区发现在peli模式下有ECC(错误寄存器),可以跟踪错误,于是开始改成用PeliCAN模式操作过程。
SJA1000 CAN驱动程序演示实验一.实验目的本驱动程序展示了如何在Small RTOS中编写SJA1000 的驱动程序。
通过调用CAN 程序库SJA1000_PEI.LIB 的基本函数,实现实验板上CAN 节点的初始化以及CAN 节点数据收发测试。
二.实验设备及器件PC 机一台DP-51PROC 单片机综合仿真实验仪一台CAN PARK 模块一台CAN 连接线一根三.实验步骤1、将CAN-bus PARK 插入到A6 区中,用导线连接A6 区的P1_IO2 到A2 区的P1 0,连接A6 区的P1_CS1 到A2 区的A15。
2、使用导线把A2 区的P16 和P17 分别于D5 区的SCL 和SDA 相连。
使用导线把D 5区的/RST 与VCC 相连。
3、由于本程序使用中断方式响应SJA1000 中断,故将A5 区的P1_INT 接到A2 区的INT0。
4、利用CAN 连接线将两台已经安装了CAN-Bus 模块的DP-51PROC 连接起来,以组成简单的CAN 网络实现CAN 的接收和发送。
5、本驱动程序已经将输出文件路径设置为“E:\Temp”,用户可自行更改输出文件路径。
将路径“E:\Temp”中的CAN. hex 文件下载到两台DP-51PROC 中运行。
四.实验参考程序主要部分/*******************************************************描述:独立的CAN 控制器SJA1000PeliCAN 在small rtos 中的应用示例*文件名: PELIRTOS.c*应用语言: KEIL C51*应用系统: small rtos*版本: V1.0*广州周立功单片机发展有限公司保留所有的版权****************************************************/#define _TIME_MODULE_H#define _SERIAL_H/********************************************************** 导入头文件******************************************************/#include "INCLUDES.h"#include "Sja1000_peli.h"sfr IPH=0xb7;sbit RESET_PIN=P1^0;// 验收代码/屏蔽寄存器的内容(4+4)uint8 xdata Send_CAN_Filter[8]={0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0xff};// 帧信息和标示码(1+4)分别对应TX,TX1,TX2,TX3,TX4uint8 xdata Send_CAN_Info_ID[3]={0xc7,0x0A,0x0B};uint8 xdata Recv_CAN_Info_ID[3];// 待发送数据(8)uint8 xdataSend_CAN_Data[13]={0xc7,0x0A,0x0B,0x04,0x05,0x06,0x07,0x08,0x07,0x0 8,0x07,0x08,0x08};uint8 xdata Recv_CAN_Data[14];uint8 xdata time_Counter=0;uint8 xdata BTR0,BTR1;uint16 xdata *p;uint8 xdata disp_buf[8];void CAN_Send(void);void display(void);void CAN_Rcv(void);void TimeSum(void);void Delay_ms(uint8 j);void SJA1000_Config_Normal(void);void Init(void){CKCON=1; //应用6clockTMOD = (TMOD & 0XF0) | 0X01;TCON=TCON|0x04; //MCU 的INT1 下降沿触发,INT0 电平触发TH0 = (65536 - (11059200 / 12) / 100) / 256;TL0 = (65536 - (11059200 / 12) / 100) % 256;TR0 = 1;ET0 = 1;TF0 = 0;}/************************************************************** ****函数名称:void CAN_Init(void)**功能描述:复位SJA1000,并设置其工作在正常模式************************************************************** ***/void CAN_Init(void){RESET_PIN=0; //将SJA1000 的复位线与P1.0 相连接Delay_ms(1);RESET_PIN=1; //控制P1.0 来实现SJA1000 的复位SJA_CS_Point=&CAN_SJA_BaseAdr;SJA1000_Config_Normal();WriteSJAReg(REG_CAN_IER,RIE_BIT); //使能SJA1000 接收中断EX0=1;}/************************************************************** ** 函数原型: void Delay_ms(uchar j)** 功能描述: 该函数用于不精确的延时。
实验一SJA1000的初始化一、实验目的:学习并完成SJA1000的初始化二、实验设备:EL-8051-III型单片机实验箱三、实验原理:SJA1000的初始化只有在复位模式下才可以进行,初始化主要包括工作方式的设置、接收滤波方式的设置、介绍屏蔽寄存器(AMR)和接收代码寄存器(ACR)的设置、波特率参数设置和中断允许寄存器(IER)的设置等。
在完成SJA1000的初始化设置以后,SJA1000就可以回到工作状态,进行正常的通信任务。
初始化流程:四、实验内容及步骤:初始化CAN节点,使SJA1000处在准备工作状态。
1.给试验箱换上CAN控制器;2.编写并编译初始化程序;3.下载程序并调试。
编写的程序如下:MODE EQU 0DE00H ;模式寄存器CMR EQU 0DE01H ;命令寄存器SR EQU 0DE02H ;状态寄存器IR EQU 0DE03H ;中断寄存器IER EQU 0DE04H ;中断使能寄存器BTR0 EQU 0DE06H ;总线定时寄存器一BTR1 EQU 0DE07H ;总线定时寄存器二OCR EQU 0DE08H ;输出控制寄存器ALC EQU 0DE0BH ;仲裁丢失捕捉寄存器ECC EQU 0DE0CH ;错误代码捕捉寄存器TXERR EQU 0DE0FH ;发送错误计数器ACR0 EQU 0DE10H ;验收代码寄存器0ACR1 EQU 0DE11H ; 1ACR2 EQU 0DE12H ; 2ACR3 EQU 0DE13H ; 3AMR0 EQU 0DE14H ;验收屏蔽寄存器0AMR1 EQU 0DE15H ; 1AMR2 EQU 0DE16H ; 2AMR3 EQU 0DE17H ; 3FIN EQU 0DE10H ;发送/接收帧信息ID1 EQU 0DE11H ;发送/接收缓冲区之标示符一ID2 EQU 0DE12H ;发送/接收缓冲区之标示符二DATA1 EQU 0DE13H ;发送/接收数据首址RBSA EQU 0DE1EH ;接收缓冲器起始地址寄存器CDR EQU 0DE1FH ;时钟分频寄存器DAMR EQU 40HDACR EQU 50HORG 4000HJMP STARTORG 4080HSTART:mov dptr,#modemov a,#01hmovx @dptr,amov dptr,#acr0mov a,#00hmovx @dptr,amov dptr,#acr1mov a,#60hmovx @dptr,amov dptr,#acr2mov a,#00hmovx @dptr,amov dptr,#acr3mov a,#00hmovx @dptr,amov dptr,#amr0mov a,#00hmovx @dptr,amov dptr,#amr1mov a,#0fhmovx @dptr,amov dptr,#amr2mov a,#0ffhmovx @dptr,amov dptr,#amr3mov a,#0ffhmovx @dptr,amov dptr,#btr0mov a,#01hmovx @dptr,amov dptr,#btr1mov a,#1chmovx @dptr,amov dptr,#ocrmov a,#0aahmovx @dptr,amov dptr,#cdrmov a,#89hmovx @dptr,amov dptr,#mode ;退出复位模式mov a,#00hmovx @dptr,amov dptr,#sr ;判断状态寄存器是否初始化成功,成功则点亮P1口的灯movx a,@dptrcjne a,#0ch,startmov P1,#00hend五、实验结果P1口连接的灯均亮了,外部存储器DE00H~DE30H的值为下图所示:六、实验心得。
(铜陵学院工业控制网络小论文题目基于SJA1000的CAN总线控制系统的设计与实现~姓名张三院系电气工程学院)学号 XXXXXXXX班级 A/2017-05-19CAN-bus(Controller Area Network)即控制器局域网是国际上应用最广泛的现场总线之一。
最初CAN-bus被设计作为汽车环境中的微控制器通讯工具,用于在车载各电子控制装置ECU之间交换信息,从而形成汽车电子控制网络。
如今,CAN-bus作为一种技术先进、可靠性高、功能完善、成本合理的远程网络通讯控制方式,已被广泛应用到各个自动化控制系统中。
而且CAN-bus总线在通信能力、可靠性、实时性、灵活性、易用性、传输距离等方面较RS-485总线有着明显的优势。
因而用CAN总线取代RS-485总线将是大势所趋。
1 CAN总线的主要特性CAN总线与其它通信网的不同之处有二:一是报文传送中不包含目标地址,它是以全网广播为基础,各接收站根据报文中反映数据性质的标识符来过滤报文,该收的收下,不该收的弃而不用。
其好处是可在线上网下网、即插即用和多站接收;二是特别强化数据安全,可满足控制系统及其它较高数据要求的系统需求。
CAN具有以下主要技术特性:(1)CAN遵从ISO模型,采用了其中的物理层、数据链路层与应用层。
采用双绞线,通信速率最高可达到1 Mbps/40 m,直接传输距离最远可达10 kin/5 kbps。
同一段总线内最多可挂接110个设备。
?(2)CAN的信号传输采用短帧结构,每一帧有效字节数为8个。
因而传输时间短,受干扰的概率低。
当节点发生严重错误时,CAN可自动关闭该节点,同时切断与总线的联系,以使总线上其它节点不受影响,因此CAN总线具有很强的抗干扰能力。
(3)CAN可支持多主工作方式,网络上任一节点在任何时候均可主动向其它节点发送信息,同时也支持点对点、一点对多点和全局广播方式来接收/发送数据。
处于优先级低的节点会主动停止发送,以此来避免总线冲突。
第3章 CAN 控制器驱动1.1 SJA1000编程基础1.1.1 MCU 访问SJA1000SJA1000使用并行总线接口与MCU 连接,对MCU 来说,SJA1000可以认为是1个外扩的RAM 芯片,51系列MCU 通过地址线、数据线和控制线与SJA1000连接,如图3.1所示。
AD[0:7]是低8位地址与数据总线复用的,MCU 在操作总线时,在该接口上先输出低8位地址线,然后再进行数据操作(读或写)。
SJA1000内部带有地址锁存器,由ALE 信号实现数据与地址的分离。
因为SJA1000的地址宽度为8位,所以寻址空间范围是0x00~0xFF 。
假如每个地址都对应一个寄存器,那么SJA1000最多支持256个寄存器。
而实际上SJA1000在BasicCAN (CAN2.0A )模式下只有32个寄存器,在FullCAN (CAN2.0B )模式下则有128个寄存器。
虽然SJA1000寄存器的访问地址会因为硬件设计不同而不同,但SJA1000内部寄存器的位置关系是固定的。
如果我们给SJA1000每个内部寄存器的地址都定义绝对地址(如程序清单3.1所示),那么在硬件设计发生变化时,特别是器件编址变化时,要修改的寄存器地址定义将会非常多。
为了提高驱动的可移植性,在实际访问SJA1000内部寄存器时,常采用基地址加偏移量的方式进行寄存器访问(如程序清单3.2所示)。
如果把SJA1000内部寄存器看做数组的话,那基地址就是这个数组的首地址,偏移量就是数组的下标,即成员在数组中的位置。
程序清单3.1 采用绝对编址的寄存器定义1 #define REG_CAN_MOD 0xA000 // 内部控制寄存器2 #define REG_CAN_CMR 0xA001 // 命令寄存器3 #define REG_CAN_SR 0xA002 // 状态寄存器4 #define REG_CAN_IR 0xA003 // 中断寄存器5 #define REG_CAN_IER0xA004// 中断使能寄存器6......程序清单3.2 采用基地址加偏移量方式的寄存器定义7 #define REG_BASE_ADD0xA000// SJA1000寄存器基地址 8 #defineREG_CAN_MOD 0x00 // 内部控制寄存器 9 #define REG_CAN_CMR 0x01 // 命令寄存器 10 #define REG_CAN_SR 0x02 // 状态寄存器 11 #define REG_CAN_IR 0x03 // 中断寄存器 12 #define REG_CAN_IER0x04// 中断使能寄存器13......通常MCU 的总线上会挂载很多器件,除了SJA1000外,可能还有RAM 和ROM 等器件。
SJA1000 CAN驱动程序演示实验一.实验目的本驱动程序展示了如何在Small RTOS中编写SJA1000 的驱动程序。
通过调用CAN 程序库SJA1000_PEI.LIB 的基本函数,实现实验板上CAN 节点的初始化以及CAN 节点数据收发测试。
二.实验设备及器件PC 机一台DP-51PROC 单片机综合仿真实验仪一台CAN PARK 模块一台CAN 连接线一根三.实验步骤1、将CAN-bus PARK 插入到A6 区中,用导线连接A6 区的P1_IO2 到A2 区的P1 0,连接A6 区的P1_CS1 到A2 区的A15。
2、使用导线把A2 区的P16 和P17 分别于D5 区的SCL 和SDA 相连。
使用导线把D 5区的/RST 与VCC 相连。
3、由于本程序使用中断方式响应SJA1000 中断,故将A5 区的P1_INT 接到A2 区的INT0。
4、利用CAN 连接线将两台已经安装了CAN-Bus 模块的DP-51PROC 连接起来,以组成简单的CAN 网络实现CAN 的接收和发送。
5、本驱动程序已经将输出文件路径设置为“E:\Temp”,用户可自行更改输出文件路径。
将路径“E:\Temp”中的CAN. hex 文件下载到两台DP-51PROC 中运行。
四.实验参考程序主要部分/*******************************************************描述:独立的CAN 控制器SJA1000PeliCAN 在small rtos 中的应用示例*文件名: PELIRTOS.c*应用语言: KEIL C51*应用系统: small rtos*版本: V1.0*广州周立功单片机发展有限公司保留所有的版权****************************************************/#define _TIME_MODULE_H#define _SERIAL_H/********************************************************** 导入头文件******************************************************/#include "INCLUDES.h"#include "Sja1000_peli.h"sfr IPH=0xb7;sbit RESET_PIN=P1^0;// 验收代码/屏蔽寄存器的内容(4+4)uint8 xdata Send_CAN_Filter[8]={0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0xff};// 帧信息和标示码(1+4)分别对应TX,TX1,TX2,TX3,TX4uint8 xdata Send_CAN_Info_ID[3]={0xc7,0x0A,0x0B};uint8 xdata Recv_CAN_Info_ID[3];// 待发送数据(8)uint8 xdataSend_CAN_Data[13]={0xc7,0x0A,0x0B,0x04,0x05,0x06,0x07,0x08,0x07,0x0 8,0x07,0x08,0x08};uint8 xdata Recv_CAN_Data[14];uint8 xdata time_Counter=0;uint8 xdata BTR0,BTR1;uint16 xdata *p;uint8 xdata disp_buf[8];void CAN_Send(void);void display(void);void CAN_Rcv(void);void TimeSum(void);void Delay_ms(uint8 j);void SJA1000_Config_Normal(void);void Init(void){CKCON=1; //应用6clockTMOD = (TMOD & 0XF0) | 0X01;TCON=TCON|0x04; //MCU 的INT1 下降沿触发,INT0 电平触发TH0 = (65536 - (11059200 / 12) / 100) / 256;TL0 = (65536 - (11059200 / 12) / 100) % 256;TR0 = 1;ET0 = 1;TF0 = 0;}/************************************************************** ****函数名称:void CAN_Init(void)**功能描述:复位SJA1000,并设置其工作在正常模式************************************************************** ***/void CAN_Init(void){RESET_PIN=0; //将SJA1000 的复位线与P1.0 相连接Delay_ms(1);RESET_PIN=1; //控制P1.0 来实现SJA1000 的复位SJA_CS_Point=&CAN_SJA_BaseAdr;SJA1000_Config_Normal();WriteSJAReg(REG_CAN_IER,RIE_BIT); //使能SJA1000 接收中断EX0=1;}/************************************************************** ** 函数原型: void Delay_ms(uchar j)** 功能描述: 该函数用于不精确的延时。
在12M,6CLK 下,大约延时j*1ms************************************************************** */void Delay_ms(uint8 j){uint8 k,l;for(l=0;l<=j;l++){for(k=0;k<=250;k++){;}}}/************************************************************ ** 函数原型: void SJA1000_Config_Normal(void)** 功能描述: 对SJA1000 的正常模式的初始化配置************************************************************** */void SJA1000_Config_Normal(void){BTR0=0x00;BTR1=0x14; //设置为80k 波特率通信SJAEntryResetMode(); //进入复位模式WriteSJAReg(REG_CAN_CDR,0xc8); //配置时钟分频寄存器,选择PeliCAN 模式WriteSJAReg(REG_CAN_MOD,0x01); //配置模式寄存器,选择双滤波、正常模式WriteSJARegBlock(16,Send_CAN_Filter,8); //配置验收代码/屏蔽寄存器WriteSJAReg(REG_CAN_BTR0,BTR0); //配置总线定时器0WriteSJAReg(REG_CAN_BTR1,BTR1); //配置总线定时器1WriteSJAReg(REG_CAN_OCR,0x1a); //配置输出管脚SJAQuitResetMode(); //退出复位模式,进入工作模式}/*********************************************************** 函数原型: void CAN_Data_Send(void)** 功能描述: SJA1000 的单次发送子函数(注意在这个函数的末尾要置位接收中断)*************************************************************/ void CAN_Data_Send(void){// 发送数据WriteSJAReg(REG_CAN_IER,0x02); //使能SJA1000 发送中断位WriteSJARegBlock(16,Send_CAN_Data,13);WriteSJAReg(REG_CAN_CMR,1); //使能发送请求Delay_ms(10);WriteSJAReg(REG_CAN_IER,RIE_BIT); //使能SJA1000 接收中断}/************************************************************** ** 函数原型: void SJA1000_INT0 (void) interrupt 0** 功能描述: SJA1000 中断响应函数************************************************************** */void SJA1000_INT0(void) interrupt 0{OS_INT_ENTER();EX0 = 0;OSIntSendSignal(0); //无条件的令CAN 接收中断处理任务(CAN_Rcv ())处于就绪状态//由于CAN_Rcv ()的优先级最高,故中断退出后立刻执行CAN_Rcv ().OSIntExit();}void main(void){uint8 i ;OSInit();Init();CAN_Init();//初始化显示缓存for(i=0;i<8;i++){disp_buf[i]=31;}//创建任务OSTaskCreate(CAN_Rcv, NULL, 0);OSTaskCreate(display, NULL, 1);OSTaskCreate(CAN_Send, NULL, 2);OSTaskCreate(TimeSum, NULL, 3);while(1){PCON = PCON | 0x01; //令CPU 进入睡眠状态}}/************************************************************** *****键值发送任务************************************************************** ***/void CAN_Send(void){uint8 key_data;while(1){key_data = ZLG7290_GetKey();if(key_data){Send_CAN_Data[3] = key_data;CAN_Data_Send();disp_buf[4] = key_data % 10;disp_buf[5] = (key_data / 10) % 10;}OSWait(K_TMO,5);}}/************************************************************** ****显示任务************************************************************** ***/void display(void){while(1){OSWait(K_TMO,5);OS_ENTER_CRITICAL();ZLG7290_SendBuf(&disp_buf[0], 8);OS_EXIT_CRITICAL();}}/************************************************************** ***CAN 接收中断处理任务*********************************************************** ****/void CAN_Rcv(void){while(1){OSWait(K_SIG, 0); //挂起当前任务,等待唤醒信号if(ReadSJAReg(REG_CAN_IR)&0x01){//数据接收一定在释放缓冲区之前,释放后数据不确定ReadSJARegBlock(16,Recv_CAN_Data,13);WriteSJAReg(REG_CAN_CMR,4); //释放SJA1000 接收缓冲区disp_buf[0] = Recv_CAN_Data[3] % 10;disp_buf[1] = (Recv_CAN_Data[3] / 10) % 10;}EX0 = 1;}}/****************************************************** *计数任务************************************************************** */void TimeSum(void){while(1){OSWait(K_TMO, 5);disp_buf[7]++;if(disp_buf[7] > 9){disp_buf[7] = 0;}}}五.实验例程简析本驱动程序采用中断方式接收CAN 总线数据。