stm32f103单片机modbus通信示例
时间: 2023-05-10 22:02:48 浏览: 245
STM32F103单片机是一款高性能ARM Cortex-M3内核的单片机,其拥有丰富的外设资源,是工业自动化、智能仪器仪表等领域的理想选择。而Modbus通信作为工业控制领域通信方案的代表,被广泛应用于工业自动化等领域。本篇文章将介绍STM32F103单片机的Modbus通信示例。
首先,我们需要了解Modbus通信的基本原理。Modbus是一种简单、易于实现、可靠的串行通信协议,广泛应用于工业自动化等领域。Modbus通信主要有两种模式:RTU模式和ASCII模式。RTU模式是一种二进制模式,具有高效性能和实时性能,常用于串口通信;而ASCII模式是一种文本模式,对于跨平台应用有优势。
接下来,我们以STM32F103单片机通过串口实现Modbus RTU通信为例进行说明。代码示例如下:
/*Modbus RTU通信*/
#include <stdlib.h>
#include <stdio.h>
#include "stm32f10x.h"
/*串口初始化*/
void USART_init(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/*开启USART1的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*开启GPIOA的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*将USART1 Tx的GPIO配置为推挽复用模式*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*将USART1 Rx的GPIO配置为浮空输入模式*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*USART1复位*/
USART_DeInit(USART1);
/*USART1的初始化设置*/
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
/*使能USART1*/
USART_Cmd(USART1, ENABLE);
}
/*Modbus数据读取函数*/
uint8_t Modbus_Read(uint8_t *data)
{
int i=0,j=0;
uint8_t temp[40];
/*等待串口数据传输完毕*/
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
/*读取串口数据*/
temp[i] = USART_ReceiveData(USART1);
if(temp[i] == 0x02)//判断地址是否正确
{
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
temp[++i] = USART_ReceiveData(USART1);
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
/*数据长度*/
int len = USART_ReceiveData(USART1);
i++;
/*读取数据*/
for(j=0; j<len; j++)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == RESET);
temp[i++] = USART_ReceiveData(USART1);
}
/*禁止串口接收中断*/
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
/*CRC校验及通信判断*/
uint16_t CRC = 0xffff;
for(i=0; i<len+3; i++)
{
CRC ^= temp[i];
for(j=0; j<8; j++)
{
if(CRC&0x0001)
{
CRC >>= 1;
CRC ^= 0xa001;
}
else
{
CRC >>= 1;
}
}
}
/*CRC校验成功,则读取数据*/
if(CRC == 0x0000)
{
for(i=0; i<len; i++)
{
data[i] = temp[3+i];
}
/*返回数据长度*/
return len;
}
}
/*返回读取数据失败*/
return 0;
}
如上代码所示,首先进行串口初始化,并定义了Modbus数据读取函数Modbus_Read。在Modbus_Read函数中,等待串口数据传输完毕,并读取数据,进行CRC校验后返回读取的数据长度。
此外,我们还需要对发送的数据进行打包和发送。代码示例如下:
/*Modbus数据发送*/
void Modbus_Write(uint8_t address, uint8_t function, uint16_t start, uint16_t count, uint8_t *data)
{
int i=0,j=0;
uint16_t CRC = 0xffff;
/*打包数据*/
uint8_t package[40] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/*Modbus数据头*/
package[0] = address;
package[1] = function;
/*Modbus数据起始地址*/
package[2] = start>>8;
package[3] = start;
/*Modbus数据数量*/
package[4] = count>>8;
package[5] = count;
/*Modbus数据长度*/
package[6] = count*2;
/*数据转化*/
for(i=0; i<count; i++)
{
package[7+i*2] = data[i]>>8;
package[8+i*2] = data[i];
}
/*计算CRC校验*/
for(i=0; i<count*2+7; i++)
{
CRC ^= package[i];
for(j=0; j<8; j++)
{
if(CRC&0x0001)
{
CRC >>= 1;
CRC ^= 0xa001;
}
else
{
CRC >>= 1;
}
}
}
/*CRC校验*/
package[count*2+7] = CRC;
package[count*2+8] = CRC>>8;
/*发送数据*/
for(i=0; i<count*2+9; i++)
{
/*等待发送数据完毕*/
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
/*发送数据*/
USART_SendData(USART1,package[i]);
}
}
以上代码定义了Modbus数据发送函数Modbus_Write,并打包了Modbus数据,进行CRC校验后发送数据。
这就是STM32F103单片机Modbus通信的一个简单示例,实现了通过串口实现Modbus RTU通信,可用于工业自动化等领域应用。
阅读全文