打印
[STM32F4]

Modbus_主从机(控制LED灯)

[复制链接]
3006|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
工程说明:Modbus_主从机(控制LED灯)
Modbus是由Modicon(现为施耐德电气公司的一个品牌)在1979年发明的,是全球第一个真正用于工业现场的总线协议。
Modbus网络是一个工业通信系统,由带智能终端的可编程序控制器和计算机通过公用线路或局部专用线路连接而成。其系统结构既包括硬件、也包括软件。
Modbus协议是应用于电子控制器上的一种通信语言。通过此协议,控制器互相之间、控制器经由网络和其它设备之间可以通信。它已经成为一通用工业标准。不同厂商生产的控制设备可以连成工业网络,进行集中监控。软件版本信息


沙发
goodluck09876|  楼主 | 2018-12-4 12:36 | 只看该作者

使用特权

评论回复
板凳
goodluck09876|  楼主 | 2018-12-4 12:36 | 只看该作者
使用开发板配套的MINI USB线连接到开发板标示“调试串口”字样的MIMI USB接口为开发板供电。
该例程的结合主从机进行通信,按下KEY1~KEY3按键,对06H线圈寄存器写数据,从机对06H寄存器数据进行解析,从而达到控制LED的目的。

使用特权

评论回复
地板
goodluck09876|  楼主 | 2018-12-4 12:37 | 只看该作者

使用特权

评论回复
5
goodluck09876|  楼主 | 2018-12-4 12:41 | 只看该作者
/**
  ******************************************************************************
  * 文件名程: main.c
  * 作    者: 硬石嵌入式开发团队
  * 版    本: V1.0
  * 编写日期: 2017-09-16
  * 功    能: Modbus协议从机RTU通信模式
  ******************************************************************************
  * 说明:
  * 本例程配套硬石stm32开发板YS-F4Pro使用。
  *
  * 淘宝:
  * 论坛:http://www.ing10bbs.com
  * 版权归硬石嵌入式开发团队所有,请勿商用。
  ******************************************************************************
  */
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "usart/bsp_debug_usart.h"
#include "key/bsp_key.h"
#include "led/bsp_led.h"
#include "GeneralTIM/bsp_GeneralTIM.h"
#include "Modbus/bsp_MB_slave.h"
#include <stdlib.h>
#include "usart/bsp_usartx.h"

/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#define MSG_ERR_FLAG  0xFFFF    // 接收错误 字符间超时
#define MSG_IDLE      0x0000    // 空闲状态
#define MSG_RXING     0x0001    // 正在接收数据
#define MSG_COM       0x0002    // 接收完成
#define MSG_INC       0x8000    // 数据帧不完整(两字符间的空闲间隔大于1.5个字符时间)
#define TIME_OVERRUN  100       // 定义超时时间 ms
/* 私有变量 ------------------------------------------------------------------*/
__IO uint16_t Rx_MSG = MSG_IDLE;   // 接收报文状态
__IO uint8_t state=0;

/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
  * 函数功能: 系统时钟配置
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 无
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __HAL_RCC_PWR_CLK_ENABLE();                                     //使能PWR时钟

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);  //设置调压器输出电压级别1

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;      // 外部晶振,8MHz
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;                        //打开HSE
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;                    //打开PLL
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;            //PLL时钟源选择HSE
  RCC_OscInitStruct.PLL.PLLM = 8;                                 //8分频MHz
  RCC_OscInitStruct.PLL.PLLN = 336;                               //336倍频
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;                     //2分频,得到168MHz主时钟
  RCC_OscInitStruct.PLL.PLLQ = 7;                                 //USB/SDIO/随机数产生器等的主PLL分频系数
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;       // 系统时钟:168MHz
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;              // AHB时钟: 168MHz
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;               // APB1时钟:42MHz
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;               // APB2时钟:84MHz
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

  HAL_RCC_EnableCSS();                                            // 使能CSS功能,优先使用外部晶振,内部时钟源为备用
  
        // HAL_RCC_GetHCLKFreq()/1000    1ms中断一次
        // HAL_RCC_GetHCLKFreq()/100000         10us中断一次
        // HAL_RCC_GetHCLKFreq()/1000000 1us中断一次
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);                // 配置并启动系统滴答定时器
  /* 系统滴答定时器时钟源 */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* 系统滴答定时器中断优先级配置 */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/**
  * 函数功能: 初始化外设
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 无
  */
void InitPeri()
{
    /* 复位所有外设,初始化Flash接口和系统滴答定时器 */
  HAL_Init();
  /* 配置系统时钟 */
  SystemClock_Config();
    /* 初始化串口并配置串口中断优先级 */
  MX_DEBUG_USART_Init();
  USARTx_Init();

  /* 定时器初始化 */
  GENERAL_TIMx_Init();
  /* LED初始化 */
  LED_GPIO_Init();
  /* 使能定时器中断 */
  __HAL_TIM_ENABLE_IT(&htimx,TIM_IT_CC1);
  __HAL_TIM_ENABLE_IT(&htimx,TIM_IT_UPDATE);
  /* 设置字符间超时时间1.5个字符的时间 */
  __HAL_TIM_SET_COMPARE(&htimx,TIM_CHANNEL_1,(uint16_t)OVERTIME_15CHAR);
  /* 设置帧间超时时间3个字符的时间 */
  __HAL_TIM_SET_AUTORELOAD(&htimx,(uint16_t)OVERTIME_35CHAR); // 设置帧内间隔时间
}

/**
  * 函数功能: 填充内存
  * 输入参数: buf:内存空间首地址,Code:功能码
  * 返 回 值: 无
  * 说    明: 功能不同的功能码填充内容不一的内存空间
  */
void FillBuf(uint8_t* buf,uint8_t Code)
{
  uint16_t i = 0;
  uint16_t j = 1;
  switch(Code)
  {
    case FUN_CODE_01H:
    case FUN_CODE_02H:
    case FUN_CODE_05H:
      for(i= 0;i<0x200;i++)
        buf[i] = j = !j;
    break;
    case FUN_CODE_03H:
    case FUN_CODE_06H:
    case FUN_CODE_10H:
      j = 0x000F;
      for(i= 0;i<0x250;i++)
      buf[i] = j++;
    break;
  }
}

/**
  * 函数功能: 主函数.
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 无
  */
