国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

單片機移植freemodbus主機(STM32、GD32、瑞薩、國民技術(shù)等)

這篇具有很好參考價值的文章主要介紹了單片機移植freemodbus主機(STM32、GD32、瑞薩、國民技術(shù)等)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、移植庫源代碼

從github下載:https://github.com/armink/FreeModbus_Slave-Master-RTT-STM32

無法下載或者下載太慢可以用資源下載,無需積分。freeModbus主機源碼下載

示例代碼

一、工程創(chuàng)建

參考從機代碼創(chuàng)建

三、源代碼移植

將FreeModbus主機源代碼拷貝到工程中間件-第三方庫-freemodbus源碼庫:即Middlewares\Third_Party\FreeModbusMaster文件夾中。
freemodbus主機,FreeModbus,STM32,單片機,stm32,嵌入式硬件
將源碼添加到工程中
freemodbus主機,FreeModbus,STM32,單片機,stm32,嵌入式硬件
頭文件包含
freemodbus主機,FreeModbus,STM32,單片機,stm32,嵌入式硬件

3.1 源碼接口完善

FreeModbus的移植主要包含:物理層接口的修改、應(yīng)用層回調(diào)的修改。具體函數(shù)如下:

3.1.1 物理層接口:
(a) portserial_m.c
1)xMBMasterPortSerialInit()
2)vMBMasterPortSerialEnable()
3)xMBMasterPortSerialPutByte()
4)xMBMasterPortSerialGetByte()
(b) porttimer_m.c
1)xMBMasterPortTimersInit()
2)vMBMasterPortTimersT35Enable()
3)vMBMasterPortTimersDisable()
(c ) port.c

實現(xiàn)一個環(huán)形緩沖隊列和臨界區(qū)進入退出函數(shù)

void EnterCriticalSection(void);
void ExitCriticalSection(void);
void Put_in_fifo(Serial_fifo *buff, uint8_t *putdata, int length);
int Get_from_fifo(Serial_fifo *buff, uint8_t *getdata, int length);
(d) user_mb_app.c

實現(xiàn)接收回調(diào)

1)eMBMasterRegInputCB()
2)eMBMasterRegHoldingCB()
3)eMBMasterRegCoilsCB()
4)eMBMasterRegDiscreteCB()
3.1.2 具體修改代碼
portserial_m.c接口
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#define USING_UART2

#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Static variables ---------------------------------*/
static volatile uint8_t rx_buff[FIFO_SIZE_MAX];
static Serial_fifo Master_serial_rx_fifo;
/* software simulation serial transmit IRQ handler thread stack */
/* software simulation serial transmit IRQ handler thread */
//static TaskHandle_t thread_serial_soft_trans_irq = NULL;
/* serial event */
static EventGroupHandle_t event_serial = NULL;
/* modbus master serial device */
static UART_HandleTypeDef *serial;

/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START    (1<<0)

/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void);
static void serial_soft_trans_irq(void *parameter);
//static void Master_TxCpltCallback(struct __UART_HandleTypeDef *huart);
void Master_RxCpltCallback(struct __UART_HandleTypeDef *huart);
static int stm32_getc(void);
static int stm32_putc(CHAR c);

/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
        eMBParity eParity)
{
    /**
     * set 485 mode receive and transmit control IO
     * @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user
     */

    /* set serial name */
  if (ucPORT == 1) 
  {
#if defined(USING_UART1)
    extern UART_HandleTypeDef huart1;
    serial = &huart1;
//    //printf("Master using uart1!\r\n");
#endif
  } 
  else if (ucPORT == 2) 
  {
#if defined(USING_UART2)
    extern UART_HandleTypeDef huart2;
    serial = &huart2;
//    //printf("Master using uart2!\r\n");
#endif
  }
   else if (ucPORT == 3) 
   {
#if defined(USING_UART3)
    extern UART_HandleTypeDef huart3;
    serial = &huart3;
//    //printf("Master using uart3!\r\n");
#endif
  }
    /* set serial configure parameter */
	serial->Init.BaudRate = ulBaudRate;
	serial->Init.StopBits = UART_STOPBITS_1;
    switch(eParity){
    case MB_PAR_NONE: {
	    serial->Init.WordLength = UART_WORDLENGTH_8B;
	    serial->Init.Parity = UART_PARITY_NONE;
        break;
    }
    case MB_PAR_ODD: {
	    serial->Init.WordLength = UART_WORDLENGTH_9B;
	    serial->Init.Parity = UART_PARITY_ODD;
        break;
    }
    case MB_PAR_EVEN: {
	    serial->Init.WordLength = UART_WORDLENGTH_9B;
	    serial->Init.Parity = UART_PARITY_EVEN;
        break;
    }
    }
	if (HAL_UART_Init(serial) != HAL_OK) 
	{
		Error_Handler();
	}
	__HAL_UART_DISABLE_IT(serial, UART_IT_RXNE);
	__HAL_UART_DISABLE_IT(serial, UART_IT_TC);
	/*registe recieve callback*/
//	HAL_UART_RegisterCallback(serial, HAL_UART_RX_COMPLETE_CB_ID, Master_RxCpltCallback);
	/* software initialize */
	Master_serial_rx_fifo.buffer = rx_buff;
	Master_serial_rx_fifo.get_index = 0;
	Master_serial_rx_fifo.put_index = 0;
	/* software initialize */

	/* ′′?¨?÷??·¢?íè??? */
	event_serial = xEventGroupCreate();
	if (NULL != event_serial)
	{
		//printf("Master create event_serial success! event_serial=%d\r\n",(int)event_serial);
	}
	else 
	{
		//printf("Master create event_serial Failed!\r\n");
	}
	BaseType_t xReturn = pdPASS;
	xReturn = xTaskCreate((TaskFunction_t)serial_soft_trans_irq, /* è???è??úoˉêy */
						  (const char *)"master trans",          /* è?????×? */
						  (uint16_t)128,                         /* è?????′óD?*/
						  (void *)NULL,    /* è???è??úoˉêy2?êy */
						  (UBaseType_t)12, /* è???μ?ó??è?? */
						  NULL);           /*è????????é*/
	if (xReturn == pdPASS) 
	{
		//printf("xTaskCreate Master trans success\r\n");
	}
	else 
	{
//	//printf("xTaskCreate Master trans faild!\r\n");
	return FALSE;
	}

    return TRUE;
}

