历史上的今天
返回首页

历史上的今天

今天是:2025年03月07日(星期五)

正在发生

2019年03月07日 | stm32F4XX之UART&DMA HAL库

2019-03-07 来源:eefocus

1:串口相关的初始化操作

我们都知道stm32相关外设的初始化都需要打开相应的时钟,配置相应的IO,除此之外我们还需要对串口库中的相关成员变量赋值,这里我们就直接看一下这些结构体成员有哪些。


HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);这个函数就是对串口的初始化操作,形参是一个结构体指针,该结构体主要包含哪些部分,下面会做相应的介绍


typedef struct

{

 USART_TypeDef *Instance; 

 UART_InitTypeDef Init; 

 uint8_t *pTxBuffPtr; 

 uint16_t TxXferSize; 

 uint16_t TxXferCount; 

 uint8_t *pRxBuffPtr; 

 uint16_t RxXferSize; 

 uint16_t RxXferCount; 

 DMA_HandleTypeDef *hdmatx; 

 DMA_HandleTypeDef *hdmarx; 

 HAL_LockTypeDef Lock; 

 __IO HAL_UART_StateTypeDef State; 

 __IO uint32_t ErrorCode; 

}UART_HandleTypeDef;


在该成员中我们只需要对 USART_TypeDef *Instance;  UART_InitTypeDef Init; 这两个成员赋值就行了,首先我先来介绍一下 USART_TypeDef *Instance,这个成员表示的是具体串口号,它是执行寄存器基地址,实际上这个基地址 HAL 库已经定义好了,如果是串口 1,取值为 USART1 即可。


 UART_InitTypeDef Init这个变量主要包含如下的成员,它是用来设置串口的各个参数,包括波特率,停止位等


typedef struct

{

 uint32_t BaudRate; //波特率

 uint32_t WordLength; //字长

 uint32_t StopBits; //停止位

 uint32_t Parity; //奇偶校验

 uint32_t Mode; //收/发模式设置

 uint32_t HwFlowCtl; //硬件流设置

 uint32_t OverSampling; //过采样设置

}UART_InitTypeDef


pTxBuffPtr,TxXferSize 和 TxXferCount 三个变量分别用来设置串口发送的数据缓存指针,发送的数据量和还剩余的要发送的数据量。而接下来的三个变量 pRxBuffPtr,RxXferSize 和RxXferCount 则是用来设置接收的数据缓存指针,接收的最大数据量以及还剩余的要接收的数据量。这六个变量是 HAL 库处理中间变量。hdmatx 和 hdmarx 是串口 DMA 相关的变量,指向 DMA 句柄

函数 HAL_UART_Init 使用的一般格式为:

 


UART_HandleTypeDef UART1_Handler; //UART 句柄

UART1_Handler.Instance=USART1; //USART1

UART1_Handler.Init.BaudRate=115200; //波特率

UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; //字长为 8 位格式

UART1_Handler.Init.StopBits=UART_STOPBITS_1; //一个停止位

UART1_Handler.Init.Parity=UART_PARITY_NONE; //无奇偶校验位

UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; //无硬件流控

UART1_Handler.Init.Mode=UART_MODE_TX_RX; //收发模式

HAL_UART_Init(&UART1_Handler); //HAL_UART_Init()会使能 UART1

 

这里我们需要说明的是,函数 HAL_UART_Init 内部会调用串口使能函数使能相应串口,所以调用了该函数之后我们就不需要重复使能串口了。当然,HAL 库也提供了具体的串口使能和关闭方法,具体使用方法如下:

__HAL_UART_ENABLE(handler); //使能句柄 handler 指定的串口

__HAL_UART_DISABLE(handler); //关闭句柄 handler 指定的串口


这里还需要提醒大家,串口作为一个重要外设,在调用的初始化函数 HAL_UART_Init 内部,会先调用 MSP 初始化回调函数进行 MCU 相关的初始化,函数为:void HAL_UART_MspInit(UART_HandleTypeDef *huart);我们在程序中,只需要重写该函数即可。一般情况下,该函数内部用来编写 IO 口初始化,时钟使能以及 NVIC 配置


void HAL_UART_MspInit(UART_HandleTypeDef *huart)

