STM32C8T6 MODBUS_SLAVE_RTU

/*
UCOS_II
STM32F10x_FWLib V3.5.0
*/
[1]includes.h

#ifndef __INCLUDES_H__
#define __INCLUDES_H__
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>

#include "ucos_ii.h"
#include "os_cpu.h"
#include "os_cfg.h"

#include "sys.h"

#include "led.h"
#include "delay.h"
#include    "Seg_Moudle.h"
#include    "USART2_Configuration.h"
#include    "DMA1_CHANNEL_Configuration.h"
#include    "ModbusSlave.h"
#include    "key.h"
//#include    "RunMachine.h"
#include    "IIC.h"
#include    "AT24C32.h"
#include    "CRC16.h"

#endif

[2]USART2_Configuration.c

/* Includes ------------------------------------------------------------------*/
#ifndef __USART2_CONFIGURATION_H
#define __USART2_CONFIGURATION_H

#include "stdio.h"    
#include "sys.h" 
    
#define USART_REC_LEN    200      //定义最大接收字节数 200
#define EN_USART2_RX     1            //使能(1)/禁止(0)串口1接收
          
extern u8  USART2_RX_BUF[USART_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 ,对外使用
//extern u8  USART2_DMA_BUF[USART_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u8 USART2_RX_COUNT;    //接收长度记录    ,对外使用

//如果想串口中断接收,请不要注释以下宏定义
void USART2_Configuration(u16 baud);
#endif

[3] USART2_Configuration.c

#include    "includes.h"

void USART2_Configuration(u16 baud)
{
// 1、定义GPIO端口、串口USART、中断NVIC初始化结构体。

//定义初始化结构体
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_Structure;
    NVIC_InitTypeDef    NVIC_InitStructure;
#ifdef VECT_TAB_RAW
        NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);//向量表存放在RAM中
#else
        NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);//向量表存放在FLASH中
#endif    

//2、打开相关外设时钟,GPIOA的时钟和引脚都在APB2总线上,USART2的时钟和引脚都在APB1总线上,所以可以直接操作,如下

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//3、给GPIO结构体成员赋值,设置引脚功能
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA.1 ModbusSlave发送接收选择
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
    GPIO_Init(GPIOA, &GPIO_InitStructure);
        
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;    //择 PA.2(TXD) 和 PA.3(RXD)      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置输出速度
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //设置复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);              //调用Init函数初始化GPIO


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;          //择 PA.2(TXD) 和 PA.3(RXD)     
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //设置模式为浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);              //调用Init函数初始化GPIO

//4、初始化GPIO端口之后我们就要配置中断分组和串口中断优先级,中断优先级分组只用设置一次。
//NVIC的全称是Nested vectoredinterrupt controller,即嵌套向量中断控制器。


//5、以上配置好之后我们就可以来配置USART了
    USART_Cmd(USART2,DISABLE);
    USART_Structure.USART_BaudRate = baud;    //设置串口波特率
    USART_Structure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;    //启用接收和传输模式
    USART_Structure.USART_Parity = USART_Parity_No;                //设置奇偶校验位
    USART_Structure.USART_StopBits = USART_StopBits_1;            //设置停止位
    USART_Structure.USART_WordLength = USART_WordLength_8b;        //设置发送或接收数据长度
    USART_Structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    //指定是否启用硬件流控制模式
    USART_Init(USART2, &USART_Structure);                        //调用Init函数初始化USART设置
#if EN_USART2_RX          //如果使能了接收  
//Usart2 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器   
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);                //使能串口接收中断标志位,当标志位为1时会触发中断
#endif    
    USART_Cmd(USART2,ENABLE);                                    //使能串口1
    USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);    //启动了DMA通道,它既可响应连到该通道上的外设的DMA请求
    USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);    //启动了DMA通道,它既可响应连到该通道上的外设的DMA请求
    USART_ClearFlag(USART2, USART_IT_IDLE);                        //清除标志位,防止误报
}

//6、最后我们不能忘记了编写口串口接收中断函数
//u8  USART2_RX_BUF[USART_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
u8 USART2_RX_COUNT;    //接收状态标记    
void USART2_IRQHandler(void)  //串口中断函名字,固定写法
    {
            if(USART_GetFlagStatus(USART2, USART_FLAG_IDLE)!=RESET)
            {
                USART_ReceiveData(USART2);//清除IDLE flag
                DMA_Cmd(DMA1_Channel6,DISABLE);    
                USART2_RX_COUNT=USART_REC_LEN-DMA_GetCurrDataCounter(DMA1_Channel6);
                 DMA1_CHANNEL6_USART2RX_Configuration();                
            }
    }

[4] DMA1_CHANNEL_Configuration.h
#ifndef __DMA1_CHANNEL_CONFIGURATION_H
#define __DMA1_CHANNEL_CONFIGURATION_H
#include "stdio.h"    
#include "sys.h" 
#include "stm32f10x_dma.h"

#define DEBUG_USART2_DR_BASE               (USART2_BASE + 0x04)
#define DEBUG_USART_DMA1_CLK               RCC_AHBPeriph_DMA1        
#define DEBUG_USART2_DMA1_CHANNEL6           DMA1_Channel6
#define DEBUG_USART2_DMA1_CHANNEL7           DMA1_Channel7

void DMA1_CHANNEL6_USART2RX_Configuration(void);
void DMA1_CHANNEL7_USART2TX_Configuration(u8 * buf,u16 len);
void MyDMA_Config(DMA_Channel_TypeDef* DMA_CHx,
    u32 PeripheralAddr,
u32 MemoryAddr,
u32 TranDir,
u16 BufferSize);
#endif

