STM32F10x串口通信

目录


前言

软件要求:Keil环境,STM32f10x系列芯片包

硬件要求:STM32F10x系列的单片机两块,ST-LINK下载器一个,杜邦线4根

一、设备间的通信

通常情况下设备间的通信分为串行通信并行通信

什么是并行通信?串行通信又是什么?

请看下图

当设备1向设备2发送1字节数据时,并行通信会同时发送8个数据位,而串行通信会逐个发送数据位。因此并行通信和串行通信的优缺点如下

本文主要分享串行通信的相关知识,如果对并行通信感兴趣的可以自行百科。

二、串行通信的分类

串行通信按通信方式可分为同步通信异步通信两类,按数据传输方向可分为单工半双工全双工这三类。

1.通信方式

通信方式是指通信双方之间的工作方式或信号传输方式

1.1.同步通信(Synchronous Communication)

两个设备在同一个时钟信号的控制下,进行数据的接收和发送,在时钟的上升沿或下降沿进行发送或传输。需要注意的是这两个设备的工作状态是一样的(同步)

同步通信要求对传输数据的每一位都必须在接收、发送两端严格保持同步,即“位同步”。所以接收、发送两端需要同一个时钟源作为时钟信号。

在发送数据时会先发送“同步字符”来表示数据发送的开始,然后有效的数据信息以连续串行的形式发送,每个时钟周期发送一位数据。其传输信息格式如下

因此每次传输的数据块越大,其非有效数据所占比越小,通信效率越高。

1.2.异步通信(Asynchronous Communication)

异步通信又称起止同步通信,异步通信是把一个字符看作一个独立的信息传送单元,字符与字符之间的传输间隔是任意的,而每一个字符中的每个位是以固定的时间传送。

在异步通信中,接收、发送双方取得同步的办法是采用在字符格式中设置起始位停止位。传输信息格式如下

因为异步通信方式总是在传送每个字符的头部(起始位)进行一次重新定位,所以即使接收、发送双方的时钟频率存在一定偏差,但只要在起始位后的采样出现错位现象,则数据传输仍可正常进行。因此异步通信的双方可以使用自己的本地时钟。

由于异步传输信息格式的原因,导致传输大量数据时,其非有效数据所占比越大,通信效率越低。

起始位:起始位必须是持续一个比特位时间的逻辑”0“电平,标示传送一个字符的开始。

数据位:数据位为5~8位。数据位紧跟在起始位之后,是被传送字符的有效数据位。传送时,先传                低位,后传高位。

奇偶校验位:奇偶校验位只占1位。可以为奇校验或偶校验,也可以不设置校验位。

停止位:停止位为1位、1.5位、或2位。它一定是逻辑”1“电平,标示传送一个字符的结束。

2.数据传输方向

2.1.单工(Simplex)

数据只在一个方向上进行传送。

                    

2.2.半双工(Semi-Simplex)

数据可以在两个方向上传输。在同一时刻,数据只能在一个方向上传输,它实际上是一种切换方向的单工通信。它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。

                    

2.3.全双工(Full-Simplex)

数据可以同时在两个方向上传输。显而易见,全双工通信是两个单工组合而来的,需要独立的接收端和发送端。

                      

三、STM32串口通信   

STM32的串口接口有UART(通用异步收发器)USART(通用同步异步收发器)两种。不同型号的STM32微控制器拥有不同数量的串口。例如STM32F103C8T6有3个串口外设(USART1、USART2、USART3),而STM32F103RCT6有5个串口外设(USART1、USART2、USART3、USART4、USART5)。

固件库里提供的是USART(universal synchronous asynchronous receiver and transmitter通用同步/异步收/发器),但在设计函数时是UART开头,这是告知读者,使用的是异步通信。

1.上位机串口助手调试

我使用的是STM32F103RCT6的USART1(串口1)来进行串口助手调试,

首先搭建工程,可以参考下面的链接

STM32f10x标准库工程搭建-CSDN博客

工程成功搭建后

