当前位置:   article > 正文

51单片机第15步_串口多机通讯使用CRC8校验_51串口crc

51串口crc

本章重点介绍串口多机通讯使用CRC8校验

数据格式:"$123xxxx*crc8\r\n";

如:"$1234567890ABCDEF*06\r\n"

如:"$1231234567890*31\r\n"

crc8是CRC校验值,为十六进制的ASCII码,不包含'$'和校验值前面的那个'*'

#include <REG51.h>    //包含头文件REG51.h,使能51内部寄存器;

#include <intrins.h>  //包含头文件intrins.h,要放在stdio.h的头文件之前;

//使能函数: _nop_();  相当于汇编的NOP指令;

//使能函数: bit  _testbit_( bit bit_value ); 对bit_value进行测试,若bit_value=1,返回1,否则返回0;

//使能函数: _cror_( unsigned char x, unsigned char n ); 将字节型变量x的值,向右循环移动n位,然后将其

//值返回;

//相当于汇编的RR A命令;

//使能函数: _iror_( unsigned int x,  unsigned char n ); 将双字节型变量x的值,向右循环移动n位,然后将

//其值返回;

//使能函数: _lror_( unsigned long x, unsigned char n ); 将4字节型变量x的值,向右循环移动n位,然后将

//其值返回;

//使能函数: _crol_( unsigned char x, unsigned char n ); 将字节型变量x的值,向左循环移动n位,然后将其

//值返回;

//使能函数: _irol_( unsigned int x,  unsigned char n ); 将双字节型变量x的值,向左循环移动n位,然后将

//其值返回;

//使能函数: _lrol_( unsigned long x, unsigned char n ); 将4字节型变量x的值,向左循环移动n位,然后将

//其值返回;

//以上的循环左移和循环右移,同C语言的左移和右移是不同的,使用时要小心;

#include <string.h>

#define OSC_FREQ     11059200L

//#define BAUD_115200  256 - (OSC_FREQ/192L)/115200L   //

//#define BAUD_38400   256 - (OSC_FREQ/192L)/38400L    //

#define BAUD_Time 1

#if(BAUD_Time==1)

//若波特率加倍,则使用下面参数;

#define BAUD_57600   256 - (OSC_FREQ/192L)/57600L    //255

#define BAUD_28800   256 - (OSC_FREQ/192L)/28800L    //254

#define BAUD_19200   256 - (OSC_FREQ/192L)/19200L    //253

#define BAUD_14400   256 - (OSC_FREQ/192L)/14400L    //252

#define BAUD_9600    256 - (OSC_FREQ/192L)/9600L     //250

#define BAUD_4800    256 - (OSC_FREQ/192L)/4800L     //244

#define BAUD_2400    256 - (OSC_FREQ/192L)/2400L     //232

#define BAUD_1200    256 - (OSC_FREQ/192L)/1200L     //208

#else

//若波特率不加倍,则使用下面参数;

#define BAUD_9600    256 - (OSC_FREQ/384L)/9600L

#define BAUD_4800    256 - (OSC_FREQ/384L)/4800L

#define BAUD_1200    256 - (OSC_FREQ/384L)/1200L

#endif

#define receive_buffer_size  30

unsigned char receive_buffer[receive_buffer_size];

bit Start_Flag,Receive_End_Flag;

unsigned char next_in;

//unsigned char crc8;

//函数功能:将y的第i_bit位,设置为1;

unsigned char bit_set( unsigned char y,unsigned char i_bit)

{ unsigned char temp;

  temp=1<<i_bit;

  y=temp|y;

  return(y);

}

//函数功能:将y的第i_bit位,设置为0;

unsigned char bit_clear(char y,char i_bit)

{ char temp;

  temp=1<<i_bit;

  temp=~temp;

  y&=temp;

  return(y);

}

//函数功能:若test_data的第test_bit位为1,则返回1,否则返回0;

bit bit_test(char test_data,char test_bit)

{ char temp;

  bit bit_value;

  temp=test_data;

  temp=temp>>test_bit;

  if( (temp&0x01)==0x01 ) bit_value=1;

  else bit_value=0;

  return(bit_value);

}

