HAL库:串口_hal库串口

本文详细介绍了在STM32单片机上使用HAL库进行串口通信的过程,包括发送和接收函数的封装,以及如何正确区分发送方和接收方。作者通过实例演示了从基本发送字符到使用printf重定向的逐步学习过程。
摘要由CSDN通过智能技术生成

{
(void)f;
UartDrvWrite((unsigned char*)&ch,1);
return ch;
}

/* USER CODE END 0 */

/**

  • @brief The application entry point.
  • @retval int
    /
    int main(void)
    {
    /
    USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals /
MX_GPIO_Init();
MX_USART1_UART_Init();
/
USER CODE BEGIN 2 */
char a = ‘a’;

printf(“%c”,a);

if(1 == UartDrvRead((unsigned char*)&a,1))
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
HAL_Delay(1000);
}

printf("%c",a);

/* USER CODE END 2 */

/* Infinite loop /
/
USER CODE BEGIN WHILE /
while (1)
{
/
USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}
/* USER CODE END 3 */
}


#### 5.结果展示


        在显示结果时,不是很方便一起录视频,所以只截图一个MobaXterm的界面。相关的软件操作放在文章最后面进行讲解。


![](https://img-blog.csdnimg.cn/14d4760f2e80493fb30c81cc840ef036.png)


#### 6.代码分析


        在学习串口时,我们有一点要进行注意,一定要分清楚,串口的发送方和接收方是谁,我们程序中的发送方其实是stm32单片机,接收方是电脑,不要错认为电脑是发送方,如果在一开始都分不清楚这一点,就很难搞明白串口的工作方式和方向,从而进入学习的误区。


##### 6.1初始思路


        初始思路很残暴,就是直接采用HAL\_UART\_Transmit和HAL\_UART\_Receive进行字母a的收和任意字符的收,程序一开始,就将a进行发出,然后程序一直卡在HAL\_UART\_Receive,等待收字符,进行led点亮,然后在对收到的字符进行回显。我们在进行仿真和正常的逻辑思维双重推理下,发现程序其实很残暴,因为当我们一直收不到字符时,程序就一直卡着不动,进行等待,现实中不会这样进行设计程序,这里只是为了学习而进行学习。



int main(void)
{

HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();

char a = ‘a’;

if(HAL_OK != HAL_UART_Transmit(&huart1,(uint8_t *)&a,1,10))
{
Error_Handler();
}

if(HAL_OK == HAL_UART_Receive(&huart1,(uint8_t *)&a,1,HAL_MAX_DELAY))
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
HAL_Delay(1000);
}

if(HAL_OK != HAL_UART_Transmit(&huart1,(uint8_t *)&a,1,HAL_MAX_DELAY))
{
Error_Handler();
}

while (1)
{
}

}


##### 6.2进一步


        接着我们会想着自己封装一个发送和接收函数,这样让程序更加清晰明了。



#include “main.h”

UART_HandleTypeDef huart1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

int UartDrvWrite(unsigned char *buf,unsigned short length)
{
if(NULL == buf) return -1;
if(0 == length) return -1;

if(HAL_OK != HAL_UART_Transmit(&huart1,buf,1,HAL_MAX_DELAY))
    return -1;
return length;

}

int UartDrvRead(unsigned char *buf,unsigned short length)
{
if(NULL == buf) return -1;
if(0 == length) return -1;

if(HAL_OK != HAL_UART_Receive(&huart1,buf,1,HAL_MAX_DELAY))
    return -1;
return length;

}

int main(void)
{

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();
MX_USART1_UART_Init();

char a = ‘a’;

if(1 != UartDrvWrite((unsigned char*)&a,1))
{
Error_Handler();
}

if(1 == UartDrvRead((unsigned char*)&a,1))
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
HAL_Delay(1000);
}

if(1 != UartDrvWrite((unsigned char*)&a,1))
{
Error_Handler();
}

while (1)
{
}
}


##### 6.3最终代码


        最后再加入重定向,形成最终代码。加入重定向以后,printf函数就是相当于发送函数,也就是写函数,这里也是要搞明白这个相关逻辑。



#include “main.h”
#include<stdio.h>

UART_HandleTypeDef huart1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

int UartDrvWrite(unsigned char *buf,unsigned short length)
{
if(NULL == buf) return -1;
if(0 == length) return -1;

if(HAL_OK != HAL_UART_Transmit(&huart1,buf,1,HAL_MAX_DELAY))
    return -1;
return length;

}

int UartDrvRead(unsigned char *buf,unsigned short length)
{
if(NULL == buf) return -1;
if(0 == length) return -1;

if(HAL_OK != HAL_UART_Receive(&huart1,buf,1,HAL_MAX_DELAY))
    return -1;
return length;

}

struct __FILE{
int handle;
};

FILE __stdout;

int fputc(int ch,FILE f)
{
(void)f;
UartDrvWrite((unsigned char
)&ch,1);
return ch;
}

int main(void)
{

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();
MX_USART1_UART_Init();

char a = ‘a’;

printf(“%c”,a);

if(1 == UartDrvRead((unsigned char*)&a,1))
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
HAL_Delay(1000);
}

printf("%c",a);

while (1)
{
}
}


#### 7.函数分析


##### 7.1HAL\_UART\_Receive


判断是否忙-->锁住-->标记接收忙-->获取tick计数-->赋值RxXferCount有多少数据要接收-->每次从DR内获取一个Byte存在pData指向的空间



HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint16_t *tmp;
uint32_t tickstart = 0U;

/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}

/* Process Locked */
__HAL_LOCK(huart);

huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;

/* Init tickstart for timeout managment */
tickstart = HAL_GetTick();

huart->RxXferSize = Size;
huart->RxXferCount = Size;

/* Process Unlocked */
__HAL_UNLOCK(huart);

/* Check the remain data to be received */
while (huart->RxXferCount > 0U)
{
  huart->RxXferCount--;
  if (huart->Init.WordLength == UART_WORDLENGTH_9B)
  {
    if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
    {
      return HAL_TIMEOUT;
    }
    tmp = (uint16_t *) pData;
    if (huart->Init.Parity == UART_PARITY_NONE)
    {
      *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
      pData += 2U;
    }
    else
    {
      *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
      pData += 1U;
    }

  }
  else
  {
    if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
    {
      return HAL_TIMEOUT;
    }
    if (huart->Init.Parity == UART_PARITY_NONE)
    {
      *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
    }
    else
    {
      *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
    }

  }
}

/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;

return HAL_OK;

}
else
{
return HAL_BUSY;
}
}

**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/4792e9a60f34724c5bd04fddae2a8c8e.png)

![img](https://img-blog.csdnimg.cn/img_convert/ced9cc0f6031ed1c7c7b88a11cccc933.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/df40e59ee092c98405bd112d0e5226e2.png)

 **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

![img](https://img-blog.csdnimg.cn/img_convert/781f1f24d3fa5534a3271eab58a2d933.png)

![img](https://img-blog.csdnimg.cn/img_convert/6c679407211b440746a5459bee54ed96.png)

 

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**

<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**

8)]

[外链图片转存中...(img-Vidg7rf1-1712245989959)]

 

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**

<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**

**[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值