本文共 6366 字,大约阅读时间需要 21 分钟。
单总线协议意思就是一个线就可以完成数据的发送和接收。IIc通信有两根线:SCL时钟线和SDA数据线,通过两根线的完美配合完成读写操作。具体可以参考第一篇文章。SPI通信有四根线:片选线,时钟线,主机输入线,从机写入线。单总线就是只有一根线。这跟线需要完成读和写的操作,通过模拟时序来完成单线读写,通过这根线的电平高低以及延时时间的情况来告知从机下一步的动作。这里结合DS18B20温度传感器来介绍单线协议
DS18b20必懂知识点():
DS18B20内部主要包括,64位ROM(只读储存器)、SCRATCHPAD(暂存寄存器)。其中暂存寄存器包括五部分,详细请看下图:64位ROM(只读寄存器)
rom中的64位序列号在出厂前就被刻好,独一无二,可以看作器件的身份证,主机通过这个独特的信息决定当多个DS181B20构成多节点系统时通信的对象。暂存寄存器,顾名思义信息被暂时存储在这里边,等待主机的读取,传感器温度转换完毕后就存储在暂存器的前两个字节(温度寄存器),寄存器的第二字节和第三字节分别存储高温限值和低温限值。第四字节是配置寄存器,用来设定传感器的精度。另外需要注意一点就是第二字节(TH),第三字节(TL)以及第四字节(配置寄存器)可以与可擦除EEPROM交换数据
温度寄存器
TH和TL限温报警寄存器(注意是有两个)
TH和TL中分别存储温度的限位,一个是高温度一个是低温,当温度处于这这个范围之外的时候就会报警。这两个温度需要主机来写入,首先主机需要在数据线上写4EH,就是写寄存器的命令,从机检测到这个信号后就知道主机开始往内部的RAM(高速暂存寄存器)的第三字节和第四字节写数据了,从机做好准备接受数据,主机也在发送外这条命令之后就开始发送两个字节(就是高温限位和低温限位)。-配置寄存器
下面介绍主机发生的命令库
-发送储存器命令
-发送ROM指令
准备工作完毕,我们来说说主机与DS18B20的数据转化的全过程
2.发送ROM命令
3.发送储存器命令下面问题又来了,我们一直在说往总线发送ROM指令,发送RAM指令。主机是怎么发送指令的呐?RAM指令中还有读取暂存器的命令,暂存器是怎么样放送数据到总线的呐?
下边我们来看看读/写时许-写时许图
void tempwritebyte(uchar dat)//向传感器写一个字节数据函数{ uint i; uchar j; bit testb; for(j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if(testb) { ds=0; i++;i++; ds=1; i=8; while(i>0) i--; } else { ds=0; i=8; while(i>0) i--; ds=1;//写0之后,上边的延时已经让从机接受到了主机发来的数据,这里就是为下一次写循环做准备,从时许图上可以看出每一次主线都是从高电平开始的。 i++;i++; } }}
-读一个字节的代码
it tempreadbit(void)//读一位数据函数{ uint i; bit dat; ds=0;i++; ds=1;i++;i++; dat=ds;//上边那行代码是把总线拉高,那只是一个释放总线的操作,在释之 //后延时的这段时间,没有其他代码指令,因为是在等从机操作总线。然后结 //束,从机已经把数据送到了总线上,然后这句代码就是读取从机送来的数据特 //别像IIC中主机读数据的逻辑。IIc中读数据时,我们实现把数据线拉高,让机 //释放了数据线(把主动权交给从机),然后延时了5微秒,其实这是从机已把 //数据送给了数据线SDA,所以这是在for循环中就会判断数据线的状态。可以看 //IIc那篇文章小标(9)读数据代码的第6行和第12行 i=8; while(i>0) i--; return(dat);}uchar tempread(void){ uchar i,j,dat; dat=0; for(i=1;i<=8;i++) { j=tempreadbit(); dat=(j<<7)|(dat>>1); } return(dat);}
好了终于编辑完了,今天比较忙,中午想清楚之后就开始编辑,一直到现在,边想边写,写了有3个小时,里边把我昨天所有的疑惑都做了解答,我以后在看到的时候肯定会明白,不知道对网友有没有帮助。
这里贴上郭天祥的温度传感器报警装置的代码(我的班子是QX-MSC51,所以略有改动)
#include#include #define uchar unsigned char#define uint unsigned intsbit ds=P2^2;sbit dula=P2^6;sbit wela=P2^7;sbit beep=P1^7;uint temp;float f_temp;uint warn_l1=270;uint warn_l2=250;uint warn_h1=300;uint warn_h2=320;sbit led0=P1^0;sbit led1=P1^1;sbit led2=P1^2;sbit led3=P1^3;uchar code table[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,//带小数点0-9 0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//不带小数0-9void delay(uint num_time){ uint i,j; for(i=num_time;i>0;i--) for(j=110;j>0;j--);}void dereset(void)//DS18B20复位。初始化函数{ uint i; ds=0; i=30; while(i>0) i--; ds=1; i=4; while(i>0) i--; }bit tempreadbit(void)//读一位数据函数{ uint i; bit dat; ds=0;i++; ds=1;i++;i++; dat=ds; i=8; while(i>0) i--; return(dat);}uchar tempread(void){ uchar i,j,dat; dat=0; for(i=1;i<=8;i++) { j=tempreadbit(); dat=(j<<7)|(dat>>1); } return(dat);}void tempwritebyte(uchar dat)//向传感器写一个字节数据函数{ uint i; uchar j; bit testb; for(j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if(testb) { ds=0; i++;i++; ds=1; i=8; while(i>0) i--; } else { ds=0; i=8; while(i>0) i--; ds=1; i++;i++; } }}void tempchange(void)//DS18B20开始获取温度并转换{ dereset(); delay(1); tempwritebyte(0xcc); tempwritebyte(0x44);}uint get_temp(){ uchar a,b; dereset(); delay(1); tempwritebyte(0xcc);//跳过ROM tempwritebyte(0xbe);//读暂存器 a=tempread(); b=tempread(); temp=b; temp<<=8; temp=temp|a; f_temp=temp*0.0625; temp=f_temp*10+0.5; f_temp=f_temp+0.05; return temp; }void display(uchar num,uchar dat){ uchar i; dula=0; P0=table[dat]; dula=1; dula=0; wela=0; i=0xFF; i=i&(~((0x01)<<(num))); P0=i; wela=1; wela=0; delay(1);}/*void display(uint num_tem){ uint shi,ge,xiaoshu; shi=num_tem/100; ge=(num_tem%100)/10; xiaoshu=num_tem%10; dula=1; P0=table[shi+10]; dula=0; P0=0xff; wela=1; P0=0xfe; wela=0; delay(5); dula=1; P0=table[ge]; dula=0; P0=0xff; wela=1; P0=0xfd; wela=0; delay(5); dula=1; P0=table[xiaoshu+10]; dula=0; P0=0xff; wela=1; P0=0xfb; wela=0; delay(5);}void dangwei(uint rank_num)//在数码管上显示0-5挡{ dula=1; P0=table[rank_num+10]; dula=0; P0=0xff; wela=1; P0=0xef; wela=0; delay(5);}*/void dis_temp(uint t){ uchar i; i=t/100; display(0,i); i=t%100/10; display(1,i+10); i=t%100%10; display(2,i);}void warn(uint s,uchar led){ uchar i;i=s; beep=0; P1=~(led); while(i--) { dis_temp(get_temp()); } beep=1; P1=0xFF; i=s; while(i--) { dis_temp(get_temp()); }}void deal(uint t)//温度处理{ uchar i; if((t>warn_l2)&&(t<=warn_l1)) { warn(40,0x01); } else if(t warn_h1) { warn(10,0x04); } else if(t>=warn_h2) { warn(10,0x0c); } else { i=40; while(i--) { dis_temp(get_temp()); } }}void init_com(void)//串口初始化{ TMOD=0x20; PCON=0x00; SCON=0x50; TH1=0xFD; TL1=0xfd; TR1=1;}void comm(char *parr){ do { SBUF=*parr++; while(!TI) { TI=0; } }while(*parr);}void main(){ uchar i; uchar buff[4]; dula=0; wela=0; init_com(); while(1) { tempchange(); for(i=10;i>0;i--) { dis_temp(get_temp()); } deal(temp); sprintf(buff,"%f",f_temp); for(i=10;i>0;i--) { dis_temp(get_temp()); } comm(buff); for(i=10;i>0;i--) { dis_temp(get_temp()); } }}
这里还有串口通讯的东西,就是传感器读到的温度转换之后传给了上位机。
串口通信以及SPI通信我们交给下几次总结。转载地址:http://igqx.baihongyu.com/