先在工程的SYSTEM文件下新建两个文件,分别是usart、delay。

然后在usart文件中创建usart.c文件和usart.h文件

                                 

随后在delay文件中创建delay.c文件和delay.h文件

                                

最后创建SYSTEM分组并将工程SYSTEM中对应的.c文件添加到SYSTEM分组中,完成后设置好对应的头文件路径

                                                        SYSTEM分组添加.c文件

              

                                                                    头文件路径设置

然后在usart.c文件写#include ”usart.h“,这时usart.h文件是空的,所以选中usart.h并右击,再Open document ”usart.h“就进入到usart.h文件

usart.h代码如下

#ifndef _USART_H
#define _USART_H

#include "stm32f10x.h"
#include "stdint.h"
#include "stm32f10x_gpio.h"
#include "string.h"

void UART1_Init(u32 bound);

void UART_SendString(USART_TypeDef* USARTx,uint8_t* str);
void UART_Rx_BuffGetData(uint8_t data,uint8_t * buff);
void Clear_RxBuff(uint8_t * rxBuff,uint16_t buffLen);

#endif

根据原理图

usart.c代码如下

#include "usart.h"


//数据包长度
#define DATA_PACKAGE_LEN 100
//串口接收缓存数组
uint8_t   USART1_REC_BUFF[DATA_PACKAGE_LEN];//串口1
//接收完成标志
uint8_t 	Finish=0;
//接收单个数据
uint8_t   Rec;

/**
*函  数:串口发送函数
*参  数:USARTx哪个串口进行发送
*参  数:str需要发送的数据
*返回值:无
*/ 
void UART_SendString(USART_TypeDef* USARTx,uint8_t* str)
{ 
	uint8_t index; 
	unsigned char len=strlen((const char*)str);
	for(index=0;index<len;index++)
    {	
	   while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//串口发送完为SET 未发送完为RESET
       USART_SendData(USARTx,str[index]); 				
    }
}

/**
*函  数:串口1初始化函数
*参  数:bound串口波特率
*返回值:无
*/ 
void UART1_Init(uint32_t 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   PA.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);
   
  //USART1_RX	  PA.10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
  //USART 初始化设置
  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(USART1, &USART_InitStructure); //初始化串口
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
  USART_Cmd(USART1, ENABLE);                    //使能串口 
}

/**
*函  数:指定缓存数组获取数据
*参  数:data串口获取到的单个数据
*参  数:buff串口缓存数组
*返回值:无
*/ 
void UART_Rx_BuffGetData(uint8_t data,uint8_t * buff)
{
    static uint8_t Rec_index = 0;//数据包下标
	
		if(';' == data)//当接收到  ';' 时结束
    {
      buff[Rec_index] = data;
      Finish = 1; //正确接收结束,Finish置为1
      Rec_index = 0;//数据包下标重置
    }else{
			if(Rec_index<DATA_PACKAGE_LEN)//数据是否超出数据包大小
			{
				buff[Rec_index++] = data;//将接收到的单个数据放入buff中
			}
			else{
				Clear_RxBuff(buff,DATA_PACKAGE_LEN);//清空缓存
				Rec_index = 0;
			}
		}
}

/**
*函  数:清空串口接收缓存
*参  数:rxBuff串口的缓存数组
*参  数:buffLen串口的缓存数组大小
*返回值:无
*/  
void Clear_RxBuff(uint8_t * rxBuff,uint16_t buffLen)
{
	int index;
	for(index=0;index<buffLen;index++)
	{
		rxBuff[index]=NULL;//清空
	}
}

/**
*函  数:串口1中断服务例程
*参  数:无
*返回值:无
*说  明:当串口1接收到数据时,触发中断,会执行该函数
*/ 
void USART1_IRQHandler(void)//串口1中断服务列程序
{
  if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//串口2触发接收中断  
  {     
      Rec	= USART_ReceiveData(USART1); //接收一个数据
      UART_Rx_BuffGetData(Rec,USART1_REC_BUFF);
			if(Finish==1)  
			{
				UART_SendString(USART1,USART1_REC_BUFF);//发送接收缓存数组的数据
				Clear_RxBuff(USART1_REC_BUFF,100);
				Finish=0;		
			}
			USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清中断
  }  
}