[5] DMA1_CHANNEL_Configuration.c
#include "includes.h"
//u8 testA[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09};
//#define DEBUG_USART_DMA_STREAM            DMA1_Stream7
/***************************************
*Function Name    :    DMA1_CHANNEL6_USART2RX_Configuration(void)
*Description    : 配置DMA1的通道6为USART2RX
*INPUT1            :    None
*INPUT2            :    None
*RETURN            :    conResult
***************************************/ 
u8  USART2_RX_BUF[USART_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
void DMA1_CHANNEL6_USART2RX_Configuration()
{
  DMA_InitTypeDef DMA_InitStructure;

    /* 开启DMA时钟*/
    RCC_AHBPeriphClockCmd(DEBUG_USART_DMA1_CLK,ENABLE);    
    DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)DEBUG_USART2_DR_BASE;
    //ModbusSlave_RX_BUF
    DMA_InitStructure.DMA_MemoryBaseAddr=(u32)USART2_RX_BUF;//
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;///接收传输DMA_DIR_PeripheralSRC,发送传输:DMA_DIR_PeripheralDST
    DMA_InitStructure.DMA_BufferSize = USART_REC_LEN;//设置DMA在传输时缓冲区的长度
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA的外设递增模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//设置DMA的内存递增模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//设置DMA在访问时每次操作的数据长度
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
//    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA的优先级别:可以分为4级:VeryHigh,High,Medium,Low.
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//设置DMA的2个memory中的变量互相访问的
    DMA_Init(DEBUG_USART2_DMA1_CHANNEL6,&DMA_InitStructure);//统一对DMA整个模块做一次初始化,使得DMA各成员与上面的参数一致。
    DMA_Cmd(DEBUG_USART2_DMA1_CHANNEL6,ENABLE);//使能通道
}

void DMA1_CHANNEL7_USART2TX_Configuration(u8 * buf,u16 TX_BUFFER_SIZE)
{

  DMA_InitTypeDef DMA_InitStructure;
    /* 开启DMA时钟*/
    RCC_AHBPeriphClockCmd(DEBUG_USART_DMA1_CLK,ENABLE);
    DMA_Cmd(DMA1_Channel7,DISABLE);//失能通道    
    DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)DEBUG_USART2_DR_BASE;
    //ModbusSlave_RX_BUF
    DMA_InitStructure.DMA_MemoryBaseAddr=(u32)buf;//MAX64
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;///接收传输DMA_DIR_PeripheralSRC,发送传输:DMA_DIR_PeripheralDST
    DMA_InitStructure.DMA_BufferSize = TX_BUFFER_SIZE;//设置DMA在传输时缓冲区的长度
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA的外设递增模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//设置DMA的内存递增模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//设置DMA在访问时每次操作的数据长度
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
//    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA的优先级别:可以分为4级:VeryHigh,High,Medium,Low.
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//设置DMA的2个memory中的变量互相访问的
    
    DMA_Init(DEBUG_USART2_DMA1_CHANNEL7,&DMA_InitStructure);//统一对DMA整个模块做一次初始化,使得DMA各成员与上面的参数一致。
    DMA_Cmd(DEBUG_USART2_DMA1_CHANNEL7,ENABLE);//使能通道    
    
    DMA_ITConfig(DEBUG_USART2_DMA1_CHANNEL7, DMA_IT_TC, ENABLE);                //使能串口接收中断标志位,当标志位为1时会触发中断
    DMA_ClearFlag(DMA1_FLAG_TC7);                        //清除标志位,防止误报    
}

void DMA1_Channel7_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC7))    //通道6传输完成中断
    {
        DMA_ClearITPendingBit(DMA1_IT_GL7);    //清除DMA通道6中断全局标志位
        DMA_Cmd(DMA1_Channel7,DISABLE);//失能通道    
    }
}

[6]CRC16.h
#ifndef __CRC16_H
#define __CRC16_H
#include    "sys.h"
u16 crc16(u8 *puchMsg, u16 usDataLen);
#endif

[7]CRC16.C
u16 crc16(u8 *puchMsg, u16 usDataLen)
{
    // 多项式 x16+x15+x2+1(0x8005) 0x8005按位颠倒后的结果为0xA001
    u16 crc=0xffff;
    u8 i,j;
    if(usDataLen>78)return 0;
    j=0;
    while(j<usDataLen)
    {
        crc ^= puchMsg[j];
        for(i=0;i<8;i++)
        {//如果是1,则移位完了,再异或;如果是0,只移位
            if(crc&0x01)//A1先比较最右边一位
            {
                //把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位,如果移出位为1,CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
                crc>>=1;//A2再进行右移
                crc ^= 0xA001;            
            }
            else
            {
                crc>>=1;
            }
        }
        j++;
    }    
    i=crc%256;
    j=crc/256;
    crc=i*256+j;
    return crc;
}

[8]ModbusSlave.h
#ifndef __ModbusSlave_H
#define __ModbusSlave_H
#include    "includes.h"
#include    "sys.h"
#define USART_TX_LEN    128      //定义最大接收字节数 128
#define holdDataRegLength    32 //定义最大寄存器长度
#define inputDataRegLength 32 //定义最大寄存器长度
#define IXLength    5    //定义最大寄存器长度
#define OXLength    5    //定义最大寄存器长度

#define ReadCoilState        0x01        //读线圈量
#define ReadInputDis    0x02        //读输入离散量
#define ReadHoldReg        0x03        //读保持寄存器
#define ReadInputReg    0x04        //读输入寄存器
#define ForceSingleCoil 0x05        //写位
#define WriteMultiCoils   0x0F        //写多位
#define WriteSingleReg     0x06        //写单个寄存器
#define WriteMultiReg        0x10        //写多个寄存器

//modbus错误码
typedef enum Error_Code{
    ErrCmd = 1,    //非法功能码
    ErrAddr = 2,    //非法数据地址
    ErrData = 3,    //非法数据值
    ErrBreakdown = 4,    //从机设备故障
    ErrBLength = 5,    //数据过长
    ErrOthers = 6,    //其它错误
    ErrCRC = 8,    //校验错误    
}Error_Code_485;