int main(void)
{
  uint16_t crc_check = 0;
  uint8_t Ex_code = 0,i=0;

  /* 初始化外设 */
  InitPeri();
  /* 申请内存空间作为线圈和输入离散量,对应功能码01H和02H
   * 每一Byte就是一个Coil或者Input
   */
  PduData.PtrCoilbase = (uint8_t*)malloc(sizeof(uint8_t)*0x200);
  FillBuf((uint8_t*)PduData.PtrCoilbase,FUN_CODE_01H);
  
  PduData.PtrHoldingbase = (uint16_t*)malloc(sizeof(uint16_t)*0x125);
  FillBuf((uint8_t*)PduData.PtrHoldingbase,FUN_CODE_03H);
  
  printf(" -------Modbus通信协议例程------ \n");
  printf("Ys-F4Pro  Modbus从机  RTU通信模式\n");
  Rx_MSG = MSG_IDLE;
  /* 无限循环 */
  while (1)
  {
    if(state==1)
    {
      state=0;
      switch(Rx_Buf[5])
      {
        case 1:
          LED1_TOGGLE;
        break;
        case 2:
          LED2_TOGGLE;
        break;
        case 3:
          LED3_TOGGLE;
        break;        
      }
    }
    /* 接收到一帧的数据,对缓存提取数据 */
    if(Rx_MSG == MSG_COM)
    {
      for(i=0;i<8;i++)
      {
        printf("Rx_Buf[%d]=%d\n",i,Rx_Buf[i]);
      }      
      /* 收到非本机地址的响应请求 */
      if((Rx_Buf[0] != MB_SLAVEADDR )&&(Rx_Buf[0] != MB_ALLSLAVEADDR))
      {
        Rx_MSG = MSG_IDLE;
        continue;
      }
      /* 解析数据帧 */
      MB_Parse_Data();

      /* CRC 校验正确 */
      crc_check = ( (Rx_Buf[RxCount-1]<<8) | Rx_Buf[RxCount-2] );
      if(crc_check == PduData._CRC)
      {
        /* 出现异常 */
        if(Ex_code !=EX_CODE_NONE)
        {
          MB_Exception_RSP(PduData.Code,Ex_code);
        }
        else
        {
          state=1;
          MB_RSP(PduData.Code);
        }
      }
      /* 重新标记为空闲状态 */
      Rx_MSG = MSG_IDLE;
    }
  }
}
/**
  * 函数功能: 串口接收中断回调函数
  * 输入参数: 串口句柄
  * 返 回 值: 无
  * 说    明: 使用一个定时器的比较中断和更新中断作为接收超时判断
  *           只要接收到数据就将定时器计数器清0,当发生比较中断的时候
  *           说明已经超时1.5个字符的时间,认定为帧错误,如果是更新中断
  *           则认为是接受完成
  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart == &husart_debug)
  {
    switch(Rx_MSG)
    {
      /* 接收到第一个字符之后开始计时1.5/3.5个字符的时间 */
      case MSG_IDLE:
        Rx_MSG = MSG_RXING;
        RxCount = 0;
        HAL_TIM_Base_Start(&htimx);
        break;
      
      /* 距离上一次接收到数据已经超过1.5个字符的时间间隔,认定为数据帧不完整 */
      case MSG_ERR_FLAG:
        Rx_MSG = MSG_INC; // 数据帧不完整
      break;
    }
   
    /* 使能继续接收 */
    Rx_Buf[RxCount] = tmp_Rx_Buf;
    RxCount++;
    __HAL_TIM_SET_COUNTER(&htimx,0); // 重设计数时间
    HAL_UART_Receive_IT(&husart_debug,(uint8_t*)&tmp_Rx_Buf,1);
  }
}
/**
  * 函数功能: 定时器比较中断回调函数
  * 输入参数: 定时器句柄
  * 返 回 值: 无
  * 说    明: 标记已经超时1.5个字符的时间没有接收到数据
  */
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* 如果是第一次发生比较中断,则暂定为错误标记 */
  if(Rx_MSG != MSG_INC)
    Rx_MSG = MSG_ERR_FLAG;
  
  /* 如果是第二次进入比较中断,则认定为报文不完整 */
  else
    Rx_MSG = MSG_INC;
}
/**
  * 函数功能: 定时器更新中断回调函数
  * 输入参数: 定时器句柄
  * 返 回 值: 无
  * 说    明: 超时3.5个字符的时间没有接收到数据,认为是空闲状态
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* 如果已经标记了接收到不完整的数据帧,则继续标记为不完整的数据帧 */
  if(Rx_MSG == MSG_INC)
  {
    Rx_MSG = MSG_INC;
  }
  /* 在正常情况下时接收完成 */
  else
  {
    Rx_MSG = MSG_COM;
  }
}

使用特权

评论回复
6
goodluck09876|  楼主 | 2018-12-4 12:41 | 只看该作者
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
   uint32_t isrflags   = READ_REG(huart->Instance->SR);
   uint32_t cr1its     = READ_REG(huart->Instance->CR1);
   uint32_t cr3its     = READ_REG(huart->Instance->CR3);
   uint32_t errorflags = 0x00U;
   uint32_t dmarequest = 0x00U;

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if(errorflags == RESET)
  {
    /* UART in mode Receiver -------------------------------------------------*/
    if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }  

  /* If some errors occur */
  if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
    /* UART parity error interrupt occurred ----------------------------------*/
    if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_PE;
    }
   
    /* UART noise error interrupt occurred -----------------------------------*/
    if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_NE;
    }
   
    /* UART frame error interrupt occurred -----------------------------------*/
    if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_FE;
    }
   
    /* UART Over-Run interrupt occurred --------------------------------------*/
    if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_ORE;
    }

    /* Call UART Error Call back function if need be --------------------------*/   
    if(huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver -----------------------------------------------*/
      if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        UART_Receive_IT(huart);
      }

      /* If Overrun error occurs, or if any error occurs in DMA mode reception,
         consider error as blocking */
      dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
      if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
      {
        /* Blocking error : transfer is aborted
           Set the UART state ready to be able to start again the process,
           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
        UART_EndRxTransfer(huart);
        
        /* Disable the UART DMA Rx request if enabled */
        if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
         
          /* Abort the UART DMA Rx channel */
          if(huart->hdmarx != NULL)
          {
            /* Set the UART DMA Abort callback :
               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
            {
              /* Call Directly XferAbortCallback function in case of error */
              huart->hdmarx->XferAbortCallback(huart->hdmarx);
            }
          }
          else
          {
            /* Call user error callback */
            HAL_UART_ErrorCallback(huart);
          }
        }
        else
        {
          /* Call user error callback */
          HAL_UART_ErrorCallback(huart);
        }
      }
      else
      {
        /* Non Blocking error : transfer could go on.
           Error is notified to user through user error callback */
        HAL_UART_ErrorCallback(huart);
        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;
  } /* End if some error occurs */

  /* UART in mode Transmitter ------------------------------------------------*/
  if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {
    UART_Transmit_IT(huart);
    return;
  }
  
  /* UART in mode Transmitter end --------------------------------------------*/
  if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {
    UART_EndTransmit_IT(huart);
    return;
  }
}

使用特权

评论回复
7
goodluck09876|  楼主 | 2018-12-4 12:42 | 只看该作者
#include "usart/bsp_debug_usart.h"

/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
UART_HandleTypeDef husart_debug;
__IO uint8_t Rx_Buf[256];            // 接收缓存,最大256字节
__IO uint8_t Tx_Buf[256];            // 发送缓存,最大256字节
__IO uint8_t tmp_Rx_Buf;             // 临时接收缓存
__IO uint16_t RxCount = 0;      // 接收字符计数
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/

/**
  * 函数功能: 串口硬件初始化配置
  * 输入参数: huart:串口句柄类型指针
  * 返 回 值: 无
  * 说    明: 该函数被HAL库内部调用
  */
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  if(huart->Instance==DEBUG_USARTx)
  {
    /* 串口外设时钟使能 */
    DEBUG_USART_RCC_CLK_ENABLE();
    RS485_REDE_GPIO_ClK_ENABLE();
    /* 串口外设功能GPIO配置 */
    GPIO_InitStruct.Pin = DEBUG_USARTx_Tx_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = DEBUG_USARTx_AFx;
    HAL_GPIO_Init(DEBUG_USARTx_Tx_GPIO, &GPIO_InitStruct);
   
    GPIO_InitStruct.Pin = DEBUG_USARTx_Rx_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Alternate = DEBUG_USARTx_AFx;   
    HAL_GPIO_Init(DEBUG_USARTx_Rx_GPIO, &GPIO_InitStruct);   
   
    /* SP3485E发送数据使能控制引脚初始化 */
    HAL_GPIO_WritePin(RS485_REDE_PORT,RS485_REDE_PIN,GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = RS485_REDE_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_REDE_PORT, &GPIO_InitStruct);
  }  
}

