基于stm32hal库开发的485通讯模块

头文件HDL_RS485.H

/**
  ******************************************************************************
  * @file    HDL_RS485.H
  * @brief   485通信硬件驱动D的头文件
  *         该头主要包括定义的类的变量,以及对外的变量接口,和行为接口(接口函数)。    
  * */
/*******************************************************************************
**                             Author(s) Identity                             **
**                             维护人员列表                                     **
********************************************************************************
** Initials     Name                                                          **
** ---------------------------------------------------------------------------**

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

/*******************************************************************************
**                         Revision Control History                           **
********************************************************************************
**@version        初始版本需求                             **
**@version        初始版本                             **
*******************************************************************************/
#ifndef _HDL_RS485_H
#define _HDL_RS485_H

#include "stm32f1xx_hal.h"


#define  TX_MODE  0x01
#define  RX_MODE  0x00

#define  TX_BUSY 0x01
#define  TX_IDLE  0x00
#define  RX_BUF_EMPTY 0x00
#define  RX_BUF_READY 0x01

#define  RS485_NUM     1       //硬件中,RS485模块的数量  

typedef struct 
{
    GPIO_TypeDef*   RxOrTxEN_Port;             //  Hal库结构体  RXEN,and TXEN 连接到1个引脚
    const uint16_t  RxOrTxEN_Gpio_Pin;       //  RXEN,and TXEN 连接到1个引脚
    GPIO_TypeDef*   Rx_Port;                   //  Hal库结构体  RX引脚的port
    const uint16_t  Rx_Gpio_Pin;             //  RX引脚的pin
    GPIO_TypeDef*   Tx_Port;                   //  Hal库结构体  TX引脚的port
    const uint16_t  Tx_Gpio_Pin;             //  TX引脚的pin
    USART_TypeDef*  Uart_Channel;           //  Hal库结构体  串口号选择 
    const uint32_t  baudrate;                      //  波特率
    uint8_t mode;                                 //  Rx mode 0x00 or TX MODE 0x01 ,接收模式或发送模式,默认接收模式
    uint8_t TxState;                              //  Busy 0x01 or idle 0x00 ,忙碌状态(正在发送),或空闲状态,默认空闲状态
    uint8_t RxBuffer;                             //  485接收数据的内容,默认0x00;
    uint8_t RxBufferstate;                        //  接收完成 0x01  接收缓存空:0x00,ready 0x01 or empty 0x00
} TypeDef_HDL_RS485;


/****HDL_PORT FUNCTION******/
uint8_t HDL_RS485_Init(TypeDef_HDL_RS485 *this_485);
uint8_t HDL_RS485_SetMode(TypeDef_HDL_RS485 *this_485, uint8_t RxOrTxMode);
uint8_t HDL_RS485_GetMode(TypeDef_HDL_RS485 *this_485);

uint8_t HDL_RS485_GetTxState(TypeDef_HDL_RS485 *this_485);
uint8_t HDL_RS485_SetTxState(TypeDef_HDL_RS485 *this_485, uint8_t TxState);

uint8_t HDL_RS485_RecData(TypeDef_HDL_RS485 *this_485);
uint8_t HDL_RS485_TransData(TypeDef_HDL_RS485 *this_485,uint8_t TxData);
void HDL_RS485_uart_IRQ_Task(void);

/****HDL_PORT GlobalParameter******/
extern TypeDef_HDL_RS485 RS485_1;  
extern TypeDef_HDL_RS485 RS485_2;
extern UART_HandleTypeDef  RS481_1_UartHandle;

#endif /* _HDL_RS485_H */

C文件HDL_RS485.C

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    HDL_RS485.c
  * @brief   485通信硬件驱动
  *         该硬件模块是实现485收发通信,属于数据链路层的驱动。
  *                   使用STM32串口模块实现485功能,并使用GPIO控制芯片引脚工作在相应的模式下。
  *         驱动要求:1、能够配置485的状态,并在串口收发中断中执行。
  *                  2、要求能配置控制485的引脚使模块处在接收,或发送状态。
  *                  3、要求能查询485通信状态: 收缓存区,发缓存区是否为空。
  *                                          收发数据时,状态置为0x01,数据取走后,软件置0x00
  *                  4、要求能够返回485通信接收值
  *                  5、可以具备STM32串口模块具备的其他功能
  * @todo                                 
  * */
 /*******************************************************************************
**                             Author(s) Identity                              **
**                             维护人员列表                                     **
********************************************************************************
** Initials     Name                                                          **
** ---------------------------------------------------------------------------**
**                                                                         **
*******************************************************************************/

