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');
		 }
	 }

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值