//函数功能:产生8位的CRC校验值;

unsigned char generate_8bit_crc(unsigned char* ptr, unsigned int length, unsigned char pattern)

{ unsigned char *current_data;

  unsigned char  crc_byte;

  unsigned int  byte_counter;

  unsigned char  bit_counter;

  current_data = ptr;

  crc_byte = *current_data++;

  for(byte_counter=0; byte_counter < (length-1); byte_counter++)

    { for(bit_counter=0; bit_counter < 8; bit_counter++)

        { if( !bit_test(crc_byte,7) )

      {  crc_byte=crc_byte<<1;

    bit_test( *current_data, 7 - bit_counter ) ? crc_byte=bit_set(crc_byte,0) : bit_clear(crc_byte,0);

             continue;

            }

          crc_byte <<= 1;

          bit_test(*current_data, 7 - bit_counter) ? crc_byte=bit_set(crc_byte,0) : bit_clear(crc_byte,0);

          crc_byte ^= pattern;

        }

      current_data++;

    }

  for(bit_counter=0; bit_counter < 8; bit_counter++)

    { if(!bit_test(crc_byte,7))

        { crc_byte <<= 1;

          continue;

        }

      crc_byte <<= 1;

      crc_byte ^= pattern;

    }

  return(crc_byte);

}

//函数功能:将'0'~'9','A'~'F'的ASCII码转换为十六进制(0x00~0x09,0x0a~0x0f)输出;

unsigned char ASCII_To_HEX(unsigned char ASCII )

{ unsigned char temp;

  if(ASCII<='9') temp=ASCII-'0';

  else temp=ASCII-0x37;

  return(temp);

}

//函数功能:从串口读入一个字符;

char getc()

{ char c;

  while (!RI);

  c = SBUF;

  RI = 0;

  return (c);

}

//函数功能:从串口输出一个字符;

void putc(char c)

{ SBUF=c;

  while (!TI);

  TI = 0;

}

//函数功能:接收和发送中断服务函数;

//数据格式:"$123xxxx*crc8\r\n";

//如:"$1234567890ABCDEF*06\r\n"

//如:"$1231234567890*31\r\n"

//crc8是CRC校验值,为十六进制的ASCII码,不包含'$'和校验值前面的那个'*'

void isr_UART(void) interrupt 4 using 0

{ unsigned char temp,crc8,crc_data;

  if( RI&&(!Receive_End_Flag) ) //处理接收数据;

    { temp=getc(); //从串口接收一个字节;

  receive_buffer[next_in]=temp;

  putc(temp);//调试时,使用;

  temp=next_in; //保存下标值;

  next_in++;    //修改下标值;

  if(temp<3) //比对从机地址是否为"$123"

    { if( Start_Flag )

    { if( (temp==0)&&(receive_buffer[0]!='1') ) next_in=0;

      if( (temp==1)&&(receive_buffer[1]!='2') ) next_in=0;

      if( (temp==2)&&(receive_buffer[2]!='3') ) next_in=0;

}

  else

    { if(receive_buffer[0]=='$') Start_Flag=1;

   next_in=0;

}

}

  else

    { if( (receive_buffer[temp-1]=='\r')&&(receive_buffer[temp]=='\n') ) //接收到"\r\n"

    { crc8=generate_8bit_crc( receive_buffer,temp-4,1); //计算接收到数据的CRC8校验值;

  crc_data=ASCII_To_HEX(receive_buffer[temp-3]);

  crc_data=(crc_data<<4)&0xf0; //获取CRC校验值的高4位值;

  temp=ASCII_To_HEX(receive_buffer[temp-2]); //获取CRC校验值的低4位值;

              crc_data=crc_data+temp; //获取接收到的CRC校验值;

  if(crc8==crc_data) //若CRC校验值正确,则执行下面语句;

    { Receive_End_Flag=1;

}

  next_in=0; //接收完成;

  Start_Flag=0;  //为下次接收起始标志做备;

}

}

      if(next_in>=receive_buffer_size)

    { next_in=0; //接收数据太长,取消接收;

  Start_Flag=0;  //为下次接收起始标志做备;

}

}

}