/*******************************************************************************
**  2-Revision Control History                                                **
**  2-版本维护历史                                                              **
********************************************************************************
**@version                      **
**@version                                  **
*******************************************************************************/

/* 3-Includes ----------------------------------------------------------------*/
#include "HDL_RS485.h"

/* 4-define ------------------------------------------------------------------*/
#define HARD_WARE_VERSION 

#define HDL_RS485_uart_IRQ_Task		USART1_IRQHandler //串口中断号重命名
#define RS485_NUM     1       //硬件中,RS485模块的数量         

//模块1的属性宏定义,关联到HAL库
#define M1_RXOrTXEN_GPIO_PORT  GPIOC       //  RXEN,and TXEN 连接到1个引脚
#define M1_RXOrTXEN_GPIO_PIN   GPIO_PIN_4       //  RXEN,and TXEN 连接到1个引脚
#define M1_RX_GPIO_PORT        GPIOA       //  RX
#define M1_RX_GPIO_PIN         GPIO_PIN_10       //  RX
#define M1_TX_GPIO_PORT        GPIOA       //  TX
#define M1_TX_GPIO_PIN         GPIO_PIN_9       //  RX
#define M1_UART                USART1       //  关联到HAL库

//模块2的属性宏定义,关联到HAL库
#define M2_RXOrTXEN_GPIO_PORT  GPIOC       //  RXEN,and TXEN 连接到1个引脚
#define M2_RXOrTXEN_GPIO_PIN   GPIO_PIN_4        //  RXEN,and TXEN 连接到1个引脚
#define M2_RX_GPIO_PORT        GPIOA       //  RX
#define M2_RX_GPIO_PIN         GPIO_PIN_10       //  RX
#define M2_TX_GPIO_PORT        GPIOA       //  TX
#define M2_TX_GPIO_PIN         GPIO_PIN_9       //  RX
#define M2_UART                USART1       //  关联到HAL库

//RS485模块一串口句柄全局定义
UART_HandleTypeDef  RS481_1_UartHandle;

/* 5-function declaration -----------------------------------------------------*/
// 5.1-Public_function declaration --------------------------------------------
uint8_t HDL_RS485_Init(TypeDef_HDL_RS485 *this_485);
uint8_t HDL_RS485_SetMode(TypeDef_HDL_RS485 *this_485, uint8_t RxOrTxMode);
uint8_t HDL_RS485_GetMode(TypeDef_HDL_RS485 *this_485);

uint8_t HDL_RS485_GetTxState(TypeDef_HDL_RS485 *this_485);
uint8_t HDL_RS485_SetTxState(TypeDef_HDL_RS485 *this_485, uint8_t TxState);

uint8_t HDL_RS485_RecData(TypeDef_HDL_RS485 *this_485);
uint8_t HDL_RS485_TransData(TypeDef_HDL_RS485 *this_485,uint8_t TxData);

void HDL_RS485_uart_IRQ_Task(void);

// 5.2-privace_function declaration --------------------------------------------

/* 6-parameter declaration and initial ---------------------------------------*/
 TypeDef_HDL_RS485 RS485_1 = 
 {
  .RxOrTxEN_Port      = M1_RXOrTXEN_GPIO_PORT,
  .RxOrTxEN_Gpio_Pin  = M1_RXOrTXEN_GPIO_PIN,
  .Rx_Port            = M1_RX_GPIO_PORT,
  .Rx_Gpio_Pin        = M1_RX_GPIO_PIN,
  .Tx_Port            = M1_TX_GPIO_PORT,
  .Tx_Gpio_Pin        = M1_TX_GPIO_PIN,
  .Uart_Channel       = M1_UART,
  .baudrate           = 9600,
  .mode               = RX_MODE,
  .TxState            = TX_IDLE,
  .RxBufferstate      = RX_BUF_EMPTY,
  .RxBuffer           = 0x00,
 };

 TypeDef_HDL_RS485 RS485_2 = 
 {
  .RxOrTxEN_Port      = M2_RXOrTXEN_GPIO_PORT,
  .RxOrTxEN_Gpio_Pin  = M2_RXOrTXEN_GPIO_PIN,
  .Rx_Port            = M2_RX_GPIO_PORT,
  .Rx_Gpio_Pin        = M2_RX_GPIO_PIN,
  .Tx_Port            = M2_TX_GPIO_PORT,
  .Tx_Gpio_Pin        = M2_TX_GPIO_PIN,
  .Uart_Channel       = M2_UART,
  .baudrate           = 9600,
  .mode               = RX_MODE,
  .TxState            = TX_IDLE,
  .RxBufferstate      = RX_BUF_EMPTY,
  .RxBuffer           = 0x00,
 };


