CRC是序列号的校验码 用来验证序列号对不对的。序列号一般是没标的要自己读。给你个读序列号的程序改下端口就能用:
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P2^0; //定义DS18B20端口DQ
sbit BEEP=P3^7 ; //蜂鸣器驱动线
bit presence ;
sbit LCD_RS = P2^6;
sbit LCD_RW = P2^5;
sbit LCD_EN = P2^4;
uchar code cdis1[ ] = ;
uchar code cdis2[ ] = ;
uchar code cdis3[ ] = ;
uchar code cdis4[ ] = ;
unsigned char data display[2] = ;
unsigned char data RomCode[8] = ;
unsigned char Temp;
unsigned char crc;
void beep();
#define delayNOP(); ;
/*******************************************************************/
void delay1(int ms)
{
unsigned char y;
while(ms--)
{
for(y = 0; y<250; y++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
/******************************************************************/
/* */
/*检查LCD忙状态 */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。 */
/* */
/******************************************************************/
bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delayNOP();
result = (bit)(P0&0x80);
LCD_EN = 0;
return(result);
}
/*******************************************************************/
/* */
/*写指令数据到LCD */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。 */
/* */
/*******************************************************************/
void lcd_wcmd(uchar cmd)
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*******************************************************************/
/* */
/*写显示数据到LCD */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。 */
/* */
/*******************************************************************/
void lcd_wdat(uchar dat)
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*******************************************************************/
/* */
/* LCD初始化设定 */
/* */
/*******************************************************************/
void lcd_init()
{
delay1(15);
lcd_wcmd(0x01); //清除LCD的显示内容
lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x0c); //显示开,关光标
delay1(5);
lcd_wcmd(0x06); //移动光标
delay1(5);
lcd_wcmd(0x01); //清除LCD的显示内容
delay1(5);
}
/*******************************************************************/
/* */
/* 设定显示位置 */
/* */
/*******************************************************************/
void lcd_pos(uchar pos)
{
lcd_wcmd(pos | 0x80); //数据指针=80+地址变量
}
/*******************************************************************/
/* */
/*us级延时函数 */
/* */
/*******************************************************************/
void Delay(unsigned int num)
{
while( --num );
}
/*******************************************************************/
/* */
/*初始化ds1820 */
/* */
/*******************************************************************/
Init_DS18B20(void)
{
DQ = 1; //DQ复位
Delay(8); //稍做延时
DQ = 0; //将DQ拉低
Delay(90); //精确延时 大于 480us
DQ = 1; //拉高总线
Delay(8);
presence = DQ; //读取存在信号
Delay(100);
DQ = 1;
return(presence); //返回信号,0=presence,1= no presence
}
/*******************************************************************/
/* */
/* 读一位(bit) */
/* */
/*******************************************************************/
uchar read_bit(void)
{
unsigned char i;
DQ = 0; //将DQ 拉低开始读时间隙
DQ = 1; // then return high
for (i=0; i<3; i++); // 延时15μs
return(DQ); // 返回 DQ 线上的电平值
}
/*******************************************************************/
/* */
/* 读一个字节 */
/* */
/*******************************************************************/
ReadOneChar(void)
{
unsigned char i = 0;
unsigned char dat = 0;
//for (i = 8; i > 0; i--)
// {
// read_bit();
// DQ = 0; // 给脉冲信号
// dat >>= 1;
// DQ = 1; // 给脉冲信号
for (i=0;i<8;i++)
{ // 读取字节,每次读取一个字节
if(read_bit()) dat|=0x01<
// if(DQ)
// dat |= 0x80;
Delay(4);
}
return (dat);
}
/*******************************************************************/
/* */
/* 写一位 */
/* */
/*******************************************************************/
void write_bit(char bitval) {
DQ = 0; // 将DQ 拉低开始写时间隙
if(bitval==1) DQ =1; // 如果写1,DQ 返回高电平
Delay(5); // 在时间隙内保持电平值,
DQ = 1; // Delay函数每次循环延时16μs,因此delay(5) = 104μs
}
/*******************************************************************/
/* */
/* 写一个字节 */
/* */
/*******************************************************************/
WriteOneChar(unsigned char dat)
{
unsigned char i = 0;
unsigned char temp;
// for (i = 8; i > 0; i--)
// {
for (i=0; i<8; i++) // 写入字节, 每次写入一位
{
// DQ = 0;
// DQ = dat&0x01;
// Delay(5);
// DQ = 1;
temp = dat>>i;
temp &= 0x01;
write_bit(temp);
// dat>>=1;
}
Delay(5);
}
/*******************************************************************/
/* */
/* 读取64位序列码 */
/* */
/*******************************************************************/
Read_RomCord(void)
{
unsigned char j;
Init_DS18B20();
WriteOneChar(0x33); // 读序列码的操作
for (j = 0; j < 8; j++)
{
RomCode[j] = ReadOneChar() ;
}
}
/*******************************************************************/
/* */
/*DS18B20的CRC8校验程序 */
/* */
/*******************************************************************/
uchar CRC8()
{
uchar i,x; uchar crcbuff;
crc=0;
for(x = 0; x <8; x++)
{
crcbuff=RomCode[x];
for(i = 0; i < 8; i++)
{
if(((crc ^ crcbuff)&0x01)==0)
crc >>= 1;
else {
crc ^= 0x18; //CRC=X8+X5+X4+1
crc >>= 1;
crc |= 0x80;
}
crcbuff >>= 1;
}
}
return crc;
}
/*******************************************************************/
/* */
/* 数据转换与显示 */
/* */
/*******************************************************************/
Disp_RomCode()
{
uchar j;
uchar H_num=0x40; //LCD第二行初始位置
for(j=0;j<8;j++)
{
Temp = RomCode[j];
display[0]=((Temp&0xf0)>>4);
if(display[0]>9)
else
lcd_pos(H_num);
lcd_wdat(display[0]); //高位数显示
H_num++;
display[1]=(Temp&0x0f);
if(display[1]>9)
else
lcd_pos(H_num);
lcd_wdat(display[1]); //低位数显示
H_num++;
}
}
/*******************************************************************/
/* */
/* 蜂鸣器响一声 */
/* */
/*******************************************************************/
void beep()
{
unsigned char y;
for (y=0;y<100;y++)
{
Delay(60);
BEEP=!BEEP; //BEEP取反
}
BEEP=1; //关闭蜂鸣器
Delay(40000);
}
/*******************************************************************/
/* */
/* DS18B20 OK 显示菜单 */
/* */
/*******************************************************************/
void Ok_Menu ()
{
uchar m;
lcd_init(); //初始化LCD
lcd_pos(0); //设置显示位置为第一行的第1个字符
m = 0;
while(cdis1[m] != '\0')
{ //显示字符
lcd_wdat(cdis1[m]);
m++;
}
lcd_pos(0x40); //设置显示位置为第二行第1个字符
m = 0;
while(cdis2[m] != '\0')
{
lcd_wdat(cdis2[m]); //显示字符
m++;
}
}
/*******************************************************************/
/* */
/* DS18B20 ERROR 显示菜单 */
/* */
/*******************************************************************/
void Error_Menu ()
{
uchar m;
lcd_init(); //初始化LCD
lcd_pos(0); //设置显示位置为第一行的第1个字符
m = 0;
while(cdis3[m] != '\0')
{ //显示字符
lcd_wdat(cdis3[m]);
m++;
}
lcd_pos(0x40); //设置显示位置为第二行第1个字符
m = 0;
while(cdis4[m] != '\0')
{
lcd_wdat(cdis4[m]); //显示字符
m++;
}
}
/*******************************************************************/
/* */
/* 主函数 */
/* */
/*******************************************************************/
void main()
{
P0 = 0xff;
P2 = 0xff;
while(1)
{
Ok_Menu ();
Read_RomCord(); //读取64位序列码
CRC8(); //CRC效验
if(crc==0) //CRC效验正确
{
Disp_RomCode(); //显示64位序列码
beep();
}
while(!presence)
{
Init_DS18B20();
delay1(1000);
}
Error_Menu ();
do
{
Init_DS18B20();
beep();
}
while(presence);
}
}
/*******************************************************************/
循环冗余校验码(CRC)
CRC校验采用多项式编码方法。被处理的数据块可以看作是一个n阶的二进制多项式,由 。如一个8位二进制数10110101可以表示为: 。多项式乘除法运算过程与普通代数多项式的乘除法相同。多项式的加减法运算以2为模,加减时不进,错位,和逻辑异或运算一致。
采用CRC校验时,发送方和接收方用同一个生成多项式g(x),并且g(x)的首位和最后一位的系数必须为1。CRC的处理方法是:发送方以g(x)去除t(x),得到余数作为CRC校验码。校验时,以计算的校正结果是否为0为据,判断数据帧是否出错。
CRC校验可以100%地检测出所有奇数个随机错误和长度小于等于k(k为g(x)的阶数)的突发错误。所以CRC的生成多项式的阶数越高,那么误判的概率就越小。CCITT建议:2048 kbit/s的PCM基群设备采用CRC-4方案,使用的CRC校验码生成多项式g(x)= 。采用16位CRC校验,可以保证在 bit码元中只含有一位未被检测出的错误 。在IBM的同步数据链路控制规程SDLC的帧校验序列FCS中,使用CRC-16,其生成多项式g(x)= ;而在CCITT推荐的高级数据链路控制规程HDLC的帧校验序列FCS中,使用CCITT-16,其生成多项式g(x)= 。CRC-32的生成多项式g(x)= 。CRC-32出错的概率比CRC-16低 倍 。由于CRC-32的可靠性,把CRC-32用于重要数据传输十分合适,所以在通信、计算机等领域运用十分广泛。在一些UART通信控制芯片(如MC6582、Intel8273和Z80-SIO)内,都采用了CRC校验码进行差错控制;以太网卡芯片、MPEG解码芯片中,也采用CRC-32进行差错控制。
二、CRC校验码的算法分析
CRC校验码的编码方法是用待发送的二进制数据t(x)除以生成多项式g(x),将最后的余数作为CRC校验码。其实现步骤如下:
(1) 设待发送的数据块是m位的二进制多项式t(x),生成多项式为r阶的g(x)。在数据块的末尾添加r个0,数据块的长度增加到m+r位,对应的二进制多项式为 。
(2) 用生成多项式g(x)去除 ,求得余数为阶数为r-1的二进制多项式y(x)。此二进制多项式y(x)就是t(x)经过生成多项式g(x)编码的CRC校验码。
(3) 用 以模2的方式减去y(x),得到二进制多项式 。 就是包含了CRC校验码的待发送字符串。
从CRC的编码规则可以看出,CRC编码实际上是将代发送的m位二进制多项式t(x)转换成了可以被g(x)除尽的m+r位二进制多项式 ,所以解码时可以用接受到的数据去除g(x),如果余数位零,则表示传输过程没有错误;如果余数不为零,则在传输过程中肯定存在错误。许多CRC的硬件解码电路就是按这种方式进行检错的。同时 可以看做是由t(x)和CRC校验码的组合,所以解码时将接收到的二进制数据去掉尾部的r位数据,得到的就是原始数据。