/**
  * 函数功能: 串口硬件反初始化配置
  * 输入参数: huart:串口句柄类型指针
  * 返 回 值: 无
  * 说    明: 该函数被HAL库内部调用
  */
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{

  if(huart->Instance==DEBUG_USARTx)
  {
    /* 串口外设时钟禁用 */
    DEBUG_USART_RCC_CLK_DISABLE();
  
    /* 串口外设功能GPIO配置 */
    HAL_GPIO_DeInit(DEBUG_USARTx_Tx_GPIO, DEBUG_USARTx_Tx_GPIO_PIN);
    HAL_GPIO_DeInit(DEBUG_USARTx_Rx_GPIO, DEBUG_USARTx_Rx_GPIO_PIN);
   
    /* 串口中断禁用 */
    HAL_NVIC_DisableIRQ(DEBUG_USART_IRQn);
  }
}

/**
  * 函数功能: 串口参数配置.
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
void MX_DEBUG_USART_Init(void)
{
  /* 使能串口功能引脚GPIO时钟 */
  DEBUG_USARTx_GPIO_ClK_ENABLE();
  
  husart_debug.Instance = DEBUG_USARTx;
  husart_debug.Init.BaudRate = DEBUG_USARTx_BAUDRATE;
  husart_debug.Init.WordLength = UART_WORDLENGTH_9B;
  husart_debug.Init.StopBits = UART_STOPBITS_1;
  husart_debug.Init.Parity = UART_PARITY_EVEN;
  husart_debug.Init.Mode = UART_MODE_TX_RX;
  husart_debug.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  husart_debug.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&husart_debug);
  
  HAL_NVIC_SetPriority(DEBUG_USART_IRQn,1,1);
  HAL_NVIC_EnableIRQ(DEBUG_USART_IRQn);
  
  /* 开启中断,存储在临时缓存中 */
  RS485_RX_MODE();
  HAL_UART_Receive_IT(&husart_debug,(uint8_t*)&tmp_Rx_Buf,1);
}
/**
  * 函数功能: 串口发送函数
  * 输入参数: Tx_Bul:发送字符串,TxCount:发送的字节数
  * 返 回 值: 无
  * 说    明: 将库函数对外封装.
  */
void UART_Tx(uint8_t *Tx_Buf,uint16_t TxCount)
{
  RS485_TX_MODE();
  HAL_UART_Transmit(&husart_debug, Tx_Buf, TxCount, 0xffff);
  RS485_RX_MODE();
}

使用特权

评论回复
8
goodluck09876|  楼主 | 2018-12-4 12:43 | 只看该作者
/* 包含头文件 ----------------------------------------------------------------*/
#include "led/bsp_led.h"

/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/

/**
  * 函数功能: 板载LED灯IO引脚初始化.
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:使用宏定义方法代替具体引脚号,方便程序移植,只要简单修改bsp_led.h
  *           文件相关宏定义就可以方便修改引脚。
  */
void LED_GPIO_Init(void)
{
   /* 定义IO硬件初始化结构体变量 */
  GPIO_InitTypeDef GPIO_InitStruct;
       
        /* 使能(开启)LED引脚对应IO端口时钟 */  
  LED1_RCC_CLK_ENABLE();
  LED2_RCC_CLK_ENABLE();
  LED3_RCC_CLK_ENABLE();
  /* 配置LED1引脚输出电压 */
  HAL_GPIO_WritePin(LED1_GPIO, LED1_GPIO_PIN, GPIO_PIN_RESET);

  /* 配置LED2引脚输出电压 */
  HAL_GPIO_WritePin(LED2_GPIO, LED2_GPIO_PIN, GPIO_PIN_RESET);
  /* 配置LED3引脚输出电压 */
  HAL_GPIO_WritePin(LED2_GPIO, LED3_GPIO_PIN, GPIO_PIN_RESET);  
  /* 设定LED1对应引脚IO编号 */
  GPIO_InitStruct.Pin = LED1_GPIO_PIN;
  /* 设定LED1对应引脚IO为输出模式 */
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  /* 设定LED1对应引脚IO操作速度 */
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  /* 初始化LED1对应引脚IO */
  HAL_GPIO_Init(LED1_GPIO, &GPIO_InitStruct);
  
  /* 设定LED2对应引脚IO编号 */
  GPIO_InitStruct.Pin = LED2_GPIO_PIN;
  /* 设定LED2对应引脚IO为输出模式 */
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  /* 设定LED2对应引脚IO操作速度 */
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  /* 初始化LED2对应引脚IO */
  HAL_GPIO_Init(LED2_GPIO, &GPIO_InitStruct);
  
  /* 设定LED3对应引脚IO编号 */
  GPIO_InitStruct.Pin = LED3_GPIO_PIN;
  /* 设定LED3对应引脚IO为输出模式 */
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  /* 设定LED3对应引脚IO操作速度 */
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  /* 初始化LED3对应引脚IO */
  HAL_GPIO_Init(LED3_GPIO, &GPIO_InitStruct);
  
}

/**
  * 函数功能: 设置板载LED灯的状态
  * 输入参数: LEDx:其中x可甚至为(1,2,3)用来选择对应的LED灯
  * 输入参数:state:设置LED灯的输出状态。
  *             可选值:LED_OFF:LED灯灭;
  *                     LED_ON: LED灯亮。
  *                     LED_TOGGLE:反转LED
  * 返 回 值: 无
  * 说    明:该函数使用类似标准库函数的编程方法,方便理解标准库函数编程思想。
  */
void LEDx_StateSet(uint8_t LEDx,LEDState_TypeDef state)
{
  /* 检查输入参数是否合法 */
  assert_param(IS_LED_TYPEDEF(LEDx));
  assert_param(IS_LED_STATE(state));
  
  /* 判断设置的LED灯状态,如果设置为LED灯灭 */
  if(state==LED_OFF)
  {
    if(LEDx & LED1)            
      LED1_OFF;/* LED1灭 */
   
    if(LEDx & LED2)
      LED2_OFF;/* LED2灭 */
   
    if(LEDx & LED3)
      LED3_OFF;/* LED3灭 */   
  }
  else if(state==LED_ON) /* 设置LED灯为亮 */
  {
    if(LEDx & LED1)
      LED1_ON;/* LED1亮 */
   
    if(LEDx & LED2)
      LED2_ON;/* LED2亮 */
   
    if(LEDx & LED3)
      LED3_ON;/* LED3亮 */
  }
  else
  {
    if(LEDx & LED1)
      LED1_TOGGLE;/* 设置引脚输出反转 */
   
    if(LEDx & LED2)
      LED2_TOGGLE;/* 设置引脚输出反转 */
   
    if(LEDx & LED3)
      LED3_TOGGLE;/* 设置引脚输出反转 */
  }
}

使用特权

评论回复
9
goodluck09876|  楼主 | 2018-12-4 12:43 | 只看该作者
/* 包含头文件 ----------------------------------------------------------------*/
#include "GeneralTIM/bsp_GeneralTIM.h"

/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
TIM_HandleTypeDef htimx;

/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/

