更改

跳转至: 导航搜索

NBDK-L4:基础实验教程

添加4,074字节2019年2月27日 (三) 17:34
gyu_uasrt_isr_ex.c
=== 实验验证 ===
下载完成后,我们打开miniUSB虚拟出的COM口,可以看到串口周期性的打印计数值。下载完成后,我们打开miniUSB虚拟出的COM口,按下复位按键,会打印“Uart ISR demo”。我们随意输入一些数据,可以看到STM32串口打印出相同的数据。[[文件:NBDK-XSHELL-UARTPRINTFUASRTISR.png|边框|居中|无框|759x759像素]]
=== 源码详解 ===
基础实验中的其他例程,大部分都是使用的相同的时钟配置函数,有特殊的时钟使用,将会在对应例程的源码详解中做针对性说明。
==== gyu_usart_isr.c ====
此文件中的函数,都是留给用户使用的(留给用户的串口API接口函数),函数名比较明朗,这边简单说一下各个函数的功能。
 
串口初始化函数,初始化串口协议波特率115200,数据位8位,停止位1位,无校验位、无流控制。<syntaxhighlight lang="c++" line="1" start="47">
void MX_USART1_UART_Init(void)
==== gyu_uasrt_isr_ex.c ====
此文件是gyu_uasrt_usr.c中函数的底层处理函数,为了方便大家使用,我们将其从中分离出来。这部分大家根据自己实际情况选择看或者不看,熟悉ti芯片的朋友,可以看出这部分的串口数据处理是copy的ti CC25XX芯片的。
 
首先是有关串口中断的结构体定义,并且根据结构体参数的具体功能,分别RX缓冲区数据长度。<syntaxhighlight lang="c++" line="1" start="30">
// 串口RX缓冲区数据长度
#define HAL_UART_ISR_RX_AVAIL() \
(isrCfg.rxTail >= isrCfg.rxHead) ? \
(isrCfg.rxTail - isrCfg.rxHead) : \
(RECE_BUF_MAX_LEN - isrCfg.rxHead + isrCfg.rxTail)
 
static uartISRCfg_t isrCfg;
</syntaxhighlight>初始化串口中断结构体的isrCfg。<syntaxhighlight lang="c++" line="1" start="47">
void UartIsr_Init(UART_HandleTypeDef*huart)
{
isrCfg.rxHead = 0;
isrCfg.rxTail = 0;
isrCfg.rxTick = 0;
isrCfg.rxShdw = 0;
hUart = huart;
}
</syntaxhighlight>获取串口RX缓冲区中的数据,由gyu_usart_isr.c的HAL_UART_StartRece()函数中调用,并指向RX缓冲区。<syntaxhighlight lang="c++" line="1" start="64">
uint8_t* UartIsr_GetBuf(void)
{
return isrCfg.rxBuf; // 指向串口RX缓冲区
}
</syntaxhighlight>读取串口RX缓冲区中的数据的函数。<syntaxhighlight lang="c++" line="1" start="78">
uint16_t UartIsr_Read(uint8_t *buf, uint16_t len)
{
uint16_t cnt = 0;
while ((isrCfg.rxHead != isrCfg.rxTail) && (cnt < len))
{
*buf++ = isrCfg.rxBuf[isrCfg.rxHead++];
if (isrCfg.rxHead >= RECE_BUF_MAX_LEN)
{
isrCfg.rxHead = 0;
}
cnt++;
}
 
return cnt;
}
</syntaxhighlight>串口RX缓冲区数据长度获取函数。<syntaxhighlight lang="c++" line="1" start="103">
uint16_t UartIsr_Avail(void)
{
return HAL_UART_ISR_RX_AVAIL();
}
</syntaxhighlight>串口轮询函数,主要目的是检测串口RX缓冲区数据,一个是是否超过了设置的缓冲区大小,另一个是是否超时了。<syntaxhighlight lang="c++" line="1" start="116">
uint8_t UartIsr_Poll(void)
{
uint8_t evt = 0;
uint16_t cnt = 0;
volatile uint16_t tail = RECE_BUF_MAX_LEN - hUart->RxXferCount;
if(isrCfg.rxHead != tail)
{
if(tail != isrCfg.rxTail)
{
isrCfg.rxTail = tail;
if(isrCfg.rxTick == 0)
{
isrCfg.rxShdw = HAL_GetTick();
}
isrCfg.rxTick = HAL_UART_ISR_IDLE;
}
else if(isrCfg.rxTick)
{
uint32_t Tick = HAL_GetTick();
uint32_t delta = Tick >= isrCfg.rxShdw ?
(Tick - isrCfg.rxShdw ):
(Tick + (UINT32_MAX - isrCfg.rxShdw));
 
if (isrCfg.rxTick > delta)
{
isrCfg.rxTick -= delta;
}
else
{
isrCfg.rxTick = 0;
}
}
cnt = UartIsr_Avail();
}
else
{
isrCfg.rxTick = 0;
}
if (cnt >= HAL_UART_ISR_FULL)
{
evt = HAL_UART_RX_FULL;
}
else if (cnt && !isrCfg.rxTick)
{
evt = HAL_UART_RX_TIMEOUT;
}
return evt;
}
 
