STM32串口接收数据包(自定义帧头帧尾)

1、基本概述

     本实验基于stm32c8t6单片机,串口作为基础且重要的外设,具有广泛的应用。本文主要理解串口数据包的发送与接收是如何实现的,重要的是理解程序的实现思路。

2、关键程序

定义好需要用到的变量:

uint8_t rxd_buf[4];//定义数组接收数据包,定长
uint8_t rxd_flag = 0;//接收标志
uint8_t rxd_index = 0;//接收索引

 程序理解:

程序放在串口中断函数里面实现。

首先,我们需要定义一个变量用于接收调试串口发过来的数据

u8 recv_dat;

 recv_dat =USART_ReceiveData(USART1);   USART_ReceiveData()是自带的函数,不需要我们定义,我们使用变量recv_dat接收上位机发送的数据。

2.1接收到数据后,进入switch判断,第一次默认从case 0进入。

2.2如果接收到帧头0xFE,将recv_state置1和索引置0,否则继续等待。

recv_state=1后就进入case 1中,将数据一个一个存入数组rxd_buf[4]中,即rxd_index++。然后我们需要判断是否接收完数据,我这个是接收4个定长数据。

2.3判断接收数据完成后,判断是否接收到帧尾0xFF,接收到帧尾后,将标志位置1,这个标志位是为了方便我们在其它程序里判断执行其它功能。记得将状态清零recv_state =0以接收下一包数据。

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 recv_dat;
	static uint8_t recv_state = 0;//默认从索引0开始
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
	{
		recv_dat =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
		switch(recv_state)
		{ 
			case 0:
                  if(recv_dat == 0XFE)//接收到包头
				  {
				     recv_state =1;//切换状态
					 rxd_index = 0;
				  }
				  else
				  {
				     recv_state =0;//切换状态
				  }
			      break;
			case 1:
                  rxd_buf[rxd_index]=recv_dat;//接收字符
			      rxd_index++;
			      if(rxd_index>=4)//判断是否接收数据包完成1
				  {
				     recv_state =2;//切换状态
				  }
			      break;
			case 2:
                  if(recv_dat == 0XFF)//接收到包尾
				  {
				     rxd_flag = 1;//标志位置1
					 recv_state =0;//并将状态清零,接收下一包数据 
				  }
			      break;
		}
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志位	 
	
	} 
}

完整程序: 

usart.c

#include "usart.h"	
#include "led.h"	


uint8_t txd_buf[4]={1,2,3,4};//数据包
uint8_t rxd_buf[4];//定义数组接收数据包,定长
uint8_t rxd_flag = 0;//接收标志
uint8_t rxd_index = 0;//接收索引


/*******************************************************************************
* 函 数 名         : USART1_Init
* 函数功能		   : USART1初始化函数
* 输    入         : bound:波特率
* 输    出         : 无
*******************************************************************************/ 
void USART1_Init(u32 bound)
{
   //GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
 
	
	/*  配置GPIO的模式和IO口 */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX			   //串口输出PA9
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;	    //复用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);  /* 初始化串口输入IO */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX			 //串口输入PA10
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;		 //浮空输入
	GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
	

	//USART1 初始化设置
	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_Cmd(USART1, ENABLE);  //使能串口1 
	
	USART_ClearFlag(USART1, USART_FLAG_TC);
		
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断

	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//响应优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、	
}


//重定义printf函数
int fputc(int ch,FILE *p)  //函数默认的,在使用printf函数时自动调用
{
	USART_SendData(USART1,(u8)ch);	
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	return ch;
}

//发送字符
void send_byte(uint8_t byte)
{
   USART_SendData(USART1,byte);
   while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待发送完成
}

//发送字符串
void send_string(uint8_t *str)//为什么是指针参数
{
   while(*str!='\0') //当字符串不为空时
   {
      send_byte(*str++);
   }
 
}

//发送一组数据
void send_buf(uint8_t *buf,uint16_t len)
{
    uint16_t i;
	for(i=0;i<len;i++)
	{
	   send_byte(buf[i]);
	}
}
	
//定义数据包
void send_pack(void)
{
    send_byte(0xFE);//包头
	send_buf(rxd_buf,4);//数据包
	send_byte(0xFF);//包尾
}


/*******************************************************************************
* 函 数 名         : USART1_IRQHandler
* 函数功能		   : USART1中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/ 
void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 recv_dat;
	static uint8_t recv_state = 0;//默认从索引0开始
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
	{
		recv_dat =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
		switch(recv_state)
		{ 
			case 0:
                  if(recv_dat == 0XFE)//接收到包头
				  {
				     recv_state =1;//切换状态
					 rxd_index = 0;
				  }
				  else
				  {
				     recv_state =0;//切换状态
				  }
			      break;
			case 1:
                  rxd_buf[rxd_index]=recv_dat;//接收字符
			      rxd_index++;
			      if(rxd_index>=4)//判断是否接收数据包完成1
				  {
				     recv_state =2;//切换状态
				  }
			      break;
			case 2:
                  if(recv_dat == 0XFF)//接收到包尾
				  {
				     rxd_flag = 1;//标志位置1
					 recv_state =0;//并将状态清零,接收下一包数据 
				  }
			      break;
		}
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志位	 
	
	} 
}

usart.h

#ifndef _usart_H
#define _usart_H

#include "system.h" 
#include "stdio.h" 


extern uint8_t rxd_flag;//接收标志

void USART1_Init(u32 bound);
void send_byte(uint8_t byte);
void send_string(uint8_t *str);
void send_buf(uint8_t *buf,uint16_t len);
void send_pack(void);


#endif


main.c

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "pwm.h"
#include "usart.h"
#include "key.h"
#include "oled.h"


int main()
{
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
	USART1_Init(115200);
	USART2_Init(115200);
	OLED_Init();
	KEY_Init();
	LED_Init();
	send_string("hello stm32");
	while(1)
	{	
        if(rxd_flag == 1)
		{
			rxd_flag = 0;
			send_pack();//回显数据包
		
		}
		
		

		
	}
}

  • 9
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值