void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
	/*?aò?2?2??üê???£?Dèòaìá?°??àíμ?±ê????£?·??ò?óê??áóD?êìa*/
	__HAL_UART_CLEAR_FLAG(serial,UART_FLAG_RXNE);
	__HAL_UART_CLEAR_FLAG(serial,UART_FLAG_TC);
	if (xRxEnable == pdTRUE) 
	{
		/* enable RX interrupt */
		__HAL_UART_ENABLE_IT(serial, UART_IT_RXNE);
	} 
	else 
	{
		/* disable RX interrupt */
		__HAL_UART_DISABLE_IT(serial, UART_IT_RXNE);
	}
	if (xTxEnable == pdTRUE)
	{
		/* start serial transmit */
		xEventGroupSetBits(event_serial, EVENT_SERIAL_TRANS_START);
	}
	else
	{
		xEventGroupClearBits(event_serial, EVENT_SERIAL_TRANS_START);
	}
}

void vMBMasterPortClose(void)
{
	__HAL_UART_DISABLE(serial);
}

BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{
    stm32_putc(ucByte);
    return TRUE;
}

BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
{
    Get_from_fifo(&Master_serial_rx_fifo, (uint8_t *)pucByte, 1);
    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)
{
    pxMBMasterFrameCBTransmitterEmpty();
}

/*
 * 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)
{
    pxMBMasterFrameCBByteReceived();
}

/**
 * Software simulation serial transmit IRQ handler.
 *
 * @param parameter parameter
 */
static void serial_soft_trans_irq(void* parameter) {
	while (1) 
	{
		/* waiting for serial transmit start */
		xEventGroupWaitBits(event_serial,             /* ê??t???ó??±ú */
							EVENT_SERIAL_TRANS_START, /* ?óê?è????DD?è¤μ?ê??t */
							pdFALSE,        /* í?3?ê±??3yê??t±ê??*/
							pdFALSE,        /* ?ú×??DD?è¤μ?è?ò?ê??t */
							portMAX_DELAY); /* ???¨3?ê±ê??t,?T?Tμè′y */
		/* execute modbus callback */
		prvvUARTTxReadyISR();
	}
}

/**
 * @brief  Rx Transfer completed callbacks.
 * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
 *                the configuration information for the specified UART module.
 * @retval None
 */
void Master_RxCpltCallback(struct __UART_HandleTypeDef *huart) 
{
	int ch = -1;
	/*UART RX·????D??μ÷ó?£?2¢??è?ò???êy?Y*/
	while (1) 
	{
		ch = stm32_getc();
		if (ch == -1)
		{
			break;
		}
		Put_in_fifo(&Master_serial_rx_fifo, (uint8_t *)&ch, 1);
	}
	prvvUARTRxISR();
}
/*UART·¢?íò???êy?Y*/
static int stm32_putc(CHAR c) 
{
	serial->Instance->DR = c;
	while (!(serial->Instance->SR & UART_FLAG_TC));
	return TRUE;
}
/*UART?óê?ò???êy?Y*/
static int stm32_getc(void) 
{
	int ch;
	ch = -1;
	if (serial->Instance->SR & UART_FLAG_RXNE) 
	{
		ch = serial->Instance->DR & 0xff;
	}
	return ch;
}

#endif
porttimer_m.c接口
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"

#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Variables ----------------------------------------*/
static USHORT usT35TimeOut50us;
static TimerHandle_t timer = NULL;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(TimerHandle_t xTimer);
static BaseType_t  pxHigherPriorityTaskWoken;

/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void);

/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
{
    /* backup T35 ticks */
    usT35TimeOut50us = usTimeOut50us;

	timer = xTimerCreate("Master timer",
						(50 * usT35TimeOut50us) / (1000 * 1000 / configTICK_RATE_HZ) + 1, pdFALSE,
						(void *)1, timer_timeout_ind);
	if (timer != NULL) 
	{
		//printf("Create Master Timer Success!\r\n");
		return TRUE;
	} 
	else 
	{
		//printf("Create Master Timer Faild!\r\n");
		return FALSE;
	}
}

