近期看了硬石电子的关于modbus rtu部分的代码,其中包括主机从机,这里记录主机如何使用,做一下笔记,方便以后查看。
一共需要移植
三个.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)将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();主要用来统计主机发送完数据后的超时时间。
将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);//用于测试向从机发送数据,正式使用有用户编写
}
}
主机发送完指令后,从机会根据指令进行数据的返回,相应的就需要把这些数据存放进寄存器
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