利用stm32cubemx移植freemodbus代码分享,片子是stm32F407,记录整个调试过程,供大家参考

测试modbus用stm32cubemx的地方很少,只需要生成USART6的串口和TIM4的定时预制
又用了一个led端口,其他的就是下载freemodbus官方提供的最新的modbus1.5.0版本
然后改改里面的设置.

本站相关程序均提供免费下载!
请到本站 区下载!

下面是调试过程:
打开官方的那个modbus1.5解压后,将modbus文件夹整体复制到你工程的src文件夹里面,重命名为modbus_driver
再次在src文件夹里面建立一个名字是modbus_user的文件夹
找到解压后的文件夹里面的demo文件夹下的BARE里面的文件都复制到modbus_user文件夹里面
首先工程中添加了modbus官方驱动代码modbus_driver文件夹,又新建了个文件夹modbus_user
里面添加文件
portevent.c , portserial.c , porttimer.c 文件
继续打开keil配置器,将添加的几个文件夹里面的H文件路径加好
第一步修改portserial.c文件内容
如下:


#include "port.h"
#include "stm32f4xx_hal.h"
#include "usart.h"
/[i] ----------------------- Modbus includes ----------------------------------[/i]/
#include "mb.h"
#include "mbport.h"

/[i] ----------------------- static functions ---------------------------------[/i]/
//void prvvUARTTxReadyISR( void );
//void prvvUARTRxISR( void );

/[i] ----------------------- Start implementation -----------------------------[/i]/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
/* If xRXEnable enable serial receive interrupts. If xTxENable enable
* transmitter empty interrupts.
*/
if (xRxEnable)
{
__HAL_UART_ENABLE_IT(&huart6,UART_IT_RXNE);
}
else
{
__HAL_UART_DISABLE_IT(&huart6,UART_IT_RXNE);
}
if (xTxEnable)
{
__HAL_UART_ENABLE_IT(&huart6,UART_IT_TXE);
}
else
{
__HAL_UART_DISABLE_IT(&huart6,UART_IT_TXE);
}
}

BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{

return TRUE ;
}

BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
/* Put a byte in the UARTs transmit buffer. This function is called
* by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
[i] called. [/i]/

if(HAL_UART_Transmit (&huart6 ,(uint8_t *)&ucByte,1,0x01) != HAL_OK )
return FALSE ;
else
return TRUE;
}

BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
/* Return the byte in the UARTs receive buffer. This function is called
* by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
*/

if(HAL_UART_Receive (&huart6 ,(uint8_t *)pucByte,1,0x01) != HAL_OK )
return FALSE ;
else
return TRUE;
}

/* Create an interrupt handler for the transmit buffer empty interrupt
* (or an equivalent) for your target processor. This function should then
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
* a new character can be sent. The protocol stack will then call
* xMBPortSerialPutByte( ) to send the character.
*/
void prvvUARTTxReadyISR( void )
{
pxMBFrameCBTransmitterEmpty( );
}

/* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
void prvvUARTRxISR( void )
{
pxMBFrameCBByteReceived( );
}
已邀请:

admin

赞同来自: 春水长天 Nuclear

上机测试,代码烧进去,
测试软件,可以用普通串口调试工具或者modbus poll软件
普通串口的话,发送代码的时候注意代码的格式,
楼上上有代码格式图片,自己去看啊,
我就写下自己测试用的代码如下:
01---------04--------00--00----------00--04----------F1--C9
从机id---功能码---请求起始地址---请求寄存器数量---CRC校验码
意思是:我准备从id为01号的片子里面连续读多个寄存器值,寄存器的起始地址从0x0000开始,读的数量是0x0004
CRC校验码由软件计算得来的,懒得手算.........如下图串口工具包含了这个功能...
你把01 04 00 00 00 04写进去点就出校验码了.
连接好你的串口,打开,波特率都写对,然后,发送,看到返回的数据了吗


1.png


2.png



返回的数据是:01 04 08 00 11 00 22 00 33 00 44 2D 37
01---------- 04-------- 08----------00 11------- 00 22--- 00 33 ---00 44--- 2D 37
从机的id---功能码---返回字节数---第一个数据---第二个---第三个---第四个---校验码
正好和我们设置的初始数据一致,所以代码移植成功!

也可以用modbus poll软件测试
如下图:打开后在白色任意地方点鼠标右键,选择
slave ID 写1 从机地址我们片子里面定义的是0x01嘛
Function选择04 我们测试上面都说了只用了0x04嘛
Address写0 请求地址从0x00开始
Quantity 写4 ,请求数量是4,即连续读取4个数据字节
ScanRate写1000ms,这个默认就行
Display 选择Hex吧,好看


3.png



设置完成后,点击导航栏的Connection按钮,选择波特率和端口,确认


4.png



连接ok了,看到里面的数据了吗?正是11 22 33 44
是我们定义的那个

5.png




ok,结束
额,对了,我配置的是115200,0,n,1串口6,定时器4
串口代码生成后不做任何修改.
打开stm32f4xx_it.c这个中断文件,头部添加

extern void prvvUARTTxReadyISR(void);
extern void prvvUARTRxISR(void);

修改串口中断函数为

void USART6_IRQHandler(void)
{

if(__HAL_UART_GET_IT_SOURCE(&huart6, UART_IT_RXNE)!= RESET)
{
prvvUARTRxISR();//接收中断处理函数
}

if(__HAL_UART_GET_IT_SOURCE(&huart6, UART_IT_TXE)!= RESET)
{
prvvUARTTxReadyISR();//发送完成中断处理函数
}

HAL_NVIC_ClearPendingIRQ(USART6_IRQn);
HAL_UART_IRQHandler(&huart6);
/[i] USER CODE END USART1_IRQn 1 [/i]/
}

对了,先去1楼中的portserial.c文件里面删掉
void prvvUARTTxReadyISR( void );
void prvvUARTRxISR( void );
前面的static 啊,不删就没办法在中断文件里面引用了
继续啊
这次打开porttimer.c文件,处理定时部分

/[i] ----------------------- Platform includes --------------------------------[/i]/
#include "port.h"
#include "stm32f4xx_hal.h"
#include "tim.h"
/[i] ----------------------- Modbus includes ----------------------------------[/i]/
#include "mb.h"
#include "mbport.h"

/[i] ----------------------- static functions ---------------------------------[/i]/
//void prvvTIMERExpiredISR( void );

/[i] ----------------------- Start implementation -----------------------------[/i]/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
return TRUE;;
}


inline void
vMBPortTimersEnable( )
{
/[i] Enable the timer with the timeout passed to xMBPortTimersInit( ) [/i]/
__HAL_TIM_CLEAR_IT(&htim4,TIM_IT_Update);
__HAL_TIM_ENABLE_IT(&htim4,TIM_IT_Update);
__HAL_TIM_SetCounter(&htim4,0);
__HAL_TIM_ENABLE(&htim4);

}

inline void
vMBPortTimersDisable( )
{
/[i] Disable any pending timers. [/i]/
__HAL_TIM_DISABLE(&htim4);
__HAL_TIM_SetCounter(&htim4,0);
__HAL_TIM_DISABLE_IT(&htim4,TIM_IT_Update);
__HAL_TIM_CLEAR_IT(&htim4,TIM_IT_Update);
}

/* Create an ISR which is called whenever the timer has expired. This function
* must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
* the timer has expired.
*/
void prvvTIMERExpiredISR( void )
{
( void )pxMBPortCBTimerExpired( );
}

不解释了啊.一看就懂,基本没修改该文件结构,
对了,此处的定时时间初始化函数xMBPortTimersInit( USHORT usTim1Timerout50us )
我就没写代码进去,因为我用stm32cubemx生成的tim4定时程序,已经自动配置好了,无需
再次初始化了
贴上定时初始化代码

htim4.Instance = TIM4;
htim4.Init.Prescaler = 4199;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 35;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim4);

定时器的中断优先级如下

HAL_NVIC_SetPriority(TIM4_IRQn, 0, 3);
HAL_NVIC_EnableIRQ(TIM4_IRQn);

再次,修改stm32f4xx_it.c中断文件里面的TIM中断
额,这次不用修改了,只需在文件的末尾添加如下代码

extern void prvvTIMERExpiredISR( void );
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
prvvTIMERExpiredISR( );
}

含义是:定时器更新中断,调用的中断回调函数,执行的prvvTIMERExpiredISR( );这个事porttimer.c里面的一个函数.至于这个函数的意思如下
Create an ISR which is called whenever the timer has expired. This function
must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
the timer has expired.
百度翻译为:创建一个ISR即每当计时器过期了。这个函数必须再打电话pxmbportcbtimerexpired()通知协议栈,计时器过期了。
哈哈

