stm32f103 uart+DMA发送接收
//stm32f1 串口通信 // 串口通信模块会为串口划分256字节的uart缓存区,缓存中断接收的数据, // 处理串口接收数据的任务会每50ms按协议处理解析缓存区里的数据。当然, // 如果没有处理完缓存区的数据,而又接收到新的数据,那新的数据将会被 // 舍弃。 // 串口的接收数据和发送数据都用到DMA处理器,其中串口接收用了串口 // 空闲中断。串口连续接收数据后检测到串口接收空闲,产生一个空闲中断, // 这时候将接收到的数据缓存到uart缓存区中,等待解析。 // 1. 配置串口IO口以及串口功能配置 // 这里使用的是uart1 #define FIFOLEN 256 static uint8_t dma_buf[FIFOLEN]; static uint8_t dma_rx[FIFOLEN]; static u8 fifo_buf[FIFOLEN]; static u16 fifo_in = 0; static u16 fifo_out = 0; static u16 fifo_used = 0; void uart1_func_init(void) { GPIO_InitTypeDef io; USART_InitTypeDef uart; //UART1 IO口配置 io.GPIO_Pin = GPIO_Pin_9; io.GPIO_Mode= GPIO_Mode_AF_PP; io.GPIO_Speed= GPIO_Speed_50MHz; GPIO_Init(GPIOA, &io); io.GPIO_Pin = GPIO_Pin_10; io.GPIO_Mode= GPIO_Mode_IN_FLOATING; io.GPIO_Speed= GPIO_Speed_50MHz;; GPIO_Init(GPIOA, &io); //USART1 功能配置 波特率115200,8位数据位,1位停止位,无校验,无硬件流控制 uart.USART_BaudRate = 115200; uart.USART_WordLength = USART_WordLength_8b; uart.USART_StopBits = USART_StopBits_1; uart.USART_Parity = USART_Parity_No; uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &uart); USART_ITConfig(USART1,USART_IT_TC,DISABLE);//使能串口空闲中断 USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//失能接收中断 USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//使能发送中断 USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//使能串口发送DMA USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//使能串口接收DMA USART_Cmd(USART1, ENABLE); } // 2. 配置DMA功能 // stm32f103手册里可以了解到,uart1-uart4有相关的DMA通道,对应如下 // uart1_tx-->DMA1_Channel4 uart1_rx-->DMA1_Channel5 // uart2_tx-->DMA1_Channel7 uart2_rx-->DMA1_Channel6 // uart3_tx-->DMA1_Channel2 uart3_rx-->DMA1_Channel3 // uart4_tx-->DMA2_Channel5 uart4_rx-->DMA2_Channel2 static void uart1_dma_init(void) { DMA_InitTypeDef dma; //DMA 配置 dma.DMA_BufferSize = 1; //初始化为1个字节 dma.DMA_DIR = DMA_DIR_PeripheralDST; //从内存到外设 dma.DMA_M2M = DMA_M2M_Disable; //内存到内存,失能 dma.DMA_MemoryBaseAddr = (uint32_t)dma_buf; //内存地址 dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度 dma.DMA_MemoryInc = DMA_MemoryInc_Enable; //使能自增 dma.DMA_Mode = DMA_Mode_Normal; //普通模式,不连续模式 dma.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; //外设地址 dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度 dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不自增 dma.DMA_Priority = DMA_Priority_High; //优先级 DMA_DeInit(DMA1_Channel4); DMA_Init(DMA1_Channel4, &dma); DMA_Cmd(DMA1_Channel4, ENABLE); dma.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); dma.DMA_MemoryBaseAddr = (uint32_t)dma_rx; dma.DMA_DIR = DMA_DIR_PeripheralSRC; dma.DMA_BufferSize = FIFOLEN; dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dma.DMA_MemoryInc = DMA_MemoryInc_Enable; dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; dma.DMA_Mode = DMA_Mode_Normal; dma.DMA_Priority = DMA_Priority_VeryHigh; dma.DMA_M2M = DMA_M2M_Disable; DMA_DeInit(DMA1_Channel5); DMA_Init(DMA1_Channel5,&dma); DMA_Cmd(DMA1_Channel5,ENABLE); } void uart1_init(void) { uart1_dma_init(); uart1_func_init(); } //3. uart 缓存区用fifo方式存取 u16 uart1_read(u8* data, u16 len) { u16 i; u16 ret; ret = (len < fifo_used) ? len : fifo_used; for(i = 0; i < ret; i++) { data = fifo_buf[fifo_out]; if(++fifo_out == FIFOLEN) { fifo_out = 0; } } fifo_used -= ret; return ret; } void uart1_write(uint8_t* data, uint16_t len) { uint16_t i; while(!DMA_GetFlagStatus(DMA1_FLAG_TC4)); DMA_Cmd(DMA1_Channel4, DISABLE); for(i=0; i = data; } DMA_ClearFlag(DMA1_FLAG_TC4); DMA_SetCurrDataCounter(DMA1_Channel4, len); DMA_Cmd(DMA1_Channel4, ENABLE); } //打印调试信息 void uart1_puts(char* s) { u16 i; for(i=0;s!=0;i++) { while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE)); USART_SendData(USART1, s); } } void USART1_IRQHandler(void) { u16 temp; u16 i; if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { temp = USART1->SR;//----清除空闲标志位 temp = USART1->DR; DMA_Cmd(DMA1_Channel5,DISABLE); temp = FIFOLEN - DMA_GetCurrDataCounter(DMA1_Channel5); for(i=0; i; if(++fifo_in == FIFOLEN) { fifo_in = 0; } fifo_used++; } } DMA_SetCurrDataCounter(DMA1_Channel5,FIFOLEN); DMA_Cmd(DMA1_Channel5,ENABLE); } else { USART_ReceiveData(USART1); USART_ClearFlag(USART1, USART_FLAG_ORE); } } //------------------------------------------------------------------------------------ 上面是c文件,在h文件的接口如下 void uart1_init(void); u16 uart1_read(u8* data, u16 len); void uart1_write(u8* data, u16 len); void uart1_puts(char* s); //--------------------------------------------------------------------------------------- 完成了上面的配置,就可以在解析数据包的任务里调用uart1_read函数了。长度一般为缓存区长度。 这里有两个发送函数,一个是uart1_put,一个是uart1_write,前者没有dma发送,不需要指定长度,发送完整的字符串出去,适合打印调试信息到上位机。后者是dma方式发送,可以一定程度上减轻cpu负担,需要指定发送长度。
stm32f103 uart+DMA发送接收
//stm32f1 串口通信 // 串口通信模块会为串口划分256字节的uart缓存区,缓存中断接收的数据, // 处理串口接收数据的任务会每50ms按协议处理解析缓存区里的数据。当然, // 如果没有处理完缓存区的数据,而又接收到新的数据,那新的数据将会被 // 舍弃。 // 串口的接收数据和发送数据都用到DMA处理器,其中串口接收用了串口 // 空闲中断。串口连续接收数据后检测到串口接收空闲,产生一个空闲中断, // 这时候将接收到的数据缓存到uart缓存区中,等待解析。 // 1. 配置串口IO口以及串口功能配置 // 这里使用的是uart1 #define FIFOLEN 256 static uint8_t dma_buf[FIFOLEN]; static uint8_t dma_rx[FIFOLEN]; static u8 fifo_buf[FIFOLEN]; static u16 fifo_in = 0; static u16 fifo_out = 0; static u16 fifo_used = 0; void uart1_func_init(void) { GPIO_InitTypeDef io; USART_InitTypeDef uart; //UART1 IO口配置 io.GPIO_Pin = GPIO_Pin_9; io.GPIO_Mode= GPIO_Mode_AF_PP; io.GPIO_Speed= GPIO_Speed_50MHz; GPIO_Init(GPIOA, &io); io.GPIO_Pin = GPIO_Pin_10; io.GPIO_Mode= GPIO_Mode_IN_FLOATING; io.GPIO_Speed= GPIO_Speed_50MHz;; GPIO_Init(GPIOA, &io); //USART1 功能配置 波特率115200,8位数据位,1位停止位,无校验,无硬件流控制 uart.USART_BaudRate = 115200; uart.USART_WordLength = USART_WordLength_8b; uart.USART_StopBits = USART_StopBits_1; uart.USART_Parity = USART_Parity_No; uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &uart); USART_ITConfig(USART1,USART_IT_TC,DISABLE);//使能串口空闲中断 USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);//失能接收中断 USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//使能发送中断 USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//使能串口发送DMA USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//使能串口接收DMA USART_Cmd(USART1, ENABLE); } // 2. 配置DMA功能 // stm32f103手册里可以了解到,uart1-uart4有相关的DMA通道,对应如下 // uart1_tx-->DMA1_Channel4 uart1_rx-->DMA1_Channel5 // uart2_tx-->DMA1_Channel7 uart2_rx-->DMA1_Channel6 // uart3_tx-->DMA1_Channel2 uart3_rx-->DMA1_Channel3 // uart4_tx-->DMA2_Channel5 uart4_rx-->DMA2_Channel2 static void uart1_dma_init(void) { DMA_InitTypeDef dma; //DMA 配置 dma.DMA_BufferSize = 1; //初始化为1个字节 dma.DMA_DIR = DMA_DIR_PeripheralDST; //从内存到外设 dma.DMA_M2M = DMA_M2M_Disable; //内存到内存,失能 dma.DMA_MemoryBaseAddr = (uint32_t)dma_buf; //内存地址 dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度 dma.DMA_MemoryInc = DMA_MemoryInc_Enable; //使能自增 dma.DMA_Mode = DMA_Mode_Normal; //普通模式,不连续模式 dma.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; //外设地址 dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度 dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不自增 dma.DMA_Priority = DMA_Priority_High; //优先级 DMA_DeInit(DMA1_Channel4); DMA_Init(DMA1_Channel4, &dma); DMA_Cmd(DMA1_Channel4, ENABLE); dma.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); dma.DMA_MemoryBaseAddr = (uint32_t)dma_rx; dma.DMA_DIR = DMA_DIR_PeripheralSRC; dma.DMA_BufferSize = FIFOLEN; dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dma.DMA_MemoryInc = DMA_MemoryInc_Enable; dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; dma.DMA_Mode = DMA_Mode_Normal; dma.DMA_Priority = DMA_Priority_VeryHigh; dma.DMA_M2M = DMA_M2M_Disable; DMA_DeInit(DMA1_Channel5); DMA_Init(DMA1_Channel5,&dma); DMA_Cmd(DMA1_Channel5,ENABLE); } void uart1_init(void) { uart1_dma_init(); uart1_func_init(); } //3. uart 缓存区用fifo方式存取 u16 uart1_read(u8* data, u16 len) { u16 i; u16 ret; ret = (len < fifo_used) ? len : fifo_used; for(i = 0; i < ret; i++) { data = fifo_buf[fifo_out]; if(++fifo_out == FIFOLEN) { fifo_out = 0; } } fifo_used -= ret; return ret; } void uart1_write(uint8_t* data, uint16_t len) { uint16_t i; while(!DMA_GetFlagStatus(DMA1_FLAG_TC4)); DMA_Cmd(DMA1_Channel4, DISABLE); for(i=0; i = data; } DMA_ClearFlag(DMA1_FLAG_TC4); DMA_SetCurrDataCounter(DMA1_Channel4, len); DMA_Cmd(DMA1_Channel4, ENABLE); } //打印调试信息 void uart1_puts(char* s) { u16 i; for(i=0;s!=0;i++) { while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE)); USART_SendData(USART1, s); } } void USART1_IRQHandler(void) { u16 temp; u16 i; if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { temp = USART1->SR;//----清除空闲标志位 temp = USART1->DR; DMA_Cmd(DMA1_Channel5,DISABLE); temp = FIFOLEN - DMA_GetCurrDataCounter(DMA1_Channel5); for(i=0; i; if(++fifo_in == FIFOLEN) { fifo_in = 0; } fifo_used++; } } DMA_SetCurrDataCounter(DMA1_Channel5,FIFOLEN); DMA_Cmd(DMA1_Channel5,ENABLE); } else { USART_ReceiveData(USART1); USART_ClearFlag(USART1, USART_FLAG_ORE); } } //------------------------------------------------------------------------------------ 上面是c文件,在h文件的接口如下 void uart1_init(void); u16 uart1_read(u8* data, u16 len); void uart1_write(u8* data, u16 len); void uart1_puts(char* s); //--------------------------------------------------------------------------------------- 完成了上面的配置,就可以在解析数据包的任务里调用uart1_read函数了。长度一般为缓存区长度。 这里有两个发送函数,一个是uart1_put,一个是uart1_write,前者没有dma发送,不需要指定长度,发送完整的字符串出去,适合打印调试信息到上位机。后者是dma方式发送,可以一定程度上减轻cpu负担,需要指定发送长度。
举报