[STM32CubeMX]学习笔记6:按键控制DMA串口发送

MCU:STM32F103ZET6

IDE:  MDK-ARM V5 +STM32CubeMX5.0.0

串口调试助手:SSCOM3.2

 

功能描述:通过KEY_UP按键控制DMA串口1数据的传送。

需要配置DMA,串口USART1,使能按键中断,LED提示灯。

 

一. 在 Pinout&Configuration---System Core中:

  • 1. 首先设置时钟RCC的HSE(外部高速时钟)为晶振模式:Crystal/ceramic Resonator

  • 2. 设置系统SYS的Debug为Serial Wire:

  • 3. 设置GPIO中的LED管脚。

在MCU管脚图中找到PC0和PC1管脚(查原理图对应的管脚号),将管脚设置为GPIO_Output输出模式,此时在System Core的GPIO中,会出现对应端口,点击端口将GPIO output level设置为low,将User Label定义为LED。

  • 4. 设置按键映射到外部中断线上。

选择PA0的端口为GPIO_EXTI0:

KEY_UP应为上升沿触发,并外接下拉电阻,点击端口将GPIO mode设置为External Interrupt Mode with Rising edge trigger detection,将GPIO Pull-up/Pull-down配置为Pull-down,将User Label定义为KEY_UP。

*TIPS:在将端口映射到EXTI线上后,SYS会出现以下警告:表示红色部分的模式不可使用,且因为PA0本身对应的是系统唤醒功能,因此System Wake-UP的功能也无法被选中。

接着在GPIO-Configuration中使能四个GPIO的中断(之前就是忘记了这个):

二. 在 Pinout&Configuration---Connectivity中:

  • 1. 打开USART1,并设置模式为异步收发模式Asynchronous:

  • 2. 设置USART1的参数,通用的“96-N-8-1”模式,即波特率9600,N校验位(无校验),数据位数为8,停止位为1位:

三. 在 Pinout&Configuration---System Core中:

1. 配置DMA参数:

经过第二步后,PA9和PA10被配置为了USART1_RX/USART1_TX:

按照图中数字顺序配置DMA,点击Add,添加USARTT1_TX, Channel会自动选择,Direction默认选择的是存储器到外设,Mode不使用循环,设置为Normal即可;外设地址无增量,存储器地址有增量;Data Width根据需要将存储器和外设的宽度都设置为字节。

四.在 Clock Configuration中:

配置时钟为72 Mhz。

五.在 Project Manager---Project中:

  • 1.设置项目的名称以及保存的位置,选择Toolchain/IDE为MDK-ARM V5,

Tips:最好把Linker Settings中的Minimum Heap Size设置为0x600。

  • 2.在Code Generator选项中如下勾选:

最后点Generate Code生成代码,并选择“Open Project”:

六.代码分析与改写:

配置思路:首先在一个数组中定义要发送的内容;让LED1不断闪烁,表示系统正在运行;编写中断回调函数,当按键按下时发送数据到外设(USART1)中,并改变LED2状态表示进入中断。

此处与笔记2的分析过程相同:

************************************************************************************************************************************************

在生成的stm32f1xx_it.c中是系统中断的相关函数,找到四个外部中断的中断服务函数:

void EXTI0_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */

  /* USER CODE END EXTI0_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  /* USER CODE BEGIN EXTI0_IRQn 1 */

  /* USER CODE END EXTI0_IRQn 1 */
}

进入“HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0)”函数后发现定义如下:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

服务函数中第一步对中断口清零,随后进入回调函数“HAL_GPIO_EXTI_Callback”:

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
}

回调函数中没有定义任何操作,因此将我们要实现的功能编写在回调函数中。

************************************************************************************************************************************************

  • 1. 定义发送的数组内容,在main.c中添加:
/* USER CODE BEGIN PV */
uint8_t serialMsg[] = "DMA has been successfully received! \r\n";
/* USER CODE END PV */
  • 2.在while(1)循环中添加LED1系统正常运行指示灯:
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	    HAL_GPIO_TogglePin(GPIOC,LED1_Pin);
	    HAL_Delay(200);
    /* USER CODE END WHILE */
  • 3.编写中断回调函数:
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin==UP_Pin)
	{
		for(long i=1;i<72000;i++){};  //软件消抖
			if(HAL_GPIO_ReadPin(UP_GPIO_Port,UP_Pin)==1)  //按键是否按下
			{
				HAL_GPIO_TogglePin(GPIOC,LED2_Pin);
				HAL_UART_Transmit_DMA(&huart1, (uint8_t *)serialMsg, sizeof(serialMsg)); 
				HAL_Delay(1000);
			}
	}
}
/* USER CODE END 4 */

至此,编译后无错并下载到开发板中,就完成了通过STM32CubeMX调用HAL库实现按键控制DMA串口发送的效果程序。

实验现象:正常运行后,按下KEY_UP后DMA发送数组至串口:

 

 

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
很抱歉,我是一名语言模型,无法上传图片和音频。但是我可以为您提供代码解释。 代码1:设置DMA传输的源地址、目的地址、传输数据量和传输方向 ```c void DMA_Configuration(void) { DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA1_Channel4); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (u32)TxBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = TxCounter; 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_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel4, &DMA_InitStructure); } ``` 代码2:检测外部按键是否按下,并触发DMA传输 ```c while (1) { if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0) //判断按键是否按下 { DMA_Cmd(DMA1_Channel4, DISABLE); //关闭DMA传输 while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET); //等待DMA传输完成 DMA_ClearFlag(DMA1_FLAG_TC4); //清除DMA传输完成标志 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //开启USART1的DMA发送请求 DMA_SetCurrDataCounter(DMA1_Channel4, TxCounter); //设置DMA传输数据量 DMA_Cmd(DMA1_Channel4, ENABLE); //开启DMA传输 while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0); //等待按键释放 } } ``` 代码3:DMA传输完成后,关闭USART1的DMA发送请求并重置TxCounter计数器 ```c void DMA1_Channel4_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_TC4) != RESET) { DMA_ClearITPendingBit(DMA1_IT_TC4); USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE); //关闭USART1的DMA发送请求 TxCounter = 0; //重置TxCounter计数器 } } ``` 以上就是实现按键触发DMA传输的主要代码。需要注意的是,在使用DMA传输时,一定要先关闭DMA传输,等待传输完成后再开启DMA传输。同时,在每次传输完成后,要关闭USART1的DMA发送请求,并重置TxCounter计数器。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值