void vMBMasterPortTimersT35Enable()
{
    uint32_t timer_tick =(50 * usT35TimeOut50us) / (1000 * 1000 / configTICK_RATE_HZ) + 1;

    /* Set current timer mode, don't change it.*/
    vMBMasterSetCurTimerMode(MB_TMODE_T35);

	if (IS_IRQ())
	{
//		xTimerStopFromISR(timer, 0);
		xTimerChangePeriodFromISR((TimerHandle_t)timer, timer_tick, &pxHigherPriorityTaskWoken);
//		xTimerStartFromISR(timer, 0);
	} 
	else 
	{
//		xTimerStop(timer, 0);
		xTimerChangePeriod((TimerHandle_t)timer, timer_tick, 0);
//		xTimerStart(timer, 0);
	}
}

void vMBMasterPortTimersConvertDelayEnable()
{
	uint32_t timer_tick = MB_MASTER_DELAY_MS_CONVERT * configTICK_RATE_HZ / 1000;
	/* Set current timer mode, don't change it.*/
	vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
	//	xTimerStop(timer, 0);
	if (IS_IRQ()) 
	{
		xTimerChangePeriodFromISR((TimerHandle_t)timer, timer_tick, &pxHigherPriorityTaskWoken);
	} 
	else 
	{
		xTimerChangePeriod((TimerHandle_t)timer, timer_tick, 0);
	}
}

void vMBMasterPortTimersRespondTimeoutEnable()
{
	uint32_t timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * configTICK_RATE_HZ / 1000;
	/* Set current timer mode, don't change it.*/
	vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
	if (IS_IRQ()) 
	{
//		xTimerStopFromISR(timer, 0);
		xTimerChangePeriodFromISR((TimerHandle_t)timer, timer_tick, &pxHigherPriorityTaskWoken);
//		xTimerStartFromISR(timer, 0);
	} 
	else 
	{
//		xTimerStop(timer, 0);
		xTimerChangePeriod((TimerHandle_t)timer, timer_tick, 0);
//		xTimerStart(timer, 0);
	}
}

void vMBMasterPortTimersDisable()
{
	if (IS_IRQ()) 
	{
		xTimerStopFromISR((TimerHandle_t)timer, 0);
	} 
	else 
	{
		xTimerStop((TimerHandle_t)timer, 0);
	}
}

void prvvTIMERExpiredISR(void)
{
    (void) pxMBMasterPortCBTimerExpired();
}

static void timer_timeout_ind(void* parameter)
{
    prvvTIMERExpiredISR();
}

#endif
port.h
#ifndef _PORT_H
#define _PORT_H

#include "FreeRTOS.h"
#include "cmsis_os.h"
#include "cmsis_os2.h"
#include "event_groups.h"
#include "main.h"
#include "usart.h"
#include "mbconfig.h"
#include "mbproto.h"
#include "semphr.h"
#include "task.h"
#include "timers.h"
#include <assert.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include "stm32f1xx_hal.h"

#define INLINE						inline
#define PR_BEGIN_EXTERN_C           extern "C" {
#define PR_END_EXTERN_C             }

#define ENTER_CRITICAL_SECTION()    EnterCriticalSection()
#define EXIT_CRITICAL_SECTION()    ExitCriticalSection()

typedef struct _serial_fifo
{
  /* software fifo */
  volatile uint8_t *buffer;
  volatile uint16_t put_index, get_index;
} Serial_fifo;
#define FIFO_SIZE_MAX 265

typedef uint8_t BOOL;

typedef unsigned char UCHAR;
typedef char    CHAR;

typedef uint16_t USHORT;
typedef int16_t SHORT;

typedef uint32_t ULONG;
typedef int32_t LONG;

#ifndef TRUE
#define TRUE            1
#endif

#ifndef FALSE
#define FALSE           0
#endif

void EnterCriticalSection(void);
void ExitCriticalSection(void);
void Put_in_fifo(Serial_fifo *buff, uint8_t *putdata, int length);
int Get_from_fifo(Serial_fifo *buff, uint8_t *getdata, int length);
extern __inline bool IS_IRQ(void);
port.c
#include "port.h"
/* ----------------------- Variables ----------------------------------------*/

/* ----------------------- Start implementation -----------------------------*/
void EnterCriticalSection(void)
{
    taskENTER_CRITICAL();
}

void ExitCriticalSection(void)
{
    taskEXIT_CRITICAL(); 
}