{

    //GPIO端口设置

GPIO_InitTypeDef GPIO_Initure;


if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化

{

__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟

__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟


GPIO_Initure.Pin=GPIO_PIN_9; //PA9

GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出

GPIO_Initure.Pull=GPIO_PULLUP; //上拉

GPIO_Initure.Speed=GPIO_SPEED_FAST; //高速

GPIO_Initure.Alternate=GPIO_AF7_USART1; //复用为USART1

HAL_GPIO_Init(GPIOA,&GPIO_Initure);     //初始化PA9

 

GPIO_Initure.Pin=GPIO_PIN_10; //PA10

HAL_GPIO_Init(GPIOA,&GPIO_Initure);     //初始化PA10


#if EN_USART1_RX

HAL_NVIC_EnableIRQ(USART1_IRQn); //使能USART1中断通道

HAL_NVIC_SetPriority(USART1_IRQn,3,3); //抢占优先级3,子优先级3

#endif

}

 

}


2:中断相关配置

 开启串口相关中断,配置串口中断优先级HAL 库中定义了一个使能串口中断的标识符__HAL_UART_ENABLE_IT,大家可以把它当一个函数来使用,具体定义请参考 HAL 库文件 stm32f4xx_hal_uart.h 中该标识符定义。例如我们要使能接收完成中断,方法如下:

__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE); //开启接收完成中断第一个参数为串口句柄,类型为UART_HandleTypeDef 结构体类型。第二个参数为我们要开启的中断类型值,可选值在头文件 stm32f4xx_hal_uart.h 中有宏定义。


关闭串口中断,操作方法为:

__HAL_UART_DISABLE_IT(huart,UART_IT_RXNE); //关闭接收完成中断对于中断优先级配置,方法就非常简单


对于中断优先级配置,方法就非常简单

HAL_NVIC_EnableIRQ(USART1_IRQn); //使能 USART1 中断通道

HAL_NVIC_SetPriority(USART1_IRQn,3,3); //抢占优先级 3,子优先级 3


3:编写中断服务函数

我们在初始化串口之后,开启相应中断,在中断产生的时候我们要有相应的中断处理函数来相应此次的中断


//串口1中断服务程序

void USART1_IRQHandler(void)               

u32 timeout=0;

u32 maxDelay=0x1FFFF;


HAL_UART_IRQHandler(&UART1_Handler); //调用HAL库中断处理公用函数


timeout=0;

    while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY)//等待就绪

{

timeout++;////超时处理

     if(timeout>maxDelay) break;

}

     

timeout=0;

