STM32 notes of USART (serial)

EDITORIAL:
This article aims to summarize the backup, to facilitate future inquiries, as is the personal summary, if wrong, please correct me; in addition, most of the content from the Internet, books, and various manuals, should please inform the infringement, immediately delete posts to apologize.

 

table of Contents

First, serial communication

Two, USART functional block diagram of a transceiver

Three, USART mode configuration

Fourth, the code implementation process

Five, printf () function redirects

Sixth, the total project code


 

First, serial communication

Here is no longer cumbersome illustrates see previous chapter  UART / USRAT, I2C, SPI communication literacy

 

Two, USART functional block diagram of a transceiver

 

Three, USART mode configuration

1, each mode features support

2, I / O multiplexing configuration

 

Fourth, the code implementation process

In this routine, we arranged UART (asynchronous serial port), which we commonly used, and The USART (synchronous serial interface) but more than one clock line, so that, when a UART, we can determine whether a need to introduce the receiving node completes, the timeout time may be determined, determination and the like terminator

Before configuring we first define the structure of a reception

#define RxBUFFER_SIZE   	0xFF

typedef struct
{
	uint8_t RxBuffer[RxBUFFER_SIZE];		// 接收暂存缓冲区
	__IO uint8_t RxCounter;				// 接收数据个数
	uint8_t Receiving_Time;				// 接收时间
	uint8_t Frame_flag;				// 一帧完成标志
}EVAL_COMx_TypeDef;

Since the transmission buffer we can share (after all, can only be sent when the single shot), so we just define an array like

#define TxBUFFER_SIZE   	100

uint8_t g_TxCounter = 0; 			// 发送数据个数
uint8_t TxBuffer[TxBUFFER_SIZE] = {0};		// 发送暂存缓冲区

Well, now you start to configure our UART it

1, UART1 Functions:

#define EVAL_COM1		USART1

/************************************************
函数名称 : UART1_Comfig
功    能 : UART1端口配置
参    数 : Baudrate ---- 波特率
返 回 值 : 无
*************************************************/
void UART1_Comfig( uint32_t Port )
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    /* config GPIOA clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
    /* config USART1 clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    /* USART1 GPIO config */
    /* Configure USART1 Tx (PA.09) as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Configure USART1 Rx (PA.10) as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Enable the USART1 Interrupt */
    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);

    /* USART1 mode config */
    USART_InitStructure.USART_BaudRate = Port;                    // 获取波特率
    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_Rx | USART_Mode_Tx;    // 配置工作模式
    USART_Init(EVAL_COM1, &USART_InitStructure);

    USART_ITConfig(EVAL_COM1, USART_IT_RXNE, ENABLE);             // 使能串口接收中断
    USART_Cmd(EVAL_COM1, ENABLE);                                 // 使能串口
}

2, interrupt receiving treatment:

/************************************************************************/
/*            STM32F10x USART Interrupt Handlers                        */
/************************************************************************/

/**
  * @brief  This function handles USART1 global interrupt request.
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(EVAL_COM1, USART_IT_RXNE) != RESET)    // 判断接收
    {
        /* Read one byte from the receive data register */
        Usart1.RxBuffer[Usart1.RxCounter++] = (USART_ReceiveData(EVAL_COM1) & 0x7F);  // 获取数据

        if(Usart1.RxCounter >= RxBUFFER_SIZE)    // 判断是否超出接收最大长度
        {
//            /* Disable the EVAL_COM1 Receive interrupt */
//            USART_ITConfig(EVAL_COM1, USART_IT_RXNE, DISABLE);

            Usart1.Frame_flag = 0;               // 接收完成标志清零
            Usart1.RxCounter = 0;                // 计数清零
            Usart1.Receiving_Time = 0;           // 接收超时时间清零
        }
        Usart1.Receiving_Time = 2;               // 设置超时判定时间
    }

    /* 因为我们不去利用中断进行发送,所以下面的操作屏蔽掉 */