admin

赞同来自: 春水长天 jk407529339

发现一篇关于modbus的文章不错
地址;http://www.tuicool.com/articles/iQF7ba

admin

赞同来自: 春水长天 jk407529339

忘了记录一点了....
port.h文件里面也要改个东西
打开后修改这两句

#define ENTER_CRITICAL_SECTION( ) __set_PRIMASK(1) //关总中断
#define EXIT_CRITICAL_SECTION( ) __set_PRIMASK(0) //开总中断

它自带的那个没定义完全,为了适应不同的片子

好,以上驱动修改完了.
打开下载的modbus1.5文件夹,找到里面的demo,打开里面的BARE里面的demo.c,将
里面的代码复制到用stm32cubemx生成的mian.c文件里面
demo.c里面是一个例子,下面我们修改下,然后上机测试
修改如下:

/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/[i] USER CODE BEGIN Includes [/i]/
#include "mb.h"
#include "mbport.h"
/[i] USER CODE END Includes [/i]/

/[i] Private variables ---------------------------------------------------------[/i]/

/[i] USER CODE BEGIN PV [/i]/

/[i] USER CODE END PV [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(void);

/[i] USER CODE BEGIN PFP [/i]/
#define REG_INPUT_START 0
#define REG_INPUT_NREGS 4

/[i] ----------------------- Static variables ---------------------------------[/i]/
static USHORT usRegInputStart = REG_INPUT_START;
static USHORT usRegInputBuf;

/[i] USER CODE END PFP [/i]/

/[i] USER CODE BEGIN 0 [/i]/
int main( void )
{

HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_TIM4_Init();
MX_USART6_UART_Init();

eMBInit(MB_RTU, 0x01, 1, 115200, MB_PAR_NONE);

/[i] Enable the Modbus Protocol Stack. [/i]/
eMBEnable( );

while(1)
{
( void )eMBPoll( );

/[i] Here we simply count the number of poll cycles. [/i]/
}
}

eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;


**usRegInputBuf = 0x11;
usRegInputBuf = 0x22;
usRegInputBuf = 0x33;
usRegInputBuf = 0x44;**



if( ( usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegInputStart );
while( usNRegs > 0 )
{
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf >> 8 );
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf & 0xFF );
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}

return eStatus;
}

eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
return MB_ENOREG;
}


eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
eMBRegisterMode eMode )
{
return MB_ENOREG;
}

eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
return MB_ENOREG;
}

admin

赞同来自: 春水长天 jk407529339

终于第一次调通了,随便看着貌似还是有bug,记录记录,好记性不如烂笔头,
下面是主机发送过来的代码格式图:

i6niAj.jpg

发送的数据帧里包括从机地址、功能码,寄存器起始地址、以及读寄存器的长度、CRC校验。eMBFuncReadInputRegister要做的事儿就是读出寄存器地址以及寄存器长度后调用eMBRegInputCB,读取成功后返回一个MB_ENOERR状态,表明没有错误发生。

下图是Freemodbus支持以下功能码:

6ZrQB3.jpg

Modbus支持的功能码

如果检测到该帧数据是协议栈支持的功能码,就调用相应的函数进行处理,比如说Read input register,就会调用 在mb.c中定义的static xMBFunctionHandler xFuncHandlers这个二维数组中注册的eMBFuncReadInputRegister函数进行处理

admin

赞同来自: 春水长天

先来简单分析一条MODBUS-RTU报文,
例如主机发送:01 06 00 01 00 17 98 04
01------------06-----------00 01--------00 17------98 04
从机地址------功能号-------数据地址-------数据-----CRC校验

这一串数据的意思是:把数据 0x0017(十进制23) 写入 1号从机地址的它的 0x0001数据的地址里。
/////////////////////////////////////////////////////////////////////////////////////////////////////////
主机进行读HoldDataReg 操作,则报文是:
01----------- 03----------00 01---------00 01-----------D5 CA
从机地址-------功能号------数据地址------读取数据个数---- CRC校验
那么单片机接收到这串数据根据数据计算CRC校验判断数据是否正确,如果判断数据无误,则结果是:返回信息给主机,返回的信息也是有格式的:
返回内容:
01--------- 03 -----------02-----------0017 ---------F8 4A
从机地址---功能号-----数据字节个数----两个字节数据----CRC校验
MODBUS主机就完成了一次对从机数据的读操作,实现了通讯。

