在STM32单片机上实现Modbus主站与从站:企业实战分享
在STM32单片机上实现Modbus主站与从站功能,通过合理配置硬件和编写软件代码,可以满足企业设备通信的需求。实际应用中还需要根据具体场景进行优化,比如处理通信超时、错误重传等情况,让通信更加稳定可靠。希望这篇文章能给你在相关项目开发中带来一些启发。Modbus 主站 从站 在STM32单片机上的实现,企业在用的程序。
Modbus 主站 从站 在STM32单片机上的实现,企业在用的程序。
在工业自动化领域,Modbus协议因其简单可靠,被广泛应用于设备间的通信。今天就来聊聊如何在STM32单片机上实现Modbus主站与从站功能,这可是企业实际在用的程序哦。
Modbus协议基础
Modbus协议定义了主站和从站之间如何通信。主站发起请求,从站响应。常见的功能码有0x03(读取保持寄存器)、0x06(写单个寄存器)等。比如主站要读取从站的保持寄存器数据,就会发送包含功能码0x03、从站地址、寄存器起始地址和数量等信息的请求帧。
STM32单片机实现Modbus主站
硬件准备
使用STM32开发板,一般需要用到串口(UART)来与外部设备进行Modbus通信。假设我们使用的是STM32F4系列开发板,将PA9(TX)和PA10(RX)配置为复用推挽输出模式用于串口通信。
软件实现
- 初始化串口
void USART_Init(void) {
USART_InitTypeDef USART_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
USART_InitStruct.USART_BaudRate = 9600;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
}
这里先使能GPIOA和USART1的时钟,配置PA9和PA10为复用功能并选择USART1的复用功能,最后设置串口的波特率、数据位、停止位等参数并使能串口。
- 发送Modbus请求帧
void Send_Modbus_Request(uint8_t slave_addr, uint8_t func_code, uint16_t reg_addr, uint16_t reg_count) {
uint8_t request[8];
uint16_t crc;
request[0] = slave_addr;
request[1] = func_code;
request[2] = (uint8_t)(reg_addr >> 8);
request[3] = (uint8_t)reg_addr;
request[4] = (uint8_t)(reg_count >> 8);
request[5] = (uint8_t)reg_count;
crc = CalculateCRC16(request, 6);
request[6] = (uint8_t)(crc & 0xFF);
request[7] = (uint8_t)(crc >> 8);
for (int i = 0; i < 8; i++) {
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, request[i]);
}
}
这个函数构建Modbus请求帧,包括从站地址、功能码、寄存器地址和数量,然后计算CRC校验并添加到帧尾,最后通过串口发送出去。
STM32单片机实现Modbus从站
硬件部分同样是串口配置,和主站类似,不再赘述。
软件实现
- 接收处理函数
void Receive_Modbus_Response(void) {
uint8_t response[256];
uint8_t len = 0;
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE)!= RESET) {
response[len++] = USART_ReceiveData(USART1);
}
// 校验CRC
uint16_t received_crc = (uint16_t)(response[len - 1] << 8 | response[len - 2]);
uint16_t calculated_crc = CalculateCRC16(response, len - 2);
if (received_crc == calculated_crc) {
// 处理请求,根据功能码不同进行不同处理
if (response[1] == 0x03) {
// 读取保持寄存器功能码处理
uint16_t reg_addr = (uint16_t)(response[2] << 8 | response[3]);
uint16_t reg_count = (uint16_t)(response[4] << 8 | response[5]);
// 这里根据实际寄存器数据填充响应帧
// 假设保持寄存器数据在数组holding_regs中
for (int i = 0; i < reg_count; i++) {
response[9 + i * 2] = (uint8_t)(holding_regs[reg_addr + i] >> 8);
response[10 + i * 2] = (uint8_t)holding_regs[reg_addr + i];
}
// 设置响应帧长度和CRC等
response[7] = reg_count * 2;
uint16_t new_crc = CalculateCRC16(response, 8 + reg_count * 2);
response[8 + reg_count * 2] = (uint8_t)(new_crc & 0xFF);
response[9 + reg_count * 2] = (uint8_t)(new_crc >> 8);
// 发送响应帧
for (int i = 0; i < 10 + reg_count * 2; i++) {
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, response[i]);
}
}
}
}
这个函数接收Modbus请求帧,校验CRC后根据功能码进行处理。这里以功能码0x03为例,读取保持寄存器数据并填充响应帧,重新计算CRC后发送响应。
总结
在STM32单片机上实现Modbus主站与从站功能,通过合理配置硬件和编写软件代码,可以满足企业设备通信的需求。实际应用中还需要根据具体场景进行优化,比如处理通信超时、错误重传等情况,让通信更加稳定可靠。希望这篇文章能给你在相关项目开发中带来一些启发。
Modbus 主站 从站 在STM32单片机上的实现,企业在用的程序。

更多推荐



所有评论(0)