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

这篇具有很好参考价值的文章主要介绍了【STM32】STM32F103C8T6串口通信,实现3个串口收发数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

串口通信(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不然会导致串口三接收数据有误文章来源地址https://www.toymoban.com/news/detail-517054.html

到了这里,关于【STM32】STM32F103C8T6串口通信,实现3个串口收发数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32驱动串口屏,STM32F103C8T6串口发送指令控制HMI串口屏

    串口屏是一个集成了单片机的屏幕模块,采用的是TTL串口协议,可以直接通过对应指令控制屏幕, 本文采用的串口屏是陶晶驰T0系列的基本型,目的是通过单片机的串口来控制串口屏 上面仅是一部分常用的基础指令,更多更仔细的指令或者函数可以访问陶晶驰资料官网。 硬

    2024年02月13日
    浏览(50)
  • Qt实现安卓手机蓝牙通信并控制stm32f103c8t6驱动VFD屏

    Qt具有跨平台的特性所以非常适合写通信的demo,但是在这个例程中Qt蓝牙部分不支持Windows平台,安卓平台使用没问题。 Qt蓝牙主要涉及到三个类的使用: QBluetoothDeviceDiscoveryAgent //扫描周围蓝牙设备 QBluetoothLocalDevice //扫描本地蓝牙 QBluetoothSocket //建立蓝牙的socket读写 安卓不支

    2024年02月08日
    浏览(55)
  • 基于STM32F103C8T6的HC-06蓝牙通信

    如果朋友们 遇到了如下问题 ,可以仔细借鉴本文章和另一篇专门讲解 蓝牙通信问题 的文章,一定能够解决你在蓝牙通信时遇到的诸多困难 1.在调试蓝牙模块AT指令时无返回值 2.身边 无USB转TTL模块 可以直接调试蓝牙模块(本人就是由于无模块花了了整整一天才调试成功)

    2024年02月03日
    浏览(69)
  • STM32 F103C8T6学习笔记7:双机无线串口通信

    今日尝试配通俩个C8T6单片机之间的无线串口通信,文章提供原理,源码,测试效果图,测试工程下载: 目录 传输不规范问题: 串口通信资源: 单个串口资源理解: 单片机串口资源: 测试目标与测试硬件连接: 串口初始化与串口中断接收逻辑: 串口初始化: 初步测试能否

    2024年02月09日
    浏览(41)
  • 使用串口烧写程序到STM32F103C8T6最小板(CH340)

    商家没给ST‐LINK V2下载器,故使用串口将程序烧录到最小板,使用仿真软件Flymcu进行。(默认安装过CH340的驱动) 联机下载时的程序文件:编译生成的.hex文件; 编程前重装文件:当选中该项后,flymcu会在每次编程之前将Hex文件重新装载一遍,这对于代码调试的时候比较有用

    2024年02月01日
    浏览(58)
  • 学习记录之STM32F103C8T6最小系统板驱动MPU6050串口打印数据

    1.使用到的工具介绍 2.MPU6050和整体和简单介绍 3.程序的介绍 1.使用到的工具介绍 硬件方面:STM32F103C8T6最小系统板核心板,MPU6050模块三维角度传感器,经典的CH340烧写和串口作用,和若干个杜邦线。 软件方面:keil5编写程序软件,烧写软件FlyMcu.exe烧写工具,sscom.exe串口调试工

    2023年04月09日
    浏览(62)
  • STM32F103C8T6最小系统板实现蜂鸣器报警

    SWD方式下载程序,4线,VCC,GND。 SWDIO:Serial Wire Data Input Output,串行数据输入输出引脚,作为仿真信号的双向数据信号线,建议上拉。 SWCLK:Serial Wire Clock,串行线时钟引脚,作为仿真信号的时钟信号线,建议下拉; 蜂鸣器的IO口接在了最小系统板的PB12引脚上。 蜂鸣器的操作

    2024年02月01日
    浏览(61)
  • 摇杆按键+SG90 实现舵机云台(STM32F103C8T6)

    STM32F103C8T6最小系统板*1 SG90舵机(180°)*2 摇杆按键*1 舵机支架*1 面包板*1(非必须) 杜邦线若干 类似这种的支架,不过需要自己裁切嵌入的部分 代码很简单,主要使用ADC双通道读取两个电位器的值(实际上就是电压),通过获取到的值的范围来确定上下左右,从而来改变两

    2024年02月14日
    浏览(55)
  • STM32F103C8T6板子介绍

    STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器 STM32常应用在嵌入式领域,如智能车、无人机、机器人、无线通信、物联网、工业控制、娱乐电子产品等 STM32功能强大、性能优异、片上资源丰富、功耗低,是一款经典的嵌入式微控制器。  STM32F103C8T6 F1XX片上资源

    2024年02月11日
    浏览(57)
  • 功耗测评 | STM32F103C8T6

    STM32F103C8T6 MCU越来越广泛的应用在生产生活的各个领域,外接丰富的传感器、功能模块、通信模块、显示存储等可以形成各种可样的产品项目应用。对于功耗要求比较高的产品,一般会选择STM32L系列的MCU,但是从功耗的评测角度,逻辑上是基本相似的。 在很多应用场合中都对

    2024年02月07日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包