stm32f4 串口收发使用dma还是很方便的。但是配置dma时需要配置数据长度,这一点对于发送来说可以预估计自己发送的长度来配置dma发送数据长度,但是对于接收不是很好解决,因为如果使用dma接收中断是要配置的数据长度减到0才能出发中断。但是我们无法判断接受数据的长度,导致无法判断数据接收完成。网上有提出的解决方法是用定时器固定周期的读dma接收的长度来判断是否接收完成,也有使用uart的空闲中断来处理的。在这里我使用uart的空闲中断来处理接收不定长数据。当然也要打开dma接收完成中断,处理数据接收超过dma配置的长度导致的dma接收中断。
1.使用dma发送时每次发送数据前需要配置发送的数据长度,此时要注意应先关闭dma,然后配置数据长度,最后开启dma发送,同时在dma发送中断里面不要忘记清除相应的中断标志位。
2.dma接收长度达到配置长度后会导致接收中断,此时在中断处理函数内要先关闭dma,然后读出数据长度,清掉相应的中断标志位,最后重新配置dma接收长度并打开dma接收。在这里的dma中断指示为了防护一次性接收数据超过dma配置长度。
3.uart空闲中断,利用空闲中断可以很好地判断dma接收不定长度的数据是否完成。初始化uart时打开空闲中断。当数据接收完成后会触发uart空闲中断。在中断内首先关闭dma,读出dma接收到的数据长度,清除dma标志,重新配置dma接收长度,清除空闲中断标志idle。这里要注意清除idle要由软件序列清除即依次读取usart1-》sr;和usart1-》dr;
下面贴出代码方便以后查看
u8receivebuff[receive_buf_size];//接收缓冲
u8sendbuff[send_buf_size];//发送数据缓冲区
u16uart1_receivesize=0;
//初始化io串口1
//bound:波特率
voiduart_init(u32bound)
{
//gpio端口设置
gpio_inittypedefgpio_initstructure;
usart_inittypedefusart_initstructure;
nvic_inittypedefnvic_initstructure;
dma_inittypedefdma_initstructure;
rcc_ahb1periphclockcmd(rcc_ahb1periph_gpioa,enable);//使能gpioa时钟
rcc_apb2periphclockcmd(rcc_apb2periph_usart1,enable);//使能usart1时钟
rcc_ahb1periphclockcmd(rcc_ahb1periph_dma2,enable);//dma2时钟使能
//串口1对应引脚复用映射
gpio_pinafconfig(gpioa,gpio_pinsource9,gpio_af_usart1);//gpioa9复用为usart1
gpio_pinafconfig(gpioa,gpio_pinsource10,gpio_af_usart1);//gpioa10复用为usart1
//usart1端口配置
gpio_initstructure.gpio_pin=gpio_pin_9|gpio_pin_10;//gpioa9与gpioa10
gpio_initstructure.gpio_mode=gpio_mode_af;//复用功能
gpio_initstructure.gpio_speed=gpio_speed_50mhz;//速度50mhz
gpio_initstructure.gpio_otype=gpio_otype_pp;//推挽复用输出
gpio_initstructure.gpio_pupd=gpio_pupd_up;//上拉
gpio_init(gpioa,&gpio_initstructure);//初始化pa9,pa10
//usart1初始化设置
usart_initstructure.usart_baudrate=bound;//波特率设置
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_cmd(usart1,enable);//使能串口1
//usart_clearflag(usart1,usart_flag_tc);
usart_itconfig(usart1,usart_it_idle,enable);//开启相关中断
//usart1nvic配置
nvic_initstructure.nvic_irqchannel=usart1_irqn;//串口1中断通道
nvic_initstructure.nvic_irqchannelpreemptionpriority=3;//抢占优先级3
nvic_initstructure.nvic_irqchannelsubpriority=3;//子优先级3
nvic_initstructure.nvic_irqchannelcmd=enable;//irq通道使能
nvic_init(&nvic_initstructure);//根据指定的参数初始化vic寄存器、
usart_dmacmd(usart1,usart_dmareq_tx,enable);//使能串口1的dma发送
usart_dmacmd(usart1,usart_dmareq_rx,enable);//使能串口1的dma接收
//****************************配置uart1发送
dma_deinit(dma2_stream7);
while(dma_getcmdstatus(dma2_stream7)!=disable);//等待dma可配置
/*配置dmastream*/
dma_initstructure.dma_channel=dma_channel_4;//通道选择
dma_initstructure.dma_peripheralbaseaddr=(u32)&usart1-》dr;//dma外设地址
dma_initstructure.dma_memory0baseaddr=(u32)sendbuff;//dma存储器0地址
dma_initstructure.dma_dir=dma_dir_memorytoperipheral;//存储器到外设模式
dma_initstructure.dma_buffersize=send_buf_size;//数据传输量
dma_initstructure.dma_peripheralinc=dma_peripheralinc_disable;//外设非增量模式
dma_initstructure.dma_memoryinc=dma_memoryinc_enable;//存储器增量模式
dma_initstructure.dma_peripheraldatasize=dma_peripheraldatasize_byte;//外设数据长度:8位
dma_initstructure.dma_memorydatasize=dma_memorydatasize_byte;//存储器数据长度:8位
dma_initstructure.dma_mode=dma_mode_normal;//使用普通模式
dma_initstructure.dma_priority=dma_priority_medium;//中等优先级
dma_initstructure.dma_fifomode=dma_fifomode_disable;
dma_initstructure.dma_fifothreshold=dma_fifothreshold_full;
dma_initstructure.dma_memoryburst=dma_memoryburst_single;//存储器突发单次传输
dma_initstructure.dma_peripheralburst=dma_peripheralburst_single;//外设突发单次传输
dma_init(dma2_stream7,&dma_initstructure);//初始化dmastream
//dmanvic
nvic_initstructure.nvic_irqchannel=dma2_stream7_irqn;
nvic_initstructure.nvic_irqchannelpreemptionpriority=0;
nvic_initstructure.nvic_irqchannelsubpriority=0;
nvic_initstructure.nvic_irqchannelcmd=enable;
nvic_init(&nvic_initstructure);
dma_itconfig(dma2_stream7,dma_it_tc,enable);
//****************************配置uart1接收
dma_deinit(dma2_stream5);
while(dma_getcmdstatus(dma2_stream5)!=disable);//等待dma可配置
/*配置dmastream*/
dma_initstructure.dma_channel=dma_channel_4;//通道选择
dma_initstructure.dma_peripheralbaseaddr=(u32)&usart1-》dr;//dma外设地址
dma_initstructure.dma_memory0
助力企业网络安全建设,华为云等保合规解决方案值得拥有
如何纠正三相电源相序
TI推出首款集成双通道异步取样率转换器的8通道脉宽调制器音频处理器
荣耀V9怎么样?荣耀V9评测:华为荣耀V9玩阴阳师,2个福利续航给力游戏机中的战斗机
电感器应用电路的详细讲解(二)
STM32F4发送和接收长度数据的判断
苹果15发布会时间 iPhone 15标准机型将增加
手机拆解维修榜:iPhone7/Plus很容易修 三星Note7、S7是硬骨头
具有电流限制的多重转换冗余电源系统
微软win10将关闭“摇动最小化”功能
全面屏时代下的屏下指纹识别模组应用而生
被质疑 5G 和云游戏方面落后?任天堂回应了
谷歌新款Pixel Buds耳机已通过无线充电联盟的认证支持5W充电功率
浅谈电瓶修复技术,电池配组到底是怎么一回事
苹果电脑处理器将摒弃英特尔处理器,采用ARM架构处理器
12英寸硅基Micro OLED微型显示器进入商业化量产阶段
归零码,归零码是什么意思
是德信号发生器N5173B介绍
柔性屏占领世界 可穿戴设计量产
ESP32-C3无线WiFi技术应用,家电智能化控制发展