//接收数据结构体
typedef struct{
    uint8_t nAddr;            
    uint8_t nCMD;
    uint16_t nRegStartAddr;
    uint16_t nRegLen;
    uint16_t Recv_Data[(USART_REC_LEN-6)/2];
        uint8_t Byte_Data[USART_REC_LEN-6];
}Stu485_Recv_t;

void ModbusSlave_TX_EN(u8 en);
void GetRegisterVal(u16 readStartPos,u16 *tempData);
void SetRegisterVal(u16 readStartPos,u16 *tempData);
void UsartClearRxBuffer(void);
void UsartClearTxBuffer(void);

void Read_CoilState(void);
void Read_InputDis(void);
void Read_HoldReg(void);
void Force_SingleCoil(void);
void Write_SingleReg(void);
void Write_MultiCoils(void);
void Write_MultiReg(void);

int Modbus_CRC_Check(u8 *buf,u8 len);
void Modbus_Send_Data(u8 *buf,u8 len);
void ModbusSlave(void);

u16 myPowTwo(u8 pow);
int LengthJudge(u8 nCMD,u16 startPos,u16 length,u16 typeofDataLength);

void Modbus_Send_Error(uint8_t Cmd, uint8_t Err);

#endif

[9]ModbusSlave.c
#include "includes.h"

u8 ModbusSlave_localAddr=1;//用于记录本站地址
u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
u8 ModbusSlave_TX_CNT=0;
u16 HoldDataReg[holdDataRegLength];
u16 InputDataReg[inputDataRegLength];
u16 OX[OXLength];   //代表是输出线圈,用功能码 0x01,0x05,0x0F 访问, 开头地址是 0 (这个后续说明)
u16 IX[IXLength];    //代表是输入线圈,用功能码 0x02 访问,开头地址是 1 (这个后续说明)
Stu485_Recv_t stu485Recv;


/*********************************
* Function Name : Modbus_Send_Data
* Description   : //485发送数据
* Input1         : u8 *buf要发送的数据
* Input2        : u8 len,要发送的字节数量
* Output        : None
* Return        : None

**********************************/
void Modbus_Send_Data(u8 *buf,u8 len)
{
    ModbusSlave_TX_EN(1); 
    DMA1_CHANNEL7_USART2TX_Configuration(buf,len);    
    USART2_RX_COUNT=0;
    ModbusSlave_TX_EN(0);//设为接收模式
}
/*********************************
* Function Name : Modbus_CRC_Check
* Description   : //查询485接收的数据CRC正确性
* Input1         : u8 *buf buf接收缓存首地址
* Input2        : u8 len 读到的数据长度
* Output        : None
* Return        : 校验正确返回1,否则返回0

**********************************/
int Modbus_CRC_Check(u8 *buf,u8 len)
{
    u8 ifRc=0;
    u16 crcCheck;
    //CRC校验
    crcCheck=crc16(buf,len-2);
    if(crcCheck==((buf[len-2]<<8)+buf[len-1]))
    {
        ifRc=1;//标志
    }
    return ifRc;    
}
/*********************************
* Function Name : ModbusSlave_TX_EN
* Description   : //设置485为发送还是接收(允许发送的IO口接max485的RE/DE,如USART2,PA1)
* Input1         : u8 en,1为发送,0为接收
* Output        : None
* Return        : None

**********************************/
void ModbusSlave_TX_EN(u8 en)
{
    if(en==1)
    {
        GPIO_SetBits(GPIOA,GPIO_Pin_1);
    }
    else
    {
        GPIO_ResetBits(GPIOA,GPIO_Pin_1);
    }
}

/*********************************
* Function Name : ModbusSlave
* Description   : //判断站号是否相同,并根据相应的功能码选择处理函数
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

“01”读取线圈状态
“02”读取输入状态
“03”保持型寄存器读取
“04”输入寄存器读取
“05”写单一线圈
“06”写单一寄存器
“15(0x0F)”写多线圈
“16(0x10)”写多寄存器

4.支持的MODBUS功能码
    功能码01H:读取开关量输出
    功能码02H:读取开关量输入
    功能码03H:读取保持寄存器
    功能码04H:读取输入寄存器
    功能码05H:强制单点继电器输出
 功能码06H:向保持寄存器写单个字
    功能码0FH:强制多个继电器输出
    功能码10H: 向保持寄存器(内存区)写多个16位的字(通讯对时)。
**********************************/
void ModbusSlave(void)
{
        if(USART2_RX_COUNT>=8)    //485通讯最少字节数
        {
            if(USART2_RX_BUF[0]==ModbusSlave_localAddr)//本地址才响应
            {
                if(Modbus_CRC_Check(USART2_RX_BUF,USART2_RX_COUNT))//CRC校验
                {
                    if(USART2_RX_BUF[1]==0x01||USART2_RX_BUF[1]==0x02||USART2_RX_BUF[1]==0x03||USART2_RX_BUF[1]==0x04||USART2_RX_BUF[1]==0x05||USART2_RX_BUF[1]==0x06||USART2_RX_BUF[1]==0x0F||USART2_RX_BUF[1]==0x10)//判断功能码
                    {
                        switch(USART2_RX_BUF[1])
                        {
                            case ReadCoilState:        Read_CoilState();//0x01
                                        break;
                            case ReadInputDis:        Read_InputDis();//0x02
                                        break;
                            case ReadHoldReg:         
                            case ReadInputReg:        Read_HoldReg();//0x03,0x04
                                        break;
                            case ForceSingleCoil:    Force_SingleCoil();//0x05                    
                                        break;
                            case WriteSingleReg:     Write_SingleReg();//0x06
                                        break;
                            case WriteMultiCoils:    Write_MultiCoils();//0x0f
                                        break;
                            case WriteMultiReg:        Write_MultiReg();//0x10
                                        break;
                        }
                    }
                    else
                    {
                        Modbus_Send_Error(USART2_RX_BUF[1],ErrCRC);//功能码错误
                    }
                }
                else
                {
                    //Modbus_Send_Error(uint8_t Cmd, uint8_t Err);
                    Modbus_Send_Error(USART2_RX_BUF[1],ErrCmd);//CRC校验错误                    
                }
            }
        }
}

