调试的时候,通过IDE查看状态是最常用的手段,但如果不断地把运行过程信息通过串口输出来,也会是一种好办法。所以创建新项目后,可以先将调试信息输出功能写好,再慢慢做写其他代码,正所谓工欲善其事必先利其器嘛。
功能的实现非常简单,就是通过串口的TX把信息print出来,使用DMA传输可以降低MCU负担,为了简化,甚至把初始化也放在print函数中,在需要输出的地方直接调用DrvDebugInfoPrint(),例如在LED任务里调用:DrvDebugInfoPrint(“LED Start to flash!”);
头文件:
/* DrvUartTool, V1.0, 2018-7-4, Yangwb ****************************************/
/* Use USART1_TX:PA9, DMA2_Stream7, DMA_Channel_4 *****************************/
/*
set USE_DEBUG_INFO_AT_UART = 1 to use this module; 0 to disable, then the
function DrvDebugInfoPrint() define as null.
module need'n init, DrvDebugInfoPrint() auto call init function.
Example: when LED task start, DrvDebugInfoPrint("LED start to flash!").
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __DrvDebug_H
#define __DrvDebug_H
/* Private functional switch -------------------------------------------------*/
#define USE_DEBUG_INFO_AT_UART 1
#if USE_DEBUG_INFO_AT_UART == 1
/* Private define ------------------------------------------------------------*/
#define DEBUG_INFO_UART_BAUDRATE 115200
#define DEBUG_INFO_UART_BUFF_SIZE 50
#define DEBUG_INFO_UART_TX_STATUS_NOT_INIT 0
#define DEBUG_INFO_UART_TX_STATUS_READY 12
#define DEBUG_INFO_UART_TX_STATUS_BUSY 123
/* Includes ------------------------------------------------------------------*/
#include "Common.h"
#include "stm32f4xx.h"
#include <stdio.h>
#include <string.h>
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
extern volatile INT8U g_u8DebugTxDmaStatus;
extern volatile INT8U g_au8DebugTxDmaBuff[DEBUG_INFO_UART_BUFF_SIZE];
#endif // end of USE_DEBUG_INFO_AT_UART
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
#if USE_DEBUG_INFO_AT_UART == 1
void DrvDebugInfoAtUartInit(void);
#define DrvDebugInfoPrint(String) \
do \
{ \
if (g_u8DebugTxDmaStatus == DEBUG_INFO_UART_TX_STATUS_NOT_INIT) \
{ \
DrvDebugInfoAtUartInit(); \
g_u8DebugTxDmaStatus = DEBUG_INFO_UART_TX_STATUS_READY; \
} \
while (g_u8DebugTxDmaStatus != DEBUG_INFO_UART_TX_STATUS_READY) \
{ \
} \
g_u8DebugTxDmaStatus = DEBUG_INFO_UART_TX_STATUS_BUSY; \
if (strlen(String) <= DEBUG_INFO_UART_BUFF_SIZE) \
{ \
strncpy((char *)g_au8DebugTxDmaBuff, String, strlen(String)); \
} \
else \
{ \
strncpy((char *)g_au8DebugTxDmaBuff, "Too long!", strlen("Too long!")); \
} \
DMA2_Stream7->CR &= ~0x1ul; \
DMA2_Stream7->M0AR = (INT32U)g_au8DebugTxDmaBuff; \
DMA2_Stream7->NDTR = (INT32U)strlen(String); \
DMA2_Stream7->CR |= 0x1ul; \
} while (0)
#else
#define DrvDebugInfoPrint(String)
#endif
#endif /* __DrvDebug_H */
C文件:
/* Attention, read head file at first. ****************************************/
/* Includes ------------------------------------------------------------------*/
#include "DrvDebug.h"
#if USE_DEBUG_INFO_AT_UART == 1
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
volatile INT8U g_u8DebugTxDmaStatus = DEBUG_INFO_UART_TX_STATUS_NOT_INIT;
volatile INT8U g_au8DebugTxDmaBuff[DEBUG_INFO_UART_BUFF_SIZE] = {"Hello!"};
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief config dma buff
* @param None
* @retval None
*/
void DrvDebugInfoAtUartInit(void)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
if (g_u8DebugTxDmaStatus != DEBUG_INFO_UART_TX_STATUS_NOT_INIT)
{
return;
}
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* uart DMA send irq */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* uart irq */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* DMA2_Stream7 config as uart1 dma send */
/* Reset DMA Stream registers (for debug purpose) */
DMA_DeInit(DMA2_Stream7);
/* Check if the DMA Stream is disabled before enabling it.
Note that this step is useful when the same Stream is used multiple times:
enabled, then disabled then re-enabled... In this case, the DMA Stream disable
will be effective only at the end of the ongoing data transfer and it will
not be possible to re-configure it before making sure that the Enable bit
has been cleared by hardware. If the Stream is used only once, this step might
be bypassed. */
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE)
{
}
/* Configure DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (INT32U)(&(USART1->DR));
DMA_InitStructure.DMA_Memory0BaseAddr = (INT32U)(g_au8DebugTxDmaBuff);
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = (INT32U)DEBUG_INFO_UART_BUFF_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream7, &DMA_InitStructure);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Stream7, DISABLE);
/* USART resources configuration (Clock, GPIO pins and USART registers) ----*/
USART_InitStructure.USART_BaudRate = DEBUG_INFO_UART_BAUDRATE;
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_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE); /* Enable USART */
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); /* use dma send*/
g_u8DebugTxDmaStatus = DEBUG_INFO_UART_TX_STATUS_READY;
}
/**
* @brief This function handles DMA Stream interrupt request.
*/
void DMA2_Stream7_IRQHandler(void)
{
if (DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);
g_u8DebugTxDmaStatus = DEBUG_INFO_UART_TX_STATUS_READY;
}
}
#endif // end of USE_DEBUG_INFO_AT_UART
通过STM32F407的串口输出运行状态信息
猜你喜欢
转载自blog.csdn.net/b260123292/article/details/81205975
今日推荐
周排行