本章重点介绍串口多机通讯使用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);
}
*/