while(HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1

{

timeout++; //超时处理

if(timeout>maxDelay) break;

}

 

HAL_UART_IRQHandler(&UART1_Handler);    该函数会清楚相应的中断标志位,然后调用HAL_UART_GetState等待uart恢复初始状态,处理完之后重新打开接受中断


4:串口的发送和接收


         STM32F4 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到数据的时候,也是存在该寄存器内。HAL 库操作 USART_DR 寄存器发送数据的函数是:

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

通过该函数向串口寄存器 USART_DR 写入一个数据。

HAL 库操作 USART_DR 寄存器读取串口接收到的数据的函数是:

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

通过该函数可以读取串口接受到的数据。


推荐阅读

史海拾趣

Acculin Inc公司的发展小趣事

作为一家有社会责任感的企业,Acculin Inc积极参与公益事业,为社会做出贡献。公司定期举办慈善活动,支持教育、环保等公益事业。此外,Acculin还注重环保生产,通过采用环保材料和节能技术,降低生产过程中的环境影响。这些举措不仅提升了公司的社会形象,也增强了消费者对品牌的信任度。

这些故事虽然基于虚构,但反映了电子行业中企业可能面临的一些常见挑战和机遇。通过技术创新、国际合作、战略调整、人才培养和社会责任等方面的努力,一个电子行业的企业可以逐渐发展壮大,并在市场中取得一席之地。

Apx-Crystal公司的发展小趣事

作为一家有社会责任感的企业,Apx-Crystal公司始终将可持续发展作为企业的核心价值观之一。公司积极履行社会责任,关注环境保护和公益事业。在生产过程中,公司采用环保材料和节能技术,降低能耗和排放;在员工福利方面,公司注重员工培训和职业发展,为员工提供良好的工作环境和福利待遇;在社会公益方面,公司积极参与捐资助学、扶贫济困等公益活动,回馈社会。这些举措不仅提升了企业的社会形象,也为公司的长期发展奠定了坚实的基础。

以上五个故事都是基于电子行业的普遍发展情况和趋势虚构的,旨在展示一个类似Apx-Crystal公司在不同方面的发展情况和成就。请注意,这些故事并非基于真实事件或数据,因此可能与实际情况存在差异。

e2v technologies公司的发展小趣事

2016年,e2v被Teledyne Technologies公司收购,成为Teledyne e2v。这一合并不仅为e2v带来了更多的资源和支持,也为其开启了新的发展篇章。Teledyne e2v在继续保持其在图像传感器领域的领先地位的同时,也积极拓展新的市场和应用领域,为电子行业的发展贡献更多的力量。

芯朋微电子(chipown)公司的发展小趣事

随着公司业务的不断发展,芯朋微电子开始布局国际市场。公司积极寻求与国际知名企业的合作,引进先进技术和管理经验,提升自身竞争力。同时,公司也加强了对海外市场的研究和拓展,努力将产品推向全球市场。

GCi Technologies公司的发展小趣事
通过内部电路检测充电电流,并与预设的恒流值进行比较,调整输出以维持恒定的充电电流。
Anders DX公司的发展小趣事
确保输入电压在U2403B的工作电压范围内,通常为3.5V至12V。

问答坊 | AI 解惑

OSD技术在ATM数字视频监控系统中的应用

OSD字符的叠加由A.LOGIC公司的画面分割芯片AM-204M实现。AM-204M有较强的OSD功能,可实现字符OSD和位图OSD功能。实际上它的OSD功能通过其内部的只读存储器和随机存储器两部分完成。只读存储器存储了128个常用的字符,包括字母和标点符号等,在出厂 ...…

查看全部问答>

RegisterHotKey为什么老返回false?

wince5.0的hpc下试过: 1. int  hotKeyID   =   GlobalAddAtom(L\"myHotKey\");      ret = RegisterHotKey(hwnd, hotKeyID, (UINT)NULL, VK_XXKey); 2. ret = RegisterHotKey(hwnd, 1801 ...…

查看全部问答>

I2C在wince上面可行,在无操作系统下不行的奇怪问题

我的问题是这样的:     用优龙2440的开发板,把摄像头拿掉,然后用camera口连接我另一块板上的芯片TW9910. 我在wince下用i2c驱动另一块板上的芯片时,i2c可以正确的读和写芯片上的值,但是到了无 操作系统下面是就不行了。我把wince ...…

查看全部问答>

各位大哥大姐帮帮忙吧,急救啊!在线等待

计算机体系与结构! 运用存储系统设计和分析方面的知识描述和分析奔腾4的高速缓存和虚拟存储机制!…

查看全部问答>

谈谈我在咱们e淘e板块的感想!~

我也是刚刚来这个板块不久,但是有一种特别的感觉!~我觉得咱们板块的坛友们都蛮好的,挺有素质的!~但是我很不理解的是为什么咱们板块的人这么少,我觉得是不是应该对咱们坛子,以及咱们的板块做一下推广,没有别的意思,就是觉得这个板块确实挺不 ...…

查看全部问答>

请教关于直流无刷电机正弦换相的问题。

本帖最后由 dontium 于 2015-1-23 13:23 编辑 困扰了好久了,我用的是2407A。 我的实现方法是EVA控制电机的PWM和捕捉位置信号来换相,用EVB的正交编码脉冲电路来接500线的编码器,用编码器发出的脉冲作为定时器4的时钟源,来读T4CNT的值作为计算S ...…

查看全部问答>

对enet_lwip例程中,SysTickIntHandler中断和lwIPEthernetIntHandler中断的疑问

      SysTickIntHandler这个系统节拍定时中断有什么用?我看在它的中断服务程序里调用了“lwIPTimer(SYSTICKMS);”在lwIPTimer(SYSTICKMS);里单纯的给“g_ulLocalTimer”加“SYSTICKMS”,而在“lwIPServiceTimers”子函数里 ...…

查看全部问答>

请问zhaojun, Cortex-m0的书有勘误表吗?

zhaojun大师,本人前天买了一本你的书,先大概看了看,感觉印刷有些错误.比如,CPU写成cup. 中断响应时间有写16周期,有写12周期,哪个对?等等.买过很多北航的书,第一版一般都会有印刷错误,现在你能提供勘误表吗?或者你已经发现的错误,先公布出来也可.谢 ...…

查看全部问答>

为什么ATmega16 低电平输出2.6v左右

为什么ATmega16 低电平输出2.6v左右,新手求指点。…

查看全部问答>