完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
最近遇到一个小问题,感觉很有意思便记下来分享一下 ,顺便也为日后类似的问题提供点思路:
使用stm32串口发送数据 ,串口是单线半双工模式,要求数据发送前串口变成发送模式,发送完后立即变回接收模式,发送操作使用DMA来发送,程序开了串口中断和DMA中断,串口中断主要是用于接收与解析数据,DMA中断是想用于操作串口收发模式切换,发现DMA发送时最后一个数据老是发不出来。 经过分析定位发现是因为DMA将传输完成后,串口其实还没有将所有的问题发送出去(至少还有一个字节没发出去),然后修改操串口收发模式切换时间点将该问题解决,具体为:串口在DMA传输前由接收模式变成发送模式,在DMA传输完成中断中开启串口发送完成中断,在串口发送完成中断中将串口工作模式从发送模式变回接收模式,问题完解决,相关配置代码如下: 串口配置: void Usart_Init( void ) { USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; //GPIO clock enable RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // USART1时钟使能 //USART1_TX GPIO_InitStructure.GPIO_Pin = USART1_TX_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_Init(USART1_TXRX_PORT, &GPIO_InitStructure); //USART1_RX GPIO_InitStructure.GPIO_Pin = USART1_RX_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入 GPIO_Init(USART1_TXRX_PORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200; // 串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 字长为8位数据格式 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); // 初始化串口1 USART_HalfDuplexCmd(USART1, ENABLE); // 使能变双工 DMA_Usart_Init(); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // USART1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2 ;// 抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能 NVIC_Init(&NVIC_InitStructure); // 根据指定的参数初始化NVIC寄存器 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启串口1接收中断 USART_Cmd(USART1, ENABLE); // 使能串口1 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 开启串口USART1的DMA发送 } DMA配置: void DMA_Usart_Init(void) { DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA1时钟 DMA_Cmd(DMA1_Channel4, DISABLE);//关闭DMA1的通道4 Usart1_TX对应通道4 DMA_DeInit(DMA1_Channel4);//恢复缺省值 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);//设置串口发送数据寄存器 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DMATXBUFF1;//设置发送缓冲区首地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//设置外设位目标,内存缓冲区->外设寄存器 DMA_InitStructure.DMA_BufferSize = 10;//需要发送的字节数,这里可以设置为0,因为在实际要发送时还会重新设置 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不做增加调整,调整不调整是DMA自动实现的 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存缓冲区地址增加调整 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据宽度8位,1个字节 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存数据宽度8位,1个字节 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//单次传输模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Low;//优先级配置 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//关闭内存到内存的DMA模式 DMA_Init(DMA1_Channel4, &DMA_InitStructure);//写入配置 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;//DMA1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1 ;//抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器 DMA_ClearFlag(DMA1_FLAG_GL4);//清除DMA所有标志 GL4:通道4全局标志 TC4:传输完成 HT4:传输过半 TE4:传输错误 DMA_Cmd(DMA1_Channel4, DISABLE);//关闭DMA1的通道4 DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);//开启发送DMA通道中断 } 串口中断: void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // 接收数据寄存器非空标志 { if(RxNum1 > (RXBUFFSIZE1 - 1)) { RxNum1 = 0; } RXBUFF1[RxNum1++] = USART_ReceiveData(USART1); } else if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)// 发送完成标志 { USART_ITConfig(USART1, USART_IT_TC, DISABLE); USART_ClearFlag(USART1,USART_FLAG_TC); USART1_RX_EN_TX_DIS(); } else { } } DMA中断: void DMA1_Channel4_IRQHandler(void) { if(DMA_GetITStatus(DMA1_FLAG_TC4) != RESET) // DMA1通道4发送完成标志 { Usart1TxBusy = 0; DMA_Cmd(DMA1_Channel4, DISABLE); // 关闭DMA1的通道4 DMA_ClearFlag(DMA1_FLAG_GL4); // 清除DMA1的通道4的所有中断标志,因为只有发送完成标志,所以直接全部清除 USART_ClearFlag(USART1,USART_FLAG_TC); // 在关中断前先清中断标志,防止是串口上一个数据发送时的中断标志 USART_ITConfig(USART1, USART_IT_TC, ENABLE);// DMA1传输完成后使能Usart1发送完成中断 } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1937浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
554浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 02:31 , Processed in 0.993131 second(s), Total 48, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号