admin

赞同来自: 春水长天

调试过程中,发现freemodbus貌似有个Bug,
官方代码不做任何修改的情况下,利用modbus poll软件调试
发现读数据的时候,地址不是按照设想的起始地址开始读的,这也导致读取的数量必须减一,要不然
会提示地址不合法........
意思就是读地址数据的时候只能从第二个地址开始读,读取的数量必须是你设想的减一,哎
不管理解没理解,反正这个貌似是个问题.
找了下,在读取函数文件名是mbfuncinput.c文件里面
有个函数
eMBFuncReadInputRegister( UCHAR pucFrame, USHORT usLen )
{
USHORT usRegAddress;
USHORT usRegCount;
UCHAR *pucFrameCur;

eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;

if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( USHORT )( pucFrame << 8 );
usRegAddress |= ( USHORT )( pucFrame );
// usRegAddress++; //这句话把传来的地址自加了1,其实不应该加的,所以要注释掉

usRegCount = ( USHORT )( pucFrame << 8 );
usRegCount |= ( USHORT )( pucFrame );

/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
*/
if( ( usRegCount >= 1 )
&& ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )
{
/ Set the current PDU data pointer to the beginning. /
pucFrameCur = &pucFrame;
*usLen = MB_PDU_FUNC_OFF;
............................................下面省略.......................................................
如上粗体所示,就是它导致了上面提到的bug,删掉就可以了,不会影响使用的.
特此记录..............................................................................

admin

赞同来自: leefine 春水长天 Nuclear

额,忘记说明下main.c文件代码的意思了.
这里说一下.
这个文件里面的代码结构基本stm32cubemx生成什么样就什么样,不要修改,只需添加一些

#include "mb.h"
#include "mbport.h"

这个必须调用,头文件嘛,

#define REG_INPUT_START 0
#define REG_INPUT_NREGS 4

定义寄存器输入开始地址0x00,和寄存器数量NREGS=number Regs(猜的)4

static USHORT usRegInputStart = REG_INPUT_START;
static USHORT usRegInputBuf;

定义一个用户要使用的起始地址和定义一个缓存器(比如你的AD值就可以放进去,到时候传给上位机)

eMBInit(MB_RTU, 0x01, 1, 115200, MB_PAR_NONE);

初始化modbus的串口和定时器....额,其实这个有用的也就是RTU和0x01了,RTU说明是使用的RTU方式,0x01
说明从机的id是0x01,上位机到时候要用到的,其他的用stm32cubemx的生成的代码已经初始化好了...........

/[i] Enable the Modbus Protocol Stack. [/i]/
eMBEnable( );

while(1)
{
( void )eMBPoll( );

/[i] Here we simply count the number of poll cycles. [/i]/
}

使能并连续查询modbus是否有数据接受到....................
下面是关键点了.
你百度modbus了的话,
eMBRegInputCB();
eMBRegHoldingCB();
eMBRegCoilsCB();
eMBRegDiscreteCB();
四个函数对应的不同的操作码,分别是
//读数字寄存器 功能码0x04
// 寄存器的读写函数 支持的命令为读 0x03 和写0x06
//读/写开关寄存器 0x01 x05
//读开关寄存器 0x02
我们测试之用到了04功能码
我们初始化一个数组值为

usRegInputBuf = 0x11;
usRegInputBuf = 0x22;
usRegInputBuf = 0x33;
usRegInputBuf = 0x44;

当上位机发送04功能码来的时候,eMBRegInputCB();就来处理

if( ( usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegInputStart );
while( usNRegs > 0 )
{
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf >> 8 );
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf & 0xFF );
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}

①,当上位机请求地址usAddress这个变量值大于系统起始地址REG_INPUT_START,并且请求的起始地址加上请求的数量小于等于系统起始地址加上系统寄存器数量,就执行下面的代码
说白了,就是请求的地址和数量必须在系统有效范围内.汗
我们刚才定义了REG_INPUT_START =0 和REG_INPUT_NREGS = 4 的说
所以只要请求地址最大和最小范围不超过系统定义就行了.
②,开始处理数据,将寄存器里面的值按照请求的地址一个一个取出来

leefine - ST产品开发大佬

赞同来自: №鸭梨鸭梨大鸭梨大鸭梨大

You are so great.

hagiliak

赞同来自:

Any chance to download full code pls?

阿躍

赞同来自:

modbusbug.jpg


版主你好,为何照步骤去移植modbus,只有第一次传输是正确,第二次以上则会出现timeout呢?,无法像文章中里面的一样每次传送正确

阿躍

赞同来自:

進入調適後當板子收完第一次指令,也送出回應給上位機,而當回應的最後一個字節送出後,逐步執行發現進入 parity error interrupt,繼續執行後就會出現串口接收中斷無法打開的現象,不曉得是傳送中斷阻塞住會是其他原因,因為重複debug 會出現 eEvent 不是 EV_EXECUTE ,不然就是 EV_FRAME_SENT 這兩種之一,不曉得為何出現這種情況@@

parity.png


accessport.png

石缝中的荨麻

赞同来自:

大哥,为啥我把定时器4改成定时器3就不好用了呢

单细胞

赞同来自:

楼主你好,我这个代码是通过串口传输的是吧。我现在要做是移植Modbus实现通过USB传输。这样的话我该怎么做?这时候还需要用到DMA跟usart吗?

单细胞

赞同来自:

vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
     * transmitter empty interrupts.
     */
    if (xRxEnable)
    {
        __HAL_UART_ENABLE_IT(&huart6,UART_IT_RXNE);
    }
    else
    {
        __HAL_UART_DISABLE_IT(&huart6,UART_IT_RXNE);
    }
    if (xTxEnable)
    {
        __HAL_UART_ENABLE_IT(&huart6,UART_IT_TXE);
    }
    else
    {
        __HAL_UART_DISABLE_IT(&huart6,UART_IT_TXE);
    }
}
这里说的利用串口中断接受数据的时候的函数。那我改用usb传输的时候这部分是该怎么做?还有那个potrtimer.c这个函数其实他的定时是做什么用的?我是新手很多东西都还不懂,望指教。