/*********************************
* Function Name : LengthJudge()
* Description   : 判断操作的数据内容是否有超过数据总长
* Input1         : startPos 操作起始位置
* Input2        : length 操作的长度
* Input3        : regDataLength设备中规定的相应类型的数据的总长
* Output        : 返回处理的结果
* Return        : None

**********************************/
int LengthJudge(u8 nCmd,u16 startPos,u16 length,u16 typeofDataLength)
{
    if(length>typeofDataLength)//如果读取数量超过holdDataRegLength报错
    {
        Modbus_Send_Error(nCmd,ErrAddr);//地址错误
        return 0;
    }
    if(!((startPos+length)<(typeofDataLength+1)))//如果起始地址正确,且总长度小于内部寄存器长度(holdDataRegLength+1)
    {
        Modbus_Send_Error(nCmd,ErrAddr);    //数据过长
        return 0;
    }
    return 1;
}


/*********************************
* Function Name : GetRegisterVal
* Description   : //根据位置返回一个16位数据给指针
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

**********************************/
void GetRegisterVal(u16 readStartPos,u16 *tempData)
{
    *tempData=HoldDataReg[readStartPos];
}

/*********************************
* Function Name : SetRegisterVal
* Description   : //把相应位置的16位数据设置好
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

**********************************/
void SetRegisterVal(u16 writeStartPos,u16 *tempData)
{
    HoldDataReg[writeStartPos]=*tempData;
}

/*********************************
* Function Name : UsartClearBuffer
* Description   : //清除缓存区数据
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

**********************************/
void UsartClearRxBuffer(void)
{
    u8 i;
    //USART2_RX_BUF;
    //ModbusSlave_oneTime_Len;
    for(i=0;i<USART_REC_LEN;i++)
    {
        USART2_RX_BUF[i]=0xFF;
    }
}

void UsartClearTxBuffer(void)
{
//    u8 i;
//    //USART2_RX_BUF;
//    //ModbusSlave_oneTime_Len;
//    for(i=0;i<USART_TX_LEN;i++)
//    {
//        ModbusSlave_Tx_Buf[i]=0xFF;
//    }
}

/**************************************
//函数功能:Modbus错误码发送
//函数返回值:无
//函数形参:Cmd:命令码,Err:错误类型
//时间:2020/06/22
//备注:无
*************************************/
void Modbus_Send_Error(uint8_t Cmd, uint8_t Err)
{
    uint16_t crcCheck = 0;    

    ModbusSlave_Tx_Buf[0] = ModbusSlave_localAddr;
    ModbusSlave_Tx_Buf[1] = 0x80 + Cmd;            
    ModbusSlave_Tx_Buf[2] = Err;
    crcCheck=crc16(ModbusSlave_Tx_Buf,3);
    ModbusSlave_Tx_Buf[3]=crcCheck/256;
    ModbusSlave_Tx_Buf[4]=crcCheck%256;
    Modbus_Send_Data(ModbusSlave_Tx_Buf,5);
}

/**************************************
//函数功能:myPowTwo计算2的几次方
//函数返回值:无
//函数形参:Cmd:命令码,Err:错误类型
//时间:2020/06/22
//备注:无
*************************************/
u16 myPowTwo(u8 pow)
{
    u16 tmpA=1;
    tmpA = tmpA<<pow;
    return tmpA;
}

[10]Read_HoldReg.c
#include "includes.h"

extern u8 ModbusSlave_localAddr;//用于记录本站地址
extern u8 ModbusSlave_TX_CNT;
extern u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
extern Stu485_Recv_t stu485Recv;
extern u16 HoldDataReg[holdDataRegLength];
extern u16 InputDataReg[inputDataRegLength];
/*********************************
* Function Name : Read_HoldReg
* Description   : //读取保持寄存器0x03
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

**********************************/
void Read_HoldReg(void)
{
//    u8 i,j;
    stu485Recv.nAddr=USART2_RX_BUF[0];
    stu485Recv.nCMD=USART2_RX_BUF[1];
    stu485Recv.nRegStartAddr=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    stu485Recv.nRegLen=((USART2_RX_BUF[4]<<8)+USART2_RX_BUF[5]);;//0x06写单个16位寄存器
    if(stu485Recv.nCMD==ReadHoldReg)
    {
        if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,holdDataRegLength))
        {
            return;
        }
    }
    if(stu485Recv.nCMD==ReadInputReg)
    {
        if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,inputDataRegLength))
        {
            return;
        }
    }        
//    j=0;
    if(stu485Recv.nCMD==ReadHoldReg||stu485Recv.nCMD==ReadInputReg)
    {
        u16 byteCount,crcData;
        u16 tmpRsbuf[1];
        u16 i,j;
        ModbusSlave_TX_CNT=0;
        byteCount=stu485Recv.nRegLen*2;
        j=0;
        for(i=0;i<stu485Recv.nRegLen;i++)
        {
            if(stu485Recv.nCMD==ReadHoldReg)
            {
                memcpy(&tmpRsbuf,&HoldDataReg[stu485Recv.nRegStartAddr+i],2);//16位
            }
            if(stu485Recv.nCMD==ReadInputReg)
            {
                memcpy(&tmpRsbuf,&InputDataReg[stu485Recv.nRegStartAddr+i],2);//16位
            }
            ModbusSlave_Tx_Buf[j+3]=tmpRsbuf[0]>>8;
            ModbusSlave_Tx_Buf[j+4]=(u8)(tmpRsbuf[0]&0x00FF);
            j+=2;
        }
        ModbusSlave_Tx_Buf[0]=ModbusSlave_localAddr;
        ModbusSlave_Tx_Buf[1]=stu485Recv.nCMD;
        ModbusSlave_Tx_Buf[2]=byteCount;
        byteCount+=3;
        crcData=crc16(ModbusSlave_Tx_Buf,byteCount);
        ModbusSlave_Tx_Buf[byteCount] = crcData >> 8;
        byteCount++;
        ModbusSlave_Tx_Buf[byteCount] = crcData & 0xff;        
        ModbusSlave_TX_CNT = byteCount + 1;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,ModbusSlave_TX_CNT);    
        UsartClearRxBuffer();
        //ModbusSlave_TX_CNT;        
    }    
            
        UsartClearRxBuffer();
}


