精华内容
下载资源
问答
  • STM32_Modbus通信实例

    2019-06-28 17:00:16
    STM32实现485通信例程,modbus协议从机通信实例,源码打包
  • 基于STM32modbus通信工程,可与组态王做界面的触摸屏通信,外加重定义的printf调试输出实现
  • stm32f103实现modbus通信,通信方式为RS485,只需设置程序变量model,自由切换主从模式。已通过调试,放心采纳
  • 利用STM32F1实现Modbus实现多台从机的通信,可以利用PC机串口助手下发指令,然后通过232回传数据。经过测试,可以在一个主机6个从机的系统中稳定运行
  • 毕业设计自己要做个基于STM32的PLC能直接跑语句表的,现在看来好像没有什么创新的地方,不过实现的方式绝对够创新的了...呵呵。自己写的开题报告中说了要有高级的通信功能。现在做以太网有点来不及了,CAN又感觉不搭...

     毕业设计自己要做个基于STM32的PLC能直接跑语句表的,现在看来好像没有什么创新的地方,不过实现的方式绝对够创新的了...呵呵。自己写的开题报告中说了要有高级的通信功能。现在做以太网有点来不及了,CAN又感觉不搭调,硬件上也没准备。串口上跑Modbus感觉不错。本来西门子的S7-200就能跑Modbus,STM32-PLC当然也要支持Modbus 什么 组态软件,触摸屏都可以连上,不过FreeModbus只支持从机有点可惜,当然本来协议也不难而且也必要实现全协议栈。

    Modbus中文协议.PDF

    STM32移植FreeModbus的步骤:

    首先去 http://www.freemodbus.org 下载文件 一定要是官方可靠的才行,我起先为了图方便网上随便下载了一个,结果白白浪费了一下午的时间

    不知道是哪里被改动了。目前最新的版本是1.5。

    http://115.com/file/bee0jrth#freemodbus-v1.5.0.zip 这是官方的可靠版本。

    Demo 文件夹下都是官方移植好的其他芯片的版本。选BARE文件下的“赤裸”文件加入工程 同时添加全部的库文件,可参考下图

    FreeModbus 移植于STM32 实现Modbus RTU通行 - java - stm32学习日志 

    需要移植修改的在 port 目录下
    porttimer.c
    中 xMBPortTimersInit( USHORT usTim1Timerout50us ) 负责配置一个 时基 ,vMBPortTimersEnable(  ) 启用这个时基。

    比如执行

    xMBPortTimersInit( 10000 );
    vMBPortTimersEnable( );
    for( ;; );
    定时器按中断内 便会每500MS调用一次pxMBPortCBTimerExpired(  );同时你也要检测vMBPortTimersDisable( ) 是否可以可靠的关闭定时器。用仿真器 用LED灯都行的.


    portother.c

    //负责一个串口的配置 为了省事我只支持了波特率的修改

    xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )

    vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )负责控制串口【收/发】中断的禁止与使能

    pxMBFrameCBByteReceived(  ); //在串口接收中断内调用 用于通讯侦测

    pxMBFrameCBTransmitterEmpty(  ); //在串口发送中断内调用 用于告知完成了发送 发送缓冲为空

    xMBPortSerialGetByte( CHAR * pucByte ) xMBPortSerialPutByte( CHAR ucByte ) 两个为 串口字节的收发

    port.h

    中定义了 全局中断的开关

    #define ENTER_CRITICAL_SECTION( )   __set_PRIMASK(1) /*关中中断*/
    #define EXIT_CRITICAL_SECTION( )    __set_PRIMASK(0) /*开总中断*/
    __set_PRIMASK() 来源于 core_cm3.c 
    这个头文件中添加了#include <assert.h> assert() 断言宏 freeModbus的作者有点意思,为此不可以定义NDEBUG 。#include "stm32f10x.h" 似乎要添加到#include <assert.h>的后边 不然编译会有问题。
    port.C
    添加了些Modbus协议栈与寄存器的接口函数 这个也要自己写。
    FreeModbus 通过 
    eMBRegInputCB eMBRegHoldingCB 
    eMBRegCoilsCB eMBRegDiscreteCB 四个接口函数完成数据的读写操作
    其中最常用的是这个 eMBRegHoldingCB 为了方便测试可以构造usRegHoldingBuf[]这样的一个数组进行读写调试。
    上位机可以用诸如Modbus调试精灵这样的软件。
    
    
    // 寄存器的读写函数 支持的命令为读 0x03 和写0x06
    eMBErrorCode
    eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    {
        eMBErrorCode    eStatus = MB_ENOERR;
        int             iRegIndex;
     u16 *PRT=(u16*)pucRegBuffer;
        if( ( usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
        {
            iRegIndex = ( int )( usAddress - usRegHoldingStart );
            switch ( eMode )
            {
            case MB_REG_READ:
                while( usNRegs > 0 )
                {
                    *PRT++ = __REV16(usRegHoldingBuf[iRegIndex++]); //数据序转 REV16.W
    //       *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );
    //              *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );
    //      iRegIndex++;
                    usNRegs--;
                }
                break;
            case MB_REG_WRITE:
                while( usNRegs > 0 )
                {
                    usRegHoldingBuf[iRegIndex++] = __REV16(*PRT++); //数据序转 REV16.W
    //      usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
    //              usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
    //              iRegIndex++;
                    usNRegs--;
                }
            }
        }
        else
        {
            eStatus = MB_ENOREG;
        }
        return eStatus;
    }
     受到freeModbus作者使用“assert()”的影响在这个里我用了__REV16()这个函数 
    *PRT++ = __REV16(usRegHoldingBuf[iRegIndex++]);
    这是Cortex—M3中的一个汇编指令REV16 功能是交换一个字的高位和地位位的两个字节,若0x1234==__REV16(0x3412)。字节在*pucRegBuffer中的顺序与串口发送的顺序是一致的所以要有这么个转换,当然用代码中注释掉的部分也能实现同样的功能。这是用__REV16()看起来更“酷”一些。当然这样编译后的结果是大约减少4条指令,效率提升有限。
    序转指令不少 功能非常强大~!__REV16()来源于core_cm3.c
    FreeModbus 移植于STM32 实现Modbus RTU通行 - java - stm32学习日志
    后边只要想法将STM32_PLC 输出的地址映射这个寄存器上边可以了
     
    FreeModbus 移植于STM32 实现Modbus RTU通行 - java - stm32学习日志
    整个移植没有什么难度 只是看官方的英文API文档 生词太多,其实意思非常简单。而且刚开始又用了来路不明的FreeModbus库文件,不伦怎样都不工作,浪费不少时间。全部工作前后总共花了两天的时间。
     
    我移植好的demo 注释很全 应该可以轻易看懂。
    DOWNLOAD:
    115:
    展开全文
  • 该资源压缩包是基于STM32单片机实现的适用于新手标准modbus模板, 内含文档资料,对modbus进行了讲解.
  • 近期需要在STM32实现Modbus协议的传输,传输的具体接口使用的是RS485。 接下来将自己的调试过程记录如下,首先关于RS-485的介绍如下: 1)何为RS485通信 RS-485通信属于半双工通信,相较于RS232,RS-485通信接收和...
    近期需要在STM32上实现Modbus协议的传输,传输的具体接口使用的是RS485。
    接下来将自己的调试过程记录如下,首先关于RS-485的介绍如下:
    1)何为RS485通信
    RS-485通信属于半双工通信,相较于RS232,RS-485通信接收和发送需要额外增加一个控制引脚。
    RS-485采用平衡发送和差分接收,因此具有抑制共模干扰的能力。RS-485采用半双工工作方式,任何时候只能有一点处于发送状态,因此,发送电路须由使能信号加以控制。RS-485用于多点互连时非常方便,可以省掉许多信号线。
    应用RS-485可以联网构成分布式系统,其允许最多并联32台驱动器和32台接收器。在RS232或RS485设备联成的设备网中,如果设备数量超过2台,就必须使用RS485做通讯介质,RS485网的设备间要想互通信息只有通过“主(Master)”设备中转才能实现,这个主设备通常是PC,而这种设备网中只允许存在一个主设备,其余全部是从(Slave)设备。
    RS-485 接口具有良好的抗噪声干扰性、长的传输距离和多站能力等。上述优点就使其成为首选的串行接口。因为工业RS485 通讯接口组成的半双工网络,一般只需二根连线,所以工业RS485 通讯接口均采用屏蔽双绞线传输。
    2)硬件电路
    

    实验用485通信电路
    3)实验内容
    通过电脑上位机向STM32发送一个字符,STM32接收到数据,并回传到电脑上位机
    4)源代码
    所包含的核心文件主要RS485.C RS485.H main.c
    4-1:宏定义相应的端口
    RS485.H
    端口宏定义
    #define RS485_TX_Pin GPIO_Pin_11
    #define RS485_TX_Port GPIOB

    #define RS485_RX_Pin GPIO_Pin_10
    #define RS485_RX_Port GPIOB

    #define RS485_EN_Pin GPIO_Pin_12
    #define RS485_EN_Port GPIOB
    /控制端电平定义/
    #define RS485_EN(x) x ? GPIO_SetBits(RS485_EN_Port,RS485_EN_Pin):GPIO_ResetBits(RS485_EN_Port,RS485_EN_Pin)

    4-2:所用到的IO配置函数
    

    RS485.C
    /**

    • 函数功能: 初始化配置485通讯GPIO引脚

    • 输入参数: 无

    • 返 回 值: 无

    • 说 明:无
      */
      void RS485_GPIO_Configuration(void)
      {
      GPIO_InitTypeDef GPIO_InitStructure;
      /初始化RCC_485_Pin 485控制引脚端口时钟/
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//RCC_APB2Periph_GPIOB
      /初始化RCC_485_RTX 485串口通讯功能端口时钟/
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//RCC_APB1Periph_USART3

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//端口复用功能开启
      /初始化控制端口/
      GPIO_InitStructure.GPIO_Pin=RS485_EN_Pin;//EN_485
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
      GPIO_Init(RS485_EN_Port,&GPIO_InitStructure);
      /初始化TX端口/
      GPIO_InitStructure.GPIO_Pin=RS485_TX_Pin;//TX
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
      GPIO_Init(RS485_TX_Port,&GPIO_InitStructure);
      /初始化RX端口/
      GPIO_InitStructure.GPIO_Pin=RS485_RX_Pin;//对应于STM32的USART3_TX
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//推挽复用输出
      GPIO_Init(RS485_RX_Port,&GPIO_InitStructure);
      }

    /**

    • 函数功能: 初始化配置485通讯功能

    • 输入参数: USART_TypeDef* USARTx:USART功能通道;uint32_t BaudRate:波特率

    • 返 回 值: 无

    • 说 明:无
      */
      void USART_Configuration(uint32_t BaudRate)
      {
      USART_InitTypeDef USART_InitStructure;

      RS485_GPIO_Configuration();//初始化RS485 GPIO引脚

      USART_InitStructure.USART_BaudRate=BaudRate;//系统USART波特率设置
      USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长设置为8位
      USART_InitStructure.USART_StopBits=USART_StopBits_1;//在帧结尾传输一个停止位
      USART_InitStructure.USART_Parity=USART_Parity_No;//奇偶校验位设置为奇偶使能
      USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//设置为硬件流控制失能
      USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//发送和接受均使能

      USART_Init(RS485,&USART_InitStructure);
      USART_ITConfig(RS485,USART_IT_RXNE,ENABLE);
      USART_Cmd(RS485,ENABLE);
      USART_ClearFlag(RS485,USART_FLAG_TC);//清空发送成功标志位
      RS485_EN(0);//初始化为接收状态
      RS485_TX_EN=0;//接收状态
      }
      4-3:接收中断
      void USART3_IRQHandler(void)
      {
      u8 temp=0;
      if(USART_GetITStatus(RS485,USART_IT_RXNE)!=RESET)//检查USART3的接收中断是否被触发
      {
      temp=USART_ReceiveData(RS485);//将USART中接收到的数据保存到临时变量temp中

      RS485_EN(1);//初始化为发送状态
      delay_ms(1);
      USART_SendData(RS485,temp);
      while(USART_GetFlagStatus(RS485, USART_FLAG_TXE)==RESET);
      delay_ms(2);				
      RS485_EN(0);//初始化为发送状态	 
      

      }
      }
      4-4:主函数,初始化完成后,则等待中断执行
      int main()
      {

      SystemInit();//72m
      USART_Configuration(9600);//初始化USART 9600 N 8 1
      NVIC_RS485_Configuration();
      USART_232_Configuration(9600);
      NVIC_RS232_Configuration();
      while(1)
      {

      }
      }
      5)实验结果
      实验结果

    展开全文
  • 实现STM32和电脑上位机任意字符组合的接收和发送 2)源代码 2-1:RS485.C文件中源代码 主要包括引脚功能配置函数,中断接收函数,发送和数据处理函数 #include “RS485.h” /** 文件名称: RS485.c 作 者: HL 版 本...

    1)实验目的
    实现STM32和电脑上位机任意字符组合的接收和发送
    2)源代码
    2-1:RS485.C文件中源代码
    主要包括引脚功能配置函数,中断接收函数,发送和数据处理函数
    #include “RS485.h”
    /**


    • 文件名称: RS485.c
    • 作 者: HL
    • 版 本: V1.0
    • 编写日期: 2019-02-02
    • 功 能: 485功能配置
      ******************************************************************************/

    #define RS485 USART3
    ModBus_Tx ModBus_T;
    u8 RS485_TX_EN=0,RS485_RX_Over;
    /**

    • 函数功能: 初始化配置485通讯GPIO引脚

    • 输入参数: 无

    • 返 回 值: 无

    • 说 明:无
      */
      void RS485_GPIO_Configuration(void)
      {
      GPIO_InitTypeDef GPIO_InitStructure;
      /初始化RCC_485_Pin 485控制引脚端口时钟/
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//RCC_APB2Periph_GPIOB
      /初始化RCC_485_RTX 485串口通讯功能端口时钟/
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//RCC_APB1Periph_USART3

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//端口复用功能开启
      /初始化控制端口/
      GPIO_InitStructure.GPIO_Pin=RS485_EN_Pin;//EN_485
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
      GPIO_Init(RS485_EN_Port,&GPIO_InitStructure);
      /初始化TX端口/
      GPIO_InitStructure.GPIO_Pin=RS485_TX_Pin;//TX
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
      GPIO_Init(RS485_TX_Port,&GPIO_InitStructure);
      /初始化RX端口/
      GPIO_InitStructure.GPIO_Pin=RS485_RX_Pin;//对应于STM32的USART3_TX
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//推挽复用输出
      GPIO_Init(RS485_RX_Port,&GPIO_InitStructure);
      }
      /**

    • 函数功能: 初始化配置485通讯功能

    • 输入参数: USART_TypeDef* USARTx:USART功能通道;uint32_t BaudRate:波特率

    • 返 回 值: 无

    • 说 明:无
      */
      void USART_Configuration(uint32_t BaudRate)
      {
      USART_InitTypeDef USART_InitStructure;

      RS485_GPIO_Configuration();//初始化RS485 GPIO引脚

      USART_InitStructure.USART_BaudRate=BaudRate;//系统USART波特率设置
      USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长设置为8位
      USART_InitStructure.USART_StopBits=USART_StopBits_1;//在帧结尾传输一个停止位
      USART_InitStructure.USART_Parity=USART_Parity_No;//奇偶校验位设置为奇偶使能
      USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//设置为硬件流控制失能
      USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//发送和接受均使能

      USART_Init(RS485,&USART_InitStructure);
      USART_ITConfig(RS485,USART_IT_RXNE,ENABLE);
      USART_Cmd(RS485,ENABLE);
      USART_ClearFlag(RS485,USART_FLAG_TC);//清空发送成功标志位
      RS485_EN(0);//初始化为接收状态
      RS485_TX_EN=0;//接收状态
      }

    void USART3_IRQHandler(void)
    {
    u8 res=0;
    if(USART_GetITStatus(RS485,USART_IT_RXNE)!=RESET)//检查RS485是否触发接收中断标志位
    {
    res=USART_ReceiveData(RS485);//将接收到的数据保存到临时变量res中
    if(ModBus_T.Rx_Count<RS485_RX_BUF_LEN)
    {
    ModBus_T.RS485_RX_BUF[ModBus_T.Rx_Count]=res; //将接收到的数据存放到接收缓冲区内
    ModBus_T.Rx_Count++;
    }
    }
    }

    //RS485发送len个字节.
    //buf:发送区首地址
    //len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
    void RS485_Send_Data(u8 *buf,u8 len)
    {
    u8 t;
    RS485_TX_EN=1; //设置为发送模式
    RS485_EN(1);
    for(t=0;t<len;t++) //循环发送数据
    {
    while(USART_GetFlagStatus(RS485, USART_FLAG_TC) == RESET);
    USART_SendData(RS485,buf[t]);
    }

    while(USART_GetFlagStatus(RS485, USART_FLAG_TC) == RESET);		
    ModBus_T.Rx_Count=0;	  	//清空接收数组计数变量
    RS485_TX_EN=0;				//设置为接收模式	
    RS485_EN(0);
    RS485_RX_Over=0;//开始下一轮接收
    

    }
    //RS485查询接收到的数据
    //buf:接收缓存首地址
    //返回接收到的字节数
    u8 RS485_Receive_Data(u8 *buf)
    {
    u8 rxlen=ModBus_T.Rx_Count;
    u8 i=0;
    u8 len=0; //默认为0
    delay_ms(10); //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
    if(rxlen==ModBus_T.Rx_Count&&rxlen)//接收到了数据,且接收完成了
    {
    for(i=0;i<rxlen;i++)
    {
    buf[i]=ModBus_T.RS485_RX_BUF[i];
    }
    len=ModBus_T.Rx_Count; //记录本次数据长度
    ModBus_T.Rx_Count=0; //清零
    RS485_RX_Over=1;//接收完成标志位置位
    }
    return len;

    }
    2-2 RS485.H中的源代码
    #ifndef RS485_H
    #define RS485_H

    #include “stm32f10x.h”
    #include “stm32f10x_usart.h”
    #include “SysTick.h”
    //#define RCC_485_Pin RCC_APB2Periph_GPIOB
    //#define RCC_485_RTX RCC_APB1Periph_USART3

    #define RS485_TX_Pin GPIO_Pin_11
    #define RS485_TX_Port GPIOB

    #define RS485_RX_Pin GPIO_Pin_10
    #define RS485_RX_Port GPIOB

    #define RS485_EN_Pin GPIO_Pin_12
    #define RS485_EN_Port GPIOB

    #define RS485_EN(x) x ? GPIO_SetBits(RS485_EN_Port,RS485_EN_Pin):GPIO_ResetBits(RS485_EN_Port,RS485_EN_Pin)

    #define RS485_RX_BUF_LEN 64 //宏定义接收缓冲区长度,最大RS485_RX_BUF_LEN个字节

    extern u8 RS485_TX_EN; //声明485通讯接收与发送模式切换标志位
    //RS485_TX_EN=1;–发送模式
    //RS485_TX_EN=0;–接收模式
    extern u8 RS485_RX_Over;
    typedef struct
    {
    u8 RS485_RX_BUF[RS485_RX_BUF_LEN];
    u8 Rx_Count;

    }ModBus_Tx;

    void RS485_GPIO_Configuration(void);
    void USART_Configuration(uint32_t BaudRate);
    void RS485_Send_Data(u8 *buf, u8 len);
    u8 RS485_Receive_Data(u8 *buf);

    #endif

    2-3 main函数
    

    #include<Include.h>

    int main()
    {
    u8 USART_RXLEN;
    ModBus_Tx ModBus_T;
    SystemInit();//72m
    USART_Configuration(9600);//初始化USART 9600 N 8 1
    NVIC_RS485_Configuration();
    USART_232_Configuration(9600);
    NVIC_RS232_Configuration();
    while(1)
    {
    if(!RS485_RX_Over)
    {
    USART_RXLEN=RS485_Receive_Data(ModBus_T.RS485_RX_BUF);

    	}
    	else
    		RS485_Send_Data(ModBus_T.RS485_RX_BUF,USART_RXLEN);//发送5个字节
    	
    }
    

    }

    展开全文
  • stm32f103的modbus通信

    2020-11-04 16:07:00
    使用stm32f103t8,移植了freemodbus,基于RS485硬件,从机地址存在EEPROM里。实现多从机。
  • STM32F103C8T6T6单片机上,利用串口空闲中断和DMA功能实现Modbus通信时数据检测功能。不再需要利用定时器中断去判断一帧数据是否接收完成。
  • stm32_实现Modbus,采用rtu,内含通信协议说明文档
  • STM32移植FreeModbus实现ModBusRTU和PLC通信。代码中实现了读线圈、写线圈、读离散输入、读输入寄存器、读保持寄存器、写保持寄存器等功能。
  • Modbus是一种串行通信协议,是Modicon于1979年,为使用可编程逻辑控制器(PLC...1、实现f103作为从机,上位机作为主机通信(从站程序)。 1.1 配置时钟 作为保证串口接收数据完整。 //通用定时器3中断初始化 //APB

    Modbus是一种串行通信协议,是Modicon于1979年,为使用可编程逻辑控制器(PLC)而发表的。Modbus是工业领域通信协议的业界标准,并且现在是工业电子设备之间相当常用的连接方式。Modbus比其他通信协议使用的更广泛的主要原因有:
    【1】公开发表并且无版税要求
    【2】相对容易的工业网络部署
    【3】对供应商来说,修改移动原生的位元或字节没有很多限制

    1、实现f103作为从机,上位机作为主机通信(从站程序)。

    1.1 配置时钟

    作为保证串口接收数据完整。

    //通用定时器3中断初始化
    //APB1为SYSCLK的2分频,即36M,因此定时器时钟为APB1的2倍频,即72M
    //arr:自动重装值
    //psc:时钟分频数
    //这里使用的是定时器3!
    void TIM3_Int_Init(u16 arr,u16 psc)
    {
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能时钟
    	
    	//定时器TIM3初始化
    	TIM_TimeBaseStructure.TIM_Period = arr; //自动重装载寄存器周期的值
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; /设置用来作为TIMx时钟频率数的预分频值
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); /使能指定的TIM3中断,允许更新中断
    
    	//中断优先级NVIC配置
    	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
    
    
    	TIM_Cmd(TIM3, ENABLE);  //使能TIMx					 
    }
    //定时器3中断服务程序,100us
    void TIM3_IRQHandler(void)   //TIM3中断
    {
    	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    		{
    			TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清理TIMx更新中断标志
    			if(time3_usart1<=200)
            time3_usart1++;
    			if(time3_usart2<=200)
            time3_usart2++;
    			if(time3_usart3<=5000)
            time3_usart3++;
    		}
    		
    }
    

    1.2 配置串口USART

    配置使用到串口,用于实际的通信端口。

    1.2.1 串口优先级配置

     /**
      * @brief 配置嵌套向量中断控制器NVIC
      * @param  ÎÞ
      * @retval ÎÞ
      */
    static void NVIC_usart1_Configuration(void)
    {
      NVIC_InitTypeDef NVIC_InitStructure;
      
      /* 嵌套向量中断控制器组选择 */
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
      
      /*配置USART为中断源*/
      NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART1_IRQ;
      /* 抢断优先级*/
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      /* 子优先级 */
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      /* 使能中断 */
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      /*初始化配置NVIC */
      NVIC_Init(&NVIC_InitStructure);
    }
    
    static void NVIC_usart2_Configuration(void)
    {
      NVIC_InitTypeDef NVIC_InitStructure;
      
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
      
      NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART2_IRQ;
    
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    
      NVIC_Init(&NVIC_InitStructure);
    }
    

    1.2.2 串口初始化

    void USART1_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    
    	// 打开串口GPIO的时钟
    	DEBUG_USART1_GPIO_APBxClkCmd(DEBUG_USART1_GPIO_CLK, ENABLE);
    	
    	// 打开串口外设的时钟
    	DEBUG_USART1_APBxClkCmd(DEBUG_USART1_CLK, ENABLE);
    
    	// 将USART Tx的GPIO配置为推挽复用模式
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART1_TX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(DEBUG_USART1_TX_GPIO_PORT, &GPIO_InitStructure);
    
      // 将USART Rx的GPIO配置为浮空输入模式
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART1_RX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(DEBUG_USART1_RX_GPIO_PORT, &GPIO_InitStructure);
    	
    	// 配置串口的工作参数
    	// 配置波特率
    	USART_InitStructure.USART_BaudRate = DEBUG_USART1_BAUDRATE;
    	// 配置 帧数据字长
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	// 配置停止位
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    	// 配置校验位
    	USART_InitStructure.USART_Parity = USART_Parity_No ;
    	// 配置硬件流控制
    	USART_InitStructure.USART_HardwareFlowControl = 
    	USART_HardwareFlowControl_None;
    	// 配置工作模式,收发一起
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    	// 完成串口的初始化配置
    	USART_Init(DEBUG_USART1, &USART_InitStructure);
    	
    	// 串口中断优先级配置
    	NVIC_usart1_Configuration();
    	
    	// 使能串口接收中断
    	USART_ITConfig(DEBUG_USART1, USART_IT_RXNE, ENABLE);	
    	
    	// 使能串口
    	USART_Cmd(DEBUG_USART1, ENABLE);	    
    }
    
    //初始化串口2
    void USART2_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    
    	DEBUG_USART2_GPIO_APBxClkCmd(DEBUG_USART2_GPIO_CLK, ENABLE);
    	
    	DEBUG_USART2_APBxClkCmd(DEBUG_USART2_CLK, ENABLE);
    
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART2_TX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(DEBUG_USART2_TX_GPIO_PORT, &GPIO_InitStructure);
    
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART2_RX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(DEBUG_USART2_RX_GPIO_PORT, &GPIO_InitStructure);
    
    	USART_InitStructure.USART_BaudRate = DEBUG_USART2_BAUDRATE;
    
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    
    	USART_InitStructure.USART_Parity = USART_Parity_No ;
    
    	USART_InitStructure.USART_HardwareFlowControl = 
    	USART_HardwareFlowControl_None;
    
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    
    	USART_Init(DEBUG_USART2, &USART_InitStructure);
    	
    	NVIC_usart2_Configuration();
    	
    	USART_ITConfig(DEBUG_USART2, USART_IT_RXNE, ENABLE);	
    	
    	USART_Cmd(DEBUG_USART2, ENABLE);	    
    }
    

    1.2.3 串口中断服务函数

    unsigned char usart1_rx_buf[USART1_RX_LENGTH_MAX];//串口1的接收数据缓存
    unsigned int usart1_rx_length=0;
    unsigned char usart2_rx_buf[USART2_RX_LENGTH_MAX];//串口2的接收数据缓存
    unsigned int usart2_rx_length=0;
    unsigned char usart3_rx_buf[USART3_RX_LENGTH_MAX];
    unsigned int usart3_rx_length=0;
    unsigned int time3_usart1,time3_usart2,time3_usart3;//time3用于各个串口接收的数据计时
    
    
    //串口1中断服务函数
    void DEBUG_USART1_IRQHandler(void)
    
    	if(USART_GetITStatus(DEBUG_USART1,USART_IT_RXNE)!=RESET)
    	{	
    		time3_usart1 =0;//每一个字节接收完都需要留出一小段时间,等待下一个字节
    		usart1_rx_buf[usart1_rx_length] = USART_ReceiveData(DEBUG_USART1);
     
    		if(usart1_rx_length < USART1_RX_LENGTH_MAX)
        usart1_rx_length++;
     
    	}	 
    }
    //串口2中断服务函数
    void DEBUG_USART2_IRQHandler(void)
    {
    
    	if(USART_GetITStatus(DEBUG_USART2,USART_IT_RXNE)!=RESET)
    	{		
    		time3_usart2 =0;
    		usart2_rx_buf[usart2_rx_length] = USART_ReceiveData(DEBUG_USART2);
          //   USART_SendData(DEBUG_USART1,u1_rx_buf[num]);  //可以直接发给上位机  
    		if(usart2_rx_length < USART1_RX_LENGTH_MAX)
        usart2_rx_length++; 
    	}	 
    }

    1.2.4 usart.h文件里的内容

    #define USART1_RX_LENGTH_MAX    200
    #define USART2_RX_LENGTH_MAX    200
    #define USART3_RX_LENGTH_MAX    250
    
    extern unsigned char USART2_OV_FLAG;
    extern unsigned char USART1_OV_FLAG;
    extern unsigned char usart1_rx_buf[USART1_RX_LENGTH_MAX];//串口1的接收数据缓存
    extern unsigned int  usart1_rx_length;
    extern unsigned char usart2_rx_buf[USART2_RX_LENGTH_MAX];
    extern unsigned int  usart2_rx_length;
    extern unsigned char usart3_rx_buf[USART3_RX_LENGTH_MAX];
    extern unsigned int  usart3_rx_length;
    extern unsigned int  time3_usart1,time3_usart2,time3_usart3;
    
    //	
    //串口1USART1
    #define  DEBUG_USART1                    USART1
    #define  DEBUG_USART1_CLK                RCC_APB2Periph_USART1
    #define  DEBUG_USART1_APBxClkCmd         RCC_APB2PeriphClockCmd
    #define  DEBUG_USART1_BAUDRATE           115200           ///波特率
    
    // USART GPIO 物理引脚宏定义
    #define  DEBUG_USART1_GPIO_CLK           (RCC_APB2Periph_GPIOA)
    #define  DEBUG_USART1_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
        
    #define  DEBUG_USART1_TX_GPIO_PORT       GPIOA   
    #define  DEBUG_USART1_TX_GPIO_PIN        GPIO_Pin_9
    #define  DEBUG_USART1_RX_GPIO_PORT       GPIOA
    #define  DEBUG_USART1_RX_GPIO_PIN        GPIO_Pin_10
    
    #define  DEBUG_USART1_IRQ                USART1_IRQn
    #define  DEBUG_USART1_IRQHandler         USART1_IRQHandler
    
    
    //串口2-USART2
    #define  DEBUG_USART2                   USART2
    #define  DEBUG_USART2_CLK                RCC_APB1Periph_USART2
    #define  DEBUG_USART2_APBxClkCmd         RCC_APB1PeriphClockCmd
    #define  DEBUG_USART2_BAUDRATE           115200
    
    // USART GPIO 物理引脚宏定义
    #define  DEBUG_USART2_GPIO_CLK           (RCC_APB2Periph_GPIOA)
    #define  DEBUG_USART2_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
        
    #define  DEBUG_USART2_TX_GPIO_PORT       GPIOA   
    #define  DEBUG_USART2_TX_GPIO_PIN        GPIO_Pin_2
    #define  DEBUG_USART2_RX_GPIO_PORT       GPIOA
    #define  DEBUG_USART2_RX_GPIO_PIN        GPIO_Pin_3
    
    #define  DEBUG_USART2_IRQ                USART2_IRQn
    #define  DEBUG_USART2_IRQHandler         USART2_IRQHandler

    1.3 MODBUS

    主要实现功能码03读取和06写入功能。

    1.3.1 MODBUS.c

    #define ADDR 1   
    #define NULL 0
    #define MODBUS_LENGTH 100
    
    //波特率列表
    u32 MODBUS_BaudRate[10]={4800,9600,14400,19200,38400,56000,57600,115200,128000,256000};    
    u16   Flash_Usart_BaudRate;       
    u16   Flash_Modbus_ADDR;        	//Modbus ID号
    			
    
    
    u8 canbuf[8]={0xff,0x00,0x30,0x31,0x32,0x01,0x02,0x03};
    unsigned int UsartNUM;
    unsigned short modbus_reg[MODBUS_LENGTH];
    
    
    unsigned int Calculate_FLAG;
    
    const unsigned char auchCRCHi[] = /* CRC��λ�ֽڱ�*/
    { 	 
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 
    } ; 
    
    const unsigned char auchCRCLo[] = /* CRC��λ�ֽڱ�*/ 
    { 
    	0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC,
    	0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 
    	0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 
    	0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 
    	0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 
    	0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 
    	0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 
    	0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 
    	0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 
    	0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 
    	0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 
    	0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 
    	0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 
    	0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 
    	0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 
    	0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
    } ;	 
    
    /******************************************************************************
    					        CRC校验
    *******************************************************************************/
    unsigned int CRC_Calculate(unsigned char *pdata,unsigned char num)
    {
      unsigned char  uchCRCHi = 0xFF ;               
    	unsigned char  uchCRCLo = 0xFF ;               
    	unsigned char uIndex ;                
    	while(num --)                    
    	{
    		uIndex = uchCRCHi^*pdata++ ;           
    		uchCRCHi = uchCRCLo^auchCRCHi[uIndex];
    		uchCRCLo = auchCRCLo[uIndex];
    	}
    	return (uchCRCHi << 8 | uchCRCLo) ;
    }
    /******************************************************************************
    							数据应答发送函数
    *******************************************************************************/
    void MODBUS_Send(unsigned char *buf,unsigned int length)///发送length个数据
    {
    	if(UsartNUM==1) 
    		Usart1_SendString(buf,length);
    	
    	if(UsartNUM==2) 
    	{	
    		Usart2_SendString(buf,length);
    	}
    }
    
    ///******************************************************************************
    //						    03功能函数
    //*******************************************************************************/
    void MODBUS_03_Return(unsigned int startaddr,unsigned int number)
    {
    
        unsigned char send_length;
        unsigned char send_buf[205];
        unsigned char i;
        unsigned int crc;
    	
        send_length = 0;
        send_buf[send_length++] = Flash_Modbus_ADDR;
        send_buf[send_length++] = 0x03;        //03功能码
        send_buf[send_length++] = number*2;	  //
        for (i = 0;i < number;i++)
        {
            send_buf[send_length++] = modbus_reg[startaddr+i]/256;
            send_buf[send_length++] = modbus_reg[startaddr+i]%256;
        }
        crc = CRC_Calculate(send_buf,send_length);
        send_buf[send_length++] = crc/256;
        send_buf[send_length++] = crc%256;
        MODBUS_Send(send_buf,send_length);
    }
    ///******************************************************************************
    //							发送MODBUS协议字符串
    //*******************************************************************************/
    void MODBUS_10_Return(unsigned int addr,unsigned int code)
    {
        unsigned char send_buf[8];
    	unsigned int crc;
    	send_buf[0] = Flash_Modbus_ADDR;
    	send_buf[1] = 16;
    	send_buf[2] = (addr / 256);
    	send_buf[3] = (addr % 256);
    	send_buf[4] = (code / 256);
    	send_buf[5] = (code % 256);
    	crc = CRC_Calculate(send_buf,6);
    	send_buf[6] = (crc / 256);
      send_buf[7] = (crc % 256);
    	MODBUS_Send(send_buf,8);
    }
    
    ///******************************************************************************
    //					    MODBUS数据接收处理函数
    //*******************************************************************************/
    void MODBUS(unsigned char *buf,unsigned int length,unsigned int NUM)
    {
    	unsigned int startaddr,number,code;
    	unsigned int crc;
    	UsartNUM=NUM;
    	  crc = CRC_Calculate(buf,length-2);
    
        if (buf[0] == Flash_Modbus_ADDR&&buf[length-2] == (crc / 256)&&buf[length-1] == (crc % 256))
        {
    			unsigned int Write_EN=0;
    	
    			MODBUS_datain();
            switch(buf[1])
            {
                case 0x03:    //03 读取数据
                    startaddr = buf[2]*256 + buf[3];
                    number = buf[4]*256 + buf[5];
    								if ((startaddr+number) > MODBUS_LENGTH)
    								{	
    									break;
    								}					
    								MODBUS_03_Return(startaddr,number);
                    break;
                case 0x06:      //写一个数据
                    startaddr = buf[2]*256 + buf[3];
                    code = buf[4]*256 + buf[5];
    								if ((startaddr) > MODBUS_LENGTH)
    								{	
    									break;
    								}
                    modbus_reg[startaddr] = code;
                    MODBUS_Send(buf,length);//原封不动的返回
    								Write_EN=1;
    								break;
    								
    							
    						case 0x10:     
    								startaddr = buf[2]*256 + buf[3];
    								number = buf[4]*256 + buf[5];
    								if ((startaddr+number) > MODBUS_LENGTH)
    								{	
    									break;
    								}
    								for (code = 0;code < number;code++)
    								{
    									modbus_reg[startaddr + code] = buf[6+code*2]*256 + buf[7+code*2];
    								}			
    								MODBUS_10_Return(startaddr,number);
    								SYS_DEBUG_AP_FLAG=10;
    								
    								break;	
    						
    						
                default:
                    break;
            }
    				
        }
    }
    
    /******************************************************************************
    		              串口接收事件
    *******************************************************************************/
    void MODBUS_event() 
    {
    	if ((usart1_rx_length) && (time3_usart1 >= (10-Flash_Usart_BaudRate)*5)) //串口1接收到一帧数据
    		{
    
    			MODBUS(usart1_rx_buf,usart1_rx_length,1);
    			usart1_rx_length = 0;
    			time3_usart1 = 0;
    		}
    	if ((usart2_rx_length) && (time3_usart2 >= (10-Flash_Usart_BaudRate)*5))
    	{
    
        		MODBUS(usart2_rx_buf,usart2_rx_length,2);
    			usart1_rx_length = 0;
    			time3_usart1 = 0;
    		
    	}
    }
    ///******************************************************************************
    //								MODBUS寄存器
    //*******************************************************************************/
    void MODBUS_datain() 
    {
    
    	modbus_reg[0]=Flash_Usart_BaudRate;///0x0007
    	modbus_reg[1]=Flash_Modbus_ADDR;  ///Modbus ID号
    	modbus_reg[2]=0x1111;        
    	modbus_reg[3]=0x2222;        
    	modbus_reg[4]=0x3333;        
    	///.....
    	///modbus_reg[n]=.....;
    }
    

    1.3.2 MODBUS.h

    #ifndef __MODBUS_H
    #define __MODBUS_H
    
    #include "stm32f10x.h"
    #include <stdio.h>
    
    extern  u32 MODBUS_BaudRate[10];
    extern  u16   Flash_Modbus_ADDR;   
    extern  u16   Flash_Usart_BaudRate;   
    
    void MODBUS_Send(unsigned char *buf,unsigned int length);
    void MODBUS(unsigned char *buf,unsigned int length,unsigned int UsartNUM);
    void MODBUS_ReadFromEEPROM(void);
    void MODBUS_event(void);
    void MODBUS_datain(void); 
    unsigned int CRC_Calculate(unsigned char *pdata,unsigned char num);
    extern unsigned short modbus_reg[];
    
    #endif	

    1.4 main函数

    	unsigned char send_buf[10];
        char receive_buf[205];
    	unsigned char i;
    
    
    int main(void)
    {	
    
        USART1_Init();
    	USART2_Init();
    
    	TIM3_Int_Init(1,7199);//10Kh的计数频率,计数1次为500us 计算串口接收等待时间
    	Flash_Modbus_ADDR=0x0001;///本设备从站地址号
    	Flash_Usart_BaudRate=0x0007;
    	
      while(1)
    	{	
    		 MODBUS_event();//串口MODBUS接收事件
    	}	
    }

    1.5 上位机仿真结果

     

    2.F103做主站(程序),另外一个设备做从站

    中断、定时器、串口等配置均与上面从站一致。不同的是:

    1、主站需要发送指令代码

    2、串口中断函数需要简单的修改,将接收到的数据发给上位机,可以查看是否正常。

    如下是一个简单的main函数

    	unsigned char send_buf[10];
        char receive_buf[205];
    	unsigned char i;
    
    int main(void)
    {	
        USART1_Init();
    	USART2_Init();
    	USART4_Init();	
    	TIM3_Int_Init(1,7199);
    	Flash_Modbus_ADDR=0x0001;
    	Flash_Usart_BaudRate=0x0007;
    		
    //	send_buf[0]=0x01;//从站地址
    //	send_buf[1]=0x03;//功能码
    //	send_buf[2]=0x00;//寄存器地址起始位高字节
    //	send_buf[3]=0x00;//寄存器地址起始位低字节
    //	send_buf[4]=0x00;//读取寄存器数量高字节
    //	send_buf[5]=0x64;//读取寄存器数量低字节
    //	send_buf[6]=0x44;///CRC高字节
    //	send_buf[7]=0x21;///CRC低字节
    	
    	send_buf[0]=0x01;
    	send_buf[1]=0x03;
    	send_buf[2]=0x00;
    	send_buf[3]=0x00;
    	send_buf[4]=0x00;
    	send_buf[5]=0x03;
    	send_buf[6]=0x05;
    	send_buf[7]=0xCB;
    	
    		for(i=0;i<8;i++)
    		{
    			Usart_SendByte( DEBUG_USART2,send_buf[i]);
    		}
    	
    	
      while(1)
    	{	
    //		 MODBUS_event();//暂时不需要对接收到的数据处理
    	}	
    }

     

    展开全文
  • 基于STM32modbus RTU源码,内容包含了CRC校验码源码、modbusRTU源码---其中实现了功能码03和功能码06,以及一个基于stm32f103的工程。下载下来可以根据自己的硬件环境修改定时器和串口函数构建好物理传输通路即可...
  • stm32f407开发板实现485串口modbus协议通信,源码打包带走
  • STM32ModBus协议

    2019-01-12 12:31:10
    STM32实现ModBus协议的通信测试连接,具有很好的参考价值。适合学习。
  • 自己写的STM32F1作为从机,实现ModBus RTU通信协议,程序测试已经实现寄存器读取、写入,注意通信的时候单片机的起始地址
  • 树莓派+stm32开发板通信树莓派上使用java+jamod实现。jamod官网stm32使用freemodbus实现 ​ 转载于:https://www.cnblogs.com/feipeng8848/p/8927238.html
  • https://blog.csdn.net/baidu_31437863/article/details/82178708 STM32(五) Modbus ... 基于STM32实现 Modbus协议调试笔记 --利用485通信实现单个字符的接收与发送 http://...
  • STM32F4 485 modbus

    2018-07-11 13:21:23
    编写了stm32f4的主从机的485通信,编写的modbus协议,能够实现主机向从机发送命令,和从机向主机发送数据,通过设定不同从机地址,读取不同从机的数据,两个stm32f4可以直连,可以直接使用,欢迎大家一起交流讨论
  • STM32中使用usart实现modbus RTU通讯

    千次阅读 2020-01-09 21:12:46
    modbus协议能实现控制器互相之间、控制器经网络和设备之间进行通信modbus协议是请求响应模式(应答),即控制器向设备发起访问请求,然后设备进行响应。 modbus协议也是主从通信,所以请求只能由主机发起,从设...
  • MODBUS移植STM32STM32做从机

    千次阅读 热门讨论 2020-04-04 18:47:13
    本文章实现MODBUS通信,并配置STM32做从机的功能。
  • STM32STM32F407实现简单的Modbus协议

    千次阅读 2020-05-11 17:27:45
    MODBUS协议是一种串行通信协议,由Modicon公司(施耐德公司前身)发表,由于其公开发表且无版权要求,易于部署和维护,在工业界广泛应用。MODBUS采用主从通信(Master/Slave),MODBUS有三种报文格式:ASCII、RTU、...
  • MODBUS协议剖析 【MODBUS协议在STM32实现 - 上】

    万次阅读 多人点赞 2018-11-11 19:02:02
    参考资料:获取资料加QQ群 736386324 ...1.Modbus通信协议.pdf 2.Modbus调试精灵1.024.rar 3.主机源码.rar 4.育灵科技视频 第一节 通讯的硬件协议机制 主从模式的建立 目的:实现在mo...
  • 近期自学了MODBUS通信协议,也从网上找了很多资料,自己也分别做了从机和主机的配置,现在进行配合操作 MCU采用STM32F103C8T6 实现功能,主机分别对从机实现读和写的操作 主机要用到一个外部中断实现发数据的操作 一...

空空如也

空空如也

1 2 3 4 5
收藏数 99
精华内容 39
关键字:

stm32实现modbus通信