八、Stm32学习-USART-中断与接收数据包

2024-01-09 10:29:54

1.通信接口

全双工就是数据的收和发可以同时进行;半双工就是数据的收和发不能同时进行。

异步时钟是设备双方需要约定对应的波特率;同步时钟是设备双方有一根时钟线,发送或接收数据是根据这根时钟线来的。

单端电平是需要共GND;差分电平不需要共GND,它的数据传输是依靠电压差来传递的。

2.电平标准

有些时候设备两端的电压是不同的,所以高低电平的表示电压也是不同的电压表示的。这个时候就需要添加电平转换电路。以上是常见的几种串口电平。485可以传输上千米,而232与TTL可能只能几十米。这些电压都是对地电压。

3.串口的参数

1000比特就是1s要发送1000位;波特率为9600时,发送一位的时间为1/9600;

固定低电平为起始位,告诉设备我要开始发送了;

固定高电平为停止位,告诉设备我发送好了。(同时把引脚恢复成了高电平)

有3种校验:奇校验,偶校验,无校验。

奇校验就是,包括奇校验在内的9位数据会出现奇数个1;发送数据的时候,若不是奇数,校验位就会补1,若是奇数,校验位就会补0;最后接收数据的时候会检查个数是否正常,是否为奇数。

偶校验就是,包括偶校验在内的9个数据会出现偶数个1;同理。

停止位有三种:1个停止位,0.5个停止位,1.5个停止位

相当于每次发送一个字节的数据,停止位占1个字节或0.5字节或1.5字节。

串口没有发送数据的时候就是空闲高电平。

4.Stm32的USART介绍

串口的同步模式一般用于兼容其他的协议,串口一般用异步。

波特率是对时钟比如72MHZ进行分频,然后得到我们想要的波特率,就可以以这样的波特率进行收发数据了。

硬件流控制要多一根线,有点像标志位,判断对面设备是否接收完成我们发送的数据,这根线置高或低电平等。

5.USART基本结构

一旦发送移位寄存器移位完成,TDR寄存器就会把数据往下送,然后置一个标志位。我们就可以判断标志位,要不要写下一个数据等。

6.程序编写-USART-发送与接收数据包

(1)USART引脚与时钟配置

打开对应外设与引脚的时钟。配置引脚的模式,发送数据就是引脚输出高低电平,所以选择复用推挽;接收数据,查阅手册可以配置位上拉或者浮空。

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //发送数据就是置高低电平,所以选复用推挽,增加输出能力
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   //接收数据上拉或者浮空,阅读手册可知道
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

?(2)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;				//发送模式
	USART_InitStruct.USART_Parity = USART_Parity_No;							//校验无
	USART_InitStruct.USART_StopBits = USART_StopBits_1;							//停止位长度为1
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;					//数据帧长度为8
	USART_Init(USART1,&USART_InitStruct);

设置波特率为9600,双方的波特率一定要相同哦。

?关闭硬件流控制。

打开发送与接收模式。

无校验。

停止位长度为1。

数据帧的长度为8。

这样我们的串口就配置好了,只差最后一步使能串口USART1

(3)配置串口中断和使能

	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef  NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
    USART_Cmd(USART1,ENABLE);

想要使用串口中断就要先打开通道。

配置中断的通道。

?(4)中断函数编写

中断函数的名字可以去系统的启动文件中查找。

void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;		//定义表示当前状态机状态的静态变量
	static uint8_t Rxcount =0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)		
	{
		Serial_RxData = USART_ReceiveData(USART1);				//读取数据寄存器,存放在接收的数据变量
		if(RxState==0)
		{
			if(Serial_RxData==0xFF)
			{
				RxState=1;
				Rxcount=0;
			}
		}
		else if(RxState==1)
		{
			RxData_Packet[Rxcount]=Serial_RxData;
			Rxcount++;
			if(Rxcount>=4)
			{
				RxState=2;
			}
			
		}
		else if(RxState==2)
		{
			if(Serial_RxData==0xFE)
			{
				RxState=0;
				Serial_RxFlag = 1;										//置接收标志位变量为1
			}
		}
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);			//清除USART1的RXNE标志位
																//读取数据寄存器会自动清除此标志位
																//如果已经读取了数据寄存器,也可以不执行此代码
	}
}

在中断函数中完成数据转存,然后在主函数中打印出来

(5)主函数

int main(void)
{
	OLED_Init();
	Serial_Init();
	OLED_ShowString(1, 1, "RxData:");
	
	while(1)
	{
		if(Serial_GetRxFlag()==1) //接收到数据了,判断标志位
		{
			OLED_ShowHexNum(2,1,RxData_Packet[0],2);
			OLED_ShowHexNum(2,4,RxData_Packet[1],2);
			OLED_ShowHexNum(2,7,RxData_Packet[2],2);
			OLED_ShowHexNum(2,10,RxData_Packet[3],2);
			SendPacket(RxData_Packet,4);
		}
	}
	
}

文章来源:https://blog.csdn.net/Xia996/article/details/135410024
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。