九、【中级篇】串行接口(USART)

1.串口简介

串口也叫做串行的接口,串行的通信接口或者串行的通讯接口,(COM接口)
串行的通信指的是数据一位一位的按顺序进行传输
操作方式简单,只需要一条数据线就可以完成数据的传输

2.串口的工作模式

  • 单工模式:A------>-----B,A设备只发送数据,B设备只接收数据,数据线只有一种方向
  • 半双工模式:A–>------<–B,A设备可以收发数据,B设备可以收发数据,在同一时间数据线只能有一种方向的传输
  • 全双工模式:------>----------,A B,-----------<-----,A设备可以收发数据,B设备可以收发数据,在同一时间A B设备既可以发送数据,也可以接收数据

3.串口与并口的区别

串口:是指数据一位一位的按顺序传输数据
并口:是指数据多位多位的传输数据
并不说并口可以一次传输多位数据,传输的速度就要比串口快,正好相反串口的传输速度要比并口快,因为并口的多条数据线之间互相有干扰,所以传输速度受到了限制

4.不同电平标准的串口

注意:如果两个设备需要通过串口进行通信,首先要确保电平标准一致,如果电平标准不一样需要使用电平转换模块MAX232…
在这里插入图片描述

RS485电平标准(工业<抗干扰能力极强>) ,距离1000米左右,如果在单工或者半双工模式下需要两条数据线,如果在全双工模式下需要4条数据线,RS485传输的是两条数据线的电压差

5.开发板上的串口

在STM32F103RBT6芯片中串口非常丰富,USART/UART I²C SPI I²S CAN …

6.USART/UART简介

由于USART/UART中只有数据线,没有时钟线所以时钟不能自动调节,
USART : 通用的同步异步收发器,相当于即支持同步模式也支持异步模式
UART : 通用的异步收发器,只支持异步模式

同步 : 在同步模式下是以数据段的格式进行交互数据,无论是位与位之间还是数据字节与字节之间都需要保持同步,例:“Hello” -> ‘H’ 1s ‘e’ 1s ‘l’ 1s ‘l’ 1s ‘o’

异步 : 在异步模式下是以数据帧的格式进行交互数据,位与位之间必须保持同步的,但是数据帧与数据帧之间可以是异步的通信,例:“YES” -> ‘Y’ 1s ‘E’ 1min ‘S’ ----- ‘E’ -> 69 -> 01000101
在这里插入图片描述

7.USART/UART的配置

注意:如果两个设备需要通过串口进行通信,其次要确保波特率一致

115200	波特率
8	8个数据位
N	没有奇偶校验
1	1个停止位

在这里插入图片描述

在STM32F103RBT6芯片中的USART/UART,有3个USART/UART:
USART1 纽扣电池的上面
USART2 无线模块的接口
USART3 扩展IO的接口

初始化USART1

void usart_1_init(void)//用来初始化USART1的函数
{
	GPIO_InitTypeDef Gpio_Value;//定义了GPIO初始化结构体类型的变量
	USART_InitTypeDef Usart_Value;//定义了USART初始化结构体类型的变量
	NVIC_InitTypeDef Nvic_Value;//定义了NVIC初始化结构体类型的变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
	//通过APB2总线使能GPIOA组和USART1的时钟
	
	Gpio_Value.GPIO_Mode = GPIO_Mode_AF_PP;//选择了推挽的复用模式
	Gpio_Value.GPIO_Pin = GPIO_Pin_9;//选择了9号管脚
	Gpio_Value.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz的输出速率
	GPIO_Init(GPIOA, &Gpio_Value);//按照上述配置初始化PA9管脚
	
	Gpio_Value.GPIO_Mode = GPIO_Mode_IN_FLOATING;//选择了浮空的输入模式
	Gpio_Value.GPIO_Pin = GPIO_Pin_10;//选择了10号管脚
	GPIO_Init(GPIOA, &Gpio_Value);//按照上述配置初始化PA10管脚
	
	Usart_Value.USART_BaudRate = 115200;//选择了115200的波特率
	Usart_Value.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//选择了关闭硬件流控
	Usart_Value.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//选择了发送和接收模式
	Usart_Value.USART_Parity = USART_Parity_No;//选择了没有奇偶校验
	Usart_Value.USART_StopBits = USART_StopBits_1;//选择了1个停止位
	Usart_Value.USART_WordLength = USART_WordLength_8b;//选择了8个数据位
	USART_Init(USART1, &Usart_Value);//按照上述配置初始化USART1
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置组优先级和子优先级的所占比例
	Nvic_Value.NVIC_IRQChannel = USART1_IRQn;//选择了USART1的中断号
	Nvic_Value.NVIC_IRQChannelCmd = ENABLE;//选择了使能该中断
	Nvic_Value.NVIC_IRQChannelPreemptionPriority = 2;//选择了组优先级的级别
	Nvic_Value.NVIC_IRQChannelSubPriority = 2;//选择了子优先级的级别
	NVIC_Init(&Nvic_Value);//按照上述配置初始化NVIC
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	//使能了USART1的接收数据触发中断
	
	USART_Cmd(USART1, ENABLE);//使能了USART1的功能
}

