串口通信:ASCII码适用于传输文本数据,而十六进制适用于传输二进制数据。选择哪种数据传输方式取决于具体的应用场景和需求。

有三个串口 UART1 UART2 UART3

波特率:每秒钟最多传输几位;常用的波特率:9600、115200、921600

波特率寄存器BRR

怎么知道串口是哪个引脚-------读表

在左侧种pins下面有各种各样的封装,我们使用的是LQFP48,关注LQFP

这是没有使能重映射的时候TX对应PA9,RX对应PA10。PA9接RX,PA10接TX

这是使能重映射后的TX和RX

TX为PB6,RX为PB7。PB6接RX,PB7接TX

又一个问题?怎么看模式和最大输出速度

IO配置表

RX最好不要选择浮空输入,避免外界干扰,选择上拉模式,在没有数据的时候默认高电平。

为什么使用上拉,不使用下拉,这就跟USART的传输模式有关,空闲位都是高电平

配置完成

若使用重映射

再此之前,完成外设的配置后,接下来实现串口发送数据

几个标志位

TxE和TC标志位 TXE监控是否能写入发送寄存器,TC监控是否完成

USART_FLAG_RXNE 接收数据寄存器(RDR)非空,已收到数据。 检查是否有数据可读取。

此时,USART1 和 USART2 本质上是 指向各自寄存器组起始地址的结构体指针

void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size)

传参类型定义为指针,后面调用的时候用,My_USART_SendBytes(USART1就行)

    //串口名;发送数据;字节数量
    void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size) {
    for(uint32_t i = 0; i < Size; i++) {
        // 1. 等待发送寄存器空(可写入新数据)
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        
        // 2. 写入数据到发送寄存器
        USART_SendData(USARTx, pData[i]);
    }
    
    // 3. 等待所有数据完全发送(包括移位寄存器)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
  注解:  当不为空的时候,一直重复while的死循环,为空的时候,才执行2.

#include "stm32f10x.h"
void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size);//声明
int main(void)
{
    
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        //串口引脚的初始化
    GPIO_InitTypeDef GPIO_InitStruct = {0};//**变量+变量名**

    
    //TX
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
  GPIO_Init(GPIOA,&GPIO_InitStruct);
    //RX
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
  GPIO_Init(GPIOA,&GPIO_InitStruct);
    
    
    
    USART_InitTypeDef USART_InitStruct={0};
    
    USART_InitStruct.USART_BaudRate = 115200;                     // 波特率115200
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;      // 8位数据
  USART_InitStruct.USART_StopBits = USART_StopBits_1;           // 1位停止位
  USART_InitStruct.USART_Parity = USART_Parity_No;              // 无校验
  USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;  // 双向通
    
    USART_Init(USART1, &USART_InitStruct);  // 初始化USART1
    
    USART_Cmd(USART1, ENABLE);  // 启动USART1
    
    uint8_t byteTosend[]={1,2,3,4,5};
    
    My_USART_SendBytes(USART1,byteTosend,5);
    
    while(1)
    {
    }

    
}
    //串口名;发送数据;字节数量,发给电脑
    void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size) 
        {
    for(uint32_t i = 0; i < Size; i++) {
        // 1. 等待发送寄存器空(可写入新数据)
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        
        // 2. 写入数据到发送寄存器
        USART_SendData(USARTx, pData[i]);
    }
    
    // 3. 等待所有数据完全发送(包括移位寄存器)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
    
 

如果要打印字符串呢?

#include "stm32f10x.h"
#include<stdio.h>
void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size);//声明发送函数
void My_USART_Init(void);
int fputc(int ch,FILE*f);

int main(void)
{
	
		
  
	//测试发送数据
//	uint8_t byteTosend[]={1,2,3,4,5};
//	My_USART_SendBytes(USART1,byteTosend,5);
	
	//测试打印字符串
	My_USART_Init();
	printf("Hello world.\r\n");
	while(1);


	
}



//通过串口发送多个字节,程序下载到单片机里面,发送的是单片机往电脑发送
//串口名;发送数据;字节数量
	void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size) 
		{
    for(uint32_t i = 0; i < Size; i++) {
        // 1. 等待发送寄存器空(可写入新数据)
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        
        // 2. 写入数据到发送寄存器
        USART_SendData(USARTx, pData[i]);
    }
    
    // 3. 等待所有数据完全发送(包括移位寄存器)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
     }
		
		 
	void My_USART_Init(void)//三部:时钟初始化,定义结构体变量,结构体变量赋值,初始化函数,开启串口函数
	{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
		//串口引脚的初始化
	GPIO_InitTypeDef GPIO_InitStruct = {0};//**变量+变量名**

	
	//TX PA9
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
  GPIO_Init(GPIOA,&GPIO_InitStruct);
	//RX PA10
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
  GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	USART_InitTypeDef USART_InitStruct={0};
	
	USART_InitStruct.USART_BaudRate = 115200;                     // 波特率115200
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;      // 8位数据
  USART_InitStruct.USART_StopBits = USART_StopBits_1;           // 1位停止位
  USART_InitStruct.USART_Parity = USART_Parity_No;              // 无校验
  USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;  // 双向通
	
	USART_Init(USART1, &USART_InitStruct);  // 初始化USART1
	
	USART_Cmd(USART1, ENABLE);  // 启动USART1
	}

