STM32学习——DMA实验三、外设到内存搬运

目录

实验要求

CubeMX配置

DMA配置:

 串口中断配置

用到的库函数

1. __HAL_UART_ENABLE_IT

2. HAL_UART_Receive_DMA

3. __HAL_UART_GET_FLAG

4. __HAL_UART_CLEAR_IDLEFLAG

5. HAL_UART_DMAStop

6. __HAL_DMA_GET_COUNTER

代码实现

main.c

main.h

stm32f1xx_it.c


实验要求

使用 DMA 的方式将串口接收缓存寄存器的值搬运到内存中,同时闪烁 LED1

CubeMX配置

DMA配置:

 串口中断配置


用到的库函数

1. __HAL_UART_ENABLE_IT

#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__)   ((((__INTERRUPT__) >> 28U) == UART_CR1_REG_INDEX)? ((__HANDLE__)->Instance->CR1 |= ((__INTERRUPT__) & UART_IT_MASK)): \
                                                           (((__INTERRUPT__) >> 28U) == UART_CR2_REG_INDEX)? ((__HANDLE__)->Instance->CR2 |= ((__INTERRUPT__) & UART_IT_MASK)): \
                                                           ((__HANDLE__)->Instance->CR3 |= ((__INTERRUPT__) & UART_IT_MASK)))
  • 参数一:HANDLE,串口句柄
  • 参数二:INTERRUPT,需要使能的中断
  • 返回值:无

2. HAL_UART_Receive_DMA

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData,uint16_t Size)
  • 参数一:UART_HandleTypeDef *huart,串口句柄
  • 参数二:uint8_t *pData,接收缓存首地址
  • 参数三:uint16_t Size,接收缓存长度
  • 返回值:HAL_StatusTypeDefHAL状态(OKbusyERRORTIMEOUT

3. __HAL_UART_GET_FLAG

#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
  • 参数一:HANDLE,串口句柄
  • 参数二:FLAG,需要查看的FLAG
  • 返回值:FLAG的值

4. __HAL_UART_CLEAR_IDLEFLAG

#define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)
  • 参数一:HANDLE,串口句柄
  • 返回值:无

5. HAL_UART_DMAStop

HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
  • 参数一:UART_HandleTypeDef *huart,串口句柄
  • 返回值:HAL_StatusTypeDefHAL状态(OKbusyERRORTIMEOUT

6. __HAL_DMA_GET_COUNTER

#define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)->Instance->CNDTR)
  • 参数一:HANDLE,串口句柄
  • 返回值:未传输数据大小

    代码实现

如何判断串口接收是否完成?如何知道串口收到数据的长度?
使用 串口空闲中断 IDLE )!
  • 串口空闲时,触发空闲中断;
  • 空闲中断标志位由硬件置1,软件清零
利用串口空闲中断,可以用如下流程实现 DMA 控制的任意长数据接收:
  1. 使能IDLE空闲中断;
  2. 使能DMA接收中断;
  3. 收到串口接收中断,DMA不断传输数据到缓冲区;
  4. 一帧数据接收完毕,串口暂时空闲,触发串口空闲中断;
  5. 在中断服务函数中,清除中断标志位,关闭DMA传输(防止干扰);
  6. 计算刚才收到了多少个字节的数据。
  7. 处理缓冲区数据,开启DMA传输,开始下一帧接收。

main.c

uint8_t rcvBUF[BUF_SIZE] = {0};// 接收数据缓存数组
uint8_t rcvlen = 0;// 接收一帧数据的长度

mian函数里

__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);// 使能IDLE空闲中断
HAL_UART_Receive_DMA(&huart1,rcvBUF,BUF_SIZE);// 使能DMA接收中断

while (1)
{
	HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
	HAL_Delay(1000);
}

main.h

#define BUF_SIZE 100

stm32f1xx_it.c

extern uint8_t rcvBUF[BUF_SIZE];// 接收数据缓存数组
extern uint8_t rcvlen;// 接收一帧数据的长度

void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart1);
	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) == SET)	 判断IDLE标志位是否被置位
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);// 清除标志位
		HAL_UART_DMAStop(&huart1);// 停止DMA传输,防止干扰
		uint8_t tmp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
		rcvlen =  BUF_SIZE - tmp;//计算数据长度
		HAL_UART_Transmit_DMA(&huart1,rcvBUF,rcvlen); //发送数据
		HAL_UART_Receive_DMA(&huart1,rcvBUF,BUF_SIZE);//再次开启DMA,接收下一帧数据
	}
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的示例代码,用于在STM32F1系列芯片中使用DMA从串口搬运数据到存储器中: ```c #include "stm32f10x.h" #include <string.h> #define BUFFER_SIZE 256 uint8_t rx_buffer[BUFFER_SIZE]; uint16_t rx_index = 0; void USART_Configuration(void) { USART_InitTypeDef USART_InitStructure; // 使能USART1时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 配置USART1 Tx (PA9) 为复用推挽输出模式 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置USART1 Rx (PA10) 为浮空输入模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置USART1 USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); // 使能USART1 USART_Cmd(USART1, ENABLE); } void DMA_Configuration(void) { DMA_InitTypeDef DMA_InitStructure; // 使能DMA1时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 配置DMA通道4,用于USART1_RX的搬运 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rx_buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel5, &DMA_InitStructure); // 使能DMA通道4中断 DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE); // 使能DMA1通道4 DMA_Cmd(DMA1_Channel5, ENABLE); } void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; // 配置DMA1通道4中断 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void DMA1_Channel5_IRQHandler(void) { if (DMA_GetITStatus(DMA1_IT_TC5)) { // 处理搬运完成的数据 // 这里可以将数据写入外部存储器,或者进行其他的操作 // ... // 清除DMA1通道4中断标志位 DMA_ClearITPendingBit(DMA1_IT_TC5); } } int main(void) { // 配置USART1 USART_Configuration(); // 配置DMA1 DMA_Configuration(); // 配置NVIC中断 NVIC_Configuration(); // 进入主循环 while (1) { // 等待DMA通道4传输完成 while (DMA_GetFlagStatus(DMA1_FLAG_TC5) == RESET); // 处理接收到的数据 // 这里可以将数据写入外部存储器,或者进行其他的操作 // ... // 重新启动DMA1通道4 DMA_Cmd(DMA1_Channel5, ENABLE); } } ``` 以上代码中,通过配置USART1和DMA1通道4实现了从串口搬运数据到存储器的功能。在主循环中,等待DMA通道4传输完成,处理接收到的数据,然后重新启动DMA1通道4。在DMA1通道4中断处理函数中,处理搬运完成的数据。需要注意,以上代码仅为示例代码,具体应用中需要根据实际情况进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值