/**
  * 函数功能: 基本定时器初始化
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 无
  */
void GENERAL_TIMx_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_OC_InitTypeDef sOCConfig;

  htimx.Instance = GENERAL_TIMx;
  htimx.Init.Prescaler = GENERAL_TIM_PRESCALER;
  htimx.Init.CounterMode = TIM_COUNTERMODE_UP;
  htimx.Init.Period = GENERAL_TIM_PERIOD;
  htimx.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_OnePulse_Init(&htimx,TIM_OPMODE_SINGLE);

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htimx, &sClockSourceConfig);

  /* 定时器比较输出配置 */
  sOCConfig.OCMode = TIM_OCMODE_TOGGLE;                // 比较输出模式:反转输出
  sOCConfig.Pulse = 0xFFFF;                      // 脉冲数
  sOCConfig.OCPolarity = TIM_OCPOLARITY_HIGH;          // 输出极性
  sOCConfig.OCNPolarity = TIM_OCNPOLARITY_LOW;         // 互补通道输出极性
  sOCConfig.OCFastMode = TIM_OCFAST_DISABLE;           // 快速模式
  sOCConfig.OCIdleState = TIM_OCIDLESTATE_RESET;       // 空闲电平
  sOCConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;     // 互补通道空闲电平
  HAL_TIM_OC_ConfigChannel(&htimx, &sOCConfig, STEPMOTOR_TIM_CHANNEL_1);
  HAL_TIM_OC_ConfigChannel(&htimx, &sOCConfig, STEPMOTOR_TIM_CHANNEL_2);
  
}

/**
  * 函数功能: 基本定时器硬件初始化配置
  * 输入参数: htim_base:基本定时器句柄类型指针
  * 返 回 值: 无
  * 说    明: 该函数被HAL库内部调用
  */
void HAL_TIM_OnePulse_MspInit(TIM_HandleTypeDef* htim_base)
{

  if(htim_base->Instance==GENERAL_TIMx)
  {
    /* 基本定时器外设时钟使能 */
    GENERAL_TIM_RCC_CLK_ENABLE();

    /* 外设中断配置 */
    HAL_NVIC_SetPriority(GENERAL_TIM_IRQ, 0, 0);
    HAL_NVIC_EnableIRQ(GENERAL_TIM_IRQ);
  }
}

/**
  * 函数功能: 基本定时器硬件反初始化配置
  * 输入参数: htim_base:基本定时器句柄类型指针
  * 返 回 值: 无
  * 说    明: 该函数被HAL库内部调用
  */
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{

  if(htim_base->Instance==GENERAL_TIMx)
  {
    /* 基本定时器外设时钟禁用 */
    GENERAL_TIM_RCC_CLK_DISABLE();

    /* 关闭外设中断 */
    HAL_NVIC_DisableIRQ(GENERAL_TIM_IRQ);
  }
}

使用特权

评论回复
10
goodluck09876|  楼主 | 2018-12-4 12:43 | 只看该作者
#include "Modbus/bsp_MB_slave.h"
#include "usart/bsp_debug_usart.h"
#include "GeneralTIM/bsp_GeneralTIM.h"
#include "led/bsp_led.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
PDUData_TypeDef PduData;

// CRC 高位字节值表
static const uint8_t auchCRCHi[] = {
    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
} ;
// CRC 低位字节值表
static const uint8_t auchCRCLo[] = {
        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
};
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
static uint8_t MB_JudgeAddr(uint16_t _Addr,uint16_t _RegNum);
static uint8_t MB_JudgeNum(uint16_t _RegNum,uint8_t _FunCode,uint16_t _ByteNum);
static uint8_t MB_10H_WR_NReg(uint16_t*Ptr,uint16_t NumofReg, uint8_t*buf);
static uint8_t MB_RSP_10H(uint16_t _TxCount,uint16_t _AddrOffset,uint16_t _ByteNum);
static uint16_t MB_RSP_01H(uint16_t _TxCount,uint8_t *_AddrOffset ,uint16_t _CoilNum);
static uint8_t MB_RSP_03H(uint16_t _TxCount,uint16_t *_AddrOffset,uint16_t _RegNum );
static uint8_t MB_RSP_05H(uint16_t _TxCount,uint16_t _AddrOffset ,uint8_t *_AddrAbs);
static uint8_t MB_RSP_06H(uint16_t _TxCount,uint16_t _AddrOffset ,uint16_t *_AddrAbs);
static uint8_t MB_RSP_10H(uint16_t _TxCount,uint16_t _AddrOffset,uint16_t _ByteNum);

/* 函数体 --------------------------------------------------------------------*/

/**
  * 函数功能: Modbus CRC16 校验计算函数
  * 输入参数: pushMsg:待计算的数据首地址,usDataLen:数据长度
  * 返 回 值: CRC16 计算结果
  * 说    明: 计算结果是高位在前,需要转换才能发送
  */
uint16_t MB_CRC16(uint8_t *_pushMsg,uint8_t _usDataLen)
{
  uint8_t uchCRCHi = 0xFF;
  uint8_t uchCRCLo = 0xFF;
  uint16_t uIndex;
  while(_usDataLen--)
  {
    uIndex = uchCRCLo ^ *_pushMsg++;
    uchCRCLo = uchCRCHi^auchCRCHi[uIndex];
    uchCRCHi = auchCRCLo[uIndex];
  }
  return (uchCRCHi<<8|uchCRCLo);
}
/* 提取数据帧,进行解析数据帧 */
void MB_Parse_Data()
{
  PduData.Code = Rx_Buf[1];                   // 功能码
  PduData.Addr = ((Rx_Buf[2]<<8) | Rx_Buf[3]);// 寄存器起始地址
  PduData.Num  = ((Rx_Buf[4]<<8) | Rx_Buf[5]);// 数量(Coil,Input,Holding Reg,Input Reg)
  PduData._CRC = MB_CRC16((uint8_t*)&Rx_Buf,RxCount-2);             // CRC校验码
  PduData.byteNums = Rx_Buf[6];               // 获得字节数
  PduData.ValueReg = (uint8_t*)&Rx_Buf[7];                          // 寄存器值起始地址
  PduData.PtrCoilOffset = PduData.PtrCoilbase + PduData.Addr;       // 离散量的内存起始地址
  PduData.PtrHoldingOffset = PduData.PtrHoldingbase + PduData.Addr; // 保持寄存器的起始地址
}
/**
  * 函数功能: 对接收到的数据进行分析并执行
  * 输入参数: 无
  * 返 回 值: 异常码或0x00
  * 说    明: 判断功能码,验证地址是否正确.数值内容是否溢出,数据没错误就发送响应信号
  */