[11] Write_SingleReg.c
#include "includes.h"
#include    "ModbusSlave_A.h"

extern u8 ModbusSlave_localAddr;//用于记录本站地址
extern u8 ModbusSlave_TX_CNT;
extern u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
extern Stu485_Recv_t stu485Recv;
extern u16 HoldDataReg[holdDataRegLength];

/*********************************
* Function Name : Write_SingleReg
* Description   : 写单个寄存器0x06
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

主:01 06 00 00 ff fa 48 79 
//把40001(ffff)
从:01 06 00 00 ff fa 48 79

**********************************/
void Write_SingleReg(void)
{
    u16 i,j;
    stu485Recv.nAddr=USART2_RX_BUF[0];
    stu485Recv.nCMD=USART2_RX_BUF[1];
    stu485Recv.nRegStartAddr=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    stu485Recv.nRegLen=1;//0x06写单个16位寄存器
    memcpy(stu485Recv.Recv_Data,&USART2_RX_BUF[4],stu485Recv.nRegLen*2);//memcpy一次一个u8,u16要2个u8
    if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,holdDataRegLength))
    {
        return;
    }    
    j=0;
    for(i=0;i<stu485Recv.nRegLen;i+=2)
    {
        stu485Recv.Recv_Data[j]=((USART2_RX_BUF[i+4]<<8)+USART2_RX_BUF[i+5]);
        j++;
    }
    //实现具体写入功能
    if(stu485Recv.nCMD==WriteSingleReg)
    {
        u8 byteCount=0;
        u16 crcData;        
        memcpy(&HoldDataReg[stu485Recv.nRegStartAddr],&stu485Recv.Recv_Data,stu485Recv.nRegLen*2);
        ModbusSlave_Tx_Buf[4]=USART2_RX_BUF[4];
        ModbusSlave_Tx_Buf[5]=USART2_RX_BUF[5];
        byteCount+=2;
        ModbusSlave_Tx_Buf[0]=ModbusSlave_localAddr;
        ModbusSlave_Tx_Buf[1]=stu485Recv.nCMD;
        ModbusSlave_Tx_Buf[2]=(u8)(stu485Recv.nRegStartAddr>>8);
        ModbusSlave_Tx_Buf[3]=(u8)(stu485Recv.nRegStartAddr&0x00FF);
        byteCount+=4;        
        crcData=crc16(ModbusSlave_Tx_Buf,byteCount);
        ModbusSlave_Tx_Buf[byteCount] = crcData >> 8;
        byteCount++;
        ModbusSlave_Tx_Buf[byteCount] = crcData & 0xff;        
        ModbusSlave_TX_CNT = byteCount + 1;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,ModbusSlave_TX_CNT);        
    }    
            
        UsartClearRxBuffer();
}

/*********************************
//原有的程序保留一下
void ReadHoldRegisters(void)
{
    u16 readByteLength;
    u16 readStartPos;
    u8 readFunc;
    //u16 crcCheck;
    readByteLength=((USART2_RX_BUF[4]<<8)+USART2_RX_BUF[5]);
    readStartPos=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    readFunc=USART2_RX_BUF[1];
    if(!LengthJudge(0x03,readStartPos,readByteLength,holdDataRegLength))
    {
        return;
    }
    if(readFunc==0x03)
    {
        u16 byteCount,tempData,crcData;
        u8 i;
        ModbusSlave_TX_CNT=0;
        tempData=0;
        byteCount=readByteLength*2;
        for(i=0;i<byteCount;i+=2,readStartPos++)
        {
            GetRegisterVal(readStartPos,&tempData);                
            ModbusSlave_Tx_Buf[i+3] = tempData >> 8;                           
            ModbusSlave_Tx_Buf[i+4] = tempData & 0xff;                
        }
        
        ModbusSlave_Tx_Buf[0]=ModbusSlave_localAddr;
        ModbusSlave_Tx_Buf[1]=readFunc;
        ModbusSlave_Tx_Buf[2]=byteCount;
        byteCount+=3;
        crcData=crc16(ModbusSlave_Tx_Buf,byteCount);
        ModbusSlave_Tx_Buf[byteCount] = crcData >> 8;
        byteCount++;
        ModbusSlave_Tx_Buf[byteCount] = crcData & 0xff;
        
        ModbusSlave_TX_CNT = byteCount + 1;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,ModbusSlave_TX_CNT);    
        UsartClearRxBuffer();
        //ModbusSlave_TX_CNT;        
    }    
}
************************************/