/* 7-function declaration and initial ---------------------------------------*/



 /**
  * @name   uint8_t HDL_RS485_Init(TypeDef_HDL_RS485 *this_485);
  * @brief  初始化485模块的变量和状态
  *         初始化485模式:读模式
  *         初始化485发送状态:空闲
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * 
  * @retval uint8_t result  ,0x00,初始化成功。
  *                         0x01,初始化失败。
  *                         可以细化更多初始化失败码
  */
uint8_t HDL_RS485_Init(TypeDef_HDL_RS485 *this_485)
 {
    RS481_1_UartHandle.Instance = this_485->Uart_Channel;
    RS481_1_UartHandle.Init.BaudRate = this_485->baudrate;
    RS481_1_UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
    RS481_1_UartHandle.Init.StopBits = UART_STOPBITS_1;
    RS481_1_UartHandle.Init.Parity = UART_PARITY_NONE;
    RS481_1_UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    RS481_1_UartHandle.Init.Mode = UART_MODE_TX_RX;

    HAL_UART_Init(&RS481_1_UartHandle);

    __HAL_UART_ENABLE_IT(&RS481_1_UartHandle,UART_IT_RXNE);  

    if(RS481_1_UartHandle.Instance == this_485->Uart_Channel && RS481_1_UartHandle.Init.BaudRate == this_485->baudrate)
    {
      return (0x00);
    }
    else
    {
      return (0x01);
    }
 }

 /**
  * @name   HAL_UART_MspInit(UART_HandleTypeDef *huart);
  * @brief  UART MSP 初始化,UART初始化时会调用该重定向函数
  * @param  huart 指针型结构体,指向所用的串口句柄
  * @retval 无
  */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
  GPIO_InitTypeDef GPIO_InitStruct;

   __HAL_RCC_USART1_CLK_ENABLE();
   __HAL_RCC_GPIOA_CLK_ENABLE();
   __HAL_RCC_GPIOC_CLK_ENABLE();

   /* 配置Tx引脚为复用功能 */ 
   GPIO_InitStruct.Pin = RS485_1.Tx_Gpio_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
   GPIO_InitStruct.Pull = GPIO_PULLUP; 
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
   HAL_GPIO_Init(RS485_1.Tx_Port, &GPIO_InitStruct);

   /* 配置Rx引脚为复用功能 */
   GPIO_InitStruct.Pin = RS485_1.Rx_Gpio_Pin;
   GPIO_InitStruct.Mode=GPIO_MODE_AF_INPUT;
   HAL_GPIO_Init(RS485_1.Rx_Port, &GPIO_InitStruct);

   /* 配置EN引脚为推挽输出功能 */
   GPIO_InitStruct.Pin = RS485_1.RxOrTxEN_Gpio_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Pull = GPIO_PULLUP;
   GPIO_InitStruct.Speed =  GPIO_SPEED_FREQ_HIGH;
   HAL_GPIO_Init(RS485_1.RxOrTxEN_Port, &GPIO_InitStruct);

   HAL_NVIC_SetPriority(USART1_IRQn ,0,1);	//抢占优先级0,子优先级1
   HAL_NVIC_EnableIRQ(USART1_IRQn);		//使能USART1中断通道 
}


 /**
  * @name   uint8_t HDL_RS485_SetMode(TypeDef_HDL_RS485 *this_485, uint8_t RxOrTxMode);
  * @brief  设置485模块的使能引脚,切换模式,模式包括:接收模式,发送模式两种,
  *         根据是否正在发送,来判断是否切换模式。
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * @param  uint8_t RxOrTxMode  ,0x00,接收模式。
  *                             0x01,发送模式,
  * 
  * @retval  uint8_t result  ,0x00,执行成功。
  *                          0x01,执行失败。
  *                         可以细化更多失败码
  */
