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