[原创] 【ST NUCLEO-U575ZI-Q 测评 】串口收发测试

qinyunti   2022-12-15 21:33 楼主

 

前言

串口作为最常用的通讯接口,我们先实现串口的收发,后面标准输入输出,但因调试等都依赖于传口。

串口模块

参见《58 Low-power universal asynchronous receiver transmitter (LPUART)》

引脚

 

使用PG7-PG8  LPUART1-TX LPUART1-RX,对应AF8

image-20221215213126-1.png  

image-20221215213126-2.png  

image-20221215213126-3.png

LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);

  /* PG7 TX */

LL_GPIO_InitTypeDef GPIO_InitStruct;

//LL_GPIO_StructInit(&GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_7;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;

GPIO_InitStruct.Alternate = LL_GPIO_AF_8;

LL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /* PG8 RX */

GPIO_InitStruct.Pin = LL_GPIO_PIN_8;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;

GPIO_InitStruct.Alternate = LL_GPIO_AF_8;

LL_GPIO_Init(GPIOG, &GPIO_InitStruct);

 

 

时钟

从时钟树可以看到LPUART1时钟可以来源于SYSCLK->AHB->APB3->PCLK3

也可以来源于MSIK,HSI16,LSE。我们选择PCLK3。

image-20221215213126-4.png  

AHB和APB3分频之前在RCC配置时设置

 

RCC_ClkInitTypeDef pRCC_ClkInitStruct;

pRCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;

pRCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

pRCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

pRCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

pRCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

pRCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV2;

HAL_RCC_ClockConfig(&pRCC_ClkInitStruct, FLASH_LATENCY_4);

 

这里分别是分频1和2所以 LPUART的输入时钟是160MHz/2=80MHz

 

使能时钟

 

LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_LPUART1);

 

 

串口配置

 

LL_LPUART_InitTypeDef LPUART_InitStruct;

LPUART_InitStruct.BaudRate = 115200;

LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;

LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;

LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;

LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;

LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;

LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;

LL_LPUART_Init(LPUART1, &LPUART_InitStruct);

 

 

中断配置

使能接收非空中断,发送非空中断暂时不使能(否则使能后马上回进入中断,后续实现中断发送再讲)

LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);

//LL_LPUART_EnableIT_TXE_TXFNF(LPUART1);

__NVIC_EnableIRQ(LPUART1_IRQn);

__NVIC_SetPriority(LPUART1_IRQn, 3);

 

 

LPUART_ISR中中断标志

RXNE中断时读RDR清除标志

TXE中断时写TDR清除标志。

image-20221215213126-5.png  

中断处理

收到数据后原样返回

 

void LPUART1_IRQHandler(void)

{

if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1) == SET)

{

LL_LPUART_TransmitData8(LPUART1,LL_LPUART_ReceiveData8(LPUART1));

}

if(LL_LPUART_IsActiveFlag_TXE_TXFNF(LPUART1))

{

}

}

 

串口使能

 

LL_LPUART_Enable(LPUART1);

 

 

测试

添加uart.c

 

#include "stm32u575xx.h"

#include "stm32u5xx_ll_gpio.h"

#include "stm32u5xx_ll_bus.h"

#include "stm32u5xx_ll_lpuart.h"

 

 

void LPUART1_IRQHandler(void)

{

if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1) == SET)

{

LL_LPUART_TransmitData8(LPUART1,LL_LPUART_ReceiveData8(LPUART1));

}

if(LL_LPUART_IsActiveFlag_TXE_TXFNF(LPUART1))

{

 

}

}

 

 

void uart_init(void)

{

 

LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);

  /* PG7 TX */

LL_GPIO_InitTypeDef GPIO_InitStruct;

//LL_GPIO_StructInit(&GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_7;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;

GPIO_InitStruct.Alternate = LL_GPIO_AF_8;

LL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /* PG8 RX */

GPIO_InitStruct.Pin = LL_GPIO_PIN_8;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;