/*put  bytes in buff*/
void Put_in_fifo(Serial_fifo *buff, uint8_t *putdata, int length) 
{
	portDISABLE_INTERRUPTS();
	while (length--)
	{
	    buff->buffer[buff->put_index] = *putdata;
	    buff->put_index += 1;
	    if (buff->put_index >= FIFO_SIZE_MAX)
	    {
			buff->put_index = 0;
	    }
	    /* if the next position is read index, discard this 'read char' */
	    if (buff->put_index == buff->get_index) 
	    {
			buff->get_index += 1;
			if (buff->get_index >= FIFO_SIZE_MAX)
			{
				buff->get_index = 0;
			}
   		}
	}
	portENABLE_INTERRUPTS();
}
/*get  bytes from buff*/
int Get_from_fifo(Serial_fifo *buff, uint8_t *getdata, int length) 
{
	int size = length;
	/* read from software FIFO */
	while (length) 
	{
		int ch;
		/* disable interrupt */
		portDISABLE_INTERRUPTS();
		if (buff->get_index != buff->put_index)
		{
			ch = buff->buffer[buff->get_index];
			buff->get_index += 1;
			if (buff->get_index >= FIFO_SIZE_MAX)
			{
				buff->get_index = 0;
			}
		} 
		else
		{
			/* no data, enable interrupt and break out */
			portENABLE_INTERRUPTS();
			break;
		}
		*getdata = ch & 0xff;
		getdata++;
		length--;
		/* enable interrupt */
		portENABLE_INTERRUPTS();
	}
	return size - length;
}
/*?D??ê?·???è??ú?D???D*/
#ifndef IS_IRQ()
extern __asm uint32_t vPortGetIPSR(void); //μ÷ó?FreeRTOS API
__inline bool IS_IRQ(void) //ê1ó??úáaoˉêyìá???ù?è
{
  if (vPortGetIPSR()) 
  {
    return TRUE;
  }
  return FALSE;
}
#endif // MACRO
回調(diào)接口user_mb_app.c
#include "user_mb_app.h"

/*-----------------------Master mode use these variables----------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
//Master mode:DiscreteInputs variables
USHORT   usMDiscInStart                             = M_DISCRETE_INPUT_START;
#if      M_DISCRETE_INPUT_NDISCRETES%8
UCHAR    ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR    ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8];
#endif
//Master mode:Coils variables
USHORT   usMCoilStart                               = M_COIL_START;
#if      M_COIL_NCOILS%8
UCHAR    ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8+1];
#else
UCHAR    ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8];
#endif
//Master mode:InputRegister variables
USHORT   usMRegInStart                              = M_REG_INPUT_START;
USHORT   usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS];
//Master mode:HoldingRegister variables
USHORT   usMRegHoldStart                            = M_REG_HOLDING_START;
USHORT   usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];

/**
 * Modbus master input register callback function.
 *
 * @param pucRegBuffer input register buffer
 * @param usAddress input register address
 * @param usNRegs input register number
 *
 * @return result
 */
eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    USHORT          iRegIndex;
    USHORT *        pusRegInputBuf;
    USHORT          REG_INPUT_START;
    USHORT          REG_INPUT_NREGS;
    USHORT          usRegInStart;

    pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress() - 1];
    REG_INPUT_START = M_REG_INPUT_START;
    REG_INPUT_NREGS = M_REG_INPUT_NREGS;
    usRegInStart = usMRegInStart;

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= REG_INPUT_START)
            && (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS))
    {
        iRegIndex = usAddress - usRegInStart;
        while (usNRegs > 0)
        {
            pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8;
            pusRegInputBuf[iRegIndex] |= *pucRegBuffer++;
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

/**
 * Modbus master holding register callback function.
 *
 * @param pucRegBuffer holding register buffer
 * @param usAddress holding register address
 * @param usNRegs holding register number
 * @param eMode read or write
 *
 * @return result
 */
eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
        USHORT usNRegs, eMBRegisterMode eMode)
{
    eMBErrorCode    eStatus = MB_ENOERR;
    USHORT          iRegIndex;
    USHORT *        pusRegHoldingBuf;
    USHORT          REG_HOLDING_START;
    USHORT          REG_HOLDING_NREGS;
    USHORT          usRegHoldStart;

    pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress() - 1];
    REG_HOLDING_START = M_REG_HOLDING_START;
    REG_HOLDING_NREGS = M_REG_HOLDING_NREGS;
    usRegHoldStart = usMRegHoldStart;
    /* if mode is read, the master will write the received date to buffer. */
    eMode = MB_REG_WRITE;

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= REG_HOLDING_START)
            && (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
    {
        iRegIndex = usAddress - usRegHoldStart;
        switch (eMode)
        {
        /* read current register values from the protocol stack. */
        case MB_REG_READ:
            while (usNRegs > 0)
            {
                *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
                *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
                iRegIndex++;
                usNRegs--;
            }
            break;
        /* write current register values with new values from the protocol stack. */
        case MB_REG_WRITE:
            while (usNRegs > 0)
            {
                pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                iRegIndex++;
                usNRegs--;
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/**
 * Modbus master coils callback function.
 *
 * @param pucRegBuffer coils buffer
 * @param usAddress coils address
 * @param usNCoils coils number
 * @param eMode read or write
 *
 * @return result
 */
eMBErrorCode eMBMasterRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
        USHORT usNCoils, eMBRegisterMode eMode)
{
    eMBErrorCode    eStatus = MB_ENOERR;
    USHORT          iRegIndex , iRegBitIndex , iNReg;
    UCHAR *         pucCoilBuf;
    USHORT          COIL_START;
    USHORT          COIL_NCOILS;
    USHORT          usCoilStart;
    iNReg =  usNCoils / 8 + 1;

    pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress() - 1];
    COIL_START = M_COIL_START;
    COIL_NCOILS = M_COIL_NCOILS;
    usCoilStart = usMCoilStart;

    /* if mode is read,the master will write the received date to buffer. */
    eMode = MB_REG_WRITE;

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= COIL_START)
            && (usAddress + usNCoils <= COIL_START + COIL_NCOILS))
    {
        iRegIndex = (USHORT) (usAddress - usCoilStart) / 8;
        iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8;
        switch (eMode)
        {
         /* read current coil values from the protocol stack. */
        case MB_REG_READ:
            while (iNReg > 0)
            {
                *pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++],
                        iRegBitIndex, 8);
                iNReg--;
            }
            pucRegBuffer--;
            /* last coils */
            usNCoils = usNCoils % 8;
            /* filling zero to high bit */
            *pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
            *pucRegBuffer = *pucRegBuffer >> (8 - usNCoils);
            break;

        /* write current coil values with new values from the protocol stack. */
        case MB_REG_WRITE:
            while (iNReg > 1)
            {
                xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8,
                        *pucRegBuffer++);
                iNReg--;
            }
            /* last coils */
            usNCoils = usNCoils % 8;
            /* xMBUtilSetBits has bug when ucNBits is zero */
            if (usNCoils != 0)
            {
                xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
                        *pucRegBuffer++);
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/**
 * Modbus master discrete callback function.
 *
 * @param pucRegBuffer discrete buffer
 * @param usAddress discrete address
 * @param usNDiscrete discrete number
 *
 * @return result
 */
eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    USHORT          iRegIndex , iRegBitIndex , iNReg;
    UCHAR *         pucDiscreteInputBuf;
    USHORT          DISCRETE_INPUT_START;
    USHORT          DISCRETE_INPUT_NDISCRETES;
    USHORT          usDiscreteInputStart;
    iNReg =  usNDiscrete / 8 + 1;

    pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress() - 1];
    DISCRETE_INPUT_START = M_DISCRETE_INPUT_START;
    DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES;
    usDiscreteInputStart = usMDiscInStart;

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= DISCRETE_INPUT_START)
            && (usAddress + usNDiscrete    <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
    {
        iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8;
        iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8;

        /* write current discrete values with new values from the protocol stack. */
        while (iNReg > 1)
        {
            xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8,
                    *pucRegBuffer++);
            iNReg--;
        }
        /* last discrete */
        usNDiscrete = usNDiscrete % 8;
        /* xMBUtilSetBits has bug when ucNBits is zero */
        if (usNDiscrete != 0)
        {
            xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex,
                    usNDiscrete, *pucRegBuffer++);
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}
#endif
user_mb_app.h
#include "mb.h"
#include "mb_m.h"
#include "mbconfig.h"
#include "mbframe.h"
#include "mbutils.h"

/* -----------------------Slave Defines -------------------------------------*/
#define S_DISCRETE_INPUT_START        0
#define S_DISCRETE_INPUT_NDISCRETES   16
#define S_COIL_START                  0
#define S_COIL_NCOILS                 64
#define S_REG_INPUT_START             0
#define S_REG_INPUT_NREGS             100
#define S_REG_HOLDING_START           0
#define S_REG_HOLDING_NREGS           100
/* salve mode: holding register's all address */
#define          S_HD_RESERVE                     0
#define          S_HD_CPU_USAGE_MAJOR             1
#define          S_HD_CPU_USAGE_MINOR             2
/* salve mode: input register's all address */
#define          S_IN_RESERVE                     0
/* salve mode: coil's all address */
#define          S_CO_RESERVE                     0
/* salve mode: discrete's all address */
#define          S_DI_RESERVE                     0

/* -----------------------Master Defines -------------------------------------*/
#define M_DISCRETE_INPUT_START        0
#define M_DISCRETE_INPUT_NDISCRETES   10
#define M_COIL_START                  5900
#define M_COIL_NCOILS                 16
#define M_REG_INPUT_START             5000
#define M_REG_INPUT_NREGS             10
#define M_REG_HOLDING_START           5400
#define M_REG_HOLDING_NREGS           10
/* master mode: holding register's all address */
#define          M_HD_RESERVE                     0
/* master mode: input register's all address */
#define          M_IN_RESERVE                     0
/* master mode: coil's all address */
#define          M_CO_RESERVE                     0
/* master mode: discrete's all address */
#define          M_DI_RESERVE                     0

其中定義了寄存器的起始地址和寄存器數(shù)量。用于判斷寄存器地址的有效性。實際應(yīng)用中可以根據(jù)需要修改。

#define M_DISCRETE_INPUT_START        0
#define M_DISCRETE_INPUT_NDISCRETES   10
#define M_COIL_START                  5900
#define M_COIL_NCOILS                 16
#define M_REG_INPUT_START             5000
#define M_REG_INPUT_NREGS             10
#define M_REG_HOLDING_START           5400
#define M_REG_HOLDING_NREGS           10
中斷處理stm32f1xx_it.c
/**
  * @brief This function handles USART2 global interrupt.
  */
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
	if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE))
	{
		Master_RxCpltCallback(&huart2);
//		HAL_UART_IRQHandler(&huart2);
		__HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_RXNE);
	}
	if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE))
	{
		uint16_t pucByte = (uint16_t)((&huart2)->Instance->DR & (uint16_t)0x01FF);
		__HAL_UART_CLEAR_OREFLAG(&huart2);
	}
	if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC))
	{
		__HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TC);
	}
	
  /* USER CODE END USART2_IRQn 0 */
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == htim6.Instance)
	{
		#if MB_MASTER_RTU_ENABLED > 0			
			pxMBMasterPortCBTimerExpired();
		#else		
			pxMBPortCBTimerExpired();
		#endif	
	}
}