main.c代码如下

#include "stm32f10x.h"

#include "usart.h"

int main(void)
{
  UART1_Init(115200);//初始化串口1设置波特率为115200
  UART_SendString(USART1,(unsigned char*)"我是RCT6");
  while (1)
  {
		
  }
}


下面进行串口调试,你需要有一个串口调试助手,如果没有可以从下面的链接中获取

链接:https://pan.baidu.com/s/1hM6SVmsI2_5zHkti3jGcaw?pwd=meg3 
提取码:meg3

选择端口(我的端口是COM4)

设置波特率为115200

打开串口

按下3次复位键后,在数据发送区输入"set led ON;"并且发送数据

其结果如下图所示

至此串口调试结束,可以收发数据。

2.两块单片机通过串口通信

如何实现两块单片机之间的通信?

首先要实现两块单片机的通信就需要有两块单片机,我使用的是STM32F103C8T6和STM32F103RCT6。

然后选择串口,由于串口1用来实现串口调试,因此选择串口2来实现单片机之间的通信。

于是需要初始化串口2和编写串口2中断服务例程。

于是上面的usart.h代码变成了下面这样

usart.h

#ifndef _USART_H
#define _USART_H

#include "stm32f10x.h"
#include "stdint.h"
#include "string.h"

void UART1_Init(u32 bound);
void UART2_Init(u32 bound);//*

void UART_SendString(USART_TypeDef* USARTx,uint8_t* str);
void UART_Rx_BuffGetData(uint8_t data,uint8_t * buff);
void Clear_RxBuff(uint8_t * rxBuff,uint16_t buffLen);

#endif

注释后面带 ”*“的表示是新加的代码。我们希望用户在串口助手发送命令,通过RCT6的串口2将用户命令发送给C8T6。因此需要在串口1的中断服务例程中添加通过串口2发送命令的代码,为什么这么做?这是因为当用户通过串口助手发送数据时,被发送的数据会在串口1的中断服务例程中得到处理,这时只需要在中断服务例程处理完数据后,退出中断服务例程之前,将处理好的数据(用户发送的数据)通过串口2发送给C8T6即可。

因此在RCT6的串口1中断服务例程中添加如下语句

/**
*函  数:串口1中断服务例程
*参  数:无
*返回值:无
*说  明:当串口1接收到数据时,触发中断,会执行该函数
*/ 
void USART1_IRQHandler(void)//串口1中断服务列程序
{
  if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//串口2触发接收中断  
  {     
      Rec	= USART_ReceiveData(USART1); //接收一个数据
      UART_Rx_BuffGetData(Rec,USART1_REC_BUFF);
			if(Finish==1)  
			{
				UART_SendString(USART1,USART1_REC_BUFF);//回显接收缓存数组的数据
//--------------------------------------添加语句--------------------------------------------
	            UART_SendString(USART2,USART1_REC_BUFF);//串口2发送命令
//--------------------------------------添加语句--------------------------------------------				
                Clear_RxBuff(USART1_REC_BUFF,100);
				Finish=0;		
			}
			USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清中断
  }  
}

RCT6完整的usart.c

usart.c

#include "usart.h"


//数据包长度
#define DATA_PACKAGE_LEN 100
//串口接收缓存数组
uint8_t   USART1_REC_BUFF[DATA_PACKAGE_LEN];//串口1
uint8_t   USART2_REC_BUFF[DATA_PACKAGE_LEN];//*串口2
//接收完成标志
uint8_t 	Finish=0;
//接收单个数据
uint8_t   Rec;