GPIO_InitStruct.Alternate = LL_GPIO_AF_8;

LL_GPIO_Init(GPIOG, &GPIO_InitStruct);

 

LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_LPUART1);

LL_LPUART_InitTypeDef LPUART_InitStruct;

LPUART_InitStruct.BaudRate = 115200;

LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;

LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;

LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;

LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;

LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;

LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;

LL_LPUART_Init(LPUART1, &LPUART_InitStruct);

 

LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);

//LL_LPUART_EnableIT_TXE_TXFNF(LPUART1);

__NVIC_EnableIRQ(LPUART1_IRQn);

__NVIC_SetPriority(LPUART1_IRQn, 3);

 

LL_LPUART_Enable(LPUART1);

}

 

uart.h

#ifndef UART_H

#define UART_H

 

void uart_init(void);

 

#endif

 

 

main.c

main中调用uart_init即可

 

#include "stm32u575xx.h"
#include "stm32u5xx_ll_gpio.h"
#include "stm32u5xx_ll_bus.h"
#include "uart.h"

void SysTick_Handler(void)
{
    static volatile uint32_t num = 0;
    if(num++ >= 1000)
    {
        LL_GPIO_TogglePin(GPIOB, 1u<<7);
        LL_GPIO_TogglePin(GPIOG, 1u<<2);
        LL_GPIO_TogglePin(GPIOC, 1u<<7);
        num=0;
    }
    HAL_IncTick();
}


void delay(uint32_t t)
{
    volatile uint32_t timeout = t;
    while(t--);
}

int main(void)
{
    HAL_Init();
    LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR);
    HAL_PWREx_EnableVddIO2();
    HAL_PWREx_ConfigSupply(PWR_SMPS_SUPPLY);
#if 1
    LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR);
    HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
    
    RCC_OscInitTypeDef pRCC_OscInitStruct;
    pRCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    pRCC_OscInitStruct.HSIState = RCC_HSI_ON;
    pRCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    pRCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
    pRCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    pRCC_OscInitStruct.PLL.PLLM = 1;
    pRCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV1;
    pRCC_OscInitStruct.PLL.PLLN = 20;
    pRCC_OscInitStruct.PLL.PLLP = 1;
    pRCC_OscInitStruct.PLL.PLLQ = 1;
    pRCC_OscInitStruct.PLL.PLLR = 2;
    pRCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_0;
    pRCC_OscInitStruct.PLL.PLLFRACN = 0;  /* */
    HAL_RCC_OscConfig(&pRCC_OscInitStruct);
    
    RCC_ClkInitTypeDef pRCC_ClkInitStruct;
    pRCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
    pRCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    pRCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    pRCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    pRCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    pRCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&pRCC_ClkInitStruct, FLASH_LATENCY_4);
#endif

    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);
    
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    //LL_GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOG, &GPIO_InitStruct);
    
    GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    
    uart_init();
    while(1)
    {

    }    
}

 

串口调试助手发送数据,原样收到说明测试OK。

image-20221215213126-6.png  

 

可以在中断服务函数中打断点调试 image-20221215213126-7.png  

也可以查看外设寄存器

image-20221215213127-8.png  

 

总结

使用库进行外设操作比较简单,一般外设操作就是时钟,引脚,外设参数,中断,使能等几个步骤,得益于完善的库操作起来都比较简单。不过也需要了解外设的基本操作逻辑,有问题查看手册,最需要注意的是,先要使能相应时钟,先清标志最后使能中断,使能模块等。

本帖最后由 qinyunti 于 2022-12-15 21:57 编辑

回复评论 (2)

U系列主打安全?

默认摸鱼,再摸鱼。2022、9、28
点赞  2022-12-27 14:17

测评汇总:免费申请|ST NUCLEO-U575ZI-Q https://bbs.eeworld.com.cn/thread-1228653-1-1.html

玩板看这里: https://bbs.eeworld.com.cn/elecplay.html EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!
点赞  2023-1-12 09:42
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复