欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

移植modbus rtu主机到STM32

程序员文章站 2022-07-09 15:26:45
...

近期看了硬石电子的关于modbus rtu部分的代码,其中包括主机从机,这里记录主机如何使用,做一下笔记,方便以后查看。
移植modbus rtu主机到STM32

一、移植步骤

一共需要移植
三个.c文件:bsp_usartx_fifo.c、modbus_slave.c、bsp_SysTick.c
三个.h文件:bsp_usartx_fifo.h、modbus_slave.h、bsp_SysTick.h

放置三个函数:Usart_FIFO_Init(); SysTick_Init(); MODH_Poll();

开启三个宏:#define USART1_FIFO_EN 1//使能初始化串口1
__________ #define USART_SELECT_NUM 1//将modbus用在串口1
__________ #define HBAUD485 USART1_BAUD//设置串口波特率

1、串口初始化、定时器初始化、定时器初始化

(1)将Usart_FIFO_Init()放在主函数的初始化位置,

#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_usartx_fifo.h"
#include "modbus_slave.h"
/*主函数*/
int main(void)
{
	Usart_FIFO_Init();
  	SysTick_Init();
	while ( 1 )
	{	 		
		MODH_Poll();
		TestModbusHost(1);//用于测试向从机发送数据,正式使用有用户编写
	}
}

(2)进入Usart_FIFO_Init(),看看有哪些需要初始化:

void Usart_FIFO_Init(void)
{  
  /* 初始化串口相关的变量 */
  UsartVarInit();
  RS485_InitTXEN();
  /* 配置NVIC,设定USART接收中断优先级 */
  NVIC_Configuration_USART();
  
  /* 初始化USART对应GPIO和USART外设 */
  InitHardUsart();  
	/* 定时器初始化 */
  bsp_InitHardTimer();
}

a.首先UsartVarInit()的作用是对串口相关的结构体变量初始化,其中需要注意的是宏定义USART1_FIFO_EN的开关,这里我使用UART1做的测试,将该宏置1来开启串口1,然后#define USART_SELECT_NUM 1//将modbus用在串口1上;这里分为两部分,为的是方便对每个串口的单独配置,可以对其他串口添加需要的应用代码。

static void UsartVarInit(void)
{
#if USART1_FIFO_EN == 1
	g_tUsart1.usart = USART1;						/* STM32 串口设备 */
	g_tUsart1.pTxBuf = g_TxBuf1;					/* 发送缓冲区指针 */
	g_tUsart1.pRxBuf = g_RxBuf1;					/* 接收缓冲区指针 */
	g_tUsart1.usTxBufSize = USART1_TX_BUF_SIZE;	    /* 发送缓冲区大小 */
	g_tUsart1.usRxBufSize = USART1_RX_BUF_SIZE;	    /* 接收缓冲区大小 */
	g_tUsart1.usTxWrite = 0;			          	/* 发送FIFO写索引 */
	g_tUsart1.usTxRead = 0;						    /* 发送FIFO读索引 */
	g_tUsart1.usRxWrite = 0;						/* 接收FIFO写索引 */
	g_tUsart1.usRxRead = 0;						    /* 接收FIFO读索引 */
	g_tUsart1.usRxCount = 0;						/* 接收到的新数据个数 */
	g_tUsart1.usTxCount = 0;						/* 待发送的数据个数 */
	g_tUsart1.SendBefor = RS485_SendBefor;			/* 发送数据前的回调函数 */
	g_tUsart1.SendOver = RS485_SendOver;			/* 发送完毕后的回调函数 */
	g_tUsart1.ReciveNew = RS485_ReciveNew;			/* 接收到新数据后的回调函数 */
#endif
...
}

b.其次是对串口驱动的配置,初始化了485的引脚,配置中断优先级,配置串口引脚波特率等。
RS485_InitTXEN();
NVIC_Configuration_USART();
InitHardUsart();
c.为简化文件的个数,没有建立tim.c,直接将定时器初始化放在了串口初始化的末尾处bsp_InitHardTimer()。分频系数72-1,时钟周期1us。
(2)初始化SysTick_Init();主要用来统计主机发送完数据后的超时时间。

2、轮循MODS_Poll()

将MODH_Poll()放在主函数的while(1)中,用于接收来自从机的返回数据,其实直接放在用户的应用函数中就行,向从机发完数据,记录当前滴答定时器的时间,然后等待100ms,这期间就不断轮循这个函数即可,实例跳进测试函数TestModbusHost()即可查看到。

#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_usartx_fifo.h"
#include "modbus_slave.h"
/*主函数*/
int main(void)
{
	Usart_FIFO_Init();
  	SysTick_Init();
	while ( 1 )
	{	 		
		MODH_Poll();
		TestModbusHost(1);//用于测试向从机发送数据,正式使用有用户编写
	}
}

3、添加寄存器

主机发送完指令后,从机会根据指令进行数据的返回,相应的就需要把这些数据存放进寄存器

void MODH_Read_03H(void)
{
	uint8_t bytes;
	uint8_t *p;
	
	if (g_tModH.RxCount > 0)
	{
		bytes = g_tModH.RxBuf[2];	/* 数据长度 字节数 */				
		switch (g_tModH.Reg03H)
		{
			case REG_P01:
//				if (bytes == 32)
//				{
					p = &g_tModH.RxBuf[3];	
					
					g_tVar.P01 = BEBufToUint16(p); p += 2;	/* 寄存器 */	
					g_tVar.P02 = BEBufToUint16(p); p += 2;	/* 寄存器 */	
		
					g_tModH.fAck03H = 1;
//				}
				break;
		}
	}
}

二、代码及软件工具

链接:https://pan.baidu.com/s/1ZQqOA9Tqkr1qbF2bHohxSg
提取码:s4p7