【ST NUCLEO-U575ZI-Q 测评 】串口收发测试
<div class='showpostmsg'> 本帖最后由 qinyunti 于 2022-12-15 21:57 编辑<p> </p>
<h1><b>前言</b></h1>
<p>串口作为最常用的通讯接口,我们先实现串口的收发,后面标准输入输出,但因调试等都依赖于传口。</p>
<h1><b>串口模块</b></h1>
<p>参见《58 Low-power universal asynchronous receiver transmitter (LPUART)》</p>
<h2><b>引脚</b></h2>
<p> </p>
<p>使用PG7-PG8 LPUART1-TX LPUART1-RX,对应AF8</p>
<p> </p>
<p> </p>
<p></p>
<div class="parsedown-markdown">
<p>LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);</p>
<p> /* PG7 TX */</p>
<p>LL_GPIO_InitTypeDef GPIO_InitStruct;</p>
<p>//LL_GPIO_StructInit(&GPIO_InitStruct);</p>
<p>GPIO_InitStruct.Pin = LL_GPIO_PIN_7;</p>
<p>GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;</p>
<p>GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;</p>
<p>GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;</p>
<p>GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;</p>
<p>GPIO_InitStruct.Alternate = LL_GPIO_AF_8;</p>
<p>LL_GPIO_Init(GPIOG, &GPIO_InitStruct);</p>
<p> /* PG8 RX */</p>
<p>GPIO_InitStruct.Pin = LL_GPIO_PIN_8;</p>
<p>GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;</p>
<p>GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;</p>
<p>GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;</p>
<p>GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;</p>
<p>GPIO_InitStruct.Alternate = LL_GPIO_AF_8;</p>
<p>LL_GPIO_Init(GPIOG, &GPIO_InitStruct);</p>
</div>
<p> </p>
<p> </p>
<h2><b>时钟</b></h2>
<p>从时钟树可以看到LPUART1时钟可以来源于SYSCLK->AHB->APB3->PCLK3</p>
<p>也可以来源于MSIK,HSI16,LSE。我们选择PCLK3。</p>
<p> </p>
<p>AHB和APB3分频之前在RCC配置时设置</p>
<p> </p>
<div class="parsedown-markdown">
<p>RCC_ClkInitTypeDef pRCC_ClkInitStruct;</p>
<p>pRCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;</p>
<p>pRCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;</p>
<p>pRCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;</p>
<p>pRCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;</p>
<p>pRCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;</p>
<p>pRCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV2;</p>
<p>HAL_RCC_ClockConfig(&pRCC_ClkInitStruct, FLASH_LATENCY_4);</p>
</div>
<p> </p>
<p>这里分别是分频1和2所以 LPUART的输入时钟是160MHz/2=80MHz</p>
<p> </p>
<p>使能时钟</p>
<p> </p>
<div class="parsedown-markdown">
<p>LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_LPUART1);</p>
</div>
<p> </p>
<p> </p>
<h2><b>串口配置</b></h2>
<p> </p>
<div class="parsedown-markdown">
<p>LL_LPUART_InitTypeDef LPUART_InitStruct;</p>
<p>LPUART_InitStruct.BaudRate = 115200;</p>
<p>LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;</p>
<p>LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;</p>
<p>LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;</p>
<p>LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;</p>
<p>LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;</p>
<p>LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;</p>
<p>LL_LPUART_Init(LPUART1, &LPUART_InitStruct);</p>
</div>
<p> </p>
<p> </p>
<h2><b>中断配置</b></h2>
<p>使能接收非空中断,发送非空中断暂时不使能(否则使能后马上回进入中断,后续实现中断发送再讲)</p>
<div class="parsedown-markdown">
<p>LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);</p>
<p>//LL_LPUART_EnableIT_TXE_TXFNF(LPUART1);</p>
<p>__NVIC_EnableIRQ(LPUART1_IRQn);</p>
<p>__NVIC_SetPriority(LPUART1_IRQn, 3);</p>
</div>
<p> </p>
<p> </p>
<p>LPUART_ISR中中断标志</p>
<p>RXNE中断时读RDR清除标志</p>
<p>TXE中断时写TDR清除标志。</p>
<p> </p>
<h2><b>中断处理</b></h2>
<p>收到数据后原样返回</p>
<p> </p>
<div class="parsedown-markdown">
<p>void LPUART1_IRQHandler(void)</p>
<p>{</p>
<p>if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1) == SET)</p>
<p>{</p>
<p>LL_LPUART_TransmitData8(LPUART1,LL_LPUART_ReceiveData8(LPUART1));</p>
<p>}</p>
<p>if(LL_LPUART_IsActiveFlag_TXE_TXFNF(LPUART1))</p>
<p>{</p>
<p>}</p>
<p>}</p>
</div>
<p> </p>
<h2><b>串口使能</b></h2>
<p> </p>
<div class="parsedown-markdown">
<p>LL_LPUART_Enable(LPUART1);</p>
</div>
<p> </p>
<p> </p>
<h1><b>测试</b></h1>
<p>添加uart.c</p>
<p> </p>
<div class="parsedown-markdown">
<p>#include "stm32u575xx.h"</p>
<p >#include "stm32u5xx_ll_gpio.h"</p>
<p >#include "stm32u5xx_ll_bus.h"</p>
<p >#include "stm32u5xx_ll_lpuart.h"</p>
<p > </p>
<p > </p>
<p >void LPUART1_IRQHandler(void)</p>
<p >{</p>
<p >if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1) == SET)</p>
<p >{</p>
<p >LL_LPUART_TransmitData8(LPUART1,LL_LPUART_ReceiveData8(LPUART1));</p>
<p >}</p>
<p >if(LL_LPUART_IsActiveFlag_TXE_TXFNF(LPUART1))</p>
<p >{</p>
<p > </p>
<p >}</p>
<p >}</p>
<p > </p>
<p > </p>
<p >void uart_init(void)</p>
<p >{</p>
<p > </p>
<p >LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);</p>
<p > /* PG7 TX */</p>
<p >LL_GPIO_InitTypeDef GPIO_InitStruct;</p>
<p >//LL_GPIO_StructInit(&GPIO_InitStruct);</p>
<p >GPIO_InitStruct.Pin = LL_GPIO_PIN_7;</p>
<p >GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;</p>
<p >GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;</p>
<p >GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;</p>
<p >GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;</p>
<p >GPIO_InitStruct.Alternate = LL_GPIO_AF_8;</p>
<p >LL_GPIO_Init(GPIOG, &GPIO_InitStruct);</p>
<p > /* PG8 RX */</p>
<p >GPIO_InitStruct.Pin = LL_GPIO_PIN_8;</p>
<p >GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;</p>
<p >GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;</p>
<p >GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;</p>
<p >GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;</p>
<p >GPIO_InitStruct.Alternate = LL_GPIO_AF_8;</p>
<p >LL_GPIO_Init(GPIOG, &GPIO_InitStruct);</p>
<p > </p>
<p >LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_LPUART1);</p>
<p >LL_LPUART_InitTypeDef LPUART_InitStruct;</p>
<p >LPUART_InitStruct.BaudRate = 115200;</p>
<p >LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;</p>
<p >LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;</p>
<p >LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;</p>
<p >LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;</p>
<p >LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;</p>
<p >LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;</p>
<p >LL_LPUART_Init(LPUART1, &LPUART_InitStruct);</p>
<p > </p>
<p >LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);</p>
<p >//LL_LPUART_EnableIT_TXE_TXFNF(LPUART1);</p>
<p >__NVIC_EnableIRQ(LPUART1_IRQn);</p>
<p >__NVIC_SetPriority(LPUART1_IRQn, 3);</p>
<p > </p>
<p >LL_LPUART_Enable(LPUART1);</p>
<p >}</p>
<p > </p>
</div>
<p>uart.h</p>
<div class="parsedown-markdown">
<p>#ifndef UART_H</p>
<p >#define UART_H</p>
<p > </p>
<p >void uart_init(void);</p>
<p > </p>
<p >#endif</p>
</div>
<p> </p>
<p> </p>
<p>main.c</p>
<p>main中调用uart_init即可</p>
<p> </p>
<div class="parsedown-markdown">
<p>#include "stm32u575xx.h"<br />
#include "stm32u5xx_ll_gpio.h"<br />
#include "stm32u5xx_ll_bus.h"<br />
#include "uart.h"</p>
<p>void SysTick_Handler(void)<br />
{<br />
static volatile uint32_t num = 0;<br />
if(num++ >= 1000)<br />
{<br />
LL_GPIO_TogglePin(GPIOB, 1u<<7);<br />
LL_GPIO_TogglePin(GPIOG, 1u<<2);<br />
LL_GPIO_TogglePin(GPIOC, 1u<<7);<br />
num=0;<br />
}<br />
HAL_IncTick();<br />
}</p>
<p><br />
void delay(uint32_t t)<br />
{<br />
volatile uint32_t timeout = t;<br />
while(t--);<br />
}</p>
<p>int main(void)<br />
{<br />
HAL_Init();<br />
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR);<br />
HAL_PWREx_EnableVddIO2();<br />
HAL_PWREx_ConfigSupply(PWR_SMPS_SUPPLY);<br />
#if 1<br />
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR);<br />
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);<br />
<br />
RCC_OscInitTypeDef pRCC_OscInitStruct;<br />
pRCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;<br />
pRCC_OscInitStruct.HSIState = RCC_HSI_ON;<br />
pRCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;<br />
pRCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;<br />
pRCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;<br />
pRCC_OscInitStruct.PLL.PLLM = 1;<br />
pRCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV1;<br />
pRCC_OscInitStruct.PLL.PLLN = 20;<br />
pRCC_OscInitStruct.PLL.PLLP = 1;<br />
pRCC_OscInitStruct.PLL.PLLQ = 1;<br />
pRCC_OscInitStruct.PLL.PLLR = 2;<br />
pRCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_0;<br />
pRCC_OscInitStruct.PLL.PLLFRACN = 0; /* */<br />
HAL_RCC_OscConfig(&pRCC_OscInitStruct);<br />
<br />
RCC_ClkInitTypeDef pRCC_ClkInitStruct;<br />
pRCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;<br />
pRCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;<br />
pRCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;<br />
pRCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;<br />
pRCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;<br />
pRCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV2;<br />
HAL_RCC_ClockConfig(&pRCC_ClkInitStruct, FLASH_LATENCY_4);<br />
#endif</p>
<p> LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);<br />
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);<br />
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);<br />
<br />
LL_GPIO_InitTypeDef GPIO_InitStruct;<br />
//LL_GPIO_StructInit(&GPIO_InitStruct);<br />
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;<br />
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;<br />
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;<br />
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;<br />
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;<br />
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;<br />
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);<br />
<br />
GPIO_InitStruct.Pin = LL_GPIO_PIN_2;<br />
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;<br />
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;<br />
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;<br />
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;<br />
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;<br />
LL_GPIO_Init(GPIOG, &GPIO_InitStruct);<br />
<br />
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;<br />
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;<br />
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;<br />
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;<br />
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;<br />
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;<br />
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);<br />
<br />
uart_init();<br />
while(1)<br />
{<br />
<br />
} <br />
}</p>
</div>
<p> </p>
<p>串口调试助手发送数据,原样收到说明测试OK。</p>
<p> </p>
<p> </p>
<p>可以在中断服务函数中打断点调试 </p>
<p>也可以查看外设寄存器</p>
<p> </p>
<p> </p>
<h1><b>总结</b></h1>
<p>使用库进行外设操作比较简单,一般外设操作就是时钟,引脚,外设参数,中断,使能等几个步骤,得益于完善的库操作起来都比较简单。不过也需要了解外设的基本操作逻辑,有问题查看手册,最需要注意的是,先要使能相应时钟,先清标志最后使能中断,使能模块等。</p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>U系列主打安全?</p>
<p>测评汇总:免费申请|ST NUCLEO-U575ZI-Q https://bbs.eeworld.com.cn/thread-1228653-1-1.html</p>
页:
[1]