单细胞

赞同来自:

UM0XN8VV_{RR@EU6CB(J599.jpg

 

bavol

赞同来自:

eMBErrorCode
eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
{
    BOOL            xFrameReceived = FALSE;
    eMBErrorCode    eStatus = MB_ENOERR;

    ENTER_CRITICAL_SECTION(  );
    assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );

    /* Length and CRC check */
    if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
        && ( usMBCRC16( ( UCHAR * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
    {
        /* Save the address field. All frames are passed to the upper layed
         * and the decision if a frame is used is done there.
         */
        *pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF];

        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
         * size of address field and CRC checksum.
         */
        *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );

        /* Return the start of the Modbus PDU to the caller. */
        *pucFrame = ( UCHAR * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
        xFrameReceived = TRUE;
    }
    else
    {
        eStatus = MB_EIO;
    }

    EXIT_CRITICAL_SECTION(  );
    return eStatus;
}



..\Src\modbus\rtu\mbrtu.c(153): warning:  #550-D: variable "xFrameReceived" was set but never used


请问为什么有这个警告,xFrameReceived不是已经被调用了吗?

miko的脑残粉1号

赞同来自:

已收藏

李川 - 90后嵌入式

赞同来自:

谢谢分享

miao0256

赞同来自:

if(HAL_UART_Transmit (&huart6 ,(uint8_t *)&ucByte,1,0x01) != HAL_OK )

没有中断发送!!??

Beloring

赞同来自:

求楼主公开源码,讲的云里雾里,不知所云

wansaiyon

赞同来自:

求楼主公开代码

我歌月徘徊 - QQ778575669

赞同来自:

学习

我歌月徘徊 - QQ778575669

赞同来自:

我在试着移植到429上面,hal库,但是遇到了问题。串口中断 定时器中断都没问题 用串口助手发送0A 03 00 00 00 01 85 71  仿真进去 就收到了一个字节。。。

blob.png

那后来呢

赞同来自:

楼主请问您定时器四设置的时间多长?50us吗?

Lotus.

赞同来自:

多多学习!


gcrisis

赞同来自:

楼主 你好 

我调用 __set_PRIMASK(1)提示未定义,然后我发现这个函数被定义为静态内联函数,请问你是把静态属性去掉了吗?

D&dol

赞同来自:

太长有点晕菜啊,想吐!

一见如故

赞同来自:

学习,借鉴

兰生

赞同来自:

按照楼主的方法弄可以进行modbus通讯。但是我在cubemx添加其他的定时器中断,就不行了。求解?

要回复问题请先登录注册