uint8_t HDL_RS485_SetMode(TypeDef_HDL_RS485 *this_485, uint8_t RxOrTxMode)
{
  switch(RxOrTxMode)
  {
    case TX_MODE:
      HAL_Delay(500);
      HAL_GPIO_WritePin(this_485->RxOrTxEN_Port, this_485->RxOrTxEN_Gpio_Pin, GPIO_PIN_SET);
      HAL_Delay(500);
      this_485->mode = TX_MODE;
      return (0x00);
    case RX_MODE:
      HAL_Delay(500);
      HAL_GPIO_WritePin(this_485->RxOrTxEN_Port, this_485->RxOrTxEN_Gpio_Pin, GPIO_PIN_RESET);
      HAL_Delay(500);
      this_485->mode = RX_MODE;
      return (0x00);
    default:
      return (0x01);
  }
}


 /**
  * @name   HDL_RS485_GetMode(TypeDef_HDL_RS485 *this_485);
  * @brief  获取485模块的状态(读取引脚),状态包括:接收状态,发送状态两种
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * 
  * @retval uint8_t RxOrTxMode  ,0x00,接收模式。
  *                             0x01,发送模式,
  */
uint8_t HDL_RS485_GetMode(TypeDef_HDL_RS485 *this_485)
{
    return (this_485->mode);
}


/**
  * @name   uint8_t HDL_RS485_GetTxState(TypeDef_HDL_RS485 *this_485);
  * @brief  获取485模块1的状态,
  *         状态包括:忙碌状态(正在发送)
  *                  或空闲状态,默认空闲状态
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * 
  * @retval uint8_t TxState  ,0x00,空闲
  *                          0x01,正在发送
  */
uint8_t HDL_RS485_GetTxState(TypeDef_HDL_RS485 *this_485)
{
    return (this_485->TxState);
}



/**
  * @name   uint8_t HDL_RS485_SetTxState(TypeDef_HDL_RS485 *this_485, uint8_t TxState);
  * @brief  设置485模块1的状态,
  *         状态包括:忙碌状态(正在发送)
  *                  或空闲状态,默认空闲状态
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * @param  uint8_t TxState  ,0x00,空闲
  *                          0x01,正在发送
  * @retval uint8_t result  ,0x00,执行成功。
  *                         0x01,执行失败。  
  */
uint8_t HDL_RS485_SetTxState(TypeDef_HDL_RS485 *this_485, uint8_t TxState)
{
  switch(TxState)
  {
    case TX_IDLE:
      this_485->TxState = TX_IDLE;
      return (0x00);
    case TX_BUSY:
      this_485->TxState = TX_BUSY;
      return (0x00);
    default:
      return (0x01);
  }
}



 /**
  * @name   uint8_t HDL_RS485_RecData(TypeDef_HDL_RS485 *this_485);
  * @brief  读取485模块接收缓存的结果,并将缓存标志位清零
  *         
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * 
  * @retval uint8_t RxData  返回缓存值
  */

uint8_t HDL_RS485_RecData(TypeDef_HDL_RS485 *this_485)
{ 
  this_485->RxBufferstate = RX_BUF_EMPTY;
  return (this_485->RxBuffer);
}



 /**
  * @name   uint8_t HDL_RS485_1_TxData(uint8_t TxData);
  * @brief  通过485发送串口数据
  *         
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * @param  uint8_t TxData  ,待发送数据
  * 
  * @retval uint8_t result      0x00,执行成功。
  *                           0x01,执行失败。
  */
uint8_t HDL_RS485_TransData(TypeDef_HDL_RS485 *this_485,uint8_t TxData)
{
  if(this_485->Uart_Channel == RS481_1_UartHandle.Instance)
  {
    HAL_UART_Transmit(&RS481_1_UartHandle,(uint8_t *)&TxData,1,0xffff);
    return (0x00);
  }
  else
  {
    return (0x01);
  }
}


/**
  * @name   void HDL_RS485_uart_IRQ_Task(void);
  * @brief  通过485串口接收中断,每个模块1个中断,
  *               刷新接收状态和数据
  *               当为接收模式时,接收完成中断触发后,则缓存接收数据,并将缓存标志位置1,
  *               .RxBufferstate   = RX_BUF_READY,
  *               .RxBuffer        = hal串口数据,
  *         
  * @param  this_485 指针型结构体,指向TypeDef_HDL_RS485类型的结构体对象,
  *         1个485模块一个结构体,方便操作多个485模块
  * 
  * @retval 无
  *                         
  */
void HDL_RS485_uart_IRQ_Task(void)
{
  if(RS481_1_UartHandle.Instance == RS485_1.Uart_Channel)
		{
			if(__HAL_UART_GET_FLAG(&RS481_1_UartHandle, UART_FLAG_RXNE) != RESET)
			{
				if(RS485_1.mode == RX_MODE)
				{
					HAL_UART_Receive(&RS481_1_UartHandle,(uint8_t *)&RS485_1.RxBuffer,1,1000);
					RS485_1.RxBufferstate = RX_BUF_READY;
				}
			}
		} 
}