//FILE报错,头文件需要引用stdio.h	
//如果需要 printf 支持(studio),不要修改 _fputc,而是重写 fputc。如果仅需底层串口发送,可以另写一个函数(如 USART_SendChar),但需手动调用。
//测试程序 printf("Hello world.\r\n");
//注意在魔法棒-target里面勾选Use MicroLIB;MicroLIB 是 ARM 公司提供的一个高度优化的简化版 C 标准库,专为资源受限的嵌入式系统设计.
// 实现 fputc(printf 依赖此函数)
int fputc(int ch, FILE *f) {
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, (uint8_t)ch);
    return ch;
}


串口接收数据?

RXNE标志位------接收数据寄存器非空(receive data register not empty),非空的时候,RXNE=1

通过电脑串口控制小灯的亮灭

#include "stm32f10x.h"
#include<stdio.h>
void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size);//声明发送函数
void My_USART_Init(void);
int fputc(int ch,FILE*f);
void My_OnBoardLED_Init(void);

int main(void)
{
	My_USART_Init();
		
  My_OnBoardLED_Init();//每次初始化函数不要漏掉了
	
	//测试发送数据
//	uint8_t byteTosend[]={1,2,3,4,5};
//	My_USART_SendBytes(USART1,byteTosend,5);
	
	//测试打印字符串
//	My_USART_Init();
//	printf("Hello world.\r\n");
//	while(1);
 
	//串口点亮led
  while(1){
	while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
		
  uint8_t btyeRcvd=USART_ReceiveData(USART1);
		
		if(btyeRcvd=='0')//字符0//不加双引号也可以串口那边字符改为Hex就可以
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
	else if(btyeRcvd=='1')
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
	}
}



//通过串口发送多个字节,程序下载到单片机里面,发送的是单片机往电脑发送
//串口名;发送数据;字节数量
	void My_USART_SendBytes(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size) 
		{
    for(uint32_t i = 0; i < Size; i++) {
        // 1. 等待发送寄存器空(可写入新数据)
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        
        // 2. 写入数据到发送寄存器
        USART_SendData(USARTx, pData[i]);
    }
    
    // 3. 等待所有数据完全发送(包括移位寄存器)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
     }
		
		 
	void My_USART_Init(void)//三部:时钟初始化,定义结构体变量,结构体变量赋值,初始化函数,开启串口函数
	{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
		//串口引脚的初始化
	GPIO_InitTypeDef GPIO_InitStruct = {0};//**变量+变量名**

	
	//TX PA9
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
  GPIO_Init(GPIOA,&GPIO_InitStruct);
	//RX PA10
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
  GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	USART_InitTypeDef USART_InitStruct={0};
	
	USART_InitStruct.USART_BaudRate = 115200;                     // 波特率115200
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;      // 8位数据
  USART_InitStruct.USART_StopBits = USART_StopBits_1;           // 1位停止位
  USART_InitStruct.USART_Parity = USART_Parity_No;              // 无校验
  USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;  // 双向通
	
	USART_Init(USART1, &USART_InitStruct);  // 初始化USART1
	
	USART_Cmd(USART1, ENABLE);  // 启动USART1
	}

//FILE报错,头文件需要引用stdio.h	
//如果需要 printf 支持(studio),不要修改 _fputc,而是重写 fputc。如果仅需底层串口发送,可以另写一个函数(如 USART_SendChar),但需手动调用。
//测试程序 printf("Hello world.\r\n");
//注意在魔法棒-target里面勾选Use MicroLIB;MicroLIB 是 ARM 公司提供的一个高度优化的简化版 C 标准库,专为资源受限的嵌入式系统设计.
// 实现 fputc(printf 依赖此函数)
int fputc(int ch, FILE *f) {
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, (uint8_t)ch);
    return ch;
}


void My_OnBoardLED_Init(void)
{
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
 GPIO_InitTypeDef GPIO_InitStruct={0};
 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;
 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;
 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;
 GPIO_Init(GPIOC,&GPIO_InitStruct);
}
	

总结:三个标志位:

两个发送,一个接收

TXE TC RXNE

TXE (Transmit Data Register Empty)

  • 含义:发送数据寄存器空-------空为1

TC (Transmission Complete)

  • 含义:发送完成

  • 触发条件:当发送移位寄存器为空且最后一个位已发送时置位----完成为1

RXNE (Receive Data Register Not Empty)

  • 含义:接收数据寄存器非空

  • 触发条件:当接收到数据并转移到接收数据寄存器时置位---非空为1

封装串口代码

后续要串口的代码,声明下#include“usart.h”

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