STM32--微项目12-USART串口输出HEX数据包

一、微项目实现目标:

1,通过STM32USART模块,实现HEX类型的数据包传送与接受;

2,数据传递过程:数据打包---发送---数据解包--根据数据解包,进入做出相应操作

关键在于状态机的建立

二、微项目硬件配置需求:

stm32F103C8T6核心板一块

0.96寸OLED显示,用于显示计数

CH340一块,用于笔记本到串口的传输

上位机接受CH340端口数据

 

三、前置知识:

1,状态机的设计与建立

 ①0xff为包头,在检测到0xff且状态为S=0时刻,进入状态机。

ps:在检测到0xff且状态为S!=0时刻,不能判定为包头开始,防止在接受的实际数据段存在0xff导致数据错误的情况;

②在S=1状态下,开始接受数据,并开始计数,当数据包内容计数达到4时刻,切换状态为S=2;

③在S=2状态下,如果等待到包尾,则一个完整的数据包接受完成,此时上传标志位,并且S=0,等待下一轮数据;

四、代码逻辑分析:

1,配置USART初始化模块

①打开USART1时钟,打开GPIO时钟 

②配置PA9和PA10参数,其中tx配置为复用推挽输出,rx配置为上拉输入模式

③配置USART参数,包括:模式、硬件流控制、传送数据字长、数据位、校验位、停止位

④开启USART中断(准备在中断中进行接受数据包处理,接受数据时刻,触发中断)

⑤配置中断优先级分组

⑥配置NVIC

⑦开启USART

2,发送数据模块,并且封装为发送为一个数组。

①主要需要关注的是,发送一个数据位,需要等待发送寄存器为空,才认为数据已经发送;

②封装数组发送

3,发送一个数据包,发送数据包很简单;

发送包头---发送数组数据---发送包尾

4,接受数据包相对就复杂的多,在中断函数中进行配置

①中断函数配置USART1_IRQHandler,中断服务函数的名称一定要与启动文件中的要保持一致;

5,状态机数据流,在中断服务函数中执行

五、代码示例:

1,配置USART初始化模块

void serial_init(void)
{
	//开启GPIO、USART 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	//配置GPIO端口,仅使用TX端口,PA9配置为复用推挽输出端口
	 GPIO_InitTypeDef GPIO_InitStruct;
	 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,& GPIO_InitStruct);
	//开启RX通道,上拉输入
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,& GPIO_InitStruct);
	//配置usart
	USART_InitTypeDef USART_InitStruct;
	USART_InitStruct.USART_BaudRate=9600;
	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//开启RX和TX
	USART_InitStruct.USART_Parity=USART_Parity_No ;
	USART_InitStruct.USART_StopBits=USART_StopBits_1;
	USART_InitStruct.USART_WordLength=USART_WordLength_8b;
	USART_Init( USART1, &USART_InitStruct);
	
	//开启USART中断
	USART_ITConfig( USART1,USART_IT_RXNE, ENABLE);
	//配置NVIC优先级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	//配置NVIC
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn ;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct);
	
	//开启USART
	USART_Cmd(USART1,ENABLE);
	
}

2,发送数据模块,并且封装为发送为一个数组

void senddata(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while(USART_GetFlagStatus( USART1,USART_FLAG_TXE)==RESET);
}

//发送一个数组
void sendArray(uint8_t *arr,uint8_t size)
{
	uint8_t i;
	for(i=0;i<size;i++)
	{
		senddata(arr[i]);
	}
}

3,发送一个数据包,发送数据包很简单;

发送包头---发送数组数据---发送包尾

//发送一个数据包,0xff为包头,0xfe为包尾
void sendpacket(void)
{
	senddata(0xff);
	sendArray(send_data,4);
	senddata(0xfe);
	
}

4,接受数据包相对就复杂的多,在中断函数中进行配置

①中断函数配置USART1_IRQHandler,中断服务函数的名称一定要与启动文件中的要保持一致;

5,状态机数据流,在中断服务函数中执行

/接受的中断服务函数
void  USART1_IRQHandler(void)
{
	static uint8_t re_state=0;
	static uint8_t pdata=0;
	//静态变量只会初始化一次,与全局变量类似,区别在于静态变量只能在函数内访问
	if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET)
	{
		uint8_t re_data=USART_ReceiveData(USART1);
		//状态执行流
		if(re_state==0 && re_data==0xff)
		{
			re_state=1;
		}
		else if(re_state==1)
		{
			receive_data[pdata++]=re_data;
			if(pdata>=4)
			{
				pdata=0;
				re_state=2;
			}
		}
		else if(re_state==2)
		{
			if(re_data==0xfe)
			{
				re_state=0;
				receive_flag=1;
			}	
		}
		
		USART_ClearITPendingBit( USART1,USART_IT_RXNE );
	}
}

在主函数中进行相应配置

#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "OLED.H"
#include "SERIAL.H"
#include <cstdio>
#include "key.H"

uint8_t keynum;

int main()
{
	OLED_Init();
	keyinit();
	OLED_ShowString(1,1,"send_data:");
	serial_init();
	
	send_data[0]=0x01;
	send_data[1]=0x02;
	send_data[2]=0x03;
	send_data[3]=0x04;
	OLED_ShowString(3,1,"receive_data:");

	while(1)
	{
		keynum=key_getnum();
		if(keynum==1)
		{	
			sendpacket();
			OLED_ShowHexNum(2,1,send_data[0],2);
			OLED_ShowHexNum(2,4,send_data[1],2);
			OLED_ShowHexNum(2,7,send_data[2],2);
			OLED_ShowHexNum(2,10,send_data[3],2);
			send_data[0]++;
	        send_data[1]++;
			send_data[2]++;
			send_data[3]++;
		}
		if(receive_flag==1)
		{
			OLED_ShowHexNum(4,1,receive_data[0],2);
			OLED_ShowHexNum(4,4,receive_data[1],2);
			OLED_ShowHexNum(4,7,receive_data[2],2);
			OLED_ShowHexNum(4,10,receive_data[3],2);
			
			receive_flag=0;
		}
		
	
		
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值