四、使用示例

freertos.c

生成的項目文件將任務(wù)初始化都生成再freertos.c文件中,配置時STM32Cube工程時,配置了一個MasterTask的任務(wù),一個StartReadTask、一個StartWriteTask。修改任務(wù)代碼如下:

初始化在void MX_FREERTOS_Init(void)函數(shù)

void MX_FREERTOS_Init(void)
{
  HAL_TIM_Base_Start(&htim6); //開啟定時器
  eMBMasterInit(MB_RTU, 2, 115200, MB_PAR_NONE); /*主機初始化*/
  eMBMasterEnable();	/*主機使能*/
  /* creation of Start_Task */
  Start_TaskHandle = osThreadNew(Start_Thread, NULL, &Start_Task_attributes);
	/*創(chuàng)建寫任務(wù)*/
  WriteTaskHandle = osThreadNew(StartWriteTask, NULL, &Write_TASK);
	/*創(chuàng)建主機任務(wù)*/
  MasterTaskHandle = osThreadNew(MasterTask, NULL, &MasterTask_attributes);
	/*創(chuàng)建讀任務(wù)*/
	ReadTaskHandle = osThreadNew(StartReadTask, NULL, &Read_Task);
}

修改主機任務(wù)

void MasterTask(void *argument)
{
  for (;;)
  {
    eMBMasterPoll();		/*主機輪詢*/
	osDelay(50);
  }
}

修改讀任務(wù)

void StartReadTask(void *argument)
{
	extern USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
	eMBMasterReqErrCode ret;
	uint16_t slaveid;
	uint16_t regaddr;
	uint16_t regnums;
	uint8_t i;

	for (;;)
 	{
		slaveid = 1;
		regaddr = 5400;
		regnums = 10;
		/*讀多個寄存器*/
		ret = eMBMasterReqReadHoldingRegister(slaveid, regaddr, regnums, 1000);
		if(ret == MB_MRE_NO_ERR)
		{
			//printf("===eMBMasterReqReadHoldingRegister successful! values : ");
			for(i = 0; i < regnums; i++)
			{
				//printf("%d ", usMRegHoldBuf[slaveid-1][i]);
			}
			//printf("\r\n");
		}
		else
		{
			//printf("===eMBMasterReqReadHoldingRegister failed! ret = %d \r\n", ret);
			for(i = 0; i < regnums; i++)
			{
				//printf("%d ", usMRegHoldBuf[slaveid-1][i]);
			}	
		}
		osDelay(1000);
	}
}

修改寫任務(wù)

void StartWriteTask(void *argument)
{
	eMBMasterReqErrCode ret;
	uint16_t data[10] = {6,2,3,4,5,8,2,50,10,11};
	unsigned long H_value;

  for (;;)
  {
		H_value = uxTaskGetStackHighWaterMark(WriteTaskHandle);
		//printf("H_value:%d\r\n", (int)H_value);
		/*寫單個寄存器*/
//		ret = eMBMasterReqWriteHoldingRegister(1, 5400, 8, 100);
		
		/*寫多個寄存器*/
		ret = eMBMasterReqWriteMultipleHoldingRegister(1, 5400, 10, data, 100);
		//printf("ret values :%d ", ret);
   		 for(uint8_t i=0;i<sizeof(data)/sizeof(uint16_t);i++)
		{
     		 data[i]++;
		}
		osDelay(1000);
  }
}

**注意:**實際使用中可以將任務(wù)代碼放在單獨的文件中。此外如果不使用操作系統(tǒng),可以在裸機程序中初始化調(diào)用。

五、調(diào)試記錄

讀寫都返回:MB_MRE_MASTER_BUSY, /*!< master is busy now. */
然后在初始化的時候發(fā)送一幀然后釋放信號量:
ret = eMBMasterReqWriteHoldingRegister(1, 1, data[0], 100);
vMBMasterRunResRelease();
后面就完全正常了。如果不寫一下再釋放信號量也沒有用。

猜想:信號量被占用了,發(fā)送數(shù)據(jù)后沒有釋放,需要釋放一次信號量。但是在哪個位置釋放會比較安全,不會影響其他狀態(tài)下的處理。

接收和發(fā)送都是通過狀態(tài)機判斷完成的,根據(jù)不同狀態(tài)進行相應(yīng)的處理。
啟動時處于BUSY狀態(tài),需要釋放才能啟動運行。啟動運行一段時間后還會出現(xiàn)BUSY狀態(tài)。MB_MRE_MASTER_BUSY。

解決辦法:在eMBMasterPoll() 的EV_MASTER_READY狀態(tài)下先釋放信號量。

