STM32串口通信

一、串口发送

1.初始化引脚

复制代码
void Serial_Init(uint32_t BaudRate)
{
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA ,ENABLE );
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 ,ENABLE );
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//由于PIN9为TX,故初始化为发送引脚
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
	GPIO_Init (GPIOA ,&GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate=BaudRate;
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件流控
	USART_InitStructure.USART_Mode=USART_Mode_Tx;//引脚初始化为发送模式
	USART_InitStructure.USART_Parity=USART_Parity_No;//无奇偶校验
	USART_InitStructure.USART_StopBits=USART_StopBits_1;//停止位为1位
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长位8bit即没有校验位
	USART_Init(USART1,&USART_InitStructure);
	
	USART_Cmd(USART1,ENABLE);//USART硬件使能
}

2.写发送函数

1.发送一个字节

每次对DR寄存器的写操作会清空TXE标志位,故不需要手动清除。

复制代码
void Serial_SendByte(uint8_t data)
{
	USART_SendData(USART1,data);//通过DR寄存器发送一个字节
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待TDR位空再发送下一个字节的数据,TDR的写命令会自动清除TXE标志位
}

2.发送一个数组

复制代码
void Serial_SendArry(uint8_t *arry,uint8_t length)
{
	for(int i=0;i<length;i++)
	{
		Serial_SendByte(arry[i]);
	}
}

3.发送一个字符串

复制代码
void Serial_String(char* String)
{
	for(int i =0;String[i]!=0;i++)
	{
		Serial_SendByte(String[i]);
	}
}

4.发送数字

复制代码
void Serial_SendNum(uint16_t Num)
{
	uint16_t weishu=1+log10(Num);
	uint8_t data=0;
	uint16_t chushu=0;
	for(int i = weishu-1;i>=0;i--)
	{
		chushu=(uint16_t) pow(10,i );
		data=Num/chushu;
		Num=Num%chushu;
		Serial_SendByte(data+0x30);
	}
}

5.printf重定向

这里需要注意,需要在魔术棒中勾上相关选项

复制代码
//重写fputc函数
int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

二、串口接收

1.轮询方式接收数据

即在主循环中不断查询DR寄存器中的RXNE标志位是否被置为,若被置位,则说明有数据被接收,此时便可以使用USART_ReceiveData()函数去取数据。同样,对DR寄存器的读操作也会被清零。故不需要手动清零。

复制代码
	 while(1)
	 {
		 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET)
		 {
			data=USART_ReceiveData(USART1);
			 printf("data=%d\r\n",data);
		 }
	 }

2.中断方式接收数据

1.在初始化中加入与中断相关的函数

复制代码
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	NVIC_InitTypeDef usart_InitStructure;
	usart_InitStructure.NVIC_IRQChannel=USART1_IRQn;
	usart_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	usart_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	usart_InitStructure.NVIC_IRQChannelSubPriority=2;
	NVIC_Init(&usart_InitStructure);

2.写中断函数以及相关接口函数

复制代码
uint8_t Serial_GetFlag(void)
{
	if(Rxflag==1)
	{
		Rxflag=0;
		return 1;
	}
	else
		return 0;
}

uint8_t Serial_GetData(void)
{
	return Rxdata;
}

void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{
		Rxdata=USART_ReceiveData(USART1);
		Rxflag=1;
	}
}

3.主函数

复制代码
	 while(1)
	 {
		 if(Serial_GetFlag()==1)
		 {
			printf("data=%d\r\n",Serial_GetData());
		 }
	 }
}	

4.或者直接在中断中输出也可以

复制代码
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{
		printf("rxdata=%d\r\n",USART_ReceiveData(USART1));
	}
}

3.串口接收HEX数据包

原理就是使用状态机的方式

复制代码
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{
		static uint8_t status=0;
		static uint8_t PacketNum=0;
		if(status==0)
		{
			if(USART_ReceiveData(USART1)==0XFF)//如果接收到了包头OXFF,则进入下一个状态
			{
				status=1;
			}
		}
		else if(status==1)//不断接受数据包的内容,如果接收了四个,则进入下一个状态
		{
			if(PacketNum<4)
			{
				Rxdata[PacketNum]=USART_ReceiveData(USART1);
				PacketNum++;
			}
			else
				status=2;
		}
		else if(status==2)//如果接收到了OXFE,则说明接收到了包尾,则将状态位以及数组个数全部清零,同时至标志位为1,允许主循环检测
		{
			if(USART_ReceiveData(USART1)==0xFE)
			{
				status=0;
				PacketNum=0;
				Rxflag=1;
			}
		}
	}
}

	 while(1)
	 {
		 if(Serial_GetFlag()==1)
		 {
			for(int i =0;i<4;i++)
			 {
				printf("Rxdata的值为[%d]=:%d\r\n",i,Rxdata[i]);
			 }
		 
		 }
	 }
}	

4.串口接收文本数据包

复制代码
char Rxdata[100] ;
uint8_t Rxflag;

void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{
		static uint8_t status=0;
		static uint8_t PacketNum=0;
		if(status==0)
		{
			if(USART_ReceiveData(USART1)=='@')
			{
				status=1;
			}
		}
		else if(status==1) 
		{
			if(USART_ReceiveData(USART1)!='\r')
			{
				Rxdata[PacketNum]=USART_ReceiveData(USART1);
				PacketNum++;
			}
			else
				status=2;
				
		}
		else if(status==2) 
		{
			if(USART_ReceiveData(USART1)=='\n')
			{
				Rxdata[PacketNum]=0;//这里加上'\0',是字符串结束的标志
				status=0;
				PacketNum=0;
				Rxflag=1;
			}
		}
	}
}

	 while(1)
	 {
		 if(Serial_GetFlag()==1)
		 {
			Serial_String(Rxdata);
			Serial_SendByte('\r');
			Serial_SendByte('\n');
		 }
	 }
相关推荐
玄芯散人32 分钟前
【元婴·114】SD卡和FatFS文件系统:数据持久化
stm32·sd卡·fatfs
恒锐丰科技林技术员40 分钟前
EG2106L 高压半桥驱动芯片解析:高性价比 600V 栅极驱动方案
经验分享·嵌入式硬件·硬件工程
cu1431 小时前
细谈IT6653的具体功能与其应用
c语言·c++·单片机·嵌入式硬件
夏虫不可与之言冰2 小时前
RMT 与 WS2812 灯带:可寻址 RGB 全彩控制
c语言·c++·单片机·物联网·visual studio
额额额对了2 小时前
【项目实战】从IMX6ULL环境监测到N647 AI视觉加速
linux·开发语言·嵌入式硬件
三佛科技-134163842123 小时前
微针美容仪数显方案开发案例,微针美容仪方案单片机选择(FT62F23X,FT62F288-LRB,FT32A072)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
天空'之城3 小时前
单片机基础核心知识点汇总(四十九)
单片机·嵌入式硬件
国科安芯3 小时前
星上计算的第一道防线:低轨遥感卫星载荷处理链中的AS32S601型抗辐射MCU—— 面向高分辨率成像与在轨智能处理的场景化综述
大数据·网络·人工智能·单片机·算法·低轨卫星·抗辐射
新晨单片机设计3 小时前
S032A-基于STM32单片机智能加湿器【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus·智能加湿器
硅基造物主4 小时前
STM32 从 0 到 1 做智能家居(九):按键消抖与三模式状态机
stm32·单片机·嵌入式硬件·cubemx·智能家居