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

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

}

*/

相关推荐
7yewh8 小时前
Linux驱动开发 IIC I2C驱动 编写APP访问EEPROM AT24C02
linux·arm开发·驱动开发·嵌入式硬件·嵌入式
上海易硅智能科技局有限公司8 小时前
AG32 MCU 的电机控制方案
单片机·嵌入式硬件
程序员JerrySUN8 小时前
Yocto 项目 - 共享状态缓存 (Shared State Cache) 机制
linux·嵌入式硬件·物联网·缓存·系统架构
嵌入式小强工作室10 小时前
stm32能跑人工智能么
人工智能·stm32·嵌入式硬件
MikelSun10 小时前
电压控制环与电流控制环
单片机·嵌入式硬件·物联网
陌夏微秋11 小时前
STM32单片机芯片与内部45 UART 不定长度接收 标志位结束 定时器超时 串口空闲中断
stm32·单片机·嵌入式硬件·信息与通信·智能硬件
挥剑决浮云 -12 小时前
STM32学习之 按键/光敏电阻 控制 LED/蜂鸣器
c语言·经验分享·stm32·单片机·嵌入式硬件·学习
Whappy00113 小时前
第13部分 1.STM32之PWR电源控制-----4个实验
stm32·单片机·嵌入式硬件
冲,干,闯14 小时前
单片机里不想阻塞系统的延时
单片机·嵌入式硬件
小菜鸟学代码··14 小时前
STM32中断详解
stm32·单片机·嵌入式硬件