/**
*函  数:串口发送函数
*参  数:USARTx哪个串口进行发送
*参  数:str需要发送的数据
*返回值:无
*/ 
void UART_SendString(USART_TypeDef* USARTx,uint8_t* str)
{ 
	  uint8_t index; 
		unsigned char len=strlen((const char*)str);
		for(index=0;index<len;index++)
        {	
		    while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)!=SET);//串口发送完为SET 未发送完为RESET
            USART_SendData(USARTx,str[index]); 				
        }
}

/**
*函  数:串口1初始化函数
*参  数:bound串口波特率
*返回值:无
*/ 
void UART1_Init(uint32_t 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   PA.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);
   
  //USART1_RX	  PA.10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  

  //Usart1 NVIC 配置                   USART1_IRQn
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
  //USART 初始化设置
	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(USART1, &USART_InitStructure); //初始化串口
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
	USART_Cmd(USART1, ENABLE);                    //使能串口 
}

/**
*函  数:串口2初始化函数
*参  数:bound串口波特率
*返回值:无
*/ 
//*
void UART2_Init(uint32_t bound)
{
	//GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
  //USART1_TX   PA.2
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  //USART1_RX	  PA.3
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PA.3
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
  //USART 初始化设置
	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(USART2, &USART_InitStructure); //初始化串口
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
	USART_Cmd(USART2, ENABLE);                    //使能串口 
}

/**
*函  数:指定缓存数组获取数据
*参  数:data串口获取到的单个数据
*参  数:buff串口缓存数组
*返回值:无
*/ 
void UART_Rx_BuffGetData(uint8_t data,uint8_t * buff)
{
    static uint8_t Rec_index = 0;//数据包下标
	
		if(';' == data)//当接收到  ';' 时结束
    {
			buff[Rec_index] = data;
      Finish = 1; //正确接收结束,Finish置为1
      Rec_index = 0;//数据包下标重置
    }else{
			if(Rec_index<DATA_PACKAGE_LEN)//数据是否超出数据包大小
			{
				buff[Rec_index++] = data;//将接收到的单个数据放入buff中
			}
			else{
				Clear_RxBuff(buff,DATA_PACKAGE_LEN);//清空缓存
				Rec_index = 0;
			}
		}
}
/**
*函  数:清空串口接收缓存
*参  数:rxBuff串口的缓存数组
*参  数:buffLen串口的缓存数组大小
*返回值:无
*/  
void Clear_RxBuff(uint8_t * rxBuff,uint16_t buffLen)
{
	int index;
	for(index=0;index<buffLen;index++)
	{
		rxBuff[index]=NULL;//清空
	}
}

/**
*函  数:串口1中断服务例程
*参  数:无
*返回值:无
*说  明:当串口1接收到数据时,触发中断,会执行该函数
*/ 
void USART1_IRQHandler(void)//串口1中断服务列程序
{
  if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//串口1触发接收中断  
  {     
	  	Rec	= USART_ReceiveData(USART1); //接收一个数据
      UART_Rx_BuffGetData(Rec,USART1_REC_BUFF);//将接收到的数据放入到指定的缓存数组中
			if(Finish==1)  
			{
				UART_SendString(USART1,USART1_REC_BUFF);//回显示接收缓存数组的数据
				//通过串口2将用户输入的命令发送出去
				UART_SendString(USART2,USART1_REC_BUFF);//*
				
				Clear_RxBuff(USART1_REC_BUFF,100);
				Finish=0;		
			}
			USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清中断
  }  
}

/**
*函  数:串口2中断服务例程
*参  数:无
*返回值:无
*说  明:当串口2接收到数据时,触发中断,会执行该函数
*/ 
//*
void USART2_IRQHandler(void)//串口2中断服务列程序
{
  if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)//串口2触发接收中断  
  {     
	  	Rec	= USART_ReceiveData(USART2); //接收一个数据
      UART_Rx_BuffGetData(Rec,USART2_REC_BUFF); //将接收到的数据放入到指定的缓存数组中
			if(Finish==1)  
			{
				//将串口2接收到的数据通过串口1回显到串口助手上
				UART_SendString(USART1,USART2_REC_BUFF);
				Clear_RxBuff(USART2_REC_BUFF,100);
				Finish=0;		
			}
			USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清中断
  }  
}