发送与接收数据

void usart_1_send_byte(u8 data)//发送一个字节的数据
{
	USART_SendData(USART1, data);//通过USART1把data变量存储的数据进行发送
	while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//以死等的方式等待USART1的发送数据成功
	USART_ClearFlag(USART1, USART_FLAG_TC);//清除USART1的发送数据成功的标志状态
}

void usart_1_send_data(char *buf)//发送一个字符串
{
	while(*buf)//判断buf指针指向的是否是''
	{
		usart_1_send_byte(*buf);//发送有效字符
		buf++;//指针偏移到下一个字符
	}
}

u8 usart_1_recv_byte(void)//接收一个字节的数据(轮询的方式)
{
	u8 ret = 0;//用于保存USART1接收到的数据
	
	if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)//判断USART1是否接收到了数据
	{
		ret = USART_ReceiveData(USART1);//通过ret变量获取USART1接收到的数据
		USART_ClearFlag(USART1, USART_FLAG_RXNE);//清除USART1接收数据寄存器不为空的标志
	}
	return ret;//把接收到的数据返回
}

void USART1_IRQHandler(void)//USART1的中断处理函数
{
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
		//判断是否是由USART1的接收数据触发的中断
	{
		u1_h(USART_ReceiveData(USART1));
		//接收USART1的数据,并把接收到的数据以传参的形式传递给回调函数
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
		//清除USART1的接收数据的中断标志状态
	}
}

void set_usart1_handler(usart1_handler h)//设置回调函数
{
	u1_h = h;//把形参h存储的地址转存到全局的函数指针中
}

主函数:有限状态机实现控制蜂鸣器(发送接收字符串)

/*
"ON"	
"OFF"	

		"ONE"

*/

#define O_FLAG 0
#define N_FLAG 1
#define F_FLAG 2
int flag = O_FLAG;//默认等于O_FLAG的状态

void recv_handler(u8 c)//解析数据的函数
{
	switch(flag)
	{
		case O_FLAG : 
									if(c == 'O')
									{
										flag = N_FLAG;
									}
									break;
		case N_FLAG : 
									if(c == 'N')
									{
										buzzer_on();
										flag = O_FLAG;
									}
									else if(c == 'F')
									{
										flag = F_FLAG;
									}
									else
									{
										flag = O_FLAG;
									}
									break;
		case F_FLAG : 
									if(c == 'F')
									{
										buzzer_off();
									}
									flag = O_FLAG;
									break;
	}
}

int main(void)
{
	char dht_buf[5] = {0};//该数组用于存储DHT11采集到的数据
	int dht_value = 0;//该变量用于存储DHT11温湿度结合的数据
	int i = 500;//循环变量
	
	led_init();//调用LED灯初始化的函数
	buzzer_init();//调用蜂鸣器初始化的函数
	button_init();//调用功能按键初始化的函数
	delay_init();//调用系统定时器初始化的函数
	eint_init();//调用按键中断初始化的函数
	dht_init();//调用DHT11初始化的函数
	ldt_init();//调用数码管初始化的函数
	usart_1_init();//调用USART1初始化的函数
	
	set_usart1_handler(recv_handler);//设置回调函数
	
	while(1)
	{
		get_dht_value(dht_buf);//获取DHT11传感器采集到的数据
		//dht_buf[0] 湿度的整数		dht_buf[1] 湿度的小数
		//dht_buf[2] 温度的整数		dht_buf[3] 温度的小数		dht_buf[4] 校验和
		printf("Hum:%d Temp:%dn", dht_buf[0], dht_buf[2]);
		dht_value = dht_buf[0] * 100 + dht_buf[2];//把湿度的整数以及温度的整数整合成一个4位数据
		while(i--)
			digit_show_data(dht_value);//通过数码管显示温湿度数据
		i = 500;
	}
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>