[12] Write_MultiReg.c
#include "includes.h"
extern u8 ModbusSlave_localAddr;//用于记录本站地址
extern u8 ModbusSlave_TX_CNT;
extern u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
extern Stu485_Recv_t stu485Recv;
extern u16 HoldDataReg[holdDataRegLength];
/*********************************
* Function Name : Write_MultiRegister
* Description   : 写多个寄存器0x10
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

**********************************/
void Write_MultiReg(void)
{
    u16 i,j;
    stu485Recv.nAddr=USART2_RX_BUF[0];
    stu485Recv.nCMD=USART2_RX_BUF[1];
    stu485Recv.nRegStartAddr=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    stu485Recv.nRegLen=((USART2_RX_BUF[4]<<8)+USART2_RX_BUF[5]);//0x06写单个16位寄存器
    //memcpy(stu485Recv.Recv_Data,&USART2_RX_BUF[4],stu485Recv.nRegLen*2);
    if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,holdDataRegLength))
    {
        return;
    }
    
    j=0;
    for(i=0;i<stu485Recv.nRegLen*2;i+=2)
    {
        stu485Recv.Recv_Data[j]=((USART2_RX_BUF[i+7]<<8)+USART2_RX_BUF[i+8]);
        j++;
    }
    if(stu485Recv.nRegStartAddr>holdDataRegLength)//判断寄存器地址
    {
            Modbus_Send_Error(USART2_RX_BUF[1],ErrAddr);//地址错误
            return;            
    }    
    //实现具体写入功能
    if(stu485Recv.nCMD==WriteMultiReg)
    {
        u16 crcCheck;
        memcpy(&HoldDataReg[stu485Recv.nRegStartAddr],&stu485Recv.Recv_Data,stu485Recv.nRegLen*2);
        ModbusSlave_Tx_Buf[0]=stu485Recv.nAddr;
        ModbusSlave_Tx_Buf[1]=stu485Recv.nCMD;
        ModbusSlave_Tx_Buf[2]=stu485Recv.nRegStartAddr/256;
        ModbusSlave_Tx_Buf[3]=stu485Recv.nRegStartAddr%256;
        ModbusSlave_Tx_Buf[4]=stu485Recv.nRegLen/256;
        ModbusSlave_Tx_Buf[5]=stu485Recv.nRegLen%256;        
        crcCheck=crc16(ModbusSlave_Tx_Buf,6);        
        ModbusSlave_Tx_Buf[6]=crcCheck/256;
        ModbusSlave_Tx_Buf[7]=crcCheck%256;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,8);    
        UsartClearRxBuffer();
    }    
}

[13] Read_CoilState.c  说到写线圈,不得不说自己指针没有学好,写得自己都不好意思贴出来
#include "includes.h"

extern u8 ModbusSlave_localAddr;//用于记录本站地址
extern u8 ModbusSlave_TX_CNT;
extern u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
extern u16 OX[OXLength];
extern Stu485_Recv_t stu485Recv;
/*********************************
* Function Name : Read_CoilState
* Description   : //读输出线圈//0x01
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

**********************************/
void Read_CoilState(void)
{
    u16 byteCount,crcData;
    u16 i,j;
    u8 XXArray[OXLength*16]; //这里就是我SB的地方了,不会啊,没办法,只有用这个替代了。
    stu485Recv.nAddr=USART2_RX_BUF[0];
    stu485Recv.nCMD=USART2_RX_BUF[1];
    stu485Recv.nRegStartAddr=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    stu485Recv.nRegLen=((USART2_RX_BUF[4]<<8)+USART2_RX_BUF[5]);//0x06写单个16位寄存器
    //判断数据是否超长
    if(stu485Recv.nCMD==ReadCoilState)
    {
        if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,OXLength*16))
        {
            return;
        }    
        for(i=0;i<OXLength;i++)
        {
            for(j=0;j<16;j++)
            {
                XXArray[i*16+j]=((OX[i]&myPowTwo(j))>0)?1:0;
            }
        }
        
        //开始处理数据

        byteCount=stu485Recv.nRegLen/8;
        for(i=0;i<byteCount;i++)
        {
            u16 tmpA=0;
            for(j=0;j<8;j++)
            {
                tmpA +=(XXArray[stu485Recv.nRegStartAddr+i*8+j]<<j);
            }
            stu485Recv.Byte_Data[i]=tmpA;
        }
        if(stu485Recv.nRegLen%8!=0)//把余下的加进来
        {
            u8 tmpByte=0;
            for(i=0;i<stu485Recv.nRegLen%8;i++)
            {
                tmpByte+=(XXArray[(stu485Recv.nRegStartAddr+8*byteCount)+i]<<i);
            }
            stu485Recv.Byte_Data[byteCount]=tmpByte;
            byteCount++;
        }
        
        
        //组合数据发送
        memcpy(&ModbusSlave_Tx_Buf[3],&stu485Recv.Byte_Data,byteCount*2);//byteCount=4位,所以,u8=byteCount*2
        ModbusSlave_Tx_Buf[0]=ModbusSlave_localAddr;
        ModbusSlave_Tx_Buf[1]=stu485Recv.nCMD;
        ModbusSlave_Tx_Buf[2]=byteCount;
        byteCount+=3;        
        crcData=crc16(ModbusSlave_Tx_Buf,byteCount);
        ModbusSlave_Tx_Buf[byteCount] = crcData >> 8;
        byteCount++;
        ModbusSlave_Tx_Buf[byteCount] = crcData & 0xff;        
        ModbusSlave_TX_CNT = byteCount + 1;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,ModbusSlave_TX_CNT);
                
        UsartClearRxBuffer();
    }
}

[14]Read_InputDis.c //这是最开始SB的写法,虽然0x01和0x02执行过程是一样的,但是还是保留了下来
#include "includes.h"
#include    "ModbusSlave_A.h"

extern u8 ModbusSlave_localAddr;//用于记录本站地址
extern u8 ModbusSlave_TX_CNT;
extern u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
extern Stu485_Recv_t stu485Recv;
extern u16 IX[IXLength];