//  if(USART_GetITStatus(EVAL_COM1, USART_IT_TXE) != RESET)
//  {
//    /* Write one byte to the transmit data register */
//    USART_SendData(EVAL_COM1, TxBuffer[TxCounter++]);

//    if(TxCounter == RxBUFFER_SIZE)
//    {
//      /* Disable the EVAL_COM1 Transmit interrupt */
//      USART_ITConfig(EVAL_COM1, USART_IT_TXE, DISABLE);
//    }
//  }
}

Here, as with the time-out determination whether a receiving end, so also in the timer determination, it is determined as follows:

if(Usart1.Receiving_Time)
{
    Usart1.Receiving_Time--;
    if(!Usart1.Receiving_Time)
        Usart1.Frame_flag = 1;
}

As for when data is considered a complete, depending on which you set the timeout factor

3, the transmission output process:

/************************************************
函数名称 : USART_SendByte
功    能 : 串口字符发送
参    数 : c ---- 发送的数据
返 回 值 : 无
*************************************************/
void USART_SendByte( USART_TypeDef* USARTx, uint8_t c )
{     
	USART_SendData(USARTx, c);
	
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}

/************************************************
函数名称 : USART_SendString
功    能 : 串口字符串发送
参    数 : USARTx ---- 串口
			pData ---- 字符串
			Length ---- 长度
返 回 值 : 无
*************************************************/
void USART_SendString( USART_TypeDef* USARTx, const uint8_t *pData, uint16_t Length )
{
    while(Length--)
    {
        USART_SendByte(USARTx, *pData);
        pData++;
    }
}

/************************************************
函数名称 : USART_Printf
功    能 : 串口打印输出
参    数 : USARTx ---- 串口
			String	---- 字符串
返 回 值 : 无
*************************************************/
void USART_Printf( USART_TypeDef* USARTx, char *String )
{
    do
    {
        USART_SendByte(USARTx, *String);
        String++;
    }while((*String) != '\0');
}

 

Five, printf () function redirects

In the routine official, we can see the following this routine function in the main.c file:

/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
    /* Place your implementation of fputc here */
    /* e.g. write a character to the USART */
    USART_SendData(EVAL_COM1, (uint8_t) ch);

    /* Loop until the end of transmission */
    while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET)
    {}

    return ch;
}

See comments we know that this is the C library printf function will be redirected to the official gives USART template, then we change it, this becomes the following:

#define DEBUG_UART		USART1

/************************************************
函数名称 : fputc
功    能 : 重定向 c库函数 printf到 DEBUG_UART
参    数 : ch
返 回 值 : 无
*************************************************/
int fputc(int ch, FILE *f)
{
    /* 发送一个字节数据到 DEBUG_UART */
    USART_SendData(DEBUG_UART, (uint8_t) ch);

    /* 等待发送完毕 */
    while (USART_GetFlagStatus(DEBUG_UART, USART_FLAG_TXE) == RESET);

    return (ch);
}

/************************************************
函数名称 : fgetc
功    能 : 重定向 c库函数 scanf到 DEBUG_UART
参    数 : f ---- 文件
返 回 值 : 无
*************************************************/
int fgetc(FILE *f)
{
    /* 等待 DEBUG_UART输入数据 */
    while (USART_GetFlagStatus(DEBUG_UART, USART_FLAG_RXNE) == RESET);

    return (int)USART_ReceiveData(DEBUG_UART);
}

 

Sixth, the total project code

bsp_uart.c source file

#include "bsp_uart.h"


uint8_t g_TxCounter = 0; 				// 发送数据个数
uint8_t TxBuffer[TxBUFFER_SIZE] = {0};	// 发送暂存缓冲区

EVAL_COMx_TypeDef Usart1,Usart2;