uint8_t MB_Analyze_Execute(void )
{
  uint16_t ExCode = EX_CODE_NONE;
  /* 校验功能码 */
  if( IS_NOT_FUNCODE(PduData.Code) ) // 不支持的功能码
  {
    /* Modbus异常响应 */
    ExCode = EX_CODE_01H;            // 异常码01H
    return ExCode;
  }
  /* 根据功能码分别做判断 */
  switch(PduData.Code)
  {
    /* 这里认为01H功能码和02功能码是一样的,其实也没什么不一样
     * 只是操作地址可能不一样,这一点结合具体来实现,可以在main函数
     * 申请单独的内存使用不同的功能码,在实际应用中必须加以区分使用
     * 不同的内存空间
     */
/* ---- 01H  02H 读取离散量输入(Coil Input)---------------------- */
    case FUN_CODE_01H:
    case FUN_CODE_02H:
      /* 判断线圈数量是否正确 */  
      ExCode = MB_JudgeNum(PduData.Num,PduData.Code,1);
      if(ExCode != EX_CODE_NONE )
        return ExCode;      
      
      /* 判断地址是否正确*/
      ExCode = MB_JudgeAddr( PduData.Addr,PduData.Num);
      if(ExCode != EX_CODE_NONE )
        return ExCode;  
      

      if(HAL_GPIO_ReadPin(LED3_GPIO,LED3_GPIO_PIN) == GPIO_PIN_RESET)
      {
        /* 读取输出状态异常 */
        ExCode = EX_CODE_04H;
        return ExCode;
      }
      break;
/* ---- 03H  04H 读取保持/输入寄存器---------------------- */
    case FUN_CODE_03H:
    case FUN_CODE_04H:
      /* 判断寄存器数量是否正确 */
      ExCode = MB_JudgeNum(PduData.Num,PduData.Code,PduData.byteNums);
      if(ExCode != EX_CODE_NONE )
        return ExCode;  
      
      /* 判断地址是否正确*/
      ExCode = MB_JudgeAddr( PduData.Addr,PduData.Num);
      if(ExCode != EX_CODE_NONE )
        return ExCode;  
     
      if(HAL_GPIO_ReadPin(LED3_GPIO,LED3_GPIO_PIN) == GPIO_PIN_RESET)
      {
        /* 读取输出状态异常 */
        ExCode = EX_CODE_04H;
        return ExCode;
      }
      break;
/* ---- 05H 写入单个离散量---------------------- */
    case FUN_CODE_05H:
      /* 输出值!=OK */
      if((PduData.Num != 0x0000) && PduData.Num != 0xFF00)
      {
        ExCode = EX_CODE_03H;
        return ExCode;        
      }
      /* 写入一个线圈值 */
      if(PduData.Num == 0xFF00)
      {
        *PduData.PtrCoilOffset = 1;
        /* 读取写入值,验证是否写入成功 */
        if( *PduData.PtrCoilOffset != 1)
        {
          ExCode = EX_CODE_04H;
          return ExCode;
        }
      }
      else
      {
        *PduData.PtrCoilOffset = 0;
        /* 读取写入值,验证是否写入成功 */
        if( *PduData.PtrCoilOffset != 0)
        {
          ExCode = EX_CODE_04H;
          return ExCode;
        }
      }
      break;
/* ---- 06H 写单个保持寄存器 ---------------------- */
    case FUN_CODE_06H:
      
      /* 写入寄存器值*/
      *PduData.PtrHoldingOffset = PduData.Num;
      /* 验证写成功 */
      if(*PduData.PtrHoldingOffset != PduData.Num)
      {
        ExCode = EX_CODE_04H;
         return ExCode;
      }
      break;
/* ---- 10H 写多个保持寄存器 ---------------------- */
    case FUN_CODE_10H:
      /* 判断寄存器数量是否正确 */
      ExCode = MB_JudgeNum(PduData.Num,PduData.Code,PduData.byteNums);
      if(ExCode != EX_CODE_NONE )
        return ExCode;   
      
      /* 判断地址是否正确*/
      ExCode = MB_JudgeAddr( PduData.Addr,PduData.Num);
      if(ExCode != EX_CODE_NONE )
        return ExCode;  
      
      /* 写入多个寄存器 */
      ExCode = MB_10H_WR_NReg((uint16_t*)PduData.PtrHoldingOffset,PduData.Num,(uint8_t*)PduData.ValueReg);
      if(ExCode != EX_CODE_NONE )
        return ExCode;  
      break;
  }
  /* 数据帧没有异常 */
  return ExCode; //   EX_CODE_NONE
}
/**
  * 函数功能: 写,读N个寄存器
  * 输入参数: _AddrOffset:偏移地址,_RegNum:寄存器数量,_Datebuf:数据指针
  * 返 回 值: 异常码:04H或NONE
  * 说    明: 在_AddrOffset所指向的空间里写入_RegNum*2个数据,并且读取验证是否写入成功
  */
uint8_t MB_10H_WR_NReg(uint16_t* _AddrOffset,uint16_t _RegNum , uint8_t* _Datebuf)
{
  uint16_t i = 0;
  uint16_t Value = 0;
  uint16_t* ValAddr = _AddrOffset;
  uint8_t* tempDatabuf = _Datebuf;
  for(i=0;i<_RegNum;i++)
  {
    Value = (uint16_t)((*_Datebuf<<8 ) | (*(_Datebuf+1)));
    *_AddrOffset++ = Value ;
    _Datebuf+=2;
  }
  /* 读取验证写入是否成功 */
  _Datebuf = tempDatabuf;
  for(i = 0;i<_RegNum;i++)
  {
    Value = (uint16_t)((*_Datebuf<<8 ) | (*(_Datebuf+1)));
    if(*ValAddr++ != Value)
    {
      return EX_CODE_04H;
    }
    _Datebuf+=2;
  }
  return EX_CODE_NONE;
}
/**
  * 函数功能: 判断地址是否符合协议范围
  * 输入参数: _Addr:起始地址,_RegNum:寄存器数量,_FunCode:功能码
  * 返 回 值: 异常码:02H或NONE
  * 说    明: 地址范围是0x0000~0xFFFF,可操作的空间范围不能超过这个区域
  */
uint8_t MB_JudgeAddr(uint16_t _Addr,uint16_t _RegNum)
{
  uint8_t Excode = EX_CODE_NONE;
  /* 地址+寄存器数量不能超过0xFFFF */
  if( ((uint32_t)_RegNum+(uint32_t)_Addr) > (uint32_t)0xFFFF)
  {
    Excode = EX_CODE_02H;// 异常码 02H
  }
  return Excode;
}
/**
  * 函数功能: 判断操作的数据量是否符合协议范围
  * 输入参数: _RegNum:寄存器数量,_FunCode:功能码,_ByteNum:字节数量
  * 返 回 值: 异常码:03或NONE
  * 说    明: 对可操作连续内存空间的功能码需要验证操作的地址是否符合范围
  */
uint8_t MB_JudgeNum(uint16_t _RegNum,uint8_t _FunCode,uint16_t _ByteNum)
{
  uint8_t Excode = EX_CODE_NONE;
  uint16_t _CoilNum = _RegNum; // 线圈(离散量)的数量
  switch(_FunCode)
  {
    case FUN_CODE_01H:
    case FUN_CODE_02H:
      if( (_CoilNum<0x0001) || (_CoilNum>0x07D0))
        Excode = EX_CODE_03H;// 异常码03H;
      break;
    case FUN_CODE_03H:
    case FUN_CODE_04H:
      if( (_RegNum<0x0001) || (_RegNum>0x007D))
        Excode = EX_CODE_03H;// 异常码03H;      
      break;
    case FUN_CODE_10H:
      if( (_RegNum<0x0001) || (_RegNum>0x007B))
        Excode = EX_CODE_03H;// 异常码03H
      if( _ByteNum != (_RegNum<<1))
        Excode = EX_CODE_03H;// 异常码03H
      break;
  }
  return Excode;
}
/**
  * 函数功能: 读取离散输出
  * 输入参数: _TxCount :发送计数器,_AddrOffset地址偏移量,_CoilNum:线圈数量
  * 返 回 值: Tx_Buf的数组元素坐标
  * 说    明: 读取离散输出,并且填充Tx_Buf
  */