/*********************************************END OF FILE**********************/





简易说明:运用串口中断接收上位机发送的一个字节数据,运用面向对象的思想进行封装,要修改不同的串口和引脚,只需修改对应的宏定义即可

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32 HAL CAN中断接收,是指在使用STM32芯片和HAL编程时,通过CAN总线的中断方式来接收数据。CAN总线是一种常用于工控和汽车电子领域的通讯总线,采用异步传输方式,具有高速、可靠和抗干扰性强等特点。 在使用HAL编程时,可以通过配置CAN总线的中断处理函数来实现CAN总线的中断接收功能。具体操作包括以下步骤: 1. 初始化CAN总线和相关的GPIO引脚,并配置CAN总线的CAN接收中断使能。 2. 定义CAN的中断处理函数,在CAN数据接收时自动调用。在函数中可以实现接收的数据处理、状态更新、回应等操作。 3. 在主程序中启用CAN的中断,以便可以在数据到达时及时响应。 4. 在CAN中断处理函数中实现数据的解析和处理,并保存到相应的数据缓冲区或变量中,以便供上层应用程序调用。 需要注意的是,CAN总线的中断接收功能需要与发送功能配合使用,才能实现双向数据传输。例如,在接收到数据后需要进行数据处理、状态更新,并向发送方回复响应,以保证数据的可靠传输和通信的完整性。 总之,STM32 HAL CAN中断接收是一种基于中断处理函数的数据接收方式,它可以实现数据的可靠传输和快速响应,广泛应用于工控和汽车电子等领域。 ### 回答2: STM32 HAL CAN 是一种基于HAL的CAN总线通信协议。其中断接收是指当CAN的接收FIFO缓冲区中有新的数据传入时,通过配置CAN的中断来触发中断服务程序的执行,并将接收到的数据存储在相应的缓冲区中。 使用STM32 HAL CAN进行中断接收的步骤如下: 1.初始化CAN:使用HAL_CAN_Init函数初始化CAN总线,并设置通信速率、帧格式、过滤器、中断等参数。 2.使能CAN中断:使用HAL_CAN_ActivateNotification函数使能CAN中断。如果要使能RS232的中断,还需使用HAL_CAN_ConfigInterrupt函数来配置RS232的中断模式。 3.在中断服务程序中实现数据接收:配置CAN的中断服务程序,并在程序中使用HAL_CAN_Receive_IT函数实现CAN数据的接收和存储。在此过程中,还需使用HAL_CAN_GetRxMessage函数来获取接收到的数据,并将其存储在相应的缓冲区中。 需要注意的是,在中断接收过程中,还需注意CAN总线的数据处理速度。如果数据处理速度太慢,会导致FIFO缓冲区溢出,从而无法存储全部的数据。因此,建议使用DMA的方式来实现数据的处理和存储,以提高CAN总线的数据处理效率。 总之,STM32 HAL CAN 中断接收是一种基于中断方式实现的CAN总线通信协议,通过配置CAN的中断,实现对接收数据的读取和存储。在实际应用中,需要结合具体的场景和要求来选取合适的CAN通信协议和实现方式。 ### 回答3: STM32 HAL是ST公司为了方便STM32系列单片机开发开发应用程序而推出的一套开发。CAN是一种串行通信总线,用于连接微控制器和外部设备。在STM32 HAL中实现CAN中断接收的方法如下: 1. 配置CAN模块:在使用CAN模块前首先对CAN模块进行配置,包括波特率、模式等配置。 2. 开启CAN中断:使用HAL_CAN_ActivateNotification函数开启CAN的中断,设置回调函数。 3. 编写CAN接收回调函数:在CAN中断发生时,将调用CAN接收回调函数。在CAN接收回调函数中,可以获取接收到的CAN数据并进行处理,如解析数据、发送响应等操作。 4. 启动CAN模块:配置完成后,使用HAL_CAN_Start函数启动CAN模块,开始接收CAN数据。 5. 等待并处理CAN数据:CAN数据接收后,在CAN接收回调函数中进行处理。如果没有接收到CAN数据,则程序会一直等待,直到CAN数据到达。 通过以上步骤,即可使用STM32 HAL实现CAN中断接收。在CAN通讯系统中,中断接收方式的优点在于响应速度快、实时性高,可以更加有效地处理CAN发来的数据。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值