MS-DTU/MS-DTU-V1/User/modbus_slave.c

283 lines
7.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "includes.h"
// 任务主体
void Modbus_Task(uint8_t c);
// modbus通讯处理
#pragma pack(push, 1)
typedef struct
{
uint8_t id; // 通信地址
uint8_t cmd; // 功能码
uint16_t reg; // 寄存器地址
union
{
uint16_t cnt; // 读取:寄存器数量
uint16_t data; // 写入:寄存器数据
};
uint16_t crc;
} modbus_request_t;
typedef struct
{
uint8_t id; // 通信地址
uint8_t cmd; // 功能码
uint16_t reg; // 寄存器地址
// union
// {
// uint16_t data[13];
//
// };
uint16_t staDiff; //30001
uint16_t diff; //差压值
uint16_t volumePct; //30003 容积百分比
uint16_t volumeH; // 容积H
uint16_t volumeL; // 容积L
uint16_t weightH; // 重量H
uint16_t weightL; // 重量L
uint16_t highMMWC;
uint16_t press;
int16_t tempr; //30010温度
uint16_t source; //30011介质
uint16_t v_H; //
uint16_t v_L; //
// uint16_t staVacuum; // 真空计状态
// uint16_t vacuum; // 真空度,
// int16_t vacuum_tempr;//30016 真空计温度
///////////////////
uint16_t crc;
} modbus_readdata_t;
#pragma pack(pop)
// modbus rtu 数据缓冲区
#define MODBUS_1ST_REG (30001) // 第1个数据地址
#define MODBUS_LAST_REG (30016) // 最后一个数据地址
#define MODBUS_ADR_REG (40001) // 通信地址的数据地址
// modbus rtu错误代码
#define MODBUS_ERR_ILF (0x01) // 无效功能码
#define MODBUS_ERR_ILA (0x02) // 无效通讯地址
#define MODBUS_ERR_ILD (0x03) // 无效数据值
#define MODBUS_ERR_FID (0x04) // 执行失败
#define MODBUS_ERR_ACK (0x05) // ACK命令已接受并在处理中
#define MODBUS_ERR_BUSY (0x06) // 设备忙,拒绝
#define MODBUS_ERR_NAK (0x07) // NAK命令无法执行
// modbus rtu 数据缓冲区
//uint8_t MODBUS_RTU_Buf[(MODBUS_LAST_REG - MODBUS_1ST_REG + 1) * 2];
modbus_readdata_t modbus_data;
void Slave_IRQHandler(USART_Handle *huart)
{
uint8_t u8DTU = (uint8_t) huart->Instance->RDR;
/* Handle received data */
Modbus_Task(u8DTU);
}
void Slave_Init()
{
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
//LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
/**USART3 GPIO Configuration
PC10 ------> USART3_TX
PC11 ------> USART3_RX
PA15 ------> USART3_DE
Pb10 ------> LPRX
Pb11 ------> LPTX
Pb1 ------> LP_DE
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_10|LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
//GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
#define RS485_EN() LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_1);
#define RS485_DIS() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_1);
/*---------------------------------------------------------------------------------------------------------*/
/* RS485 Transmit Control (Address Byte: Parity Bit =1 , Data Byte:Parity Bit =0) */
/*---------------------------------------------------------------------------------------------------------*/
static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
{
/* Set UART parity as SPACE and skip baud rate setting */
// UART_SetLine_Config(UART1, 0, UART_WORD_LEN_8, UART_PARITY_SPACE, UART_STOP_BIT_1);
/* Send data */
// UART_Transmit_IT(&huart3, pu8TxBuf, u32WriteBytes);
RS485_EN();
delay_us(1);
// 设置超时和结果
modbus_outTick = GetDelayTick(500);
UART_Transmit_IT(&hlpuart1, pu8TxBuf, u32WriteBytes);
delay_ms(9); // 至少8ms保险起见9ms
RS485_DIS();
}
void Slave_Open()
{
// LL_USART_InitTypeDef USART_InitStruct = {0};
// huart3.RxISR = Slave_IRQHandler;
// /* Peripheral clock enable */
// LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3);
// /* USART3 interrupt Init */
// NVIC_SetPriority(USART3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
// NVIC_EnableIRQ(USART3_IRQn);
// /* USER CODE BEGIN USART3_Init 1 */
// /* USER CODE END USART3_Init 1 */
// USART_InitStruct.BaudRate = 9600;
// USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
// USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
// USART_InitStruct.Parity = LL_USART_PARITY_NONE;
// USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
// USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
// USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
// LL_USART_Init(USART3, &USART_InitStruct);
// LL_USART_EnableDEMode(USART3);
// LL_USART_SetDESignalPolarity(USART3, LL_USART_DE_POLARITY_HIGH);
// LL_USART_SetDEAssertionTime(USART3, 0);
// LL_USART_SetDEDeassertionTime(USART3, 0);
// LL_USART_ConfigAsyncMode(USART3);
// SET_BIT(USART3->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
// LL_USART_Enable(USART3);
LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
hlpuart1.RxISR = Slave_IRQHandler;
/* Peripheral clock enable */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
NVIC_EnableIRQ(LPUART1_IRQn);
LPUART_InitStruct.BaudRate = 9600;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
LL_LPUART_EnableDEMode(LPUART1);
LL_LPUART_SetDESignalPolarity(LPUART1, LL_LPUART_DE_POLARITY_HIGH);
LL_LPUART_SetDEAssertionTime(LPUART1, 0);
LL_LPUART_SetDEDeassertionTime(LPUART1, 0);
SET_BIT(LPUART1->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
LL_LPUART_Enable(LPUART1);
}
uint32_t Fill_MODBUS_RTU_Buf()
{
return 1;
}
// 处理modbus rtu命令已经验证过长度和CRC的包
void MODBUS_RTU_CMD(modbus_readdata_t *req)
{
// 检查通信地址
if(req->id != 0x01)
return;
if(req->cmd != 0x04)
return;
}
// 模块任务主体:处理射频接收数据
// 任务主体
uint8_t modbus_idx2 = 0;
uint8_t MODBUS_BUFF[sizeof(modbus_readdata_t)] = {0};
uint16_t CRC2=0;
void Modbus_Task(uint8_t c)
{
uint8_t len = 0;
////////////
uint16_t i;
uint8_t frameOk, frameErr;
uint32_t mask;
//rs_data_t *rsData = (rs_data_t *) (RS_TranFrame.data + sizeof(mask));
if(modbus_idx2 == 0 && c != 0x01)
return;
MODBUS_BUFF[modbus_idx2++] = c;
// printf("\n***\n***\n*** read data[%d]=%d ***\n***\n***\n",len,c);
// 验证长度和CRC值
len=sizeof(modbus_readdata_t)-1;
if(modbus_idx2 == len)
{
if(MODBUS_RTU_CRC16(MODBUS_BUFF, sizeof(modbus_readdata_t)) == 0)
{
MODBUS_RTU_CMD((modbus_readdata_t *) MODBUS_BUFF);
modbus_idx2 = 0;
}
else
{
// 丢掉第一个字节
memmove(MODBUS_BUFF, MODBUS_BUFF + 1, --modbus_idx2);
}
}
}
void modbus_read_data(void)
{
// uint8_t id; // 通信地址
// uint8_t cmd; // 功能码
// uint16_t reg; // 寄存器地址
// union
// {
// uint16_t cnt; // 读取:寄存器数量
// uint16_t data; // 写入:寄存器数据
//// };
uint16_t crc;
// static uint8_t BUFF2[sizeof(modbus_request_t)] = {0x01,0x04,0x00,0x00,0x00,0x0d,0x31,0xcf};
static uint8_t BUFF2[sizeof(modbus_request_t)] = {0};
uint8_t len=0;
// 计算CRC
BUFF2[len++]=0x01; //addr
BUFF2[len++]=0x04; //cmd
BUFF2[len++]=0x00; //regaddr
BUFF2[len++]=0x00; //regaddr
BUFF2[len++]=0x00; //cnt
BUFF2[len++]=0x0d; //cnt
crc = MODBUS_RTU_CRC16(BUFF2, len);
crc = htons(crc);
memmove(BUFF2 + len, &crc, 2);
len += 2;
RS485_SendDataByte(BUFF2, len);
}