/*********************************
* Function Name : Read_InputDis
* Description   : //输入开关量状态//x02
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

**********************************/
void Read_InputDis(void)
{
    u16 byteCount,crcData;
    u16 i;
    u8 XXArray[IXLength*16];

    stu485Recv.nAddr=USART2_RX_BUF[0];
    stu485Recv.nCMD=USART2_RX_BUF[1];
    stu485Recv.nRegStartAddr=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    stu485Recv.nRegLen=((USART2_RX_BUF[4]<<8)+USART2_RX_BUF[5]);//0x06写单个16位寄存器
    //判断数据是否超长
    if(stu485Recv.nCMD==ReadInputDis)
    {
        if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,IXLength*16))
        {
            return;
        }
        for(i=0;i<IXLength;i++)
        {
            //低八位
            XXArray[i*16+0]=((IX[i]&0x0001)>0)?1:0;//10001
            XXArray[i*16+1]=((IX[i]&0x0002)>0)?1:0;
            XXArray[i*16+2]=((IX[i]&0x0004)>0)?1:0;
            XXArray[i*16+3]=((IX[i]&0x0008)>0)?1:0;
            XXArray[i*16+4]=((IX[i]&0x0010)>0)?1:0;
            XXArray[i*16+5]=((IX[i]&0x0020)>0)?1:0;
            XXArray[i*16+6]=((IX[i]&0x0040)>0)?1:0;//10007
            XXArray[i*16+7]=((IX[i]&0x0080)>0)?1:0;//10008
            //高八位
            XXArray[i*16+8]=((IX[i]&0x0100)>0)?1:0;//10009
            XXArray[i*16+9]=((IX[i]&0x0200)>0)?1:0;
            XXArray[i*16+10]=((IX[i]&0x0400)>0)?1:0;
            XXArray[i*16+11]=((IX[i]&0x0800)>0)?1:0;
            XXArray[i*16+12]=((IX[i]&0x1000)>0)?1:0;
            XXArray[i*16+13]=((IX[i]&0x2000)>0)?1:0;
            XXArray[i*16+14]=((IX[i]&0x4000)>0)?1:0;
            XXArray[i*16+15]=((IX[i]&0x8000)>0)?1:0;//10016
        }    
    //开始处理数据

        byteCount=stu485Recv.nRegLen/8;
        for(i=0;i<byteCount;i++)
        {
            stu485Recv.Byte_Data[i]=
            XXArray[stu485Recv.nRegStartAddr+i*8+0]+
            (XXArray[stu485Recv.nRegStartAddr+i*8+1]<<1)+
            (XXArray[stu485Recv.nRegStartAddr+i*8+2]<<2)+
            (XXArray[stu485Recv.nRegStartAddr+i*8+3]<<3)+
            (XXArray[stu485Recv.nRegStartAddr+i*8+4]<<4)+
            (XXArray[stu485Recv.nRegStartAddr+i*8+5]<<5)+
            (XXArray[stu485Recv.nRegStartAddr+i*8+6]<<6)+
            (XXArray[stu485Recv.nRegStartAddr+i*8+7]<<7);
        }
        if(stu485Recv.nRegLen%8!=0)//把余下的加进来
        {
            u8 tmpByte=0;
            for(i=0;i<stu485Recv.nRegLen%8;i++)
            {
                tmpByte+=(XXArray[(stu485Recv.nRegStartAddr+8*byteCount)+i]<<i);
            }
            stu485Recv.Byte_Data[byteCount]=tmpByte;
            byteCount++;
        }
        
        
        //组合数据发送
        memcpy(&ModbusSlave_Tx_Buf[3],&stu485Recv.Byte_Data,byteCount*2);//byteCount=4位,所以,u8=byteCount*2
        ModbusSlave_Tx_Buf[0]=ModbusSlave_localAddr;
        ModbusSlave_Tx_Buf[1]=stu485Recv.nCMD;
        ModbusSlave_Tx_Buf[2]=byteCount;
        byteCount+=3;        
        crcData=crc16(ModbusSlave_Tx_Buf,byteCount);
        ModbusSlave_Tx_Buf[byteCount] = crcData >> 8;
        byteCount++;
        ModbusSlave_Tx_Buf[byteCount] = crcData & 0xff;        
        ModbusSlave_TX_CNT = byteCount + 1;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,ModbusSlave_TX_CNT);
    }
            
        UsartClearRxBuffer();
}

[15] Force_SingleCoil.c
#include "includes.h"

extern u8 ModbusSlave_localAddr;//用于记录本站地址
extern u8 ModbusSlave_TX_CNT;
extern u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
extern u16 OX[OXLength];
extern Stu485_Recv_t stu485Recv;

/*********************************
* Function Name : Force_SingleCoil
* Description   : //强制单个线圈//0x05
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

*    主:01 05 00 00 ff 000 8c 3a    //把10001置1
*    从:01 05 00 00 ff 000 8c 3a

**********************************/
void Force_SingleCoil(void)
{
    u16 coilBytePos;
    u8 coilArrayPos;
    stu485Recv.nAddr=USART2_RX_BUF[0];
    stu485Recv.nCMD=USART2_RX_BUF[1];
    stu485Recv.nRegStartAddr=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    stu485Recv.nRegLen=1;
    stu485Recv.Recv_Data[0]=((USART2_RX_BUF[4]<<8)+USART2_RX_BUF[5]);
    if(stu485Recv.nCMD==ForceSingleCoil)
    {
        //u16 crcCheck;
        u8 byteCount=0;
        u16 crcData;
        //memcpy(&HoldDataReg[stu485Recv.nRegStartAddr],&stu485Recv.Recv_Data,stu485Recv.nRegLen*2);
        if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,OXLength*16))
        {
            return;
        }    
        coilBytePos=stu485Recv.nRegStartAddr/16;
        coilArrayPos=stu485Recv.nRegStartAddr%16;
        if(stu485Recv.Recv_Data[0])
        {
            OX[coilBytePos]=OX[coilBytePos]|(1<<coilArrayPos);
        }
        else
        {
            OX[coilBytePos]=OX[coilBytePos]&(~(1<<coilArrayPos));
        }    
        ModbusSlave_Tx_Buf[4]=USART2_RX_BUF[4];
        ModbusSlave_Tx_Buf[5]=USART2_RX_BUF[5];
        byteCount+=2;
        ModbusSlave_Tx_Buf[0]=ModbusSlave_localAddr;
        ModbusSlave_Tx_Buf[1]=stu485Recv.nCMD;
        ModbusSlave_Tx_Buf[2]=(u8)(stu485Recv.nRegStartAddr>>8);
        ModbusSlave_Tx_Buf[3]=(u8)(stu485Recv.nRegStartAddr&0x00FF);
        byteCount+=4;        
        crcData=crc16(ModbusSlave_Tx_Buf,byteCount);
        ModbusSlave_Tx_Buf[byteCount] = crcData >> 8;
        byteCount++;
        ModbusSlave_Tx_Buf[byteCount] = crcData & 0xff;        
        ModbusSlave_TX_CNT = byteCount + 1;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,ModbusSlave_TX_CNT);    
    }    
            
        UsartClearRxBuffer();
}

