【STM32】STM32F103C8T6串口通信,实现3个串口收发数据

2023-05-16

串口通信(Serial Communications)实现单片机与电脑或者其它外设进行通信,通信时只需两根线(TX,RX)就可以实现数据传输。STM32f103有三个串口,分别为串口1(RX PA10, TX PA 9),串口2(RX PA3,TX PA2),串口3(RX PB11,TX PB10)。
以下代码是配置三个串口:
usart.c

#include "sys.h"
#include "usart.h"	  
 
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//ucos 使用	  
#endif

#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_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 

 
 
#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART1_RX_BUF[USART1_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART1_RX_STA=0;       //接收状态标记	  
  
void uart1_init(u32 bound){
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
	//USART1_RX	  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
	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=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	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 

}

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据		
		if((USART1_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART1_RX_STA&0x4000)//接收到了0x0d
			{
				if(Res!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
				else USART1_RX_STA|=0x8000;	//接收完成了 
			}
			else //还没收到0X0D
			{	
				if(Res==0x0d)USART1_RX_STA|=0x4000;
				else
					{
					USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ;
					USART1_RX_STA++;
					if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 

#endif	

#if EN_USART2_RX
u8  USART2_RX_BUF[USART2_REC_LEN]; 	//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
u16 USART2_RX_STA = 0;         			//接收状态标记	

void uart2_init(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStrue;
	USART_InitTypeDef USART_InitStrue;
	NVIC_InitTypeDef NVIC_InitStrue;
	
	// 外设使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	USART_DeInit(USART2);  //复位串口2 -> 可以没有
	
	// 初始化 串口对应IO口  TX-PA2  RX-PA3
	GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStrue.GPIO_Pin=GPIO_Pin_2;
	GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStrue);
	
	GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStrue.GPIO_Pin=GPIO_Pin_3;
	GPIO_Init(GPIOA,&GPIO_InitStrue);
	
	// 初始化 串口模式状态
	USART_InitStrue.USART_BaudRate=bound; // 波特率
	USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // 硬件流控制
	USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; // 发送 接收 模式都使用
	USART_InitStrue.USART_Parity=USART_Parity_No; // 没有奇偶校验
	USART_InitStrue.USART_StopBits=USART_StopBits_1; // 一位停止位
	USART_InitStrue.USART_WordLength=USART_WordLength_8b; // 每次发送数据宽度为8位
	USART_Init(USART2,&USART_InitStrue);
	
	USART_Cmd(USART2,ENABLE);//使能串口
	USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//开启接收中断
	
	// 初始化 中断优先级
	NVIC_InitStrue.NVIC_IRQChannel=USART2_IRQn;
	NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStrue.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStrue);
}
 
void USART2_IRQHandler(void) // 串口2中断服务函数
{
	u8 res;
	if(USART_GetITStatus(USART2,USART_IT_RXNE)) // 中断标志
	{
		res= USART_ReceiveData(USART2);  // 串口2 接收
//		USART_SendData(USART2,res);   // 串口2 发送
		if((USART2_RX_STA&0x8000)==0)//接收未完成
		{
		if(USART2_RX_STA&0x4000)//接收到了0x0d
			{
			if(res!=0x0a)USART2_RX_STA=0;//接收错误,重新开始
			else USART2_RX_STA|=0x8000;	//接收完成了 
			}
		else //还没收到0X0D
			{	
			if(res==0x0d)USART2_RX_STA|=0x4000;
			else
				{
				USART2_RX_BUF[USART2_RX_STA&0X3FFF]=res ;
				USART2_RX_STA++;
				if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		} 
	}
}

#endif

#if EN_USART3_RX
u8  USART3_RX_BUF[USART3_REC_LEN]; 	//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
u16 USART3_RX_STA = 0;         			//接收状态标记	

void uart3_init(u32 bound)
{

	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// GPIOB时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能
 
 	USART_DeInit(USART3);  //复位串口3
		 //USART3_TX   PB10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
   
    //USART3_RX	  PB11
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11
	
	USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
	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_Cmd(USART3, ENABLE);                    //使能串口 
	
	//使能接收中断
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   
	
	//设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	USART3_RX_STA=0;		//清零
}
 
void USART3_IRQHandler(void) // 串口3中断服务函数
{
	u8 res;
	if(USART_GetITStatus(USART3,USART_IT_RXNE)) // 中断标志
	{
		res= USART_ReceiveData(USART3);  // 串口3 接收
//		USART_SendData(USART2,res);   // 串口3 发送
		if((USART3_RX_STA&0x8000)==0)//接收未完成
		{
		if(USART3_RX_STA&0x4000)//接收到了0x0d
			{
			if(res!=0x0a)USART3_RX_STA=0;//接收错误,重新开始
			else USART3_RX_STA|=0x8000;	//接收完成了 
			}
		else //还没收到0X0D
		{	
			if(res==0x0d)USART3_RX_STA|=0x4000;
			else
				{
				USART3_RX_BUF[USART2_RX_STA&0X3FFF]=res ;
				USART3_RX_STA++;
				if(USART3_RX_STA>(USART3_REC_LEN-1))USART3_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
		}
	} 
	}
}

#endif

usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 

#define USART1_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1			//使能(1)/禁止(0)串口1接收 	
extern u8  USART1_RX_BUF[USART1_REC_LEN]; 	//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART1_RX_STA;         			//接收状态标记	
void uart1_init(u32 bound);

#define USART2_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART2_RX 			1			//使能(1)/禁止(0)串口2接收
extern u8  USART2_RX_BUF[USART2_REC_LEN]; 	//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART2_RX_STA;         			//接收状态标记	
void uart2_init(u32 bound);

#define USART3_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART3_RX 			1			//使能(1)/禁止(0)串口2接收
extern u8  USART3_RX_BUF[USART3_REC_LEN]; 	//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART3_RX_STA;         			//接收状态标记	
void uart3_init(u32 bound);
#endif

main.c

/*
本程序用于实现stm32f103c8t6三个串口通信
三个串口接线说明
	串口1:
		RX PA10
		TX PA9
	串口2:
		RX PA3
		TX PA2
	串口3:
		RX PB11
		TX PB10
运行现象:
	串口1接到串口助手时,电脑端发送信息给单片机,单片
机收到后会返回:串口1:我接收到了串口数据:***  其中,
***表示单片机收到的信息。
	串口2接到串口助手时,电脑端发送信息给单片机,单片
机收到后开发板会开启LED灯。
	串口3接到串口助手时,电脑端发送信息给单片机,单片
机收到后开发板会关闭LED灯。
作者:ZX
时间:2022年9月19日
*/
#include "stm32f10x.h"                             // Device header
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "sys.h"
int main()
{
//    u8 i = 0;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart1_init(9600);	                           //串口1初始化波特率为9600
	uart2_init(9600);							   //串口2初始化波特率为9600
	uart3_init(9600);							   //串口3初始化波特率为9600
    delay_init(50);	                               //延时初始化 
    LED_Init();                                    //初始化LED灯
    LED = 0;                                       //关闭led灯
    while(1)
    {    
		if(USART1_RX_STA&0x8000)
		{
			printf("串口1:我接收到了串口数据:%s\r\n",USART1_RX_BUF);
			USART1_RX_STA = 0;
		}
		if(USART2_RX_STA&0x8000)
		{
			LED = 0;	//开启led灯
			USART2_RX_STA = 1;
		}
		if(USART3_RX_STA&0x8000)
		{
			LED = 1;	//关闭led灯
			USART3_RX_STA = 1;
		}
        delay_ms(500);
    }
    
    return 0;
}

注意,程序里有点问题单不影响使用,在主函数中USART2_RX_STA = 1;应改为USART2_RX_STA = 0; USART3_RX_STA = 1;应改为USART3_RX_STA = 0;,在例程代码里记得修改!!!
以上代码可以直接使用(亲测有效),实验现象如main函数注释一样。
完整程序链接:https://pan.baidu.com/s/1ueNuL6bq1aHhaEjrfNzYWA
提取码:5656
侵删!!!!
/*********************************************************/
更新:2023年5月11日
将usart.c文件USART3_IRQHandler函数中的

USART3_RX_BUF[USART2_RX_STA&0X3FFF]=res ;

改为

USART3_RX_BUF[USART3_RX_STA&0X3FFF]=res ;

USART3_RX_STA手滑写成了USART2_RX_STA不然会导致串口三接收数据有误

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32】STM32F103C8T6串口通信,实现3个串口收发数据 的相关文章

  • 小学生学AD16(入门级别,看这篇就够了)

    1 软件安装 xff1a AD16的安装我就不多介绍了 xff0c csdn一搜一大把 要学一个软件 xff0c 那么软件安装是必经之路 xff0c 不要认为软件安装不重要 xff08 如果你的安装完之后桌面没快捷方式 xff0c 那么可以

随机推荐

  • Arduino串口绘图器双通道绘制

    Serial print val Serial print 34 34 Serial println muBiao 其实只用在两个变量之间加个 xff0c 就行了 参考网址 https www norwegiancreations com
  • 关于神舟笔记本TX8连副屏经常蓝屏的问题

    大概率是3060显卡驱动的问题 xff0c 可以试试重新安装显卡驱动 若还是不行就换个接口 xff0c 不要用hdim的接口 xff0c 那个是直接连3060的 换剩下两个的minidp接口其中一个 xff0c 第一个不要接 xff0c 那
  • 51单片机入门(小学生都能学会)

    序 xff1a 时隔一年 xff0c 我终于从二年级到三年级了 xff01 由于小学三年级这学期要学单片机 xff0c 故写下这篇笔记留下些什么 由于自己也是新手 xff0c 欢迎各位指出本文的各种错误 1 什么是51单片机 为什么要说这个
  • 解决使用WinScp连接Ubantu系统失败的问题---SSH无法连接

    起因 为了互通Linux系统和Windows系统的文件 xff0c 以更好的实现文件管理和资源共享 所以在查阅资料后 xff0c 使用WinScp xff0c WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端 它的
  • 小学生51系列之基础知识

    1 单片机的基本结构 说到基本结构 xff0c 就是指51单片机的硬件组成 51单片机由中央处理器CPU 储存器 定时器 I O端口 组成 其中储存器包含数据储存器 xff08 RAM xff09 和程序储存器 xff08 ROM xff0
  • ros 接入Livox Mid-70

    最近在研究3d避障激光 大疆Livox mid 70 xff0c 记录下接入过程 环境信息 xff1a Ubuntu 18 04 ros melodic 1 livox view 点云可视化 xff08 1 xff09 根据livox mi
  • ROS+opencv实践-二维码识别

    一 安装二维码识别的功能包 sudo apt span class token operator span get install ros span class token operator span melodic span class
  • C语言简单链表详细步骤详解

    43 链表 gt 小阿豪带你写链表 xff01 xff01 xff01 xff01 进入正文 span class token number 1 span 首先 xff0c 先想好自己要创建的链表格式以及最后的的显示界面 xff01 xff
  • 滚球控制系统详解 —— (附核心代码)

    最近练习了17年的国赛题 滚球控制系统 这里展示一下画圆 xff1a 观看完整视频点这里 接下来 xff0c 我来分享一下从搭整体结构到调试完的过程 这是我搭完的整体结构 xff08 缩小版 xff09 不管什么题 xff0c 结构部分还是
  • 【Linux网络编程】你了解TIME_WAIT状态吗?

    在Linux网络编程中 xff0c 我相信大多数人觉得最难理解的就是TCP中的TIME WAIT状态了吧 xff0c 那么TIME WAIT的概念到底是什么 xff0c 有几个类型呢 xff0c 以及在面试中经常会问到的TIME WAIT状
  • 【图解】八幅图带你轻松掌握八大排序(上):冒泡排序、选择排序、插入排序、快速排序

    在算法中 xff0c 八大排序算是最简单的也是重中之重 xff0c 所以掌握好八大排序的思想是非常重要的 xff0c 很多人学排序的时候会觉得似懂非懂 xff0c 本篇文章作者耗时两小时绘制了八大排序的详细图解 xff0c 让大家快速理解八
  • 最详细整理STL之vector基础

    前言 xff1a Vector是一种可以存储任意类型的动态数组 xff0c 属于序列式容器 xff0c 可以用sort对其进行排序 xff0c 底层数据结构是数组 xff0c 可以随机访问元素 Vectors 包含着一系列连续存储的元素 其
  • STL之vector扩容机制

    前言 大家好 xff0c 我是萝卜 上期结尾说到vector的push back操作一般情况下时间复杂度为O 1 xff0c 是否存在特殊情况 那么本期就讲讲vector在容器空间不足时进行push back操作会发生什么 vector作为
  • 求职嵌入式软件开发linux kernel/BSP leader/工程师职位

    个人工作说明 xff1a 目前从事linux系统网络设备的开发工作 xff0c 负责bootloader linux kernel文件系统 xff0c driver移植 xff0c 以及开源app移植 主要技能和过去的经验 xff1a 1
  • 【2023最新】计算机网络面试题【收藏持续更新】

    你好 xff0c 我是萝卜 xff0c 我会在本篇文章持续更新关于计算机网络的面试题 最新内容更新日期 xff1a 2023 04 11 基础 说一下计算机网络体系结构 网络体系结构一般有三种 xff1a ISO七层模型 xff0c TCP
  • UDP协议详解

    概述 xff1a UDP只在IP的数据报服务之上增加了两个最基本的服务 xff1a 复用和分用以及差错检测 UDP不保证可靠交付 xff0c 但是不意味着应用对数据的要求是不可靠的 xff0c 只是所有维护可靠性的工作可由用户在应用层完成
  • TCP传输可靠性保证机制之重传机制

    TCP重传机制 tcp重传机制包括超时重传 快速重传 带选择确认的重传 SACK 重复SACK 四种 超时重传 xff1a 超时重传是tcp协议保证数据可靠性的一个重要机制 原理是在发送某一个数据以后开启一个计时器 xff0c 在一定时间内
  • VSCode:终端控制台常用指令

    常用的指令 以下是一些在 Visual Studio Code 终端控制台中常用的指令 xff1a 1 清除终端 xff1a clear 2 列出当前目录中的文件和文件夹 xff1a ls 3 切换到指定目录 xff1a xff1a cd
  • Ubuntu18.04安装ROS时rosdep update报错解决办法

    在安装ros进行rosdep update时经常会报错 xff0c 有时候可以通过换网解决 xff0c 但从我安装那么多次的经验来看 xff0c 仅有一次换手机热点后更新成功了 xff0c 其他都是失败 xff0c 成功率太低 从网上搜到了
  • 【STM32】STM32F103C8T6串口通信,实现3个串口收发数据

    串口通信 xff08 Serial Communications xff09 实现单片机与电脑或者其它外设进行通信 xff0c 通信时只需两根线 xff08 TX xff0c RX xff09 就可以实现数据传输 STM32f103有三个串