eMBErrorCode
eMBMasterPoll( void )
{
    static UCHAR   *ucMBFrame;
    static UCHAR    ucRcvAddress;
    static UCHAR    ucFunctionCode;
    static USHORT   usLength;
    static eMBException eException;

    int             i , j;
    eMBErrorCode    eStatus = MB_ENOERR;
    eMBMasterEventType    eEvent;
    eMBMasterErrorEventType errorType;

    /* Check if the protocol stack is ready. */
    if(( eMBState != STATE_ENABLED ) && ( eMBState != STATE_ESTABLISHED))
    {
        return MB_EILLSTATE;
    }

    /* Check if there is a event available. If not return control to caller.
     * Otherwise we will handle the event. */
    if( xMBMasterPortEventGet( &eEvent ) == TRUE )
    {
        switch ( eEvent )
        {
        case EV_MASTER_READY:
            eMBState = STATE_ESTABLISHED;
			vMBMasterRunResRelease();	/**< add by leo */
            break;

        case EV_MASTER_FRAME_RECEIVED:
            eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
            /* Check if the frame is for us. If not ,send an error process event. */
            if ( ( eStatus == MB_ENOERR ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) )
            {
                ( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
            }
            else
            {
                vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
                ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
            }
            break;

        case EV_MASTER_EXECUTE:
            ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
            eException = MB_EX_ILLEGAL_FUNCTION;
            /* If receive frame has exception .The receive function code highest bit is 1.*/
            if(ucFunctionCode >> 7) {
                eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
            }
            else
            {
                for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
                {
                    /* No more function handlers registered. Abort. */
                    if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
                        break;
                    }
                    else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
                        vMBMasterSetCBRunInMasterMode(TRUE);
                        /* If master request is broadcast,
                         * the master need execute function for all slave.
                         */
                        if ( xMBMasterRequestIsBroadcast() ) {
                            usLength = usMBMasterGetPDUSndLength();
                            for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++){
                                vMBMasterSetDestAddress(j);
                                eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
                            }
                        }
                        else {
                            eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
                        }
                        vMBMasterSetCBRunInMasterMode(FALSE);
                        break;
                    }
                }
            }
            /* If master has exception ,Master will send error process.Otherwise the Master is idle.*/
            if (eException != MB_EX_NONE) {
                vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
                ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
            }
            else {
                vMBMasterCBRequestScuuess( );
                vMBMasterRunResRelease( );
            }
            break;

        case EV_MASTER_FRAME_SENT:
            /* Master is busy now. */
            vMBMasterGetPDUSndBuf( &ucMBFrame );
            eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
            break;

        case EV_MASTER_ERROR_PROCESS:
            /* Execute specified error process callback function. */
            errorType = eMBMasterGetErrorType();
            vMBMasterGetPDUSndBuf( &ucMBFrame );
            switch (errorType) {
            case EV_ERROR_RESPOND_TIMEOUT:
                vMBMasterErrorCBRespondTimeout(ucMBMasterGetDestAddress(),
                        ucMBFrame, usMBMasterGetPDUSndLength());
                break;
            case EV_ERROR_RECEIVE_DATA:
                vMBMasterErrorCBReceiveData(ucMBMasterGetDestAddress(),
                        ucMBFrame, usMBMasterGetPDUSndLength());
                break;
            case EV_ERROR_EXECUTE_FUNCTION:
                vMBMasterErrorCBExecuteFunction(ucMBMasterGetDestAddress(),
                        ucMBFrame, usMBMasterGetPDUSndLength());
                break;
            }
            vMBMasterRunResRelease();
            break;

        default:
            break;
        }

    }
    return MB_ENOERR;
}

六、FreeModbus主機驗證

使用從機Modbus Slave工具設(shè)定好寄存器地址、數(shù)量、以及數(shù)值。然后通過程序連接讀取數(shù)據(jù)或者寫修改數(shù)據(jù)。讀的時候注意要設(shè)定好寄存器地址和數(shù)量。否則返回的是MB_MRE_EXE_FUN
freemodbus主機,FreeModbus,STM32,單片機,stm32,嵌入式硬件

七、示例代碼

STM32F103ZET6_TESTCODE文章來源地址http://www.zghlxwxcb.cn/news/detail-670385.html

