完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
重启网上很多讲故事+DMA接收不定长字符串的例子,有谁抄来抄去不加验证,没有没有代码,还有可能对解决方案源每天解释。空来整理一下,下面的代码经过本人验证。
接收定长字符串简单,直接在中断里将字符放到数组里即可。 但是接收不定长字符串就比较麻烦,因为你不知道什么时候一帧数据接收结束。通常有两种方法来接收不定长时间:超时判断,服务中断。今天我们先介绍第二种方法。 首先明确一个概念,什么是STM32的后续中断,下面是stm32数据手册1对中断的定义: '1'符号被完全由'1'组成的一个完整的数据帧,伴随着包含了下一个帧的开始位('1'的数据也包括了停止位的隐私)。一串数据全部由1组构成,包括我们发送帧停止位都是1。发送完这一串的数据的最后一个字节后,紧跟着一个空闲中断图1是手册里面的解释。 问题解决思路:用DMA1的通道5接收串口数据,当一帧数据发送完,进入32的串口中断,在串口中断里面计算本次DMA传输接收了多少字符,同时置位标志位,在main()函数中查询标志位来处理数据,别忘了处理完之后将标志位清零。 下面是代码: 串口1初始化: void usart1_config(u32 baud) { GPIO_InitTypeDef io; USART_InitTypeDef temp; //RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); io.GPIO_Pin = GPIO_Pin_9; io.GPIO_Mode = GPIO_Mode_AF_PP;//txd io.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &io); io.GPIO_Pin = GPIO_Pin_10; io.GPIO_Mode = GPIO_Mode_IN_FLOATING;//rxd io.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &io); temp.USART_BaudRate = baud; temp.USART_HardwareFlowControl = USART_HardwareFlowControl_None; temp.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; temp.USART_Parity = USART_Parity_No; temp.USART_StopBits = USART_StopBits_1; temp.USART_WordLength = USART_WordLength_8b; USART_Init(USART1, &temp); #if(USART1_RX_INT_EN)//这个宏为1 { NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//使能串口1的空闲中断,注意这里并没有使能接收中断! } #endif USART_Cmd(USART1, ENABLE); } DMA初始化 void usart1_DMA_config(DMA_Channel_TypeDef* DMAy_Channelx,u32 memAddr,u32 periphAddr,u8 bufSize) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1???? /* 初始化DMA */ DMA_InitStructure.DMA_PeripheralBaseAddr = periphAddr;// DMA外设地址 DMA_InitStructure.DMA_MemoryBaseAddr = memAddr;// DMA内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;// ·传输方向从外设到内存 DMA_InitStructure.DMA_BufferSize = bufSize; //传输数据大小 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_Medium;//优先级中等,一个DMA通道工作的话可以不设置 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //关闭内存到内存 DMA_Init(DMAy_Channelx, &DMA_InitStructure);//初始化 #if(USART1_RX_DMA_INT_EN )//这个宏定义没开 { NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn;//USART1_RX-channel5 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); DMA_ITConfig(DMAy_Channelx,DMA_IT_TC,ENABLE); } #endif } DMA的使能 包括两部分,DMA使能与串口的接收请求使能。 void usart1_DMA_enable(DMA_Channel_TypeDef* DMAy_Channelx,u8 bufSize) { USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);//DMA接收请求使能 DMA_Cmd(DMAy_Channelx, DISABLE);//先关闭才能写传送的数据 DMA_SetCurrDataCounter(DMAy_Channelx, bufSize);//写入传送数量,如果此值为0DMA开不了 DMA_Cmd(DMAy_Channelx, ENABLE); } 串口中断函数 void USART1_IRQHandler(void) { u16 clear; if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE)) { clear = USART_ReceiveData(USART1);//通过先读状态寄存器再读数据寄存器将IDLE清除 usart1IdleItFlag = 1;//接收完成标志位置1 bufRemainByte = 50 - DMA_GetCurrDataCounter(DMA1_Channel5);//计算本次传送的字节数。总数以50为例子 PBout(11) = ~PBout(11);//配合led观察接收完毕 } } 上面需要注意,清除IDLE标志位的次序,根据数据手册的说明: IDLE:监测到总线空闲 (IDLE line detected) 当检测到总线空闲时,该位被硬件置位。如果USART_CR1中的IDLEIE为’1’,则产生中断。由 软件序列清除该位(先读USART_SR,然后读USART_DR)。 注意比对上面代码。 在main()函数里面查询标志位处理数据 int main() { ST_USART1_RCV_BUF rxbuf={{0},0,0,0}; extern u8 usart1IdleItFlag; extern u8 bufRemainByte; SysTick_Init(72); NVIC_PriorityGroupConfig(2); LED_Init(); usart1_config(9600); usart1_DMA_config(DMA1_Channel5,(u32)rxbuf.buf,(u32)&USART1->DR,50); usart1_DMA_enable(DMA1_Channel5,50); while(1) { if(usart1IdleItFlag) { usart1_send_string(rxbuf.buf,bufRemainByte); usart1_DMA_enable(DMA1_Channel5,50);//ʹÄÜÏÂÒ»´ÎDMA usart1IdleItFlag = 0;//一定不要忘记将标志位清零。 } } 以上代码别写结束,下面是测试: 下面是测试图 如上图,发送了8次“12345678”,进入中断8次,一共接收到64个字符。测试完毕。第一次发帖,不足 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1780 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1081 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1679 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 16:33 , Processed in 0.630557 second(s), Total 43, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号