/************************************************
函数名称 : UART1_Comfig
功    能 : UART1端口配置
参    数 : Baudrate ---- 波特率
返 回 值 : 无
*************************************************/
void UART1_Comfig( uint32_t Port )
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    /* config GPIOA clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
    /* config USART1 clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    /* USART1 GPIO config */
    /* Configure USART1 Tx (PA.09) as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Configure USART1 Rx (PA.10) as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Enable the USART1 Interrupt */
    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);

    /* USART1 mode config */
    USART_InitStructure.USART_BaudRate = Port;                    // 获取波特率
    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_Rx | USART_Mode_Tx;    // 配置工作模式
    USART_Init(EVAL_COM1, &USART_InitStructure);

    USART_ITConfig(EVAL_COM1, USART_IT_RXNE, ENABLE);             // 使能串口接收中断
    USART_Cmd(EVAL_COM1, ENABLE);                                 // 使能串口
}

/************************************************
函数名称 : USART_SendByte
功    能 : 串口字符发送
参    数 : c ---- 发送的数据
返 回 值 : 无
*************************************************/
void USART_SendByte( USART_TypeDef* USARTx, uint8_t c )
{     
	USART_SendData(USARTx, c);
	
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}

/************************************************
函数名称 : USART_SendString
功    能 : 串口字符串发送
参    数 : USARTx ---- 串口
			pData ---- 字符串
			Length ---- 长度
返 回 值 : 无
*************************************************/
void USART_SendString( USART_TypeDef* USARTx, const uint8_t *pData, uint16_t Length )
{
    while(Length--)
    {
        USART_SendByte(USARTx, *pData);
        pData++;
    }
}

/************************************************
函数名称 : USART_Printf
功    能 : 串口打印输出
参    数 : USARTx ---- 串口
			String	---- 字符串
返 回 值 : 无
*************************************************/
void USART_Printf( USART_TypeDef* USARTx, char *String )
{
    do
    {
        USART_SendByte(USARTx, *String);
        String++;
    }while((*String) != '\0');
}


/************************************************
函数名称 : fputc
功    能 : 重定向 c库函数 printf到 DEBUG_UART
参    数 : ch
返 回 值 : 无
*************************************************/
int fputc(int ch, FILE *f)
{
    /* 发送一个字节数据到 DEBUG_UART */
    USART_SendData(DEBUG_UART, (uint8_t) ch);

    /* 等待发送完毕 */
    while (USART_GetFlagStatus(DEBUG_UART, USART_FLAG_TXE) == RESET);

    return (ch);
}

/************************************************
函数名称 : fgetc
功    能 : 重定向 c库函数 scanf到 DEBUG_UART
参    数 : f ---- 文件
返 回 值 : 无
*************************************************/
int fgetc(FILE *f)
{
    /* 等待 DEBUG_UART输入数据 */
    while (USART_GetFlagStatus(DEBUG_UART, USART_FLAG_RXNE) == RESET);

    return (int)USART_ReceiveData(DEBUG_UART);
}


/************************************************************************/
/*            STM32F10x USART Interrupt Handlers                        */
/************************************************************************/

/**
  * @brief  This function handles USART1 global interrupt request.
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(EVAL_COM1, USART_IT_RXNE) != RESET)    // 判断接收
    {
        /* Read one byte from the receive data register */
        Usart1.RxBuffer[Usart1.RxCounter++] = (USART_ReceiveData(EVAL_COM1) & 0x7F);  // 获取数据

        if(Usart1.RxCounter >= RxBUFFER_SIZE)    // 判断是否超出接收最大长度
        {
//            /* Disable the EVAL_COM1 Receive interrupt */
//            USART_ITConfig(EVAL_COM1, USART_IT_RXNE, DISABLE);

            Usart1.Frame_flag = 0;               // 接收完成标志清零
            Usart1.RxCounter = 0;                // 计数清零
            Usart1.Receiving_Time = 0;           // 接收超时时间清零
        }
        Usart1.Receiving_Time = 2;               // 设置超时判定时间
    }

    /* 因为我们不去利用中断进行发送,所以下面的操作屏蔽掉 */
//  if(USART_GetITStatus(EVAL_COM1, USART_IT_TXE) != RESET)
//  {
//    /* Write one byte to the transmit data register */
//    USART_SendData(EVAL_COM1, TxBuffer[TxCounter++]);

//    if(TxCounter == RxBUFFER_SIZE)
//    {
//      /* Disable the EVAL_COM1 Transmit interrupt */
//      USART_ITConfig(EVAL_COM1, USART_IT_TXE, DISABLE);
//    }
//  }
}


/*---------------------------- END OF FILE ----------------------------*/


 

bsp_uart.h header file

#ifndef __BSP_UART_H
#define __BSP_UART_H


#include <stdio.h>
#include "stm32f10x.h"

#define DEBUG_UART			USART1
#define EVAL_COM1			USART1
#define EVAL_COM2			USART2

#define TxBUFFER_SIZE   	100
#define RxBUFFER_SIZE   	0xFF

typedef struct
{
	uint8_t RxBuffer[RxBUFFER_SIZE];		// 接收暂存缓冲区
	__IO uint8_t RxCounter;				// 接收数据个数
	uint8_t Receiving_Time;				// 接收时间
	uint8_t Frame_flag;				// 一帧完成标志
}EVAL_COMx_TypeDef;
extern EVAL_COMx_TypeDef Usart1,Usart2;

extern uint8_t g_TxCounter;
extern uint8_t TxBuffer[TxBUFFER_SIZE];

void UART1_Comfig( uint32_t Baudrate );
void USART_SendByte( USART_TypeDef* USARTx, uint8_t c );
void USART_SendString( USART_TypeDef* USARTx, const uint8_t *pData, uint16_t Length );
void USART_Printf( USART_TypeDef* USARTx, char *String );


#endif	/* __BSP_UART_H */


/*---------------------------- END OF FILE ----------------------------*/


 

main.c file

/**
  ******************************************************************************
  * @file    Project/STM32F10x_StdPeriph_Template/main.c
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "bsp.h"
#include "bsp_uart.h"



/* Private functions ---------------------------------------------------------*/

const uint32_t Baudrate_1 = 115200;		// 波特率设置	支持的波特率:115200,19200,9600,38400,57600,1200,2400,4800
const uint32_t Baudrate_2 = 115200;		// 波特率设置	支持的波特率:115200,19200,9600,38400,57600,1200,2400,4800

/************************************************
函数名称 : main
功    能 : 主函数入口
参    数 : 无
返 回 值 : 无
*************************************************/
int main(void)
{
    /* Initial Configuration */
    SystemInit();
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    SysTick_Init();
    UART1_Comfig(Baudrate_1);
	
    /* -------- End -------- */
	
	
    /* Infinite loop */
    while (1)
    {
        if(Usart1.Frame_flag)
        {
            Usart1.Frame_flag = 0;
            USART_SendString(USART1, Usart1.RxBuffer, Usart1.RxCounter);
            printf("\n>>>>> 接收成功\n");
            Usart1.RxCounter = 0;
        }
    }
}

#if 0
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
    /* Place your implementation of fputc here */
    /* e.g. write a character to the USART */
    USART_SendData(EVAL_COM1, (uint8_t) ch);

    /* Loop until the end of transmission */
    while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET)
    {}

    return ch;
}

#endif

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

    /* Infinite loop */
    while (1)
    {
    }
}
#endif

/**
  * @}
  */


/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

在这里,没有把 UART的串口中断放到 stm32f10x_it.c文件中,是个人觉得统一放在自定义的 uart文件中易于管理,包括后面的 Time、ADC等,而那些 I/O中断就放回 stm32f10x_it.c文件中(主要是觉得不可能一些 LED、Key什么的,又创一个 bsp文件给她吧,这样就太太累赘了);还有就是那个超时判定的那部分在定时器中代码并没有贴出来(主要是还没发 Time的篇章,等待下一篇吧!)

发布了40 篇原创文章 · 获赞 14 · 访问量 1万+

Guess you like

Origin blog.csdn.net/qq_42992084/article/details/104098531