RCT6和C8T6使用的usart.h和usart.c文件基本是一样的,这是因为两个单片机通过串口通信时,不仅要规定它们的波特率一样,还要规定接收数据的格式一样,比如上面规定当串口遇到";"时表示接收数据结束。

下面来看RCT6的main.c

main.c

#include "stm32f10x.h"

#include "usart.h"


int main(void)
{

	UART1_Init(115200);
	UART2_Init(115200);
	UART_SendString(USART1,(unsigned char*)"我是RCT6");
	
  while (1)
  {
		
  }
}

接着是C8T6的main.c

main.c

#include "stm32f10x.h"

#include "usart.h"



int main(void)
{
	UART2_Init(115200);
	UART_SendString(USART2,(unsigned char*)"我是C8T6;");

  while (1)
  {
		
  }
}

需要注意的是在C8T6的串口2中断服务例程中需要注释掉语句

UART_SendString(USART1,USART2_REC_BUFF);

并添加语句

if(0==strcmp(USART2_REC_BUFF,"C8T6;"))
                UART_SendString(USART2,"C8T6已收到;");

添加语句的意思是当C8T6的串口2接收到“C8T6;”时会向RCT6发送一个“C8T6已收到;”

C8T6的串口2中断服务例程

/**
*函  数:串口2中断服务例程
*参  数:无
*返回值:无
*说  明:当串口2接收到数据时,触发中断,会执行该函数
*/ 
//*
void USART2_IRQHandler(void)//串口2中断服务列程序
{
  if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)//串口2触发接收中断  
  {     
	  	Rec	= USART_ReceiveData(USART2); //接收一个数据
      UART_Rx_BuffGetData(Rec,USART2_REC_BUFF); //将接收到的数据放入到指定的缓存数组中
			if(Finish==1)  
			{
				//将串口2接收到的数据通过串口1回显到串口助手上
				//UART_SendString(USART1,USART2_REC_BUFF);
				if(0==strcmp(USART2_REC_BUFF,"C8T6;"))
				    UART_SendString(USART2,"C8T6已收到;");
				Clear_RxBuff(USART2_REC_BUFF,100);
				Finish=0;		
			}
			USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清中断
  }  
}

将上面程序分别烧录到RCT6和C8T6中,然后像下图一样将对应引脚用杜邦线链接起来

以上便完成了两块单片机通过串口通信。

当按下RCT6的复位键时,RCT6会通过串口1发送 “我是RCT6“ 到串口助手上。随后按下C8T6的复位键,C8T6会通过串口2发送 “我是C8T6;”,这时RCT6的串口2接收到来自C8T6串口2发送的数据,触发中断,经过处理检测到了“;”,于是又通过RCT6的串口1将“我是C8T6;”发送到串口助手。

串口助手中,用户输入数据,并以“;”结束,都会被RCT6的串口1正确接收。用户在串口助手上发送”C8T6;“ ,当RCT6的串口1接收到”C8T6;“时,会将数据回显,并且通过自己的串口2将用户输入的命令发送给C8T6,这时C8T6的串口2触发接收中断,如果正确接收“C8T6;”,C8T6的串口2会发送“C8T6已收到;”,随后RCT6的串口2接收并通过串口1将“C8T6已收到;”发送到串口助手上。演示视屏链接放下面

演示-CSDN直播

演示截图

总结

1.串口通信按通信方式可分为同步和异步,按数据传输方向可分为单工、半双工、全双工

2.在实现两个设备之间的串口通信时,我们一般不用调试串口(串口1),这会导致一些问题,可以自行尝试。还需要注意的是要约定好双方传输数据的格式,这样才能让设备之间更好的交互。

3.当使能了某个串口的中断后,如果这个串口的RX引脚接收到数据就会触发该串口中断服务例程,执行相应的操作

  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值