uint16_t MB_RSP_01H(uint16_t _TxCount,uint8_t *_AddrOffset ,uint16_t _CoilNum)
{
  uint16_t ByteNum = 0;
  uint16_t i = 0;
  uint16_t r = 0 ;
  ByteNum = _CoilNum/8;
  /* 如果存在余数,需要将多余的位置0 */
  r = _CoilNum%8;
  if(r != 0)
  {
    ByteNum += 1; //字节数+1
    Tx_Buf[_TxCount++] = ByteNum;  
   
    /* 在忽略余数的情况下读取线圈(bit)的状态 */
    for(i=0;i<ByteNum-1;i++)
    {
      Tx_Buf[_TxCount] = 0x00;
      /* 每8个线圈(bit)一次循环,读取8个线圈的状态放置在一个Byte*/
      for(uint8_t j=0;j<8;j++)
      {
        /* 如果是1,则将byte对应位(bit)置1 */
        if(*(_AddrOffset++))
        {
          /* 在这里相当于将一个Byte当成一个线圈(bit)映射到一个Byte上
           * 由8个Byte组成一个Byte的8个bit
           */
          Tx_Buf[_TxCount] |= (0x01<<j);
        }
      }
      _TxCount++;
    }
    /* 有余数部分组成一个字节,多余的bit设置为0 */
    Tx_Buf[_TxCount] = 0x00;
    for(uint8_t j=0;j<r;j++)
    {
      if(*(_AddrOffset++))
      {
        Tx_Buf[_TxCount] |= (0x01<<j);// 读取数据
      }
    }
    _TxCount++;
  }
  /* 如果余数r==0,说明需要读取的线圈数量(bits)刚好是Byte的整数倍 */
  else
  {
    Tx_Buf[_TxCount++] = ByteNum;
    for(i=0;i<ByteNum;i++)
    {
      Tx_Buf[_TxCount] = 0x00;
      for(uint8_t j=0;j<8;j++)
      {
        if(*(_AddrOffset++))
        {
          Tx_Buf[_TxCount] |= (0x01<<j);// 读取数据
        }
      }
      _TxCount++;
    }
  }
  return _TxCount;
}
/**
  * 函数功能: 读取保持寄存器
  * 输入参数: _TxCount :发送计数器,_AddrOffset地址偏移量,_RegNum:寄存器数量
  * 返 回 值: Tx_Buf的数组元素坐标
  * 说    明: 读取保持寄存器的内容,并且填充Tx_Buf
  */
uint8_t MB_RSP_03H(uint16_t _TxCount,uint16_t *_AddrOffset,uint16_t _RegNum )
{
  Tx_Buf[_TxCount++] = _RegNum<<1;
  for(uint8_t i = 0;i< _RegNum;i++)
  {
    Tx_Buf[_TxCount++] = ((*_AddrOffset)>>8);
    Tx_Buf[_TxCount++] = *_AddrOffset++;
  }
  return _TxCount;
}
/**
  * 函数功能: 根据05H功能码填充发送缓冲区
  * 输入参数: _TxCount :发送计数器,_AddrOffset地址偏移量,_AddrAbs:绝对地址值
  * 返 回 值: Tx_Buf的数组元素坐标
  * 说    明: 填充Tx_Buf
  */
uint8_t MB_RSP_05H(uint16_t _TxCount,uint16_t _AddrOffset ,uint8_t *_AddrAbs)
{
  /* 填充地址值 */
  Tx_Buf[_TxCount++] = _AddrOffset>>8;
  Tx_Buf[_TxCount++] = _AddrOffset;
  /* 填充输出值 */
  if((*_AddrAbs) == 1)
    Tx_Buf[_TxCount++] = 0xFF;
  else Tx_Buf[_TxCount++] = 0x00;
  Tx_Buf[_TxCount++] = 0x00;
  return _TxCount;
}
/**
  * 函数功能: 根据06H功能码填充发送缓冲区
  * 输入参数: _TxCount :发送计数器,_AddrOffset地址偏移量,_AddrAbs:绝对地址值
  * 返 回 值: Tx_Buf的数组元素坐标
  * 说    明: 填充Tx_Buf
  */
uint8_t MB_RSP_06H(uint16_t _TxCount,uint16_t _AddrOffset ,uint16_t *_AddrAbs)
{
  /* 填充地址值 */
  Tx_Buf[_TxCount++] = _AddrOffset>>8;
  Tx_Buf[_TxCount++] = _AddrOffset;
  /* 填充输出值 */
  Tx_Buf[_TxCount++] = (*_AddrAbs)>>8;
  Tx_Buf[_TxCount++] = *_AddrAbs;
  return _TxCount;
}
/**
  * 函数功能: 根据10H功能码填充发送缓冲区
  * 输入参数: _TxCount :发送计数器,_AddrOffset地址偏移量,_ByteNum:字节数量
  * 返 回 值: Tx_Buf的数组元素坐标
  * 说    明: 填充Tx_Buf
  */
uint8_t MB_RSP_10H(uint16_t _TxCount,uint16_t _AddrOffset,uint16_t _ByteNum)
{
  Tx_Buf[_TxCount++] = _AddrOffset>>8;
  Tx_Buf[_TxCount++] = _AddrOffset;
  
  Tx_Buf[_TxCount++] = _ByteNum>>8;
  Tx_Buf[_TxCount++] = _ByteNum;
  return _TxCount;
}
/**
  * 函数功能: 异常响应
  * 输入参数: _FunCode :发送异常的功能码,_ExCode:异常码
  * 返 回 值: 无
  * 说    明: 当通信数据帧发生异常时,发送异常响应
  */
void MB_Exception_RSP(uint8_t _FunCode,uint8_t _ExCode)
{
  uint16_t TxCount = 0;
  uint16_t crc = 0;
        Tx_Buf[TxCount++] = MB_SLAVEADDR;                    /* 从站地址 */
        Tx_Buf[TxCount++] = _FunCode|0x80;                  /* 功能码 + 0x80*/       
        Tx_Buf[TxCount++] = _ExCode ;                  /* 异常码*/
       
  crc = MB_CRC16((uint8_t*)&Tx_Buf,TxCount);
  Tx_Buf[TxCount++] = crc;                  /* crc 低字节 */
        Tx_Buf[TxCount++] = crc>>8;                      /* crc 高字节 */
  UART_Tx((uint8_t*)Tx_Buf, TxCount);
}
/**
  * 函数功能: 正常响应
  * 输入参数: _FunCode :功能码
  * 返 回 值: 无
  * 说    明: 当通信数据帧没有异常时并且成功执行之后,发送响应数据帧
  */