</syntaxhighlight>
== 实验12-串口DMA ==
串口打印实验,给大家展示的是如何配置STM32L476一个有效的硬件串口功能,并且顺带给大家介绍了如何去配置一个格式化打印函数printf()。实验11中,我们给大家介绍了串口使用中断的方式去接收和打印数据。这一章给大家带来串口DMA方式的数据交互。
=== STM32L476 UART简介 ===
# 使用miniUSB线,连接PC与开发板USB接口。
# 将SW1拨到USB端,SW2拨到MCU。
# 使用Keil打开基础实验的实验10使用Keil打开基础实验的实验12-串口打印。串口DMA。
# 使用Xshell打开miniUSB虚拟出的COM口
# 下载程序,并完成功能测试。
=== 实验验证 ===
下载完成后,我们打开miniUSB虚拟出的COM口,可以看到串口周期性的打印计数值。下载完成后,我们打开miniUSB虚拟出的COM口,按下复位按键,会打印“Uart ISR demo”。我们随意输入一些数据,可以看到STM32串口打印出相同的数据。[[文件:NBDK-XSHELL-UARTPRINTFUASRTISR.png|边框|居中|无框|759x759像素]]
=== 源码详解 ===
==== stm32l4xx_hal_conf.h ====
此文件位于“实验10此文件位于“实验12-串口打印串口DMA\Inc”路径中,主要用途是选择使能此例程使用到的库文件。
此例程我们主要给大家展示STM32L4的串口功能,所以我们宏定义中打开UART相关的。<syntaxhighlight lang="c" line="1" start="103">
main函数,我们的例程由此处开始执行,首先调用HAL_Init()函数初始化我们的模块,接着调用SystemClock_Config()函数初始化此例程用到的时钟,具体有哪些时钟被初始化,在gyu_util.c部分有详细说明。
接下来我们初始化串口UASRT1。接下来我们初始化串口,并且初始化DMA。并且打印欢迎语“USART DMA demo”。
在while()循环中,我们每隔100ms通过格式化输出"TimeCount = xx:xx:xx"。循环中,检测当前串口RX缓冲区中是否有数据(串口是否接收到数据),如果有,则打印到串口显示。
<syntaxhighlight lang="c++" line="1" start="3438">
int main(void)
{
uint32_t hour = 0; uint32_t minute = 0; uint32_t second uint16_t msgLen = 0;
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
SystemClock_Config();
// 初始化DMA
MX_DMA_Init();
// 初始化串口USART1
MX_USART1_UART_Init();
// 串口DMA初始化
HAL_UARTDMA_Init();
printf("USART DMA demo"); // 展示printf
//
while (1)
{
// 模拟时钟计时,这边的1s实际只是100ms轮训串口是否有数据 HAL_Delayif(100); // 100ms延时 printfHAL_UART_Poll("TimeCount = %02d:%02d:%02d\r\n",hour,minute,second); // 格式化输出"TimeCount = xx:xx:xx"  // 时分秒计数 second++; if(second == 60)
{
second msgLen = 0HAL_UART_RxBufLen(); // 获取当前串口缓冲区的数据长度 minute++;// 超过100字节长度的部分不获取 } if(minute == 60msgLen > APP_BUF_LEN) { minute msgLen = 0APP_BUF_LEN; hour++; } if msgLen = HAL_UART_Read(hour == 24app_buf,msgLen) {; // 获取串口数据 hour = 0HAL_UART_Write(app_buf,msgLen); // 将获取的数据通过串口TX打印显示
}
}
基础实验中的其他例程,大部分都是使用的相同的时钟配置函数,有特殊的时钟使用,将会在对应例程的源码详解中做针对性说明。
==== gyu_usartgyu_dma.c ====DMA初始化函数,使能DMA1时钟,并且使能DMA1 CH4和CH5中断。<syntaxhighlight lang="c++" line="1" start="31">void MX_DMA_Init(void) { // 使能DMA1时钟 __HAL_RCC_DMA1_CLK_ENABLE();  // DMA1 CH4中断配置 HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 10, 0); HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); // DMA1 CH5中断配置 HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 10, 0); HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);}</syntaxhighlight> ==== gyu_usart_dma.c ==== ==== gyu_usart_dma_ex.c ==== 
== 实验13-TFT显示屏 ==
510
个编辑

本PDF由谷雨文档中心自动生成,点击下方链接阅读最新内容。

取自“http://doc.iotxx.com/特殊:移动版差异/1646

导航菜单