单片机
返回首页

基于RS485主从结构通信单片机代码

2020-08-21 来源:51hei

RS485主从结构通信代码,用于组网内部通信

单片机源程序如下:

#ifndef        _485MON_H                                 // 防止485Mon.h被重复引用

#define        _485MON_H


#include                             // 引用标准库的头文件

#include

#include


#define uchar unsigned char

#define uint unsigned int


#define ACTIVE          0x11

#define GETDATA          0x22

#define READY                  0x33

#define SENDDATA        0x44        


#define RECFRMMAXLEN 16                 // 接收帧的最大长度,超过此值认为帧超长错误

#define STATUSMAXLEN 10                        // 设备状态信息最大长度         


uchar DevNo;                                        // 设备号

xdata uchar StatusBuf[STATUSMAXLEN];


//为简化起见,假设了10位固定的采集数据

#define DATA0          0x10

#define DATA1          0x20

#define DATA2          0x30

#define DATA3          0x40

#define DATA4          0x50

#define DATA5          0x60

#define DATA6          0x70

#define DATA7          0x80

#define DATA8          0x90

#define DATA9          0xA0

sbit DE = P1^6;                        //驱动器使能,1有效

sbit RE = P1^7;                        //接收器使能,0有效

void init();                                        // 系统初始化

void Get_Stat();                                // 简化的数据采集函数

bit Recv_Data(uchar *type);                // 接收数据帧函数

void Send(uchar m);                                        // 发送单字节数据

void Send_Data(uchar type,uchar len,uchar *buf);                                // 发送数据帧函数        

void Clr_StatusBuf();                        //  清除设备状态信息缓冲区函数   

/****************************************/

/* Copyright (c) 2005, 通信工程学院     */

/* All rights reserved.                 */

/****************************************/


#include '485Mon.h'

void main(void)

{

        uchar type;


        /* 初始化 */

        init();

        

        while (1)

        {

                if (Recv_Data(&type)==0)                        // 接收帧错误或者地址不符合,丢弃

                        continue;

                switch (type)

                {

                        case ACTIVE:                                // 主机询问从机是否在位

                                Send_Data(READY,0,StatusBuf);        // 发送READY指令

                                break;

                        case GETDATA:                                // 主机读设备请求

                                Clr_StatusBuf();

                                Get_Stat();                                // 数据采集函数

                                Send_Data(SENDDATA,strlen(StatusBuf),StatusBuf);

                                break;

                        default:

                                break;                                        // 指令类型错误,丢弃当前帧

                }

        }

}


/* 初始化 */

void init(void)

{

        P1 = 0xff;

        DevNo = (P1&0x00111111);                        // 读取本机设备号


        TMOD = 0x20;

        SCON = 0x50;

        TH1 = 0xfd;

        TL1 = 0xfd;

        TR1 = 1;

        PCON = 0x00;                                                // SMOD=0

        EA = 0;

                                                

}


/* 接收数据帧函数,实际上接收的是主机的指令 */

bit Recv_Data(uchar *type)

{

        uchar tmp,rCount,i;

        uchar r_buf[RECFRMMAXLEN];                        // 保存接收到的帧

        uchar Flag_RecvOver;                                // 一帧接收结束标志        

        uchar Flag_StartRec;                                // 一帧开始接收标志

        uchar CheckSum;                                                // 校验和

        uchar DataLen;                                                // 数据字节长度变量

               

        /* 禁止发送,允许接收 */

        DE = 0;

        RE = 0;


        /* 接收一帧数据 */

        rCount = 0;

        Flag_StartRec = 0;

    Flag_RecvOver = 0;

        while (!Flag_RecvOver)

        {

                RI = 0;

                while (!RI);

                tmp = SBUF;

                RI=0;


                /* 判断是否收到字符',其数值为0x24 */         

                if ((!Flag_StartRec) && (tmp == 0x24))

                {

                        Flag_StartRec = 1;        

                }


                if (Flag_StartRec)

                {

                        r_buf[rCount] = tmp;

                        rCount ++;               

                        

                        /* 判断是否收到字符'*',其数值为0x2A,根据接收的指令设置相应标志位 */

                        if (tmp == 0x2A)

                                Flag_RecvOver = 1;

                }


                if (rCount == RECFRMMAXLEN)                // 帧超长错误,返回0

                        return 0;

        }

        

        /* 计算校验和字节 */

        CheckSum = 0;

        DataLen = r_buf[3];

        for (i=0;i++;i<3+DataLen)

        {

                CheckSum = CheckSum + r_buf[i+1];

        }

        

        /* 判断帧是否错误 */

        if (rCount<6)                                                // 帧过短错误,返回0,最短的指令帧为6个字节                                                

                return 0;

        if (r_buf[1]!=DevNo)                                  // 地址不符合,错误,返回0

                return 0;

        if (r_buf[rCount-2]!=CheckSum)                // 校验错误,返回0

            return 0;


        *type = r_buf[2];                                        // 获取指令类型


        return 1;                                                        // 成功,返回1

}


/* 发送数据帧函数 */

void Send_Data(uchar type,uchar len,uchar *buf)

{

        uchar i,tmp;

        uchar CheckSum = 0;

        

        /* 允许发送,禁止接收 */

        DE = 1;

        RE = 1;

        

        /* 发送帧起始字节 */

        tmp = 0x24;

        Send(tmp);

        

        Send(DevNo);                                                // 发送地址字节,也即设备号

        CheckSum = CheckSum + DevNo;


        Send(type);                                                        // 发送类型字节

        CheckSum = CheckSum + type;


        Send(len);                                                        // 发送数据长度字节

        CheckSum = CheckSum + len;


        /* 发送数据 */

        for (i=0;i        {

                Send(*buf);

                CheckSum = CheckSum + *buf;

                buf++;

        }

        

        Send(CheckSum);                                                // 发送校验和字节


        /* 发送帧结束字节 */

        tmp = 0x2A;

        Send(tmp);

}


/* 采集数据函数经过简化处理,取固定的10个字节数据 */

void Get_Stat(void)

{

        StatusBuf[0]=DATA0;

        StatusBuf[1]=DATA1;

        StatusBuf[2]=DATA2;

        StatusBuf[3]=DATA3;

……………………



进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • CCD图像传感器在微光电视系统中的应用

  • 如何利用ESP8266制作一个简单的四轴飞行器

  • 非常简单的150W功放电路图

  • 基于IC555的可变PWM振荡器电路

  • 优化电路板布局的简单方法

  • 分享一个电网倾角计电路

    相关电子头条文章