[16] Write_MultiCoils.c
#include "includes.h"

extern u8 ModbusSlave_localAddr;//用于记录本站地址
extern u8 ModbusSlave_TX_CNT;
extern u8 ModbusSlave_Tx_Buf[USART_TX_LEN];//
extern u16 OX[OXLength];
extern Stu485_Recv_t stu485Recv;

/*********************************
* Function Name : Write_MultiCoils
* Description   : 写多个寄存器0x0f
* Input1         : 
* Input2        : 
* Output        : None
* Return        : None

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

void Write_MultiCoils(void)
{
    u16 crcData;
    u8 byteCount=0;
    u16 i,j,k;
    u8 XXArray[OXLength*16];

    stu485Recv.nAddr=USART2_RX_BUF[0];
    stu485Recv.nCMD=USART2_RX_BUF[1];
    stu485Recv.nRegStartAddr=((USART2_RX_BUF[2]<<8)+USART2_RX_BUF[3]);
    stu485Recv.nRegLen=((USART2_RX_BUF[4]<<8)+USART2_RX_BUF[5]);
    memcpy(stu485Recv.Byte_Data,&USART2_RX_BUF[7],USART2_RX_BUF[6]);
    if(stu485Recv.nCMD==WriteMultiCoils)
    {
        if(!LengthJudge(stu485Recv.nCMD,stu485Recv.nRegStartAddr,stu485Recv.nRegLen,OXLength*16))
        {
            return;
        }
        for(i=0;i<OXLength;i++)
        {
    /*
    主:H 01 0f 00 01 00 17 03 80 80 40 65 6d    0x17=23
    // 0x3f=高00111111低 0xbf=10111111
    //把10001置0 把10002置0 10003置0 10004置0 10005置0 10006置0 10007置0 10008置1 
    //把10009置0 把10010置0 10011置0 10012置0 10013置0 10014置0 10015置0 10016置1
    //把10017置0 把10018置0 10019置0 10020置0 10021置0 10022置0 10023置1
    从:H 01 0f 00 01 00 17 44 05
    */
            for(j=0;j<16;j++)
            {
                XXArray[i*16+j]=((OX[i]&myPowTwo(j))>0)?1:0;
            }
        }            
        
        //开始处理数据
        //MoveMemToStart(u16 startPos, u16 nLength,u16 * MemorySourece, u16 * MemoryDest)
        j=0;
        for(i=0;i<stu485Recv.nRegLen/8;i++)
        {
            for(k=0;k<8;k++)
            {
            XXArray[stu485Recv.nRegStartAddr+j]=((stu485Recv.Byte_Data[i]&myPowTwo(k))>0)?1:0;
                j++;
            }
        }
        //补足8的余数
        if(stu485Recv.nRegLen%8!=0)
        {
            for(i=0;i<stu485Recv.nRegLen%8;i++)
            {
                XXArray[stu485Recv.nRegStartAddr+j]=((stu485Recv.Byte_Data[stu485Recv.nRegLen/8]&myPowTwo(i))>0)?1:0;
                j++;
            }
        }
        //存回OX
        for(i=0;i<OXLength;i++)
        {
            OX[i]=0;//16位
            for(j=0;j<16;j++)
            {
                //XXArray[i*16+j]=((OX[i]&myPowTwo(j))>0)?1:0;
                OX[i]+=XXArray[i*16+j]<<j;
            }
        }    
        
        //实现内存按start位置移动至新区域
        /*
        主:H 01 0f 00 01 00 17 03 80 80 40 65 6d    0x17=23
        从:H 01 0f 00 01 00 17 44 05
        */
        
        ModbusSlave_Tx_Buf[0]=ModbusSlave_localAddr;
        ModbusSlave_Tx_Buf[1]=stu485Recv.nCMD;
        ModbusSlave_Tx_Buf[2]=USART2_RX_BUF[2];
        ModbusSlave_Tx_Buf[3]=USART2_RX_BUF[3];
        ModbusSlave_Tx_Buf[4]=USART2_RX_BUF[4];
        ModbusSlave_Tx_Buf[5]=USART2_RX_BUF[5];
        byteCount=6;        
        crcData=crc16(ModbusSlave_Tx_Buf,byteCount);
        ModbusSlave_Tx_Buf[byteCount] = crcData >> 8;
        byteCount++;
        ModbusSlave_Tx_Buf[byteCount] = crcData & 0xff;        
        ModbusSlave_TX_CNT = byteCount + 1;
        Modbus_Send_Data(ModbusSlave_Tx_Buf,ModbusSlave_TX_CNT);    
    }        
        UsartClearRxBuffer();
}

[17]至于UCOSII及其它的这里就不写了。
自己也是刚学STM32三个月,很多地方都还不懂,甚至有些源程序都是看别人写的。
只是苦于MODBUS_SLAVE_RTU查找的资料不多,就把自己的思路分享出来。v

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值