CAN-bus现场总线基础教程【第3章】CAN控制器驱动-SJA1000编程基础(9)
- 格式:pdf
- 大小:470.54 KB
- 文档页数:7
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 独立的CAN控制器应用指南1 介绍SJA1000是一个独立的CAN控制器,它在汽车和普通的工业应用上有先进的特征。
由于它和PCA82C200 在硬件和软件都兼容,因此它将会替代PCA82C200。
SJA1000有一系列先进的功能适合于多种应用,特别在系统优化、诊断和维护方面非常重要。
本文是要指导用户设计基于SJA1000 的完整的CAN节点。
同时本文还提供典型的应用电路图和编程的流程图。
2 概述SJA1000 独立的CAN控制器有2个不同的操作模式:BasicCAN模式(和PCA82C200)兼容PeliCAN模式BasicCAN模式是上电后默认的操作模式。
因此,用PCA82C200开发的已有硬件和软件可以直接在SJA1000上使用,而不用作任何修改。
PeliCAN模式是新的操作模式,它能够处理所有CAN2.0B 规范的帧类型。
而且它还提供一些增强功能使SJA1000能应用于更宽的领域。
2.1 CAN 节点结构通常,每个CAN 模块能够被分成不同的功能块。
SJA1000使用[3] [4] [5]最优化的CAN收发器连接到CAN 。
收发器控制从CAN控制器到总线物理层或相反的逻辑电平信号。
上面一层是一个CAN 控制器,它执行在CAN规范[8]里规定的完整的CAN协议。
它通常用于报文缓冲和验收滤波,而所有这些CAN功能,都由一个模块控制器控制它负责执行应用的功能。
例如,控制执行器、读传感器和处理人机接口(MMI)。
如图1所示,SJA1000独立的CAN控制器通常位于微型控制器和收发器之间,大多数情况下这个控制器是一个集成电路。
图1 CAN模块装置2.2 结构图下图是SJA1000 的结构图图2 SJA1000的结构图根据CAN规范,CAN核心模块控制CAN帧的发送和接收。
接口管理逻辑负责连接外部主控制器,该控制器可以是微型控制器或任何其他器件。
经过SJA1000复用的地址/数据总线访问寄存器和控制读/写选通信号都在这里处理。
SJA1000程序给你提供一些思路1、sja1000初始化2、发送子程序3、中断方式接收下面是一些程序段你参考下(已用于产品)/**********SJA1000初始化***********//void Init_SJA1000(void){uchar state;uchar ACRR[4]={0XAA,0XFF,0X22,0X11};// 接收代码寄存器uchar AMRR[4]={0xff,0xff,0xff,0xff};// 接收屏蔽寄存器//uchar AMRR[4]={0x00,0x00,0xff,0xff};// 接收屏蔽寄存器do// 使用do--while语句确保进入复位模式{MODR = 0x09; // 设置MOD.0=1--进入复位模式,以便设置相应的寄存器state = MODR;}while( !(state & 0x01) );// 对SJA1000部分寄存器进行初始化设置CDR = 0x88; // CDR为时钟分频器,CDR.3=1--时钟关闭, CDR.7=0---basic CAN, CDR.7=1---Peli CANBTR0 = 0x04;//0x31; // 总线定时寄存器0 ;总线波特率设定BTR1 = 0x1c;//0x1c; // 总线定时寄存器1 ;总线波特率设定IER = 0x01; // IER.0=1--接收中断使能;IER.1=0--关闭发送中断使能OCR = 0xaa; // 配置输出控制寄存器CMR = 0x04; // 释放接收缓冲器ACR0 = ACRR[0];// 初始化接收代码寄存器ACR1 = ACRR[1];ACR2 = ACRR[2];ACR3 = ACRR[3];AMR0 = AMRR[0];// 初始化接收屏蔽寄存器AMR1 = AMRR[1];AMR2 = AMRR[2];AMR3 = AMRR[3];do// 使用do--while语句确保退出复位模式{MODR = 0x08; //MOD.3=0--双滤波器模式state = MODR;}while( state & 0x01 );}////////////////////////////////////////**********CAN发送数据到CAN-Bus***********//void CAN_TXD(void){uchar state;//初始化标示码头信息TX_buffer[0] = 0x88; //.7=0--扩展帧;.6=0--数据帧; .0-.3=100--数据长度为8字节// TX_buffer[1] = 0xFF; //本帧信息的ID//TX_buffer[2] = 0xFF;TX_buffer[3] = 0xFF;TX_buffer[4] = 0xFF;do //查询SJA1000是否处于接收状态,当SJA1000不处于接收状态时才可继续执行{state = SR; //SR为SJA1000的状态寄存器}while( state & 0x10 ); //SR.4=1 正在接收,等待do //查询SJA1000是否处于发送完毕状态{state = SR;}while(!(state & 0x08)); //SR.3=0,发送请求未处理完,等待直到SR.3=1do //查询发送缓冲器状态{state = SR;}while(!(state & 0x04)); //SR.2=0,发送缓冲器被锁。
文库资料 ©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.第3章 CAN 控制器驱动1.1 SJA1000初始化1.1.1 初始化流程SJA10000在上电复位后处于复位模式,要使SJA1000能正常收发CAN 帧数据,必须对SJA1000进行初始化,SJA1000初始化流程详见图3.1。
1. 进入复位模式SJA1000的配置寄存器只有在复位模式下才能访问,所以必须首先置位模式寄存器的0位,以进入复位模式。
2. 设置模式寄存器模式寄存器用于设置SJA1000工作模式,定义详见表3.1。
表3.1 SJA1000模式寄存器定义RM :复位模式位,置位该位将使SJA1000进入复位模式,清零该位则退出复位模式返回工作模式。
LOM :只听模式位,设置该位后,SJA1000处于只听模式。
只听模式只从CAN 总线接收数据,不能向总线上发送数据也不会产生错误帧。
只听模式常用于自动波特率检测功能,例如在软件里预先定义一个包含所有可能的位频率以及它们的位时序参数的表格,使能SJA1000接收和错误中断,依次尝试表格中的位时序参数,如果在CAN 总线上产生了错误,软件转向下一个位时序参数,在一条信息的成功地接收后,表明软件已经检测到正确的位时序参数。
STM :只检测模式位,设置该位后,SJA1000在发送CAN 帧时不检查应答位,可以实现单个CAN 节点的发送功能。
AFM :验收滤波器模式,设置该位时使用单滤波功能;清零该位时使用双滤波功能。
SM :睡眠模式位,设置该位时,SJA1000进入睡眠模式,降低功耗。
3. 设置时钟分频寄存器时钟分频寄存器用于选择BasicCAN 模式还是PeliCAN 模式、CLKOUT 管脚控制、CAN 输入比较器控制,寄存器的位定义详见表3.2。
表3.2 SJA1000时钟分频寄存器定义4. 设置CAN 波特率波特率是异步串行通信中的重要参数,指每秒钟能发送的数据位元数量,只有相同波特率图3.1 SJA1000初始化流程图文库资料 ©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.的设备才能互相通信,CAN-bus 使用异步串行通信技术,同样需要遵守该规则。
canbus现场总线第三章 CANbus现场总线现场总线是安装在生产过程区域的现场设备仪表与控制室内的自动控制装置系统之间的一种串行、数字式、多点通信的数据总线。
现场总线(Fieldbus)技术是实现现场级控制设备数字化通信的一种工业现场层网络通信技术,可使用一条通信电缆将现场设备(智能化、带有通信接口)连接,用数字化通信代替4-20mA/24VDC信号,完成现场设备控制、监测、远程参数化等功能。
CAN,全称为“Controller Area Network”,即控制器局域网,由德国Bosch 公司最先提出,已成为国际标准ISO11898(高速应用)和ISO11519(低速应用)。
CAN是一种多主方式的串行通讯总线,CAN的规范定义了OSI模型的最下面两层:数据链路层和物理层。
CAN 协议有2.0A和2.0B两个版本,CAN协议的2.0A版本规定CAN 控制器必须有一个11位的标志符,在2.0B版本中规定CAN控制器的标志符长度可以是11位或29位。
第一节 CAN通信协议3.1.0协议特点CAN总线是一种串行数据通信协议。
它有如下特点:1、CAN协议分层分为目标层、传输层、物理层。
目标层的功能:确定要发送的报文、确认传输层接收到的报文、为应用层提供接口。
传输层的功能:帧组织、总线仲裁、检错、错误报告、错误处理。
物理层的范围包括实际位传送过程中的电气特性。
2、CAN协议逻辑位使用2种逻辑位表达方式。
当总线上的CAN控制器发送的都是弱位时,此时总线状态是弱位(逻辑1);如果总线上有强位出现,弱位总是让位于强位,即总线状态是强位(逻辑0)。
上有强位出现,弱位总是让位于强位,即总线状态是强位(逻辑0)。
3、CAN协议校验.采用CRC校验并可提供相应的错误处理功能,保证了数据通信的可靠性。
4、CAN协议编码方式.使用了数据块编码方式,使得网络内的节点个数在理论上不受限制。
5、CAN协议数据块的长度.规定了数据块的长度最多为8个字节,传输时不会过长占用总线,保证了通信的实时性。
第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的。
因此当MCU 在访问SJA1000图3.1 SJA1000与MCU 扩展总线连接时,为了明确的表明下面的操作对象是SJA1000,MCU 会把SJA1000的片选(CS )信号拉低。
SJA1000的片选信号由MCU 未使用的高位地址线经过译码电路产生,译码电路的设计决定了MCU 访问SJA1000的基地址。
MCU 产生片选信号有以下三种方法。
1. 线选法所谓线选法,就是直接利用MCU 的空闲高位地址线作为扩展芯片的片选信号。
优点是线路连接简单明了,无需另外增加译码电路,缺点是寻址范围不唯一(可通过多个地址访问扩展芯片),地址空间没有被充分利用,使用单个扩展芯片时可使用该方法。
2. 全地址译码法全地址译码法利用译码器对未使用的高位地址线进行译码,使用译码器的输出作为扩展芯片的片选信号,常用的译码芯片有74HC138、74HC139、74HC154等。
优点是扩展器件的每个存储单元具有唯一的访问地址,不存在地址重叠现象,对地址的空间的使用是连续的,能有效地利用地址空间,缺点是所需译码电路较多,外扩芯片较多时使用该方法。
3. 部分地址译码法部分地址译码法对未使用的部分高位地址线进行译码。
优点是使用译码电路较少,缺点是外扩器件地址范围有重叠。
在本设计中,通过并行总线扩展的器件只有SJA1000,可以采用线选法产生SJA1000的片选信号,但考虑到系统的扩展性,我们使用部分地址译码法来产生SJA1000的片选信号。
如图3.2所示,SJA1000的片选信号通过对地址线A15~A12译码来得到。
74HC139内部包含了两个“2线—4线”译码器,其真值表如表3.1所示。
根据图3.2中74HC139的电路连接关系,对比74HC139的真值表,我们可以发现,当A14为低电平、A15为高电平时,1Y2输出为低电平;当A12为低电平、A13为高电平并且1Y2为低电平时,2Y2输出为低电平,即SJA1000片选信号有效,所以只要MCU 在访问SJA1000时16位地址线上输出地址为0b1010 xxxxxxxx xxxx ,SJA1000的片选信号就会有效。
因此SJA1000的访问基址为0xA000~0xAF00,为了编写程序方便,在以后的例程中,MCU 访问SJA1000的基地址统一使用0xA000。
1.1.2 读写寄存器在C 语言中,一般使用指针来访问存储空间,SJA1000按照存储器的方式与MCU 连接,所以我们可以通过指针的方式来访问SJA1000的寄存器,实现对SJA1000的操作控制。
使用C 语言读写SJA1000寄存器的代码如程序清单3.3所示。
图3.2 SJA1000片选译码电路程序清单3.3 读写SJA1000寄存器14#define SJA_BASE_ADDR 0xA000 // 定义SJA1000访问基址15xdata unsigned char *SJA_CS_Point = ( xdata unsigned char *) SJA_BASE_ADDR;16// 写SJA1000寄存器17void WriteSJAReg (unsigned char RegAdr,unsigned char Value)18{19*(SJA_CS_Point + RegAdr) = Value;20return ;21}22// 读SJA1000寄存器23unsigned char ReadSJAReg (unsigned char RegAdr)24{25return (*(SJA_CS_Point + RegAdr));26}程序清单3.3第1行定义了访问SJA1000的基地址,按照电路的连接关系,该值为0xA0000。
第2行定义了一个指向外部存储空间的指针变量,并将其指向SJA1000访问的基地址,对SJA1000寄存器的读写通过操作该指针来完成。
xdata是C51编译器用于指定存储类型的扩展关键字,表示用MOVX@DPTR指令访问的外部存储器空间。
( xdata unsigned char *)完成强制类型转换功能,将SJA_BASE_ADDR强制转换为1个xdata unsigned char类型的指针。
程序清单3.3第3~13行定义了对SJA1000寄存器的读写函数,在下文中对SJA1000的所有操作都以这2个函数为基础实现的。
1.1.3 寄存器位操作在控制SJA1000时,有时我们需要对某些寄存器进行位操作(只改写指定位,其它位保持不变),如进入复位模式(模式寄存器的第0位置1)、退出复位模式(模式寄存器的第0位清0)。
对寄存器的位操作一般是通过“读、改、写”的方式实现,基本步骤如下:●读寄存器的当前值;●根据需要修改读到的值的指定位;●将修改后的值写回寄存器。
基于以上原理,我们实现“设置寄存器位”和“清零寄存器位”函数,以方便对SJA1000的操作。
1.设置寄存器位设置寄存器位函数用于将指定寄存器的指定位置1,具体实现见程序清单3.4。
程序清单3.4 设置寄存器位函数27/****************************************************************************************** ** 函数名称:SetBitMask28** 函数功能:设置指定寄存器的指定位为129** 输入参数:RegAdr->寄存器地址30** BitValue ->设置的位值31** 输出参数:无32** 返回值:1=操作成功,0=操作失败33******************************************************************************************/ 34char SetBitMask(unsigned char RegAdr,unsigned char BitValue)35{36char status=0;37unsigned char temp;38temp = ReadSJAReg(RegAdr); // 读取寄存器的当前值39t emp = temp | BitValue; // 将寄存器值的BitValue指定的位置140WriteSJAReg(RegAdr,temp); // 重写寄存器41if(ReadSJAReg(RegAdr) == temp){ // 判断寄存器是否写成功42status = 1; // 设置状态值为143} else {44status = 0 ; // 设置状态值为045}46return (status); // 返回状态值47}2.清零寄存器位清零寄存器位函数用于将指定寄存器的指定位置0,具体实现见程序清单3.5。
程序清单3.5 清零寄存器位函数48/****************************************************************************************** ** 函数名称:ClearBitMask49** 函数功能:将指定寄存器的指定位清050** 输入参数:RegAdr -> 寄存器地址51** BitValue -> 设置的位值52** 输出参数:无53** 返回值:1=操作成功,0=操作失败54******************************************************************************************/ 55char ClearBitMask(unsigned char RegAdr,unsigned char BitValue)56{57char status=0;58unsigned char temp;59temp = ReadSJAReg(RegAdr); // 读取寄存器的当前值60temp = temp&(~BitValue); // 将寄存器值的BitValue指定的位清零61WriteSJAReg(RegAdr,temp); // 重写寄存器62if(ReadSJAReg(RegAdr) == temp){ // 判断寄存器是否写成功63status = 1; // 设置状态参数为164} else {65status = 0 ; // 设置状态参数为066}67return (status); // 返回操作标志68}1.1.4 连续读写寄存器在访问SJA1000时,我们需要连续读写多个寄存器,如设置验收滤波器、收发CAN报文等,为方便这类程序的编写,我们可以先实现连续读写寄存器函数。