//函数功能:若接收到的数据有效,则打印出来;

void Print_Receive_data()

{ unsigned char i;

  i=0;   

  if(Receive_End_Flag)

    { while(receive_buffer[i]!='\n')

    { putc(receive_buffer[i]);

  i++;

}

  putc(receive_buffer[i]); //打印'\n';

  Receive_End_Flag=0;

    }

}

//函数功能:初始化串口,设置波特率为9600bps@11.0592MHz,使能接收,使用8位UART;

void Serial_Port_Initialization()

{ PCON = 0x80;

  SCON=0x50; //串行控制寄存器: SM0,SM1,SM2,REN,TB8,RB8,TI,RI

             //SM1:SM0=01,选择方式1,SM2=0,表示非多机通讯,8-bit UART;

     //REN=1,使能接收;

  TMOD&=0x0f;

  TMOD|= 0x20;

//定时器方式控制寄存器:GATE1,C/T1,M11,M10,GATE0,C/T0,M01,M00

      //GATE=0,TR置1便可以启动Timer;GATE=1,TR置1,且INT脚输入高电平,才可以启动Timer;

     //M11:M10=10,选择方式2,8位自动重装载; 

  TH1=BAUD_9600;  //TH1:  reload value for 9600 baud @11.0592MHz;

  TL1=TH1;

  TR1=1;   //启动Timer1;

  TI=0;    //为下次发送做准备;

  RI=0;

  next_in=0;

  Start_Flag=0;

  Receive_End_Flag=0; //将接收完成标志设置为0;

  ES=1; //使能串口接收和发送中断;

  EA=1; //开总中断 

}

//函数功能: Delay 50us

void delay_50us(unsigned char _50us)

{ while(_50us--)

{ _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

  _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

  _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

  _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

  _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

  _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

  _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

  _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();

    }

}

void main(void)

{

  Serial_Port_Initialization(); //初始化串口,设置波特率9600bps@11.0592MHz,使能接收,使用8位UART;

  for(;;)

    {  Print_Receive_data();  //若接收到的数据有效,则打印出来;

      delay_50us(20);    //延时1ms;

   }

}

