📄 通讯ok.c
字号:
#include<reg52.h>// 包含52单片机头文件,此头文件中包含52单片机中的资源定义,包括IO口,寄存器等
#include"modbus.h"
uchar idata Send_buf[30];//发送数据数组
uchar idata Receive_buf[30];//接收数据数组
uchar count=0;//,time=0;//count为收到数据的次数,time应用于发送03代码时,中间的字数量是多少个数值
uchar flag_finish=0;//,flag_led=0;//是否接收完成位,flag_led暂时不用
uint begin_address=0;//,address_leg=0;//数值字开始位,数值字长度
uchar sign7,sign6,sign5,sign4,sign3,sign2,sign1,sign0;//用于判定发送的8个位,即0x1-0x8的位状态
//* LED亮灭情况表示相应的位状态,LED0-LED7分别对于0x1-0x8*//
sbit LED0=P1^0;
sbit LED1=P1^1;
sbit LED2=P1^2;
sbit LED3=P1^3;
sbit LED4=P1^4;
sbit LED5=P1^5;
sbit LED6=P1^6;
sbit LED7=P1^7;
/*************串口初始化函数***************/
/********设定的参数为9600,N,8,1*********/
void init_uart(void)
{
TH1=0xfa;
TL1=0xfa; // 波特率设为9600
TMOD=0x21; // 使用T1定时器,模式2
PCON=PCON | 0x80; // 启用波特率加强位
SCON=0x50; // 串口模式为2,即8位数据位,停止位为1,无校验
PS=1; // 设定串口中断优先级为最高
TR1=1; // 开始定时
ES=1; // 打开串口中断
EA=1; // 打开总中断
}
/******************发送函数******************/
/***********发送一个字符即一个字节***********/
void send(uchar num)
{
SBUF=num; //把字符放到发送数据缓存区SBUF,num可以是字符也可以是一个字节数据
while(!TI); //当发送完之后,TI自动置位,即TI=1,表示发送完成
TI=0; //当发送完之后TI不会自动置0,所以需手动将其置0,表示还没发送完数据
}
/**********************发送函数***********************/
/***********发送字符串或者一连串的字节数据************/
/****mydata表示要发送的字符串数组,num表示数组长度****/
void send_word(uchar *mydata,uchar num)
{
int i;
for(i=0;i<num;i++)
{
send(*(mydata+i));
}
count=0;
}
/********************中断接收函数**********************/
/****当数据接收完时,进入串口中断将接收的值放入数组****/
void comm() interrupt 4 using 1
{
if(RI) //当接收完一个字节的数据后,RI会自动置位,即RI=1
{
uchar a;
RI=0; //接受中断标志软件清零
a=SBUF; //把缓存在单片机的数据给a
Receive_buf[count]=a; //将接受数据放入预置数组
count++; //数组自动递增,用于存储下一个数据
if(count==8) //当接收完8个MODBUS的功能码之后,自动清0,从新接收(支持的01、05、03、06命令读取或者写入每次都发送8个字节)
{
count=0;
flag_finish=1; //接受完8个MODBUS功能码的标志位
}
}
}
/**************************MODBUS功能码处理***************************/
/********目前只能识别01,03,05,06功能码,而且只能挂载单台***********/
void command(void)
{
uint crc_end;//CEC校验值
char hi_type,low_type; //03、06功能码发送字节高低位
if(Receive_buf[1] == 0x01)//01功能码
{
crc_end=crc16(Receive_buf,6);//校验
if(crc_end==Receive_buf[6]<<8 | Receive_buf[7])//当校验一致时
{
hi_type=0;//高位状态
low_type=sign0 | sign1 | sign2 | sign3 | sign4 | sign5 | sign6 | sign7; //低位状态
Send_buf[0]=Receive_buf[0]; //站号
Send_buf[1]=Receive_buf[1]; //功能码
Send_buf[2]=0x02;//字节数
Send_buf[3]=low_type; //低位状态,即LED开关情况
Send_buf[4]=hi_type; //高位状态
crc_end=crc16(Send_buf,5); //校验
Send_buf[5]=crc_end%256;//校验低位
Send_buf[6]=crc_end/256;//校验高位
send_word(Send_buf,7);//发送返回屏
}
}
if(Receive_buf[1] == 0x05)//05功能码
{
begin_address=Receive_buf[3];//开始地址
crc_end=crc16(Receive_buf,6);//校验
if(crc_end==Receive_buf[6]<<8|Receive_buf[7])//校验正确时
{
if(Receive_buf[4]==0xff)//当为强制打开时
{
switch(begin_address)//对应的地址
{
case 0x00: LED0=0; sign0=0x01; break;//相应的LED点亮,记录下相应的P0位状态
case 0x01: LED1=0; sign1=0x02; break;
case 0x02: LED2=0; sign2=0x04; break;
case 0x03: LED3=0; sign3=0x08; break;
case 0x04: LED4=0; sign4=0x10; break;
case 0x05: LED5=0; sign5=0x20; break;
case 0x06: LED6=0; sign6=0x40; break;
case 0x07: LED7=0; sign7=0x80; break;
}
}
else//当强制为OFF时
{
switch(begin_address)
{
case 0x00: LED0=1; sign0=0; break;//相应的LED熄灭,记录下相应的P0位状态
case 0x01: LED1=1; sign1=0; break;
case 0x02: LED2=1; sign2=0; break;
case 0x03: LED3=1; sign3=0; break;
case 0x04: LED4=1; sign4=0; break;
case 0x05: LED5=1; sign5=0; break;
case 0x06: LED6=1; sign6=0; break;
case 0x07: LED7=1; sign7=0; break;
}
}
Send_buf[0]=Receive_buf[0]; //站号
Send_buf[1]=Receive_buf[1]; //功能码
Send_buf[2]=Receive_buf[2]; //起始高位
Send_buf[3]=Receive_buf[3]; //起始低位
Send_buf[4]=Receive_buf[4]; //返回状态
Send_buf[5]=Receive_buf[5]; //返回状态
crc_end=crc16(Send_buf,6); //校验
Send_buf[6]=crc_end%256;//校验低位
Send_buf[7]=crc_end/256;//校验高位
send_word(Send_buf,8);//发送返回屏
}
}
}
/*------------------ main code following -----------------*/
void main(void)
{
init_uart(); //初始化串口
while(1)
{
while(flag_finish) //当接收完成时
{
command(); //识别相应的功能码
flag_finish=0; //重新接收
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -