STM32F103 串口1和串口3对发数据 配合蓝牙模块 实现手机和单片机的简单通信demo

@

前言

开发板:正点原子 STM32F103 精英版
语言:C语言
开发环境:Keil5
使用了 KEY LED USART USB转TTL模块 智向的蓝牙模块(ps:电脑安装驱动CH340)
代码下载码云 GitHub
在这里插入图片描述

代码参考:正点原子 源码 串口实验例程
功能介绍
1、LED的0.2秒一闪,表示程序正在运行。
2、串口1收到的数据会发给串口3,串口3收到的数据会发给串口1。
3、按键KEY1按下会向串口1发送数据‘1’,按键KEY0按下会向串口3发送数据‘3’。

接线

USB转TTL

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

蓝牙

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

效果图

USB转TTL

在这里插入图片描述

蓝牙

使用的手机软件(安卓)为 BLE调试助手
在这里插入图片描述
打开软件、蓝牙、给予权限等
扫描到我们的蓝牙模块,然后连接
在这里插入图片描述
连接成功后
在这里插入图片描述
点击最下面的 Unkonwn Service,展开,有接收 和 发送 按钮
在这里插入图片描述

手机收 电脑发

在这里插入图片描述
在这里插入图片描述

手机发 电脑收

在这里插入图片描述
在这里插入图片描述

蓝牙的连接/断开

蓝牙收到了手机发来的 连接 和 断开 信息
在这里插入图片描述

参考用图

STM32F103

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

蓝牙模块相关

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

核心代码

完整代码下载码云 GitHub

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart1.h"
#include "usart3.h"

// 串口收发函数 type为1,串口1收,发往串口3  type不为1,串口3,发往串口1
void usart_recv_send(u8 type);

int main(void)
{
    vu8 key = 0;
    delay_init();												 // 延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    usart1_init(115200);									 // USART1初始化 波特率115200 默认数据位8 停止位1 校验位none
    usart3_init(115200);									 // USART3初始化 波特率115200 默认数据位8 停止位1 校验位none
    LED_Init();												 // LED端口初始化
    KEY_Init();										  	 	 // 初始化与按键连接的硬件接口
    while (1)
    {
        // 串口收发
        usart_recv_send(1);
        usart_recv_send(3);

        // 得到键值
        key = KEY_Scan(0);
        if (key)
        {
            switch (key)
            {
                case KEY1_PRES: // 向串口1发送'1'
                    usart1_send_byte(0x31);
                    break;
                case KEY0_PRES: // 向串口3发送'3'
                    usart3_send_byte(0x33);
                    break;
            }
        }

        LED0 = !LED0; //闪烁LED,提示系统正在运行.
        delay_ms(100);
    }
}

// 串口收发函数 type为1,串口1收,发往串口3  type不为1,串口3,发往串口1
void usart_recv_send(u8 type)
{
    u8 i = 0;
    u8 tmp_len = 0;
    // 数据缓存
    static u8 buf[255] = {0};
    // 数据长度
    u8 buf_len = 0;

    // 返回缓存区数据的个数
    if(1 == type)
        tmp_len = usart1_getdata_count();
    else
        tmp_len = usart3_getdata_count();

    for(i=0; i<tmp_len; i++)
    {
        // 返回缓存区当前指针所指数据
        if(1 == type)
            buf[i] = usart1_receive_data();
        else
            buf[i] = usart3_receive_data();

        buf_len++;
        // 超过约定的上限长度
        if(buf_len >= 250)
        {
            buf_len=0;
            break;
        }
    }

    // 数据不为空
    if(0 != buf_len)
    {
        // 串口数据发送
        if(1 == type)
            usart3_send_bytes(buf, buf_len);
        else
            usart1_send_bytes(buf, buf_len);
    }
}

usart1.c

#include "usart1.h"
#include "stdio.h"

static uint8_t usart1_buffer[255];
static uint8_t usart1_index;
static uint8_t usart1_count;

// USART1初始化 默认数据位8 停止位1 校验位none
void usart1_init(u32 bound)
{
    // GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* config USART1 clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 使能USART1,GPIOA时钟

    /* 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); // 初始化GPIOA.9
    /* 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); //初始化GPIOA.10

    // Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

    USART_InitStructure.USART_BaudRate = bound; // 串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    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(USART1, &USART_InitStructure); // 初始化串口1
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启串口接受中断

    USART_Cmd(USART1, ENABLE); // 使能串口1

    usart1_index=0;
    usart1_count=0;
}

// 中断服务函数
void USART1_IRQHandler(void)
{
    // 接收中断
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        if(usart1_count==usart1_index)
        {
            // 缓存区无数据,回到起点开始存储
            usart1_count=0;
            usart1_index=0;
        }
        usart1_buffer[usart1_count]=USART1->DR;
        usart1_count++;
        if(usart1_count>=250)
        {
            // 没有及时取出数据,导致存储位置到达末尾,回到起点
            usart1_count=0;
            usart1_index=0;
        }
    }
}

/*返回缓存区数据的个数*/
uint8_t usart1_getdata_count(void)
{
    return usart1_count-usart1_index;
}

/*返回缓存区当前指针所指数据*/
uint8_t usart1_receive_data(void)
{
    return usart1_buffer[usart1_index++];
}

/*串口数据发送函数
data_send:发送数据
*/
void usart1_send_byte(uint8_t data_send)
{
    USART_SendData(USART1, data_send);
    while (!(USART1->SR & USART_FLAG_TXE));
}

/*串口数据发送函数
data_buffer:发送数据串的首地址
length:发送数据的长度
*/
void usart1_send_bytes(uint8_t* data_buffer,uint8_t length)
{
    uint8_t i;
    for(i=0; i<length; i++)
    {
        usart1_send_byte(data_buffer[i]);
    }
}

usart3.c

#include "usart3.h"
#include "stdio.h"

static uint8_t usart3_buffer[255];
static uint8_t usart3_index;
static uint8_t usart3_count;

// USART3初始化 默认 数据位8 停止位1 校验位none
void usart3_init(u32 bound)
{
	// GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* config USART3 clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //使能USART3,GPIOB时钟

    /* USART3 GPIO config */
    /* Configure USART3 Tx (PB.10) as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    /* Configure USART3 Rx (PB.11) as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

    USART_InitStructure.USART_BaudRate = bound; // 串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    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(USART3, &USART_InitStructure); // 初始化串口3
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // 开启串口接受中断

    USART_Cmd(USART3, ENABLE); // 使能串口3 

    usart3_index=0;
    usart3_count=0;
}

// 中断服务函数
void USART3_IRQHandler(void)
{
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
    {
        if(usart3_count==usart3_index)
        {
            //缓存区无数据,回到起点开始存储
            usart3_count=0;
            usart3_index=0;
        }
        usart3_buffer[usart3_count]=USART3->DR;
        usart3_count++;
        if(usart3_count>=250)
        {
            //没有及时取出数据,导致存储位置到达末尾,回到起点
            usart3_count=0;
            usart3_index=0;
        }
    }
}

/*返回缓存区数据的个数*/
uint8_t usart3_getdata_count(void)
{
    return usart3_count-usart3_index;
}

/*返回缓存区当前指针所指数据*/
uint8_t usart3_receive_data(void)
{
    return usart3_buffer[usart3_index++];
}

/*串口数据发送函数
data_send:发送数据
*/
void usart3_send_byte(uint8_t data_send)
{
    USART_SendData(USART3, data_send);
    while (!(USART3->SR & USART_FLAG_TXE));
}

/*串口数据发送函数
data_buffer:发送数据串的首地址
length:发送数据的长度
*/
void usart3_send_bytes(uint8_t* data_buffer,uint8_t length)
{
    uint8_t i;
    for(i=0; i<length; i++)
    {
        usart3_send_byte(data_buffer[i]);
    }
}

拓展应用

实现简单的账号认证,通过命令控制LED1和蜂鸣器的开关

功能介绍

手机连接蓝牙,发送登录命令login#admin#admin

login#用户名#密码#

在这里插入图片描述

登录成功后,发送控制命令

cmd#device#status#

最后发送登出命令cmd#login#out
在这里插入图片描述

效果图

在这里插入图片描述

在这里插入图片描述

代码

main.c
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart1.h"
#include "usart3.h"
#include "string.h"
#include "stdio.h"
#include "beep.h"

u8 login = 0;
u8 username[21] = "admin";
u8 password[21] = "admin";

// 串口收发函数 type为1,串口1收,发往串口3  type不为1,串口3收,发往串口1
void usart_recv_send(u8 type);
// 检查登录 传入收到的数据和数据长度 返回 0验证成功,1账号或密码错误,2数据超长
u8 check_login(u8* buf, u8 len);
/*
	函数功能: 命令解析
	传参:     收到的数据和数据长度
	命令格式: cmd#device#status#
	返回: 	   0不符合规则 1解析成功
*/
u8 cmd_analysis(u8* buf, u8 len);

int main(void)
{
    vu8 key = 0;
    delay_init();											 // 延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 		 // 设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    usart1_init(115200);									 // USART1初始化 波特率115200 默认数据位8 停止位1 校验位none
    usart3_init(115200);									 // USART3初始化 波特率115200 默认数据位8 停止位1 校验位none
    LED_Init();												 // LED端口初始化
    KEY_Init();										  	 	 // 初始化与按键连接的硬件接口
	BEEP_Init();									  	 	 // 蜂鸣器初始化
	LED0 = 1;
    while (1)
    {
        // 串口收发
        usart_recv_send(1);
        usart_recv_send(3);

        // 得到键值
        key = KEY_Scan(0);
        if (key)
        {
            switch (key)
            {
				case KEY1_PRES: // 向串口1发送'1'
					usart1_send_byte(0x31);
					break;
				case KEY0_PRES: // 向串口3发送'3'
					usart3_send_byte(0x33);
					break;
            }
        }

        LED0 = !LED0; //闪烁LED,提示系统正在运行.
        delay_ms(100);
    }
}

// 串口收发函数 type为1,串口1收,发往串口3  type不为1,串口3收,发往串口1
void usart_recv_send(u8 type)
{
    u8 i = 0;
    u8 tmp_len = 0;
    // 数据缓存
    static u8 buf[255] = {0};
    //static u8 buf2[255] = {0};
    // 数据长度
    u8 buf_len = 0;

    // 返回缓存区数据的个数
    if(1 == type)
        tmp_len = usart1_getdata_count();
    else
        tmp_len = usart3_getdata_count();

    for(i=0; i<tmp_len; i++)
    {
        // 返回缓存区当前指针所指数据
        if(1 == type)
            buf[i] = usart1_receive_data();
        else
            buf[i] = usart3_receive_data();

        buf_len++;
        // 超过约定的上限长度
        if(buf_len >= 250)
        {
            buf_len=0;
            break;
        }
    }

    // 数据不为空
    if(0 != buf_len)
    {
        // 串口数据发送
        if(1 == type)
            usart3_send_bytes(buf, buf_len);
        else
        {
            usart1_send_bytes(buf, buf_len);
			printf("
");
            // 如果没有登录
            if(0 == login)
            {
                // 检查登录
                if(0 == check_login(buf, buf_len))
                {
                    login = 1;
                    printf("登录成功
");
                }
                else if(2 == check_login(buf, buf_len))
                {
                    printf("账号或密码超长
");
                }
				else if(3 == check_login(buf, buf_len))
                {
                    printf("命令过短,请发送命令"login#账号#密码#"登录
");
                }
                else
                {
                    printf("账号或密码错误,请发送命令"login#账号#密码#"登录
");
                }
            }
            // 已经登录
            else
            {
				cmd_analysis(buf, buf_len);
            }
        }
    }
}

// 检查登录 传入收到的数据 返回 0验证成功,1账号或密码错误,2数据超长,3数据过短
u8 check_login(u8* buf, u8 len)
{
    u8 i = 0, j = 0;
    u8 str_username[21] = {0};
    u8 str_password[21] = {0};
	if(len < 9)
	{
		return 3;
	}
    // 登录命令
    if(buf[0] == 'l' && buf[1] == 'o' && buf[2] == 'g' && buf[3] == 'i' && buf[4] == 'n' && buf[5] == '#')
    {
        // 解析数据获取username和password 分隔符为'#'
        j = 0;
        i = 6;
        while(buf[i] != '#' && i < len)
        {
            // 数据超长
            if(j >= 20)
            {
                return 2;
            }
            str_username[j++] = buf[i++];
        }
        str_username[j] = '';

        j = 0;
        i++;
        while(buf[i] != '#' && i < len)
        {
            // 数据超长
            if(j >= 20)
            {
                return 2;
            }
            str_password[j++] = buf[i++];
        }
        str_password[j] = '';

        if(0 == strcmp((char *)str_username, (char *)username) && 0 == strcmp((char *)str_password, (char *)password))
        {
            return 0;
        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 1;
    }
}

/*
	函数功能: 命令解析
	命令格式: cmd#device#status#
	返回: 	   0不符合规则 1解析成功
*/
u8 cmd_analysis(u8* buf, u8 len)
{
	u8 device[10] = {0};
	u8 status[6] = {0};
	u8 i = 0, j = 0;
	if(len < 7)
	{
		printf("命令过短
");
		return 0;
	}
	
	// 命令格式校验
	if(buf[0] == 'c' && buf[1] == 'm' && buf[2] == 'd' && buf[3] == '#')
	{
		// 解析数据获取devicestatus 分隔符为'#'
        j = 0;
        i = 4;
        while(buf[i] != '#' && i < len)
        {
            // 数据超长
            if(j >= 9)
            {
				printf("device超长
");
                return 0;
            }
            device[j++] = buf[i++];
        }
        device[j] = '';
		
		j = 0;
        i++;
        while(buf[i] != '#' && i < len)
        {
            // 数据超长
            if(j >= 5)
            {
				printf("status超长
");
                return 0;
            }
            status[j++] = buf[i++];
        }
        status[j] = '';
		
		// LED1的命令 ON/OFF
		if(0 == strcmp((char *)device, "LED1"))
        {
			if(0 == strcmp((char *)status, "ON"))
			{
				LED1 = 0;
				printf("LED1打开
");
				return 1;
			}
			else if(0 == strcmp((char *)status, "OFF"))
			{
				LED1 = 1;
				printf("LED1关闭
");
				return 1;
			}
			else
			{
				printf("命令错误
");
				return 0;
			}  
        }
		else if(0 == strcmp((char *)device, "BEEP"))
        {
			if(0 == strcmp((char *)status, "ON"))
			{
				BEEP = 1;
				printf("BEEP打开
");
				return 1;
			}
			else if(0 == strcmp((char *)status, "OFF"))
			{
				BEEP = 0;
				printf("BEEP关闭
");
				return 1;
			}
			else
			{
				printf("命令错误
");
				return 0;
			}  
        }
		else if(0 == strcmp((char *)device, "login"))
        {
			if(0 == strcmp((char *)status, "out"))
			{
				login = 0;
				printf("账号登出
");
				return 1;
			}
			else
			{
				printf("命令错误
");
				return 0;
			}  
        }
		else
		{
			printf("命令错误
");
			return 0;
		}
	}
	else
	{
		printf("命令错误
");
		return 0;
	}
}



usart1.c
#include "usart1.h"
#include "stdio.h"

static uint8_t usart1_buffer[255];
static uint8_t usart1_index;
static uint8_t usart1_count;

//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

// USART1初始化 默认数据位8 停止位1 校验位none
void usart1_init(u32 bound)
{
    // GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* config USART1 clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 使能USART1,GPIOA时钟

    /* 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); // 初始化GPIOA.9
    /* 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); //初始化GPIOA.10

    // Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

    USART_InitStructure.USART_BaudRate = bound; // 串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    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(USART1, &USART_InitStructure); // 初始化串口1
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启串口接受中断

    USART_Cmd(USART1, ENABLE); // 使能串口1

    usart1_index=0;
    usart1_count=0;
}

// 中断服务函数
void USART1_IRQHandler(void)
{
    // 接收中断
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        if(usart1_count==usart1_index)
        {
            // 缓存区无数据,回到起点开始存储
            usart1_count=0;
            usart1_index=0;
        }
        usart1_buffer[usart1_count]=USART1->DR;
        usart1_count++;
        if(usart1_count>=250)
        {
            // 没有及时取出数据,导致存储位置到达末尾,回到起点
            usart1_count=0;
            usart1_index=0;
        }
    }
}

/*返回缓存区数据的个数*/
uint8_t usart1_getdata_count(void)
{
    return usart1_count-usart1_index;
}

/*返回缓存区当前指针所指数据*/
uint8_t usart1_receive_data(void)
{
    return usart1_buffer[usart1_index++];
}

/*串口数据发送函数
data_send:发送数据
*/
void usart1_send_byte(uint8_t data_send)
{
    USART_SendData(USART1, data_send);
    while (!(USART1->SR & USART_FLAG_TXE));
}

/*串口数据发送函数
data_buffer:发送数据串的首地址
length:发送数据的长度
*/
void usart1_send_bytes(uint8_t* data_buffer,uint8_t length)
{
    uint8_t i;
    for(i=0; i<length; i++)
    {
        usart1_send_byte(data_buffer[i]);
    }
}

原文地址:https://www.cnblogs.com/ikaros-521/p/15323396.html