/*

//函数功能:将hex8的低4位(0~9,a~f)转换为'0'~'9','A'~'F'输出;

unsigned char HEX_To_ASCII(unsigned char hex8 )

{unsigned char temp;

 temp=hex8;

 temp=(unsigned char)(temp&0x0f); //求低4位值;

 if(temp<0x0a) temp+=0x30;  //将低4位值(在0~9中)转换为ASCII码;

 else temp+=0x37;           //将低4位值(在a~f中)转换为大写字母的ASCII码;

 return(temp);

}

//函数功能:将'0'~'9','A'~'F'的ASCII码转换为十六进制(0x00~0x09,0x0a~0x0f)输出;

unsigned char ASCII_To_HEX(unsigned char ASCII )

{ unsigned char temp;

  if(ASCII<='9') temp=ASCII-'0';

  else temp=ASCII-0x37;

  return(temp);

}

//函数功能:将y的第i_bit位,设置为1;

unsigned char bit_set( unsigned char y,unsigned char i_bit)

{ unsigned char temp;

  temp=1<<i_bit;

  y=temp|y;

  return(y);

}

//函数功能:将y的第i_bit位,设置为0;

unsigned char bit_clear(char y,char i_bit)

{ char temp;

  temp=1<<i_bit;

  temp=~temp;

  y&=temp;

  return(y);

}

//函数功能:若test_data的第test_bit位为1,则返回1,否则返回0;

bit bit_test(char test_data,char test_bit)

{ char temp;

  bit bit_value;

  temp=test_data;

  temp=temp>>test_bit;

  if( (temp&0x01)==0x01 ) bit_value=1;

  else bit_value=0;

  return(bit_value);

}

//函数功能:产生8位的CRC校验值;

unsigned char generate_8bit_crc(unsigned char* ptr, unsigned int length, unsigned char pattern)

{ unsigned char *current_data;

  unsigned char  crc_byte;

  unsigned int  byte_counter;

  unsigned char  bit_counter;

  current_data = ptr;

  crc_byte = *current_data++;

  for(byte_counter=0; byte_counter < (length-1); byte_counter++)

    { for(bit_counter=0; bit_counter < 8; bit_counter++)

        { if( !bit_test(crc_byte,7) )

    {

  crc_byte=crc_byte<<1;

  bit_test( *current_data, 7 - bit_counter ) ? crc_byte=bit_set(crc_byte,0) : bit_clear(crc_byte,0);

              continue;

            }

          crc_byte <<= 1;

          bit_test(*current_data, 7 - bit_counter) ? crc_byte=bit_set(crc_byte,0) : bit_clear(crc_byte,0);

          crc_byte ^= pattern;

        }

      current_data++;

    }

  for(bit_counter=0; bit_counter < 8; bit_counter++)

    { if(!bit_test(crc_byte,7))

        { crc_byte <<= 1;

          continue;

        }

      crc_byte <<= 1;

      crc_byte ^= pattern;

    }

  return(crc_byte);

}

//函数功能:将y的第i_bit位,设置为1;调用方式: sbit_set(&x,i);

void bit_set( unsigned char *y,unsigned char i_bit)

{ unsigned char temp;

  temp=1<<i_bit;

  y[0]=temp|y[0];

}

//函数功能:将y的第i_bit位,设置为0;调用方式: sbit_clear(&x,i);

void bit_clear(char *y,char i_bit)

{ char temp;

  temp=1<<i_bit;

  temp=~temp;

  y[0]&=temp;

}

//函数功能:若test_data的第test_bit位为1,则返回1,否则返回0;

void bit_test(char test_data,char test_bit,unsigned char *return_value)

{ char temp;

  //bit bit_value;

  temp=test_data;

  temp=temp>>test_bit;   

  if( (temp&0x01)==0x01 ) return_value[0]=1;

  else return_value[0]=0;

  //return(bit_value);

}

//函数功能:产生8位的CRC校验值;

void generate_8bit_crc(unsigned char* ptr, unsigned int length, unsigned char *return_value )

{ unsigned char tenp_value;

  unsigned char *current_data;

  unsigned char  crc_byte;

  unsigned int  byte_counter;

  unsigned char  bit_counter;

  unsigned char pattern=0x01;

  current_data = ptr;

  crc_byte = *current_data++;

  for(byte_counter=0; byte_counter < (length-1); byte_counter++)

    { for(bit_counter=0; bit_counter < 8; bit_counter++)

        { bit_test( crc_byte,7,&tenp_value );

  //if( !bit_test(crc_byte,7) )

  if(tenp_value==0)

    {

  crc_byte=crc_byte<<1;

  bit_test( *current_data, 7 - bit_counter,&tenp_value );

  //bit_test( *current_data, 7 - bit_counter ) ? bit_set(crc_byte,0) : bit_clear(crc_byte,0);

  if(tenp_value==1) bit_set(&crc_byte,0);

  else bit_clear(&crc_byte,0);

              continue;

            }

          crc_byte <<= 1;

  bit_test( *current_data, 7 - bit_counter,&tenp_value );

          //bit_test(*current_data, 7 - bit_counter) ? crc_byte=bit_set(crc_byte,0) : bit_clear(crc_byte,0);

  if(tenp_value==1) bit_set(&crc_byte,0);

  else bit_clear(&crc_byte,0);

          crc_byte ^= pattern;

        }

      current_data++;

    }

  for(bit_counter=0; bit_counter < 8; bit_counter++)

    { bit_test( crc_byte,7,&tenp_value );

  //if(!bit_test(crc_byte,7))

  if(tenp_value==0)

        { crc_byte <<= 1;

          continue;

        }

      crc_byte <<= 1;

      crc_byte ^= pattern;

    }

  return_value[0]=crc_byte;

  //return(crc_byte);

}

*/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/961925
推荐阅读
相关标签
  

闽ICP备14008679号