到了這里,關(guān)于單片機移植freemodbus主機(STM32、GD32、瑞薩、國民技術(shù)等)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 如果STM32/GD32一類的ARM單片機解除讀寫保護的方法

    如果STM32/GD32一類的ARM單片機解除讀寫保護的方法

    有時候啊,使用ST-Link給STM32一類的ARM單片機下載程序的時候,發(fā)現(xiàn)怎么也下載不了,可能是由于芯片被寫保護了。那怎么辦呢?可以使用STM32 ST-LINK Utility工具解除芯片的寫保護,本篇博文介紹操作步驟,文章最后有工具下載鏈接。 雙擊“STM32 ST-LINK Utility.exe”,打開軟件。 軟

    2024年02月09日
    瀏覽(26)
  • STM32 GD32 瑞薩 psoc 等單片機 無線wifi藍牙最佳解決方案

    新聯(lián)鑫威一系列低功耗高性價比sdio wifi/藍牙combo的模塊CYWL6208 , CYWL6312, CYW6209等可以搭配stm32 各種型號例如以下,支持sta/ap/ap+sta,雙模藍牙的應(yīng)用,支持ThreadX,rt-thread, freertos, Azure RTOS, Linux, Android系統(tǒng). 穩(wěn)定強,功耗低,吞吐量高等優(yōu)勢可以應(yīng)用在新能源充電樁 安防 工控 智能

    2024年01月17日
    瀏覽(61)
  • 單片機移植Lua(STM32H743移植Lua-5.4.6)

    單片機移植Lua(STM32H743移植Lua-5.4.6)

    通常單片機都是使用C/C++來開發(fā)的,任何修改都需要重新編譯固件然后下載運行。在一些需要靈活性更強的場合中可以內(nèi)嵌Lua解釋器實現(xiàn)動態(tài)更新應(yīng)用程序的功能。這篇文章將對相關(guān)內(nèi)容做個簡單說明。 Lua本身就是純C實現(xiàn)的,不管是移植到上位機程序還是單片機程序中本質(zhì)上

    2024年02月21日
    瀏覽(19)
  • FreeRTOS_Stm32F103系列單片機標(biāo)準(zhǔn)庫移植

    FreeRTOS_Stm32F103系列單片機標(biāo)準(zhǔn)庫移植

    鏈接:FreeRTOS 下面的教程是基于從github下載壓縮包進行的,最好下載這個或者直接看3.1,從我百度網(wǎng)盤下載。如果是別的下載源也問題不大,大同小異。 此時我們需要下載以下兩個倉庫, 點進去按下面的步驟下載就行了,另一個也是這樣下。 鏈接: FreeRTOS官網(wǎng) 打開鏈接我們

    2024年01月22日
    瀏覽(31)
  • POWERLINK協(xié)議在stm32單片機+w5500移植成功經(jīng)驗分享

    POWERLINK協(xié)議在stm32單片機+w5500移植成功經(jīng)驗分享

    連續(xù)折騰了多個晚上,又趁周末又花了一天時間,終于把powerlink協(xié)議移植成功到單片機上啦。本想放棄,但想了下不管我能不能用上,結(jié)個尾吧,分享給有需要的人。放棄并不難,但堅持一定很酷。為了移植測試這個協(xié)議花了不少血本。stm32開發(fā)板就買了兩套,其中第一套板

    2024年02月09日
    瀏覽(22)
  • STM32 -- 實現(xiàn)按鍵的長按與短按檢測(其他單片機可移植)

    STM32 -- 實現(xiàn)按鍵的長按與短按檢測(其他單片機可移植)

    目錄 資源獲取 一 前言 二 思路 ?三 實現(xiàn)代碼 1.主要代碼 四 完整代碼 Key.h Key.c 該改進版本(1ms太繁瑣了,我改成了25ms檢測一次)? ?1.定時器部分 2.按鍵檢測部分 ?五、參考 歡迎關(guān)注微信公眾號--星之援工作室 發(fā)送(長短按檢測) 今天在逛博客的時候,偶然看到了一

    2024年02月12日
    瀏覽(26)
  • 基于gd32f103移植freemodbus master 主棧

    基于gd32f103移植freemodbus master 主棧

    1.移植freemodbus master需要先移植RT-Thread操作系統(tǒng) GD32F103C8T6移植 RTT Nano 教程-CSDN博客 2.移植freemodbus master協(xié)議棧 在移植了RTT以后,我們需要移植就只有串口相關(guān)的函數(shù) 移植freemodbus master協(xié)議棧具體步驟 下載移植freemodbus master協(xié)議棧 源碼 添加協(xié)議棧文件 向mdk添加頭文件路徑 修改

    2024年01月18日
    瀏覽(28)
  • 【GD32單片機】GD32工程構(gòu)建,快速上手GD32

    【GD32單片機】GD32工程構(gòu)建,快速上手GD32

    之前在學(xué)校接觸最多的是STM32單片機,但出來工作后發(fā)現(xiàn),GD32或MM32單片機卻是經(jīng)常能接觸到的,雖然學(xué)習(xí)資料和生態(tài)沒有STM32好,但基本芯片內(nèi)外設(shè)資源卻差不多,開發(fā)起來大同小異。 在開始構(gòu)建工程之前需要去GD32的官網(wǎng)下載一些資料; 打開官網(wǎng) https://www.gigadevice.com.cn/ 選

    2024年02月03日
    瀏覽(29)
  • GD32單片機串口DMA發(fā)送

    GD32單片機串口DMA發(fā)送

    一:在使用GD32單片機進行串口DMA發(fā)送時,需要進行以下配置: 使能 DMA 時鐘和 串口時鐘 。 配置 DMA通道 ,包括數(shù)據(jù) 方向 、數(shù)據(jù) 寬度 、傳輸 模式 等參數(shù)。 配置串口發(fā)送端口 GPIO 的模式和引腳。 配置串口的 基本參數(shù) ,如波特率、數(shù)據(jù)位、停止位、校驗位等。 配置串口D

    2024年02月12日
    瀏覽(19)
  • GD32 單片機 硬件I2C死鎖解決方法

    GD32 單片機 硬件I2C死鎖解決方法

    在I2C恢復(fù)函數(shù)下個斷點(檢測到I2C多次超時之后,應(yīng)該能跳轉(zhuǎn)到I2C恢復(fù)函數(shù)) 使用鑷子,將SCL與SDA短接,很快就能看到程序停到恢復(fù)函數(shù)的斷點上,此時再執(zhí)行恢復(fù)函數(shù),看能否正常走出(可在回復(fù)函數(shù)中寫個死循環(huán),只有I2C正常才跳出,檢測I2C正常的辦法,可以讀從設(shè)備的

    2024年02月05日
    瀏覽(47)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包