void MB_RSP(uint8_t _FunCode)
{
  uint16_t TxCount = 0;
  uint16_t crc = 0;        Tx_Buf[TxCount++] = MB_SLAVEADDR;                 /* 从站地址 */
        Tx_Buf[TxCount++] = _FunCode;        /* 功能码   */       
  switch(_FunCode)
  {
    case FUN_CODE_01H:
    case FUN_CODE_02H:
      TxCount = MB_RSP_01H(TxCount,(uint8_t*)PduData.PtrCoilOffset,PduData.Num);
      break;
    case FUN_CODE_03H:
    case FUN_CODE_04H:
      TxCount = MB_RSP_03H(TxCount,(uint16_t*)PduData.PtrHoldingOffset,PduData.Num);
      break;
    case FUN_CODE_05H:
      TxCount = MB_RSP_05H(TxCount,PduData.Addr,(uint8_t*)PduData.PtrCoilOffset);
      break;
    case FUN_CODE_06H:
      TxCount = MB_RSP_06H(TxCount,PduData.Addr,(uint16_t*)PduData.PtrHoldingOffset);
      break;
    case FUN_CODE_10H:
      TxCount = MB_RSP_10H(TxCount,PduData.Addr,PduData.Num);
      break;
  }
  crc = MB_CRC16((uint8_t*)&Tx_Buf,TxCount);
  Tx_Buf[TxCount++] = crc;                  /* crc 低字节 */
        Tx_Buf[TxCount++] = crc>>8;                      /* crc 高字节 */
  UART_Tx((uint8_t*)Tx_Buf, TxCount);
}

使用特权

评论回复
11
goodluck09876|  楼主 | 2018-12-4 12:44 | 只看该作者
/* 包含头文件 ----------------------------------------------------------------*/
#include "usart/bsp_usartx.h"
#include <string.h>
#include <stdio.h>

/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
UART_HandleTypeDef husartx;
static __IO uint32_t TimingDelay=0;

/* 扩展变量 ------------------------------------------------------------------*/
extern uint8_t aRxBuffer;
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
  * 函数功能: GSM通信功能引脚GPIO初始化
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
void GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    /* 串口外设时钟使能 */
    USARTx_GPIO_ClK_ENABLE();
   
    /* 串口外设功能GPIO配置 */
    GPIO_InitStruct.Pin = USARTx_Tx_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(USARTx_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = USARTx_Rx_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(USARTx_PORT, &GPIO_InitStruct);
   
}

/**
  * 函数功能: 串口参数配置.
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
void USARTx_Init(void)
{
  /* GSM通信功能引脚GPIO初始化 */
  GPIO_Init();
  USARTx_RCC_CLK_ENABLE();
  husartx.Instance = USARTx;
  husartx.Init.BaudRate = USARTx_BAUDRATE;
  husartx.Init.WordLength = UART_WORDLENGTH_8B;
  husartx.Init.StopBits = UART_STOPBITS_1;
  husartx.Init.Parity = UART_PARITY_NONE;
  husartx.Init.Mode = UART_MODE_TX_RX;
  husartx.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  husartx.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&husartx);

  
}

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&husartx, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE * f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&husartx,&ch, 1, 0xffff);
  return ch;
}

使用特权

评论回复
12
goodluck09876|  楼主 | 2018-12-4 12:44 | 只看该作者
#ifndef __BSP_DEBUG_USART_H__
#define __BSP_DEBUG_USART_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
#define DEBUG_USARTx                                 USART3
#define DEBUG_USARTx_BAUDRATE                        19200
#define DEBUG_USART_RCC_CLK_ENABLE()                 __HAL_RCC_USART3_CLK_ENABLE()
#define DEBUG_USART_RCC_CLK_DISABLE()                __HAL_RCC_USART3_CLK_DISABLE()

#define DEBUG_USARTx_GPIO_ClK_ENABLE()               __HAL_RCC_GPIOB_CLK_ENABLE()
#define DEBUG_USARTx_Tx_GPIO_PIN                     GPIO_PIN_10
#define DEBUG_USARTx_Tx_GPIO                         GPIOB
#define DEBUG_USARTx_Rx_GPIO_PIN                     GPIO_PIN_11
#define DEBUG_USARTx_Rx_GPIO                         GPIOB

#define DEBUG_USARTx_AFx                             GPIO_AF7_USART3

#define DEBUG_USART_IRQn                             USART3_IRQn
#define DEBUG_USART_IRQHANDLER                       USART3_IRQHandler

/* 使用485通信的时候才会用到使能IO */
#define RS485_REDE_GPIO_ClK_ENABLE()                 __HAL_RCC_GPIOH_CLK_ENABLE()
#define RS485_REDE_PORT                              GPIOH
#define RS485_REDE_PIN                               GPIO_PIN_8
#define RS485_RX_MODE()                              HAL_GPIO_WritePin(RS485_REDE_PORT,RS485_REDE_PIN,GPIO_PIN_RESET)
#define RS485_TX_MODE()                              HAL_GPIO_WritePin(RS485_REDE_PORT,RS485_REDE_PIN,GPIO_PIN_SET)

/* RTU通信需要确定超时时间 */
#if DEBUG_USARTx_BAUDRATE <= 19200
  /* 1.5个字符的超时时间 T = BAUDRATE/11/1000*/
  #define OVERTIME_15CHAR             (((float)DEBUG_USARTx_BAUDRATE/11)*1.5f)
  /* 3个字符的超时时间 */
  #define OVERTIME_35CHAR             (((float)DEBUG_USARTx_BAUDRATE/11)*3.5f)
#else
  /* 波特率超过19200bit/s的情况下建议的超时时间 */
  #define OVERTIME_15CHAR                750.0f    // 750us
  #define OVERTIME_35CHAR               1750.0f  // 1.75ms  
  
#endif
/* 扩展变量 ------------------------------------------------------------------*/
extern UART_HandleTypeDef husart_debug;
extern __IO uint8_t Rx_Buf[256];    // 接收缓存,最大256字节
extern __IO uint8_t Tx_Buf[256];    // 接收缓存,最大256字节
extern __IO uint8_t tmp_Rx_Buf;     // 接收缓存
extern  __IO uint16_t RxCount;      // 接收字符计数
  
/* 函数声明 ------------------------------------------------------------------*/
void MX_DEBUG_USART_Init(void);
void UART_Tx(uint8_t *Tx_Buf,uint16_t TxCount);

#endif  /* __BSP_DEBUG_USART_H__ */

使用特权

评论回复
13
goodluck09876|  楼主 | 2018-12-4 12:44 | 只看该作者
#ifndef __BSP_LED_H__
#define __BSP_LED_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* 类型定义 ------------------------------------------------------------------*/
typedef enum
{
  LED_OFF = 0,
  LED_ON  = 1,
  LED_TOGGLE = 2,
}LEDState_TypeDef;
#define IS_LED_STATE(STATE)           (((STATE) == LED_OFF) || ((STATE) == LED_ON) || ((STATE) == LED_TOGGLE))

/* 宏定义 --------------------------------------------------------------------*/
#define LED1                          (uint8_t)0x01
#define LED2                          (uint8_t)0x02
#define LED3                          (uint8_t)0x04
#define IS_LED_TYPEDEF(LED)           (((LED) == LED1) || ((LED) == LED2) || ((LED) == LED3))

/*
* 以下宏定义内容跟开发板硬件息息相关,需要查看开发板电路原理图才能正确编写。
* 例如,查原理图可在LED1灯接在stm32f407芯片的PH9引脚上,所以有关LED1的宏定义
* 都是与GPIOH,GPIO_Pin_9相关的,我们专门把这些与开发板硬件相关的内容定义为宏,
* 这对于修改或者移植程序非常方便。
*/
#define LED1_RCC_CLK_ENABLE()         __HAL_RCC_GPIOH_CLK_ENABLE()
#define LED1_GPIO_PIN                 GPIO_PIN_9
#define LED1_GPIO                     GPIOH


#define LED2_RCC_CLK_ENABLE()         __HAL_RCC_GPIOE_CLK_ENABLE()
#define LED2_GPIO_PIN                 GPIO_PIN_5
#define LED2_GPIO                     GPIOE


