100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > stm32中断方式和DMA方式完成串口通信

stm32中断方式和DMA方式完成串口通信

时间:2023-07-18 13:22:39

相关推荐

stm32中断方式和DMA方式完成串口通信

这里写目录标题

中断知识点HAL库 GPIO函数库讲解HAL库串口通信DMA知识外部中断点亮led串口中断通信串口DMA收发数据测试DMA传输总结三个工程完整代码参考文献

中断知识点

EXTI0 至 EXTI15 用于 GPIO ,通过编程控制可以实现任意一个 GPIO 作为 EXTI 的输入源。 EXTI0 可以通过 AFIO 的外部中断配置寄存器的1 (AFIO_EXTICR1) 的EXTI0[3:0] 位选择配置为 PA0 、 PB0 、 PC0 、 PD0 、 PE0 、 PF0 、 PG0 、 PH0 或者 PI0 ,见图其他 EXTI 线 (EXTI 中断 / 事件线 ) 使用配置都是类似的。

HAL库 GPIO函数库讲解

在正常使用中,除了STM32CubeMX配置之外,我们有时候还需要自己配置一些东西,学习并理解HAL库,也是我们必须要学习的一个地方

首先打开stm32f4xx_hal_gpio.h 发现一共定义有8个函数

void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);

功能: GPIO初始化

实例:HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);

功能:在函数初始化之后的引脚恢复成默认的状态,即各个寄存器复位时的值

实例:HAL_GPIO_Init(GPIOC, GPIO_PIN_4);

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

功能:读取端口下引脚的电平状态、函数返回值为0或1

实例:HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4);

void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

功能:将引脚变成0或1

实例:HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4,0);

void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

功能:翻转引脚的电平状态

实例:HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_4); 常用在LED上

HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

功能:锁住引脚电平,比如说一个管脚的当前状态是1,当引脚发生变化时状态不变

实例:HAL_GPIO_LockPin(GPIOC, GPIO_PIN_4);

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);

功能: 外部中断服务函数,清除中断标志位

实例:HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

功能: 中断回调函数,可以理解为中断函数具体要响应的动作。

实例:HAL_GPIO_EXTI_Callback(GPIO_PIN_4);

HAL库串口通信

串口发送/接收函数

HAL_UART_Transmit();串口发送数据,使用超时管理机制 HAL_UART_Receive();串口接收数据,使用超时管理机制HAL_UART_Transmit_IT();串口中断模式发送 HAL_UART_Receive_IT();串口中断模式接收HAL_UART_Transmit_DMA();串口DMA模式发送HAL_UART_Transmit_DMA();串口DMA模式接收

串口中断函数

HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //串口发送中断回调函数HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //串口发送一半中断回调函数(用的较少)HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //串口接收中断回调函数HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(用的较少)HAL_UART_ErrorCallback();串口接收错误函数

串口查询函数格式

HAL_UART_GetState(); 功能:判断UART的接收是否结束,或者发送数据是否忙碌举例:while(HAL_UART_GetState(&huart4) == HAL_UART_STATE_BUSY_TX) //检测UART发送结束,观察状态

DMA知识

DMA定义:

DMA用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。

DMA传输方式:

内存到内存,外设到外设,内存到外设,外设到内存

DMA函数操作:

串口DMA发送数据:HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

串口DMA接收数据:HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

串口DMA恢复函数HAL_UART_DMAResume(&huart1)

外部中断点亮led

采用stm32cube,HAL库编写

1,创建工程

选择芯片

设置GPIOA6为输出,GPIOB1为中断,并命名方便观察

之后设置PB1为上拉电阻,下降沿触发。

设置中断优先级,由于只有一个中断,因此设置最高优先级0,

接下来配置时钟,设置为外部高速

接下来设置时钟参数,

后面即可生成相关程序,将主函数里面的相关部分填写代码

即user code begin

user code end里面填写代码

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){{HAL_GPIO_TogglePin(led1_GPIO_Port,led1_Pin);}}

即采用回调函数,修改电平大小

烧录成功后

进行置换接地,即可观察到现象

串口中断通信

创建工程

跟前面的一样,只是改变几个设置

后面进行创建工程即可

打开keil,找到stm32f1xx_hal.c添加头文件和定义代码,

#include <stdio.h>extern UART_HandleTypeDef huart1; //声明串口

之后在stm32f1xx_hal.c中写入下面两个函数

/*** 函数功能: 重定向c库函数printf到DEBUG_USARTx* 输入参数: 无* 返 回 值: 无* 说 明:无*/int fputc(int ch, FILE *f){HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);return ch;}/*** 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx* 输入参数: 无* 返 回 值: 无* 说 明:无*/int fgetc(FILE *f){uint8_t ch = 0;HAL_UART_Receive(&huart1, &ch, 1, 0xffff);return ch;}

接下来在main.c里面改写函数

#define RXBUFFERSIZE 256char RxBuffer[RXBUFFERSIZE];

printf("hello world\n");HAL_Delay(1000);

可以写入printf函数

需要加入中断函数

并在main.c中添加下列定义:

#include <string.h>#define RXBUFFERSIZE 256//最大接收字节数char RxBuffer[RXBUFFERSIZE]; //接收数据

在main()主函数中,调用一次接收中断函数

/* USER CODE BEGIN 2 */HAL_UART_Receive_IT(&huart1, RxBuffer, 1);/* USER CODE END 2 */

在main.c下方添加中断回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {if(huart->Instance==USART1){HAL_UART_Transmit(&huart1,RxBuffer,1,0xff);}HAL_UART_Receive_IT(&huart1, RxBuffer, 1); }

之后微调keil相关设置

之后编译烧录即可

串口DMA收发数据

创建工程

和之前串口创建一样

usart也一样

只需要添加DMA设置即可

打开DMA设置,点击add,选择USART_RX USART_TX 传输速率设置为中速

之后修改速率,模式,和DMA内存自增地址

右侧点击system core 点击DMA

点击add添加MENTOMEN

Normal:正常模式

当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次

DMA指针递增设置

Increment Address:地址指针递增

左侧Src Memory 表示外设地址寄存器

功能:设置传输数据的时候外设地址是不变还是递增。如果设置 为递增,那么下一次传输的时候地址加 Data Width个字节,

右侧Dst Memory 表示内存地址寄存器

功能:设置传输数据时候内存地址是否递增。如果设置 为递增,那么下一次传输的时候地址加 Data Width个字节,

这个Src Memory一样,只不过针对的是内存

后面生成工程即可

测试DMA传输

添加以下代码

main.c

/* USER CODE BEGIN Init */uint8_t Senbuff[] = "HELLO WORLD"; //定义数据发送数组/* USER CODE END Init */

while循环

while (1){/* USER CODE END WHILE */HAL_UART_Transmit_DMA(&huart1, Senbuff, sizeof(Senbuff));HAL_Delay(1000);/* USER CODE BEGIN 3 */}

结果

总结

通过本次实验,我更加了解了串口通信和中断程序,收获很多,更加了解stm32的传输方式,DAM更加节省资源,绕开了cpu,我觉得这个方式很好

三个工程完整代码

链接:/s/1abi_lr52tNIRbvzdojABiw

提取码:1s29

参考文献

关于HAL库对串口的代码理解

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。