实例1
总线的楼宇温度检测系统
前言
基于单片机实现传统温度检测技术的特点,提出了基于CAN总线的楼宇温度检测系统方案。该系统方案的硬件平台主要包括温度检测模块和主控平台,并详细介绍了其硬件实现、软件设计思想及流程。实验表明:该系统可实现对楼宇温度的实时检测,并由数码管显示检测结果,对异常情况进行处理,从而实现对楼宇房间温度的有效检测。
在传统的检测技术中,温度检测基本采用单片机系统为主,且大多数都针对工业需要,日常生活中的应用并不多;而通信多基于落后的485总线,不能进行远距离的实时数据传输,更不能与因特网相连,可靠性也不高。因此,本文提出一种基于CAN总线的温度测控技术,该技术适合远距离控制与传输,具有非常高的可靠性。
控制器局域网(Controller Area Network,CAN)是国际上应用最广泛的现场总线之一。CAN总线最早出现在20世纪80年代末的汽车工业中,由德国BOSCH公司最先提出,其主要特性为低成本,且总线利用率高。CAN采用串行通信方式工作,所提供的最高数据传输速率为1Mbit/s,最大通信距离为
正是基于CAN总线的上述优点,目前CAN总线在众多领域被广泛应用,其应用范围不再局限于原先的汽车行业,而向过程工业、机械工业、纺织工业、数控机床、医疗器械及传感器等领域发展,CAN总线已经形成国际标准,并已被公认为是几种最有前途的现场总线之一。
考虑到CAN总线的高可靠性和远距离传输优点,结合目前温度检测技术的技术瓶颈,即距离短和实时性差的特点,本系统CAN总线应用于传统的温度检测中,也是一种新的尝试。
1 基于CAN总线楼宇温度检测系统的实现
1.1 温度检测节点的硬件设计
图3 中DS18B20为数字温度传感器,主要用于组网温度测量,它是I-Wire总线通信协议数字式温度传感器,测温范围为-55~+
2 软件设计
2.1 主控台软件设计
主控台软件分为初始化和主调度。初始化部分仅在上电启动或复位时运行;主调度主要包括CAN信息帧处理、键盘按键处理、显示处理和警报、数据和时间处理、中断控制等部分。软件框图如图5所示。
主调度始终不停地在多个子任务之间巡查和调用。主调度负责管理多个子任务的运行,巡查各个子任务,当外部事件触发主调度的相关子任务时,则此子任务被激活,进行子任务处理,否则主调度跳过这一子任务。
任何系统在使用之前都要对系统进行初始化,此系统的初始化包括CAN总线接口的初始化、时钟芯片的初始化等。键盘扫描电路及按键处理程序则用来实现键盘的输入按键的识别及相关处理。CAN信息帧处理模块主要实现基于CAN总线的控制台和个控制节点间的通讯协议。显示处理和报警模块则实现将数据和时间处理模块的结果进行数码管显示,并控制报警系统。
3 设计原理
本系统主要由三部分组成,分布在现场的节点,即温度检测模块;主控台,是所有节点的控制核心;还有就是连接主控台和各个节点通讯的CAN总线。温度检测模块是系统构成的基础与关键,它直接与温度采集机构相连接,实现对温度的检测与控制,如温度超限报警等。虽然该模块是系统的一个组成部分,但它也可以独立工作,即在系统其它部分停止工作的情况下,自动温度测控模块仍可以独立控制执行机构来实现基本的温度测控功能,提高了系统工作的可靠性。同时由于系统对主控台的依赖并不是绝对的,因此就降低了各个节点独立工作的风险。这样就算是由于年久失修使总线失去通讯功能时,温度检测模块仍可根据以前的设定对相应事件做出反应。
系统工作时,首先主控台将各个温度检测点的温度设定值及极限温度设定值通过CAN总线发送给相应的温度检测模块,各个节点的温度检测模块将接收到的各个设定值保存,这样在不更新设置的情况下,温度检测模块可以脱离主控台而独立工作。
各个节点的温度测控模块与主控台之间通过CAN现场总线通讯。与其它网络不同,在CAN总线的通信协议中,没有节点地址的概念,也没有任何与节点地址相关的信息存在,它支持的是基于数据的工作方式。即,CAN总线面向的是数据而不是节点;因此加入或撤销节点设备都不会影响网络的工作,这样的结构十分适用于控制系统要求快速、可靠、简明的特点。同时,CAN总线的直接通讯距离最远可以达到
本系统使用的温度采集模块是数字温度传感器DS18B20,它的温度测量范围为-55~+
本系统在设计时主要考虑的是使用CAN总线进行主控制台和各个节点之间通讯控制。因此在设计时使用的报警器只是用简单的蜂鸣器替代,而在现实应用中则应选择合适的报警器。不同的报警器有不同的报警方式,因人使用的区别而异。如果要将此系统应用到实际之中,只需用合适的报警器替代本系统中的蜂鸣器。实现原理相同,只需稍加改变。
显示部分使用的则是人们日常使用的数码管,它的功耗极低,抗干扰能力强,因而在低功耗的单片机系统中能够得到广泛的应用。数码管的显示方法是动态扫描方式,通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O端口。
4 结束语
楼宇温度检测系统不仅具有基本的温度测控功能,而且通过CAN总线将分布在各处的节点连接起来,可以在主控台上进行集中监控以及查询和统计等数据的管理,具有结构灵活、集中控制和管理于一体等优点,克服了人工方式控制精度差,劳动强度大,且集中综合管理更加困难等缺点,降低了各种损耗,管理手段实现了现代化。
在本设计方案中硬件电路主要由微处理器、CAN控制器、温度芯片DS18B20、显示数码管、按键键盘、复位电路、蜂鸣器等几部分组成。单片机AT89S51是硬件电路的核心,承担CAN控制器的初始化、数据收发控制等任务;CAN总线控制器用于同主控台进行远程通讯,能够独立完成CAN总线上数据的接收和发送工作;DS18B20芯片用于检测和发送温度数据。温度测控模块是系统构成的基础与关键,它直接与温度采集机构相连,实现对温度的检测与控制,如温度超限报警等。
基于CAN总线的智能测温系统具有测量范围广、精度高、环境适应能力强等特点。该系统通过CAN总线控制器和主控台连接,可以方便地构成分布式测控系统。此外,该智能测温系统可以应用于其它远距离分布式控制场合,而且该智能测温系统在电力、油田、楼宇、冶金等工业自动化领域也具有广泛的应用前景。
在此,需要说明的是本系统测得的温度误差是DS18B20芯片的测量误差及单片机的处理误差,而系统传输过程中不会增加新的误差,但有时也有可能由于CAN总线协议编写不对,会引起丢失数据现象的情况存在。本系统基本可以实现对楼宇房间温度的有效检测,达到城市用电高峰时的电能耗主动控制检测。
主控台程序
#include <reg52.h>
#include <intrins.h>
#include <can_showdef.h>
void CAN_init( void ); // 初始化CAN总线芯片
void CAN_TXD( void );//CAN发送子函数
void Rxd_deal(void);//接收处理函数
void Txd_deal(void);//发送处理函数
void Delay(uchar delay_time);//延时子函数
void fasong();//显示子函数
void jieshou();//接收显示子函数
void shezhi();//设置子函数
void bojing();
sbit key1 = P3^0;
sbit key2 = P3^1;
sbit key3 = P3^3;
sbit bao = P3^4;
sbit key4 = P3^5;
sbit p2 = P2;
sbit p22 = P2^2;
sbit p24 = P2^4;
sbit key5 = P2^6;
sbit key6 = P2^7;
uchar shi=3,ge=0,shezhishi;
//CAN_init();
/********延时1MS函数***/
void delay(uchar x)
{ uchar i,j;
for(i=0;i<x;i++)
for(j=0;j<120;j++);
}
void main(void)
{
//CPU初始化
SJA_RST = 0;
delay(10);
SJA_RST = 1;//CAN总线复位管脚
SJA_CS = 0;//CAN总线片选有效
EX1 = 1;//外部中断1使能;CAN总线接收中断
IT1 = 0;//低电平触发
IT0 = 1;//脉冲方式触发,外部中断0负边沿触发
EX0 = 1;//打开外部中断0
EA = 1; //打开总中断
SJA_CS = 1;//CAN总线片选无效,保证数据线上的变化不会影响SJA1000
//CPU初始化
CAN_init( ); //SJA1000初始化,对 SJA1000寄存器的读写是采用外部寄存器寻址方式,所以不需
要程序单独控制片选有效无效
_nop_();
_nop_();
while(1)
{
_nop_();
_nop_();
////////显示///////////////
if(key5==0)
{
if( TXD_flag == 1 )
Txd_deal();//发送处理程序
while(!key5);//按下5键,将设置好的数据发送
fasong();
}
if(key6==0)
{
if( RXD_flag )
Rxd_deal();//接收处理程序
while(!key6);//按下6键,接收到来的数据
jieshou();
}
bojing();
}
}
//***********接收处理函数************
void Rxd_deal(void)
{
EA = 0;//关闭CPU中断
RXD_flag = 0;
Rxd_data = RX_buffer【5】;
EA = 1;
}
//*************发送处理函数*********
void Txd_deal(void)
{
_nop_();
TXD_flag = 0;
TX_buffer【5】 = Txd_data;//
CAN_TXD();
_nop_();
_nop_();
}
///中断处理程序//////////////
void CAN_RXD( void ) interrupt 2
{//接收数据函数,在中断服务程序中调用
uchar data Judge;
EA = 0;//关CPU中断
IE0 = 0;
Judge = IR;
if( Judge & 0x01)
{//IR.0 = 1 接收中断
RX_buffer【0】 = RBSR;
RX_buffer【1】 = RBSR1;
RX_buffer【2】 = RBSR2;
RX_buffer【3】 = RBSR3;
RX_buffer【4】 = RBSR4;
RX_buffer【5】 = RBSR5;
RX_buffer【6】 = RBSR6;
RX_buffer【7】 = RBSR7;
RX_buffer【8】 = RBSR8;
RX_buffer【9】 = RBSR9;
RX_buffer【10】 = RBSR10;
RX_buffer【11】 = RBSR11;
RX_buffer【12】 = RBSR12;
RXD_flag = 1;//置有接收标志
CMR = 0X04;
Judge = ALC;//释放仲裁随时捕捉寄存器
Judge = ECC;//释放错误代码捕捉寄存器
}
IER = 0x01;// .0=1--接收中断使能;
EA = 1;//打开CPU中断
}
//--------按键中断发送处理---
/////////////////////SJA1000 的初始化///////
void CAN_init( void )
{
uchar bdata Judge;
uchar ACRR【4】;
uchar AMRR【4】;
ACRR【0】 = 0x11;
ACRR【1】 = 0x22;
ACRR【2】 = 0x33;
ACRR【3】 = 0x44;//接收代码寄存器,节点1
AMRR【0】 = 0xff;
AMRR【1】 = 0Xff;
AMRR【2】 = 0xff;
AMRR【3】 = 0xff;//接收屏蔽寄存器。 只接收主机发送的信息
do
{// .0=1---reset MODRe,进入复位模式,以便设置相应的寄存器
//防止未进入复位模式,重复写入;
MODR = 0x09;
Judge = MODR ;
}//保证在复位模式下操作
while( !(Judge & 0x01) );
CDR = 0x88;//时钟分频; CDR.3=1--时钟关闭, CDR.7=0---basic CAN, CDR.7=1---Peli CAN
BTR0 = 0x03;
BTR1 = 0x
IER = 0x01;// .0=1--接收中断使能; .1=0--关闭发送中断使能
OCR = 0xaa;// 配置输出控制寄存器
CMR = 0x04;//命令寄存器;释放接收缓冲器
ACR = ACRR【0】;
ACR1 = ACRR【1】;
ACR2 = ACRR【2】;
ACR3 = ACRR【3】;//初始化标示码
AMR = AMRR【0】;
AMR1 = AMRR【1】;
AMR2 = AMRR【2】;
AMR3 = AMRR【3】;//初始化掩码
do//回到工作模式
{
MODR = 0x08;
Judge = MODR;
}
while( Judge & 0x01 );
}
/////////CAN初始化结束/////////////////////////////
///////////发送初始化//////////////
void CAN_TXD( void )
{
uchar data Judge;
uchar data TX_buffer【 N_can 】 ;//初始化标示码头信息
TX_buffer【0】 = 0x88;//TX.7=1扩展帧;TX.6=0数据帧; .3=1数据长度
TX_buffer【1】 = 0x00;//本节点地址
TX_buffer【2】 = 0x02;
TX_buffer【3】 = 0x03;
TX_buffer【4】 = 0x00;
//初始化标示码头信息 //初始化发送数据单元
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;
//初始化数据信息
EA = 0; //关中断
//-----接收状态??---------------------------------
do
{
Judge = SR;//状态寄存器
LED_RED = 0;//红灯亮
}
while( Judge & 0x10 ); //SR.4=1 正在接收,等待
//-----发送状态???----
do
{
Judge = SR;
}
while(!(Judge & 0x08)); //SR.3=0,发送请求未处理完,等待
//----发送缓冲器被锁???------
do
{
Judge = SR;
}
while(!(Judge & 0x04)); //SR.2=0,发送缓冲器被锁。等待
//----------------------------------
TBSR = TX_buffer【0】;
TBSR1 = TX_buffer【1】;
TBSR2 = TX_buffer【2】;
TBSR3 = TX_buffer【3】;
TBSR4 = TX_buffer【4】;
TBSR5 = TX_buffer【5】;
TBSR6 = TX_buffer【6】;
TBSR7 = TX_buffer【7】;
TBSR8 = TX_buffer【8】;
TBSR9 = TX_buffer【9】;
TBSR10 = TX_buffer【10】;
TBSR11 = TX_buffer【11】;
TBSR12 = TX_buffer【12】;
CMR = 0x01;//置位发送请求//P57
EA = 1;
}
/////////delay程序////////////////
void Delay(uchar delay_time)
{//延时程序
while(delay_time--)
{}
}
void bojing()
{
if(Rxd_data>shezhishi)
bao=1;
//主控台接收到的数据大于设定值,报警响起
else
bao=0;//否则,报警器不响
}
void fasong() //显示要发送的温度数值,用数码管动态扫描显示
{
uchar shezhizhi;
shezhizhi=shi*10+ge;
p2=led【shi】;
p22=0;
p24=1;
delay(1);
p2=led【ge】;
p22=1;
p24=0;
delay(1);
Txd_data=shezhizhi;
}
void jieshou() //显示接收到的温度数值,用数码管动态扫描显示
{
uchar shi1,ge1;
shi1=Rxd_data%10;
ge1 =Rxd_data/10;
p2=led【shi1】;
p22=0;
p24=1;
delay(1);
p2=led【ge1】;
p22=1;
p24=0;
delay(1);
}
void shezhi() //设置要发送给节点的门限值
{
uchar shi=3,ge=0;
if(key1==0)//对十位数字进行设置
{
if(key3==0)
{
while(!key3)
shi=shi+1;//十位数字累加
}
if(key4==0)
{
while(key4==0)
shi=shi-1;//十位数字递减
}
}
if(key2==0)//对个位数字进行设置
{
if(key3==0)
{
while(!key3)
ge=ge+1; //个位数字累加
} if(key4==0)
{
while(key4==0)
ge=ge-1; //个位数字递减
}
}
}
节点程序
#include <reg52.h>
#include <intrins.h>
#include <can_showdef.h>
void CAN_init( void ); // 初始化CAN总线芯片
void CAN_TXD( void );//CAN发送子函数
void Rxd_deal(void);//接收处理函数
void Txd_deal(void);//发送处理函数
void Delay(uchar delay_time);//延时子函数
void bojing();//报警子程序函数
sbit DQ=P1^0;
sbit bo=P3^4;
uchar temp;
void main(void)
{
//CPU初始化开始
SJA_RST = 0;
Delay(10);
SJA_RST = 1;//CAN总线复位管脚
SJA_CS = 0;//CAN总线片选有效
EX1 = 1;//外部中断1使能;CAN总线接收中断
IT1 = 0;//低电平触发
IT0 = 1;//脉冲方式触发,外部中断0负边沿触发
EX0 = 1;//打开外部中断0
EA = 1; //打开总中断
SJA_CS = 1;//CAN总线片选无效,保证数据线上的变化不会影响SJA1000
//CPU初始化结束
CAN_init( ); //SJA1000初始化,对 SJA1000寄存器的读写是采用
_nop_();//外部寄存器寻址方式,所以不需要程序单独控制片选有效无效
_nop_();
while(1)
{
_nop_();
_nop_();
if( TXD_flag == 1 )
Txd_deal();//发送处理程序
if( RXD_flag ==1)
Rxd_deal();//接收处理程序
bojing();
}
}
void Rxd_deal(void)
{
EA = 0;//关闭CPU中断
RXD_flag = 0;
Rxd_data = RX_buffer【5】;
EA = 1;
}
//*****发送处理函数********
void Txd_deal(void)
{
_nop_();
TXD_flag = 0;
TX_buffer【5】 = Txd_data;
CAN_TXD();
_nop_();
_nop_();
}
/////中断处理程序///////
void CAN_RXD( void ) interrupt 2
{//接收数据函数,在中断服务程序中调用
uchar data Judge;
EA = 0;//关CPU中断
IE0 = 0;
Judge = IR;
if( Judge & 0x01)
{//IR.0 = 1 接收中断
RX_buffer【0】 = RBSR;
RX_buffer【1】 = RBSR1;
RX_buffer【2】 = RBSR2;
RX_buffer【3】 = RBSR3;
RX_buffer【4】 = RBSR4;
RX_buffer【5】 = RBSR5;
RX_buffer【6】 = RBSR6;
RX_buffer【7】 = RBSR7;
RX_buffer【8】 = RBSR8;
RX_buffer【9】 = RBSR9;
RX_buffer【10】 = RBSR10;
RX_buffer【11】 = RBSR11;
RX_buffer【12】 = RBSR12;
RXD_flag = 1;//置有接收标志
CMR = 0X04;
Judge = ALC;//释放仲裁随时捕捉寄存器
Judge = ECC;//释放错误代码捕捉寄存器
}
IER = 0x01;// .0=1--接收中断使能;
EA = 1;//打开CPU中断
}
//-------按键中断发送处理-----
//////SJA1000 的初始化/////////
void CAN_init( void )
{
uchar bdata Judge;
uchar ACRR【4】;
uchar AMRR【4】;
ACRR【0】 = 0x11;
ACRR【1】 = 0x22;
ACRR【2】 = 0x33;
ACRR【3】 = 0x44;//接收代码寄存器,节点1
AMRR【0】 = 0xff;
AMRR【1】 = 0Xff;
AMRR【2】 = 0xff;
AMRR【3】 = 0xff;//接收屏蔽寄存器。 只接收主机发送的信息
do
{// .0=1---reset MODRe,进入复位模式,以便设置相应的寄存器
//防止未进入复位模式,重复写入;
MODR = 0x09;
Judge = MODR ;
}//保证在复位模式下操作
while( !(Judge & 0x01) );
CDR = 0x88;//时钟分频CDR.3=1--时钟关闭,CDR.7=0---basic CAN,CDR.7=1---Peli CAN
BTR0 = 0x03;
BTR1 = 0x
IER = 0x01;// .0=1--接收中断使能; .1=0--关闭发送中断使能
OCR = 0xaa;// 配置输出控制寄存器
CMR = 0x04;//命令寄存器;释放接收缓冲器
ACR = ACRR【0】;
ACR1 = ACRR【1】;
ACR2 = ACRR【2】;
ACR3 = ACRR【3】;//初始化标示码
AMR = AMRR【0】;
AMR1 = AMRR【1】;
AMR2 = AMRR【2】;
AMR3 = AMRR【3】;//初始化掩码
do//回到工作模式
{
MODR = 0x08;
Judge = MODR;
}
while( Judge & 0x01 );
}
////CAN初始化结束///
///////////发送初始化//////////////
void CAN_TXD( void )
{
uchar data Judge;
uchar data TX_buffer【 N_can 】;
//初始化标示码头信息
TX_buffer【0】 = 0x88;//TX.7=1扩展帧;TX.6=0数据帧; .3=1数据长度
TX_buffer【1】 = 0x00;//本节点地址
TX_buffer【2】 = 0x02;
TX_buffer【3】 = 0x03;
TX_buffer【4】 = 0x00;
//初始化标示码头信息
//初始化发送数据单元
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;
//初始化数据信息
EA = 0; //关中断
//-----接收状态??----------
do
{
Judge = SR;//状态寄存器
}
while( Judge & 0x10 ); //SR.4=1 正在接收等待
//---------发送状态? -----------
do
{
Judge = SR;
}
while(!(Judge & 0x08)); //SR.3=0,发送请求未处理完,等待
//---------发送缓冲器被锁 --------
do
{
Judge = SR;
}
while(!(Judge & 0x04)); //SR.2=0,发送缓冲器被锁。等待
//---------------------------------------
TBSR = TX_buffer【0】;
TBSR1 = TX_buffer【1】;
TBSR2 = TX_buffer【2】;
TBSR3 = TX_buffer【3】;
TBSR4 = TX_buffer【4】;
TBSR5 = TX_buffer【5】;
TBSR6 = TX_buffer【6】;
TBSR7 = TX_buffer【7】;
TBSR8 = TX_buffer【8】;
TBSR9 = TX_buffer【9】;
TBSR10 = TX_buffer【10】;
TBSR11 = TX_buffer【11】;
TBSR12 = TX_buffer【12】;
CMR = 0x01;//置位发送请求//P57
EA = 1;
}
/////////delay程序////////////////
void Delay(uchar delay_time)
{//延时程序
while(delay_time--)
{}
}
void init_com()
{
TMOD=0x20; //设置定时器1为模式2
TH1=0xfd; //装初值设定波特率
TL1=0xfd;
TR1=1; //启动定时器
SM0=0; //选择串口通信模式设置
SM1=1;
PCON=0;
}
void DQ_reset()
{
uchar flag;
DQ=1;
Delay(1); //1us
DQ=0;
Delay(480); //当总线停留在低电平超过480us
//总线上所有器件都将被复位线停留在低电平超过480μs,总线上的所有器件都复位
DQ=1; //产生复位脉冲后,微处理器释放总线,让总线处于空闲状态。
Delay(5); //释放总线后,以便从机18b20通过拉低总线来指示其是否在线,
if(DQ==0)
flag=1; //检测到DS18B20
else
flag=0; //没有检测到DS18B20
Delay(150); //存在检测低电平时间延时约150us
DQ=1; //再次拉高总线,让总线处于空闲状态
}
bit DQ_read_bit(void) //读一位
{
bit dat;
DQ=0; //单片机(微处理器)将总线拉低
Delay(1); //读时隙起始于微处理器将总线拉低至少1us
DQ=1; //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
Delay(2); //延时2us
dat=DQ;//主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现//15us内有效
Delay(100); //所有读"时间隙"必须60~120us,这里100us
return(dat); //返回有效数据
}
uchar DQ_read_byte(void ) //读一字节
{
uchar value,i,j;
value=0; //先对采集的数值进行初始化
for(i=0;i<8;i++)
{
j=DQ_read_bit();
value=(j<<7)|(value>>1); //循环移位直到采集到所有的数据
}
return(value); //返回一个字节的数据
}
void DQ_write_byte(uchar dat) //写一个字节
{
uchar i;
bit abit;
for(i=1;i<=8;i++)
{
abit=dat&0x01;
dat=dat>>1;
if(abit) //写 1
{
DQ=0;
Delay(2); //延时2us。
DQ=1; //写时间隙开始后的15μs内允许数据线拉到高电平
Delay(5); //所有写时间隙必须最少持续60us
}
else
{
DQ=0;
Delay(80);//主机要生成一个写0时间隙这里把数据线拉到低电平并保持80μs
DQ=1;
Delay(2);
}
}
}
void tem_change()
{
DQ_reset();
Delay(1);
DQ_write_byte(0xcc);
DQ_write_byte(0x44);
}
uint get_temperature()
{
uchar temp,a,b;
float wendu;
DQ_reset();
Delay(1);
DQ_write_byte(0xcc);
DQ_write_byte(0xbe);
a=DQ_read_byte();
b=DQ_read_byte();
temp=b;
temp<<=8;
temp=temp|a;
wendu=temp*0.0625;
temp=wendu*10+0.5;
return temp;
}
void bojing()
{
uchar bao;
if(temp>Rxd_data)
bao=1; //主控台接收到的数据大于设定值,报警响起
else
bao=0;//否则,报警器不响
实例二:
CAN总线及应用实例
(1)CAN特点
●CAN为多主方式工作,网络上任意智能节点均可在任意时刻主动向网络上其他节点发送信息,而不分主从,且无需站地址等节点信息,通信方式灵活。利用这特点可方便地构成多机备份系统。
●CAN网络上的节点信息分成不同的优先级(报文有2032种优先权),可满足不同的实时要求,高优先级的数据最多可在134,us内得到传输。
●CAN采用非破坏性总线仲裁技术,当多个节点同时向总线发送信息时,优先级较低的节点会主动地退出发送,大大节省了总线冲突仲裁时间。
●CAN只需通过报文滤波即可实现点对点、一点对多点及全局广播等几种方式收发数据,无需专门“调度”。
●CAN的直接通信距离最远可达l
●CAN上的节点数主要取决于总线驱动电路,目前可达110个;报文标识符可达2032种(CAN
(2)CAN总线协议
CAN协议以国际标准化组织的开放性互连模型为参照,规定了物理层、传输层和对象层,实际上相当于ISO网络层次模型中的物理层和数据链路层。图3.9 为CAN总线网络层次结构,发送过程中,数据、数据标识符及数据长度,加上必要的总线控制信号形成串行的数据流,发送到串行总线上,接收方再对数据流进行分析,从中提取有效的数据。CAN协议的一个最大特点是废除了传统的站地址编码,而代之以对通信数据块进行编码,数据在网络上通过广播方式发送。其优点是可使网络内的节点个数在理论上不受限制(实际中受网络硬件的电气特性限制),还可使同一个通信数据块同时被不同的节点接收,这在分布式控制系统中非常有用。CAN
对象层:报文滤波、报文和状态的处理 |
传输层:故障界定、错误检测和信令、报文校验、应答、仲裁、报文分帧、传输速率和定时 |
物理层:信号电平和位表示、传输媒体 |
图3.9 CAN总线层次结构
(3)报文传送和帧结构
CAN总线以报文为单位进行信息传送。报文中包含标识符,它标志了报文的优先权。CAN总线上各个节点都可主动发送。如同时有两个或更多节点开始发送报文,采用标识符ID来进行仲裁,具有最高优先权报文节点赢得总线使用权,而其他节点自动停止发送。在总线再次空闲后,这些节点将自动重发原报文。CAN系统中,一个CAN节点不使用有关系统结构的任何信息。报文中的标识符并不指出报文的目的地址,而是描述数据的含义。网络中的所有节点都可有标识符来自动决定是否接收该报文。每个节点都有标识符寄存器和屏蔽寄存器,接收到的报文只有与该屏蔽的功能相同时,该节点才开始正式接收报文,否则它将不理睬标识符后面的报文。
CAN支持4种不同类型报文帧:数据帧、远程帧、出错帧、超载帧、帧间空间
1)数据帧用于在各个节点之间传送数据或命令,它有7个不同的位场组成:帧起始、仲裁场、控制场、数据场、CRC场、应答场和帧结束,如图3.10-13所示。
、
图3.10 数据帧
●帧起始标志数据帧的开始。它由一个主控位构成。
●仲裁场由11位标识符(M)和远程发送请求位(RTR)组成,其中最高7位。
不能全是隐性位。M决定了报文的优先权。如主控位为0,隐性位为1,则M的数值越小,优先权越高。对数据帧,RTR为主控电平。
●控制场r1和r0为保留位,应发送主控电平。DLC为数据长度码n,它为0-80
●数据场允许的数据字节长度为0-8,由n决定。
●应答场包括应答位和应答分隔符。发送站发出的这两位均为隐性电平。而正确地接收到有效报文的接收站,在应答位期间应传送主控电平给发送站。应答分隔符为隐性电平。
●帧结束由7位隐性电平组成。
以上为标准格式的数据帧,除此之外,在CAN规范2.0 B中,还定义了扩展格式的数据帧,它的标识符扩展为29位。它的前11位标识符后的两位为SRR和ME,它们均为隐性电平,后面为新增的18位标识符,其余与标准格式相同。
表3.2 数据长度码中数据字节数目编码
数据字节数目 | 数据长度码 | |||
DLC3 | DLC2 | DLC1 | DLC0 | |
0 | d | D | d | d |
1 | d | D | d | r |
2 | d | d | r | d |
3 | d | d | r | r |
4 | d | r | d | d |
5 | d | r | d | r |
6 | d | r | r | d |
7 | d | r | r | r |
8 | r | d | d | d |
(4)CAN通信接口
图3.17是CAN通信部分电路,SJA1000是一种独立用于移动目标和一般工业环境中的区域网络控制。它是Philips半导体公司PCA
图3.17 CAN通信部分电路
1)SJA1000 的特征能分成3组:
①已建立的PCA
② 改良的PCA
③PeliCAN 模式的增强功能在PeliCAN 模式里SJA1000 支持一些错误分析功能支持系统诊断系统维护系统优化而且这个模式里也加入了对一般CPU 的支持和系统自身测试的功能。
SJA1000管脚:
AD0----AD7:地址/数据复用信号
ALE/AS:ALE输入信号(Intel模式),AS输入信号(Motorola模式)
/CS:片选信号,低电平有效
/RD:微控制器的/RD信号(Intel模式),或E使能信号(Motorola模式)
/WR:微控制器的/WR信号(Intel模式),或R/W使能信号(Motorola模式)
CLKOUT:提供给微控制器的时钟输出信号,通过可编程分频器由内部晶振产生;时钟分频寄存器的时钟关闭位可禁止该引脚。
VSS1:接地端 ,VSS2:输入比较器接地端,VSS3:输出驱动器接地端。
VDD1 :逻辑电路的5V电源,VDD2输入比较器5V电源,VDD3输出驱动器5V电源。
XTAL1,2:分别位振荡器放大电路输入输出。
MODE:模式选择输入,1= Intel模式,0= Motorola模式。
TX0,TX1: 由输出驱动器0、1到物理线路的输出端。
/INT:中断输出,开漏输出。
/RST:复位输入。
RX0,RX1:由物理总线到SJA1000输入比较器的输入端,显性电平将会唤醒SJA1000的睡眠模式;如果RX1>RX0的电平高,读出为显性电平,反之读出的隐性电平;如果时钟分频寄存器的CBP位被置位,就忽略CAN输入比较器以减少内延时(此时连有外部收发电路);这种情况下只有RX0是激活的;隐性电平被认为是高,而显性电平被认为是低。
PCA
PCA
TXD:发送数据输入
GND:地
Vcc:电源 4.5——5.5 V
RXD:接收数据输出
Vref:参考电压输出
CANH:低电平CAN电压输入/输出
CANH:高电平CAN电压输入/输出
Rs:斜率电阻输入,接地选择高速工作模式
2)SJA1000 的基本功能和寄存器:
① BasicCAN 功能说明
表3.3 为SJA1000寄存器说明。
表3.3 SJA1000寄存器说明
地址 | 功能段 | 操作模式中的寄存器功能 | 复位模式中的寄存器高功能 | ||
0 | 各类控制器 | 读 | 写 | 读 | 写 |
1 | 控制 | 控制 | 控制 | 控制 | |
2 | FFH | 命令 | FFH | 命令 | |
3 | 状态 | - | 状态 | - | |
4 | FFH | - | 中断 | - | |
5 | FFH | - | 验收代码 | 验收代码 | |
6 | FFH | - | 验收屏蔽 | 验收屏蔽 | |
7 | FFH | - | 总时序0 | 总时序0 | |
8 | FFH | - | 总时序1 | 总时序1 | |
9 | 测试 | 测试 | 测试 | 测试 | |
10 | 发送缓冲器 | 标识符位域 10-3 | 标识符位域10-3 | FFH | - |
11 | 标识符位域 2-0 RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | FFH | - | |
12- 19 | 数据字节1——数据字节8 | 数据字节1——数据字节8 | FFH—— FFH | ―… ― | |
20 | 接受缓冲器 | 标识符位域 10-3 | 标识符位域 10-3 | 标识符位域 10-3 | 标识符位域 10-3 |
21 | 标识符位域 2-0RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | |
22-29 | 数据字节1——数据字节8 | 数据字节1——数据字节8 | 数据字节1——数据字节8 | 数据字节1—— 数据字节8 | |
30 | FFH | - | FFH | - | |
31 | 时钟分频器 | 时钟分频器 | 时钟分频器 | 时钟分频器 | 时钟分频器 |
【1】 控制寄存器(CR):如表3.4所示。
表3.4 控制寄存器
位 | 符号 | 名称 | 值 | 功能 |
CR.7 | ||||
CR.6 | ||||
CR.5 | ||||
CR.4 | OIE | 超载中断使能 | 1 | 使能:如果数据超载位置位,微控制器接收一个超载中断信号 |
0 | 禁止:微控制器不从SJA1000接收超载中断信号 | |||
CR.3 | EIE | 错误中断使能 | 1 | 使能:如果出错或总线状态改变,微控制器接收一个错误中断信号 |
0 | 禁止:微控制器不从SJA1000接收错误中断信号 | |||
CR.2 | TIE | 发送中断使能 | 1 | 使能:当报文被成功或发送缓冲器可再次被访问时,SJA1000向微控制器发出一次发送中断信号 |
0 | 禁止:SJA1000不向微控制器发送中断信号 | |||
CR.1 | RIE | 接收中断使能 | 1 | 使能:报文被无错误接收时,SJA1000向微控制器发出一次中断信号 |
0 | 禁止:SJA1000不向微控制器发送接收中断信号 | |||
CR.0 | RR | 复位请求 | 1 | 常态:SJA1000检测到复位请求后,忽略当前发送/接收的报文,进入复位模式 |
0 | 非常态:复位请求位接收到一个下降沿后,SJA1000回到工作模式 |
2)SJA1000 的基本功能和寄存器:
① BasicCAN 功能说明
表3.3 为SJA1000寄存器说明。
表3.3 SJA1000寄存器说明
地址 | 功能段 | 操作模式中的寄存器功能 | 复位模式中的寄存器高功能 | ||
0 | 各类控制器 | 读 | 写 | 读 | 写 |
1 | 控制 | 控制 | 控制 | 控制 | |
2 | FFH | 命令 | FFH | 命令 | |
3 | 状态 | - | 状态 | - | |
4 | FFH | - | 中断 | - | |
5 | FFH | - | 验收代码 | 验收代码 | |
6 | FFH | - | 验收屏蔽 | 验收屏蔽 | |
7 | FFH | - | 总时序0 | 总时序0 | |
8 | FFH | - | 总时序1 | 总时序1 | |
9 | 测试 | 测试 | 测试 | 测试 | |
10 | 发送缓冲器 | 标识符位域 10-3 | 标识符位域10-3 | FFH | - |
11 | 标识符位域 2-0 RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | FFH | - | |
12- 19 | 数据字节1——数据字节8 | 数据字节1——数据字节8 | FFH—— FFH | ―… ― | |
20 | 接受缓冲器 | 标识符位域 10-3 | 标识符位域 10-3 | 标识符位域 10-3 | 标识符位域 10-3 |
21 | 标识符位域 2-0RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | 标识符位域 2-0RTR和DLC位域 | |
22-29 | 数据字节1——数据字节8 | 数据字节1——数据字节8 | 数据字节1——数据字节8 | 数据字节1—— 数据字节8 | |
30 | FFH | - | FFH | - | |
31 | 时钟分频器 | 时钟分频器 | 时钟分频器 | 时钟分频器 | 时钟分频器 |
【1】 控制寄存器(CR):如表3.4所示。
表3.4 控制寄存器
位 | 符号 | 名称 | 值 | 功能 |
CR.7 | ||||
CR.6 | ||||
CR.5 | ||||
CR.4 | OIE | 超载中断使能 | 1 | 使能:如果数据超载位置位,微控制器接收一个超载中断信号 |
0 | 禁止:微控制器不从SJA1000接收超载中断信号 | |||
CR.3 | EIE | 错误中断使能 | 1 | 使能:如果出错或总线状态改变,微控制器接收一个错误中断信号 |
0 | 禁止:微控制器不从SJA1000接收错误中断信号 | |||
CR.2 | TIE | 发送中断使能 | 1 | 使能:当报文被成功或发送缓冲器可再次被访问时,SJA1000向微控制器发出一次发送中断信号 |
0 | 禁止:SJA1000不向微控制器发送中断信号 | |||
CR.1 | RIE | 接收中断使能 | 1 | 使能:报文被无错误接收时,SJA1000向微控制器发出一次中断信号 |
0 | 禁止:SJA1000不向微控制器发送接收中断信号 | |||
CR.0 | RR | 复位请求 | 1 | 常态:SJA1000检测到复位请求后,忽略当前发送/接收的报文,进入复位模式 |
0 | 非常态:复位请求位接收到一个下降沿后,SJA1000回到工作模式 |
【2】 命令寄存器(CMR):如表3.5所示。
表3.5 命令寄存器
位 | 符号 | 名称 | 值 | 功能 |
CMR.7 | ||||
CMR.6 | ||||
CMR.5 | ||||
CMR.4 | CTS | 睡眠 | 1 | 睡眠:如果没有CAN中断等待和总线活动,SJA1000进入睡眠模式 |
0 | 唤醒:SJA1000正常工作模式 | |||
CMR.3 | CDO | 清除超载状态 | 1 | 清除:清除数据超载状态位 |
0 | 无作用 | |||
CMR.2 | RRB | 释放接收缓冲器 | 1 | 释放:接收缓冲器中存放报文的内存空间将被释放 |
0 | 无作用 | |||
CMR.1 | AT | 夭折发送 | 1 | 常态:如果不是在处理过程中,等待处理的发送请求将忽略 |
0 | 非常态:无作用 | |||
CMR.0 | TR | 发送请求 | 1 | 常态:报文被发送 |
0 | 非常态:无作用 |
【3】 状态寄存器(SR):如表3.6所示。
表3.6 状态寄存器
位 | 符号 | 名称 | 值 | 功能 |
SR.7 | BS | 总线状态 | 1 | 总线关闭:SJA1000退出总线活动 |
0 | 总线开启:SJA1000进入总线活动 | |||
SR.6 | ES | 出错状态 | 1 | 出错:至少出现一个错误计数器满或超过CPU报警机制 |
0 | 正常:两个错误计数器都在报警限制以下 | |||
SR.5 | TS | 发送状态 | 1 | 发送:SJA1000正在发送报文 |
0 | 空闲:没有要发送的报文 | |||
SR.4 | RS | 接收状态 | 1 | 接收:SJA1000正在接收 |
0 | 空闲:没有要接收的报文 | |||
SR.3 | TCS | 发送完毕状态 | 1 | 完成:最近一次发送请求被成功处理 |
0 | 未完成:当前发送请求未处理完毕 | |||
SR.2 | TBS | 发送缓冲器状态 | 1 | 释放:CPU可以向发送缓冲器写报文 |
0 | 锁定:CPU不能访问发送缓冲器,有报文正在等待发送或正在发送 | |||
SR.1 | DOS | 数据超载状态 | 1 | 超载:报文丢失,因为RXFIFO中没有足够的空间来存储它 |
0 | 未超载:自从最后一次清除数据超载命令执行,无数据超载发生 | |||
SR.0 | RBS | 接收缓冲状态 | 1 | 满:RXFIFO中有可用报文 |
0 | 空:无可用报文 |
【4】中断寄存器(IR):如表3.7所示。
表3.7 中断寄存器
位 | 符号 | 名称 | 值 | 功能 |
IR.7 | ||||
IR.6 | ||||
IR.5 | ||||
IR.4 | WUI | 唤醒中断 | 1 | 置位:退出睡眠模式时此位被置位 |
0 | 复位:微控制器的任何读访问将清除此位 | |||
IR.3 | DOI | 数据超载中断 | 1 | 置位:当数据超载中断使能位被置为1时,数据超载状态位由低到高的跳变,将其置位。 |
0 | 复位:微控制器的任何读访问将清除此位 | |||
IR.2 | EI | 错误中断 | 1 | 置位:错误中断使能时,错误状态位或总线状态位的变化会置位此位 |
0 | 复位:微控制器的任何读访问将清除此位 | |||
IR.1 | TI | 发送中断 | 1 | 置位:发送缓冲器状态由低到高的跳变(释放)和发送中断使能时,置位此位 |
0 | 复位:微控制器的任何读访问将清除此位 | |||
IR.0 | RI | 接收中断 | 1 | 置位:当接收FIFO不空和接收中断使能时置位此位 |
0 | 复位:微控制器的任何读访问将清除此位 |
【5】验收代码寄存器(ACR):如表3.8所示。
表3.8 验收代码寄存器
BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
AC.7 | AC.6 | AC.5 | AC.4 | AC.3 | AC.2 | AC.1 | AC.0 |
复位请求位被置高(当前)时,该寄存器可以访问。如果一条报文通过了接收滤波器的测试而且接收缓冲器有空间,描述符和数据将被分别顺次写入RXFIFO,当报文被正确的接收完毕,则有:接收状态位置高(满);接收中断使能位置高(使能),接收中断置高(产生中断)。
验收代码(AC.7~AC.0)和报文标识符的高8位(ID.10~ID.3)必须相等,或验收屏蔽位(AM.7~AM.0)的所有位为1。即如果满足以下方程的描述,则予以接收。
【(ID.10~ID.3)≡(AC.7~AC.0)】 ∨(AM.7~AM.0)≡11111111
【6】验收屏蔽寄存器(AMR):如表3.9所示。
表3.9 验收屏蔽寄存器
BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
AM.7 | AM.6 | AM.5 | AM.4 | AM.3 | AM.2 | AM.1 | AM.0 |
复位请求位被置高(当前)时,该寄存器可以访问。验收屏蔽寄存器定义验收代码寄存器的哪些位对接收过滤器是“相关的”或“无关的”(即可为任意值)
当AM.i=0时,是“相关的”
当AM.i=1时,是“无关的”(i=0~7)