#define LED3_RCC_CLK_ENABLE()         __HAL_RCC_GPIOE_CLK_ENABLE()
#define LED3_GPIO_PIN                 GPIO_PIN_6
#define LED3_GPIO                     GPIOE

#define LED1_ON                       HAL_GPIO_WritePin(LED1_GPIO,LED1_GPIO_PIN,GPIO_PIN_SET)    // 输出高电平
#define LED1_OFF                      HAL_GPIO_WritePin(LED1_GPIO,LED1_GPIO_PIN,GPIO_PIN_RESET)  // 输出低电平
#define LED1_TOGGLE                   HAL_GPIO_TogglePin(LED1_GPIO,LED1_GPIO_PIN)                // 输出反转

#define LED2_ON                       HAL_GPIO_WritePin(LED2_GPIO,LED2_GPIO_PIN,GPIO_PIN_SET)    // 输出高电平
#define LED2_OFF                      HAL_GPIO_WritePin(LED2_GPIO,LED2_GPIO_PIN,GPIO_PIN_RESET)  // 输出低电平
#define LED2_TOGGLE                   HAL_GPIO_TogglePin(LED2_GPIO,LED2_GPIO_PIN)                // 输出反转

#define LED3_ON                       HAL_GPIO_WritePin(LED3_GPIO,LED3_GPIO_PIN,GPIO_PIN_SET)    // 输出高电平
#define LED3_OFF                      HAL_GPIO_WritePin(LED3_GPIO,LED3_GPIO_PIN,GPIO_PIN_RESET)  // 输出低电平
#define LED3_TOGGLE                   HAL_GPIO_TogglePin(LED3_GPIO,LED3_GPIO_PIN)                // 输出反转


/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void LED_GPIO_Init(void);
void LEDx_StateSet(uint8_t LEDx,LEDState_TypeDef state);

#endif  // __BSP_LED_H__

使用特权

评论回复
14
goodluck09876|  楼主 | 2018-12-4 12:45 | 只看该作者
#ifndef __GENERAL_TIM_H__
#define __GENERAL_TIM_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
/********************通用定时器TIM参数定义,TIM2~TIM5************/

#define GENERAL_TIMx                     TIM5
#define GENERAL_TIM_RCC_CLK_ENABLE()     __HAL_RCC_TIM5_CLK_ENABLE()
#define GENERAL_TIM_RCC_CLK_DISABLE()    __HAL_RCC_TIM5_CLK_DISABLE()
#define GENERAL_TIM_IRQ                  TIM5_IRQn
#define GENERAL_TIM_INT_FUN              TIM5_IRQHandler

#define STEPMOTOR_TIM_CHANNEL_1          TIM_CHANNEL_1
#define STEPMOTOR_TIM_CHANNEL_2          TIM_CHANNEL_2
// 定义定时器预分频,定时器实际时钟频率为:84MHz/(GENERAL_TIM_PRESCALER+1)
#define GENERAL_TIM_PRESCALER           83  // 实际时钟频率为:1MHz
// 定义定时器周期,当定时器开始计数到BASIC_TIMx_PERIOD值是更新定时器并生成对应事件和中断
#define GENERAL_TIM_PERIOD              0xFFFF

/* 扩展变量 ------------------------------------------------------------------*/
extern TIM_HandleTypeDef htimx;

/* 函数声明 ------------------------------------------------------------------*/

void GENERAL_TIMx_Init(void);

#endif        /* __GENERAL_TIM_H__ */
/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/

使用特权

评论回复
15
goodluck09876|  楼主 | 2018-12-4 12:45 | 只看该作者
#ifndef __BSP_MB_SLAVE_H__
#define __BSP_MB_SLAVE_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* 类型定义 ------------------------------------------------------------------*/
typedef struct {
  __IO uint8_t  Code ;                  // 功能码
  __IO uint8_t byteNums;                 // 字节数
  __IO uint16_t Addr ;            // 操作内存的起始地址
  __IO uint16_t Num;                     // 寄存器或者线圈的数量
  __IO uint16_t _CRC;                     // CRC校验码
  __IO uint8_t *ValueReg;               // 10H功能码的数据
  __IO uint8_t *PtrCoilbase;                  // Coil和Input内存首地址
  __IO uint8_t *PtrCoilOffset;    // Coil和Input偏移内存首地址
  __IO uint16_t *PtrHoldingbase;  // HoldingReg内存首地址
  __IO uint16_t *PtrHoldingOffset;// HoldingReg内存首地址
}PDUData_TypeDef;

/* 宏定义 --------------------------------------------------------------------*/
#define MB_SLAVEADDR            0x0001
#define MB_ALLSLAVEADDR         0x00FF

#define FUN_CODE_01H            0x01  // 功能码01H
#define FUN_CODE_02H            0x02  // 功能码02H
#define FUN_CODE_03H            0x03  // 功能码03H
#define FUN_CODE_04H            0x04  // 功能码04H
#define FUN_CODE_05H            0x05  // 功能码05H
#define FUN_CODE_06H            0x06  // 功能码06H
#define FUN_CODE_10H            0x10  // 功能码10H

/* 本例程所支持的功能码,需要添加新功能码还需要在.c文件里面添加 */
#define IS_NOT_FUNCODE(code)  (!((code == FUN_CODE_01H)||\
                                 (code == FUN_CODE_02H)||\
                                 (code == FUN_CODE_03H)||\
                                 (code == FUN_CODE_04H)||\
                                 (code == FUN_CODE_05H)||\
                                 (code == FUN_CODE_06H)||\
                                 (code == FUN_CODE_10H)))

#define EX_CODE_NONE           0x00  // 异常码 无异常
#define EX_CODE_01H            0x01  // 异常码
#define EX_CODE_02H            0x02  // 异常码
#define EX_CODE_03H            0x03  // 异常码
#define EX_CODE_04H            0x04  // 异常码
/* 扩展变量 ------------------------------------------------------------------*/
extern PDUData_TypeDef PduData;
/* 函数声明 ------------------------------------------------------------------*/
uint16_t MB_CRC16(uint8_t *pushMsg,uint8_t usDataLen);
void MB_Parse_Data(void);
void MB_WriteNumHoldingReg_10H(uint8_t _addr, uint16_t _reg, uint16_t _num,uint8_t *_databuf);
uint8_t MB_Analyze_Execute(void );
uint8_t MB_JudgeNum(uint16_t _Num,uint8_t _FunCode,uint16_t ByteNum);
uint8_t MB_JudgeAddr(uint16_t _Addr,uint16_t _Num);
void MB_Exception_RSP(uint8_t _FunCode,uint8_t _ExCode);
void MB_RSP(uint8_t _FunCode);
#endif /* __BSP_MB_SLAVE_H__ */
/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/

使用特权

评论回复
16
renzheshengui| | 2018-12-5 13:26 | 只看该作者
感谢分享 好详细啊

使用特权

评论回复
17
木木guainv| | 2018-12-5 14:33 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
18
goodluck09876|  楼主 | 2018-12-5 14:41 | 只看该作者
modbus 主机从机全有的!

使用特权

评论回复
19
734774645| | 2018-12-5 20:45 | 只看该作者
目前好多工业设备还是要求具备这个通信接口

使用特权

评论回复
20
yklstudent| | 2018-12-6 08:40 | 只看该作者
嗯 支持一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

220

主题

5843

帖子

21

粉丝