stm32 串口处理多种数据帧

1.写出用户需要报文格式,例如:

/******************************************************************
									LED报文
	请求	pwm	  LED命令	PWM时间	  CRC      结  束   
	0xfe	4byte	1byte 	4byte 	 0bytes     0X55	
*******************************************************************/

2.创建一个数组去接包,例如接受到0xfe为包头,接下来就是有效数据,接收到0X55就代表结束,说明这这一帧数据代表有效,对应在main.c里面拆包去拿出所需要的值,这样有个问题,收到的数据不一定是客户想要的,应该加上CRC校验才是完美的。

对应USART.H文件:

#ifndef __MY_USART_H__
#define __MY_USART_H__
#include "sys.h"
#include "stdio.h"
#include "string.h"

typedef struct
{
   u8 rx[200];//接收数据
		 int rx_len;//接受长度
	 u8 rx_fla;//接受成功标志位

	
	 
}usart1_t;


extern usart1_t usart1;

extern  u8 rx_head;//头部位置
extern  u8 i;//位置偏移
void uart1_init(u32 bound);//串口初始化
void print_usart1(u8 *buf,u16 len);//接受数据并打印出来
u16 net_crc16(u8 *buf, u16 len);//CRC校验



#endif

USART.C文件如下:

#include "MY_USART.H"

#include "stdio.h"
#include "string.h"


usart1_t usart1;

u8 rx_head;//头部位置
u8 i=0;//位置偏移

//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 

int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}

void print_usart1(u8 *buf,u16 len)
{
   for(int i=0;i<len;i++)
	{
	   printf("0x%x ",buf[i]);
	}
}



void my_tx(u8 *buf)
{
    while(*buf != '\0')
		{
		    USART_SendData(USART1,*buf++);
			while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == 0);					//等待数据发送成功
			USART_ClearFlag(USART1,USART_FLAG_TC);	
		}
}

//CRC校验代码
u16 net_crc16(u8 *buf, u16 len)
{
		u8 j;
		u16 i;
		u16 a=0xffff;
		u16 b=0xa001;
		
		for(i=0; i<len; i++)
		{
			a ^= buf[i];
			for(j=0;j<8;j++)
			{
				u16 last;
				last = a % 2;
				a >>= 1;
				if(last == 1)
				{
					a ^= b;
				}
			}
		}
    return a;
}



void USART1_IRQHandler(void)   
{
	  
  	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	 {
	     usart1.rx[i] = USART_ReceiveData(USART1);
		   //printf("0X%x,%d\r\n",usart1.rx[i],i);//加上这句话会导致延迟

		   if(usart1.rx[i] == 0XFE)//接受到头部
			 {
			    rx_head = i; //记录头部位置
				
			 }
			 	if(usart1.rx[rx_head] == 0XFE)//头部信息以后都是有效数据
			 { 
					 if((usart1.rx[rx_head] == 0XFE) && (usart1.rx[i] == 0X55))//接受到尾部 且接受到头部
					{
						    usart1.rx_len = i+1;//接受到长度
						    usart1.rx_fla = 1;//标记接受成功
								//printf("OK");//调试可以打开
					}
					i++; 
			 }
		
			 
	 }
}

//串口初始化
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=0 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//子优先级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 

}

main.c函数:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "beep.h"
#include "MY_USART.h"

#include "PWM.H"



/******************************************************************
											LED报文
					请求	pwm	  LED命令	PWM时间	  CRC      结  束   
					0xfe	4byte	1byte 	4byte 	 0bytes     0X55	
*******************************************************************/

 int main(void)
 {
	__IO int pwm = 0;
	__IO int led_mode = 0;
	__IO int time= 0;
	int j = 0;
 	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	delay_init();	    	 //延时函数初始化	  
 	LED_Init();			     //LED端口初始化
	TIM3_PWM_Init(71,499);
  uart1_init(115200);
						
	while(1)
	{
		    printf("HELLO");
			 	if(usart1.rx_fla)//进行
			 {
				 pwm = usart1.rx[1];//PWM计数值
         led_mode = usart1.rx[2];//LED模式 接收到1从慢慢点亮 接受到2慢慢熄灭
				 time = usart1.rx[3];//PWM时间
				 if(led_mode == 0x01)
				 {
					  for(j=0;j<499;j++)
					 {
						   TIM3->CCR2 = j;
					     delay_ms(time);
					 }
				   
				 }
				 else if(led_mode == 0x02)
         {
					  for(j=499;j>0;j--)
					 {
					     TIM3->CCR2 = j;
						    delay_ms(time);
					 }
				 }
				 printf("ledn:%d\r\n",usart1.rx_len);
			   print_usart1(usart1.rx,usart1.rx_len);//打印数值
				
				 memset(usart1.rx,0,sizeof(usart1.rx));
				 printf("\r\nLED OK\r\n");
       
				 usart1.rx_len = 0;
				 usart1.rx_fla = 0;
				 i=0;
			 }
	}	 
}

通过以上例子对串口的使用更加深刻。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32F4中,可以使用以下代码来发送数据帧: ```c void USART1_Tx(uint8_t *data, uint8_t len) { int i; for(i = 0; i < len; i++) { while(!LL_USART_IsActiveFlag_TXE(USART1)); //等待发送缓冲区为空 LL_USART_TransmitData8(USART1, data\[i\]); //发送数据 while(!LL_USART_IsActiveFlag_TC(USART1)); //等待发送完成 } } ``` 这个函数使用了LL库函数来操作USART1串口。在发送数据帧之前,需要将数据存储在一个uint8_t类型的数组中,并将数组的长度作为参数传递给函数。函数会逐个字节地发送数据,并在每个字节发送完成后等待发送完成标志位被置位,以确保数据发送完整。 #### 引用[.reference_title] - *1* *2* [STM32开发小结--使用STM32F4串口的空闲中断模式+DMA接收不定长数据帧](https://blog.csdn.net/u014421520/article/details/81227606)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [CubeMx LL库 STM32 通过串口接收一数据(解决接收丢包问题)](https://blog.csdn.net/weixin_42721131/article/details/119675160)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DENG YIRU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值