【STM32HAL库】串口通信-UART

一、数据通信基础

1.串行/并行

并行通信可以进行8,16,32位的通信

串行通信 传输速率低,抗干扰能力强,通信距离长,成本低,IO资源少
并行通信 传输速率高,抗干扰能力弱,通信距离断,成本高,IO资源多

2.单工/半双工/全双工

注意:有两个数据线不一定是全双工,一定是要分别有输入输出通道才叫全双工

3.同步/异步通信

4.波特率

比特率

每秒钟传送的比特数,即二进制的位数,单位bit/s

波特率

每秒钟传送的码元,单位Baud,例如有9v6v3v0v,我们分别让他们对应1234,那么就是四个码元,简单来说,就是信息经过编码后的个数

二者关系

比特率=波特率∗log2M,M表示每个码元承载的信息量,若是以上面为例子,那么M就是4

二进制系统中

波特率数值上等于比特率

5.常见串行通信

6.串口::串行通信接口,指按位发送和接收的接口,如RS232/422/485

 7.RS232异步通信协议

二、USART/UART

1.USART和UART的关系

USART:通用同步异步收发器

UART:通用异步收发器

两者都可以与外部设备进行全双工通信

2.框图分析

3.简化之后的框图

4.波特率计算公式

 5.HAL库配置步骤

#ifndef __USART_H
#define __USART_H

#include "./SYSTEM/sys/sys.h"

extern UART_HandleTypeDef huart1;
extern uint8_t g_usart1_rx_flag;//串口接收到数据标志 0表示未接受到
extern uint8_t g_rx_buffer[1];//HAL库使用的串口接收缓冲区
void USART_Init(uint32_t BaudRate);
#define RXBUFFERSIZE  1
#define USART_REC_LEN  200
extern uint16_t g_usart_rx_sta;

/* 接收缓冲, 最大USART_REC_LEN个字节. */
extern uint8_t g_usart_rx_buf[USART_REC_LEN];

#endif
UART_HandleTypeDef huart1;
uint8_t g_usart1_rx_flag=0;//串口接收到数据标志 0表示未接受到
uint8_t g_rx_buffer[1];//HAL库使用的串口接收缓冲区

uint16_t g_usart_rx_sta=0;

/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart_rx_buf[USART_REC_LEN];



int fputc(int ch, FILE *f)
{
    while ((USART1->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */

    USART1->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}

void USART_Init(uint32_t BaudRate)
{
	huart1.Instance = USART1;
	huart1.Init.BaudRate = BaudRate;
	huart1.Init.WordLength = UART_WORDLENGTH_8B;
	huart1.Init.StopBits = UART_STOPBITS_1;
	huart1.Init.Parity = UART_PARITY_NONE;//校验位
	huart1.Init.Mode = UART_MODE_TX_RX;
	huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;//硬件流
	//huart1.Init.OverSampling = //过采样,F1系列没有这个东西
	HAL_UART_Init(&huart1);
	HAL_UART_Receive_IT(&huart1, g_rx_buffer, 1);//开启接收中断

}

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef GPIO_Init;
	if(huart->Instance==USART1)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();
		__HAL_RCC_AFIO_CLK_ENABLE();
		__HAL_RCC_USART1_CLK_ENABLE();
		//TX
		GPIO_Init.Pin = GPIO_PIN_9;
		GPIO_Init.Mode = GPIO_MODE_AF_PP;//输出,并且根据原理图可知并没有外部上拉,所以开漏输出不能输出高电平,所以这里选择推挽输出
		//GPIO_Init.Pull = //输出没有上下拉
		GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIO_Init);
		
		//RX
		GPIO_Init.Pin = GPIO_PIN_10;
		GPIO_Init.Mode = GPIO_MODE_AF_INPUT;//输入
		GPIO_Init.Pull = GPIO_PULLUP;//根据时序图,空闲时TX为高电平,又因为RX是连接到TX,所以这里用上拉
		GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIO_Init);
		
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		HAL_NVIC_SetPriority(USART1_IRQn,0,0);
		HAL_NVIC_EnableIRQ(USART1_IRQn);
	}

}

//中断服务函数
void USART1_IRQHandler(void)
{
	HAL_UART_IRQHandler(&huart1);//这个函数会清除中断标志位
}


//回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		if((g_usart_rx_sta & 0x8000) == 0)//检测第15位,即换行0x0a       还没接收完
		{
			if(g_usart_rx_sta & 0x4000) //检测第14位,即回车0x0d     接收到了
			{
				if(g_rx_buffer[0] != 0x0a)//不是换行
				{
					g_usart_rx_sta = 0; //数据错误,重新接收  
				}
				else
				{
					g_usart_rx_sta |= 0x8000;//接收完成 即第15位被置1
				}
			}
			else //还没收到回车
			{
				if(g_rx_buffer[0] == 0x0d)//如果是回车
					g_usart_rx_sta |= 0x4000;//就给第14位置1

				else//不是回车,就继续接收数据
				{    
						g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];
						g_usart_rx_sta++;//0x3fff -> 0011 1111 1111 1111 即0~13位为数据位
					if(g_usart_rx_sta>(USART_REC_LEN - 1))
					{
						 g_usart_rx_sta = 0;//接收数据错误,重新开始接收 
					}
				}
			}
		}
		HAL_UART_Receive_IT(&huart1,g_rx_buffer, RXBUFFERSIZE);//每进一次中断,标志位就会被清除,所以回调函数这里就要再开一次接收中断
	}
}

回调函数接收数据的思路:

定义一个16位的状态位        g_usart_rx_sta

位0~13是接收到的数据

位14  接收到0x0d即回车

位15  接收到0x0a即换行,就置1,表示数据接收完成了

uint32_t time;
int main(void)
{
	uint16_t len;
    HAL_Init();                              /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);      /* 设置时钟, 72Mhz */
    delay_init(72);                          /* 延时初始化 */
    LED_Init();                              /* LED初始化 */
	USART_Init(115200);
    while(1)
    { 
			if(g_usart_rx_sta & 0x8000)//接收完成了
			{
				len=g_usart_rx_sta & 0x3FFF;//取出数据长度
				printf("您发送的消息是:\r\n");
				HAL_UART_Transmit(&huart1,g_usart_rx_buf,len,1000);//发送接收到的数据到串口助手
				while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET);//发送寄存器为空时结束
				printf("\r\n");
				g_usart_rx_sta=0;//状态位给0,准备下一次接收
			}
			else
			{
				time++;
				if(time%500==0)
				{
						printf("请输入数据\r\n");
				}		
				if(time%100==0)
					 HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);
				delay_ms(10);
			}
    }
}

 

相关推荐

  1. K210 UART串口通信介绍与 STM32通信

    2024-04-21 02:40:05       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-21 02:40:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-21 02:40:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-21 02:40:05       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-21 02:40:05       20 阅读

热门阅读

  1. 东岸科技将赴港IPO,冲刺催收第一股

    2024-04-21 02:40:05       14 阅读
  2. 线程池的创建方式

    2024-04-21 02:40:05       15 阅读
  3. 用爬石玩转石墨文档

    2024-04-21 02:40:05       28 阅读
  4. 程序员写付费专栏

    2024-04-21 02:40:05       22 阅读
  5. vue 数据类型转换

    2024-04-21 02:40:05       19 阅读
  6. oracle rman的大小不一定比segment的大小大

    2024-04-21 02:40:05       24 阅读
  7. 力学笃行(五)Qt QWidgets类

    2024-04-21 02:40:05       46 阅读