stm32串口DMA收发,可以接收不定长数据,格式化输出。

来源:互联网 发布:帝国cms好吗 编辑:程序博客网 时间:2024/06/06 12:58
<pre name="code" class="html"><span style="font-size:24px;color:#ff0000;"><strong>这个程序同时初始化了五个串口,前四个串口具有dma,所以均采用DMA接收和发送,并提供了格式化输出的类似printf的接口,可以接收未知长度的数据,但是收发字节数</strong></span><pre name="code" class="html">UART_RECV_BUF_MAX_LEN 和<pre name="code" class="html">UART_SEND_BUF_MAX_LEN有关 
,和串口5没有用于485通信。
<strong><span style="font-size:24px;color:#ff0000;">//usrt.h</span></strong>
#ifndef _USART_H#define _USART_H#include "stm32f10x.h"typedef enum {  UART1_3520D = 0,     UART2_RS232 = 1,UART3_GPS = 2,UART4_GPRS = 3,UART5_RS485 = 4} COM_TypeDef;   #define UART_RECV_BUF_MAX_LEN 1024#define UART_SEND_BUF_MAX_LEN 1024__align(8) typedef struct {u8 RecvLen;u8 RecvBuf[UART_RECV_BUF_MAX_LEN];u8 SendLen;u8 SendBuf[UART_SEND_BUF_MAX_LEN];u8 Status;//状态位的第一个是忙状态位//COM_TypeDef Com;} SERIAL_TypeDef;#define USART1_Port GPIOA      #define USART1_Tx   GPIO_Pin_9#define USART1_Rx   GPIO_Pin_10#define USART2_Port  GPIOA#define USART2_Tx   GPIO_Pin_2#define USART2_Rx   GPIO_Pin_3#define USART3_Port  GPIOB#define USART3_Tx   GPIO_Pin_10#define USART3_Rx   GPIO_Pin_11#define USART4_Port  GPIOC#define USART4_Tx   GPIO_Pin_10#define USART4_Rx   GPIO_Pin_11#define USART5_Port  GPIOD#define USART5_Tx   GPIO_Pin_5#define USART5_Rx   GPIO_Pin_6#define UART_485_TX_EN GPIOA->BSS   = GPIO_Pin_1 //485 控制引脚#define UART_485_RX_EN GPIOA->BRSS  = GPIO_Pin_1extern u8 UART_STATE_FLAG; extern SERIAL_TypeDef serial1, serial2, serial3,serial4,serial5;void print(char* fmt,...);void Serial_Init(void);void UART_Send(COM_TypeDef COM, u8 *buf, u16 len);void UART_Read(COM_TypeDef COM, u8 *buf);void USART_Config(COM_TypeDef COM, u32 COM_BaudRate, u8 *recvbuf, u8 *sendbuf);#endif 


<pre name="code" class="html"><strong><span style="font-size:24px;color:#ff0000;">//usrt.c</span></strong>
/***************************************************串口初始化程序2014年12月李乾坤*************************************************/#include "usart.h"#include "stdarg.h"#include "common.h"USART_TypeDef* USART[5] = {USART1, USART2, USART3, UART4, UART5}; DMA_Channel_TypeDef *DMA_Channel[8] = {DMA1_Channel4, DMA1_Channel5, DMA1_Channel7, \DMA1_Channel6, DMA1_Channel2,DMA1_Channel3, DMA2_Channel5, DMA2_Channel3};SERIAL_TypeDef serial1, serial2, serial3,serial4,serial5;SERIAL_TypeDef *serial[5] = {&serial1,&serial2,&serial3,&serial4,&serial5};void Serial_Init(void){mymemset(&serial1, 0, sizeof(SERIAL_TypeDef));mymemset(&serial2, 0, sizeof(SERIAL_TypeDef));mymemset(&serial3, 0, sizeof(SERIAL_TypeDef));mymemset(&serial4, 0, sizeof(SERIAL_TypeDef));mymemset(&serial5, 0, sizeof(SERIAL_TypeDef));USART_Config(UART1_3520D, 115200, serial1.RecvBuf, serial1.SendBuf);//与3520D通信USART_Config(UART2_RS232, 115200, serial2.RecvBuf, serial2.SendBuf);//接RS232USART_Config(UART3_GPS, 9600, serial3.RecvBuf, serial3.SendBuf);//GPSUSART_Config(UART4_GPRS, 115200, serial4.RecvBuf, serial4.SendBuf);//3G// USART_Config(UART5_RS485, 9600, serial1.RecvBuf, serial1.SendBuf);//485云台}/**************************************************************************************@Decr: 初始化串口(利用串口接受完数据会进入空闲中断,在空闲中断里对DMA重新初始化,设置下次传输的参数,\关闭DMA发送完成中断,直接判断CNDTR的值来判断上次传输是否完成@Para1:COM口@Para2:波特率@Para3:发送缓冲区@Para4:接受缓冲区,为NULL表示对应DMA功能不开启@Ret:void***************************************************************************************/void USART_Config(COM_TypeDef COM, u32 COM_BaudRate, u8 *recvbuf, u8 *sendbuf){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup);switch(COM){case 0: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin = USART1_Rx; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USART1_Port, &GPIO_InitStructure); //做RX GPIO_InitStructure.GPIO_Pin = USART1_Tx; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(USART1_Port, &GPIO_InitStructure); //做TX NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART1_IT_MAIN_PRI; //接受空闲中断只影响下次的发送 NVIC_InitStructure.NVIC_IRQChannelSubPriority = USART1_IT_SUB_PRI; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); break;case 1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); GPIO_InitStructure.GPIO_Pin = USART2_Rx; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USART1_Port, &GPIO_InitStructure); //做RX GPIO_InitStructure.GPIO_Pin = USART2_Tx; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(USART1_Port, &GPIO_InitStructure); //做TX NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART2_IT_MAIN_PRI; NVIC_InitStructure.NVIC_IRQChannelSubPriority = USART2_IT_SUB_PRI; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); break;case 2: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); GPIO_InitStructure.GPIO_Pin = USART3_Rx; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USART3_Port, &GPIO_InitStructure); //做RX GPIO_InitStructure.GPIO_Pin = USART3_Tx; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(USART3_Port, &GPIO_InitStructure); //做TX NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART3_IT_MAIN_PRI; NVIC_InitStructure.NVIC_IRQChannelSubPriority = USART3_IT_SUB_PRI; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); break; case 3: RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); GPIO_InitStructure.GPIO_Pin = USART4_Rx; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USART4_Port, &GPIO_InitStructure); //做RX GPIO_InitStructure.GPIO_Pin = USART4_Tx; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(USART4_Port, &GPIO_InitStructure); //做TX NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = UART4_IT_MAIN_PRI; NVIC_InitStructure.NVIC_IRQChannelSubPriority = UART4_IT_SUB_PRI; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); break;case 4: //串口5外接485云台RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //485控制引脚 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_ResetBits(GPIOA, GPIO_Pin_1); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //485_TX GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //485_RX GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, &GPIO_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = UART5_IT_MAIN_PRI;NVIC_InitStructure.NVIC_IRQChannelSubPriority = UART5_IT_SUB_PRI;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); break;}USART_InitStructure.USART_BaudRate = COM_BaudRate; USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_Init(USART[COM], &USART_InitStructure);USART_ITConfig(USART[COM], USART_IT_IDLE, ENABLE); USART_ClearITPendingBit(USART[COM], USART_IT_IDLE); USART_Cmd(USART[COM], ENABLE);if(COM == 4) //解决第一个字符不能打印{USART_ITConfig(UART5, USART_IT_IDLE, DISABLE);USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);USART_ClearITPendingBit(UART5, USART_IT_RXNE);return ;//串口5不支持DMA功能}DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART[COM]->DR; 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_PeripheralDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;if(sendbuf == NULL)//不启动发送DMAgoto UART_DMA_RECV_SETUP;USART_DMACmd(USART[COM], USART_DMAReq_Tx, ENABLE); //使能串口DMA收发功能DMA_InitStructure.DMA_MemoryBaseAddr = (u32)sendbuf; DMA_InitStructure.DMA_BufferSize = 0; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_Init(DMA_Channel[2*COM], &DMA_InitStructure);//DMA_ITConfig(DMA_Channel[2*COM], DMA_IT_TC, ENABLE);//开启DMA传输完完成中断//DMA_Cmd(DMA_Channel[2*COM], ENABLE);UART_DMA_RECV_SETUP:if(recvbuf == NULL)//不启动接收DMAreturn ;USART_DMACmd(USART[COM], USART_DMAReq_Rx,ENABLE); //使能DMA接收功能 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)recvbuf; DMA_InitStructure.DMA_BufferSize = UART_RECV_BUF_MAX_LEN; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//最高DMA优先级DMA_Init(DMA_Channel[2*COM + 1], &DMA_InitStructure);DMA_Cmd(DMA_Channel[2*COM + 1], ENABLE);}/**************************************************************************************@Decr: 串口发送@Para1:串口号@Para2:发送内容指针@Para3:数据长度@Para4:@Ret:void***************************************************************************************/void UART_Send(COM_TypeDef COM, u8 *buf, u16 len){ u16 i = 0;//printf("COM = %d,len = ");if(COM != UART5_RS485){while(DMA_Channel[2*COM]->CNDTR != 0);//判断是否可以发送for(;i < len; i ++)serial[COM]->SendBuf[i] = *buf ++;//放入串口1发送缓冲区DMA_Cmd(DMA_Channel[2*COM],DISABLE);DMA_SetCurrDataCounter(DMA_Channel[2*COM],len); //设置DMA传输数据量 DMA_Cmd(DMA_Channel[2*COM],ENABLE); //势能DMA传输}else {GPIO_SetBits(GPIOA, GPIO_Pin_1);//使能发送while(*buf) { USART_SendData(UART5, *buf++); while(USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);}GPIO_ResetBits(GPIOA, GPIO_Pin_1); //使能接收}}void UART_Read(COM_TypeDef COM, u8 *buf){u8 i;for(i = 0; i < serial[COM]->RecvLen; i ++)buf[i] = serial[COM]->RecvBuf[i];}//void print(char *format, ...)//调试打印接口,串口2,可以格式化输出//{// uint32_t length;// va_list args;// u8 timeout = 0;// while((DMA1_Channel7->CNDTR != 0) && timeout ++ < 100)//200ms超时检测// {// Delay_ms(1);// }// va_start(args, format);// length = vsnprintf((char*)serial2.SendBuf, sizeof(serial2.SendBuf), (char*)format, args);// va_end(args);// DMA_Cmd(DMA1_Channel7, DISABLE);// DMA_SetCurrDataCounter(DMA1_Channel7, length);// serial2.Status |= 0x01;// DMA_Cmd(DMA1_Channel7, ENABLE);//}void print(char *format, ...){uint32_t length;va_list args;u8 timeout = 0;//while(USART_GetFlagStatus(USART2, USART_FLAG_IDLE)) while((DMA1_Channel4->CNDTR != 0) && timeout ++ < 100)//200ms????{Delay_us(100);}va_start(args, format);length = vsnprintf((char*)serial1.SendBuf, sizeof(serial1.SendBuf), (char*)format, args);va_end(args);DMA_Cmd(DMA1_Channel4, DISABLE);DMA_SetCurrDataCounter(DMA1_Channel4, length);serial2.Status |= 0x01;DMA_Cmd(DMA1_Channel4, ENABLE);}
//stm32f10x_it.c
u8 tmp;void USART1_Process(void);void USART1_IRQHandler(void) //与3520D通信{<span style="white-space:pre"></span>if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//空闲总线中断<span style="white-space:pre"></span>{<span style="white-space:pre"></span>serial1.RecvLen = UART_RECV_BUF_MAX_LEN - (u16)DMA1_Channel5->CNDTR;//获得当前接受的数量<span style="white-space:pre"></span>tmp = USART1->SR;<span style="white-space:pre"></span>tmp = USART1->DR; //清除最后一个字节,免得不停进空闲中断<span style="white-space:pre"></span>DMA_Cmd(DMA1_Channel5,DISABLE);<span style="white-space:pre"></span>serial1.Status &= ~UART_BUSY_FLAG;<span style="white-space:pre"></span><span style="white-space:pre"></span>/*这里可以增加对串口数据的操作串口收数据地址serial1.RecvBuf,长度serial1.RecvLen*/<span style="white-space:pre"></span>//<span style="white-space:pre"></span>Debug_printf("recv = %s len = %d\r\n", serial1.RecvBuf, serial1.RecvLen);<span style="white-space:pre"></span>//<span style="white-space:pre"></span>USART1_Process();<span style="white-space:pre"></span><span style="white-space:pre"></span>mymemset(serial1.RecvBuf, 0, serial1.RecvLen);<span style="white-space:pre"></span>DMA_SetCurrDataCounter(DMA1_Channel5, UART_RECV_BUF_MAX_LEN);<span style="white-space:pre"></span>DMA_Cmd(DMA1_Channel5,ENABLE);<span style="white-space:pre"></span>}}void USART2_IRQHandler(void)//外接RS232{<span style="white-space:pre"></span>if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)//一帧数据接受完才会进入<span style="white-space:pre"></span>{<span style="white-space:pre"></span>//USART_ClearITPendingBit(USART2, USART_IT_IDLE);<span style="white-space:pre"></span>tmp = USART2->SR;<span style="white-space:pre"></span>tmp = USART2->DR;<span style="white-space:pre"></span>serial2.RecvLen = UART_RECV_BUF_MAX_LEN - DMA_GetCurrDataCounter(DMA1_Channel6);//在关闭DMA前取出CNDTR里的数据<span style="white-space:pre"></span>DMA_Cmd(DMA1_Channel6,DISABLE);<span style="white-space:pre"></span>serial2.Status &= ~UART_BUSY_FLAG;<span style="white-space:pre"></span><span style="white-space:pre"></span><span style="white-space:pre"></span><span style="white-space:pre"></span>DMA_SetCurrDataCounter(DMA1_Channel6,UART_RECV_BUF_MAX_LEN);<span style="white-space:pre"></span>DMA_Cmd(DMA1_Channel6,ENABLE);<span style="white-space:pre"></span>}}void USART3_IRQHandler(void)<span style="white-space:pre"></span>//GPS{<span style="white-space:pre"></span>if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>serial3.RecvLen = UART_RECV_BUF_MAX_LEN - (u16)DMA1_Channel3->CNDTR;//获得接受数量<span style="white-space:pre"></span>tmp = USART3->SR;<span style="white-space:pre"></span>tmp = USART3->DR;<span style="white-space:pre"></span>DMA1_Channel3->CCR &= (u16)~DMA_CCR1_EN;//关闭DMA<span style="white-space:pre"></span>serial3.Status |= 0x01;<span style="white-space:pre"></span>
<span style="white-space:pre"></span>
<span style="white-space:pre"></span>DMA1_Channel3->CNDTR = (u16)UART_RECV_BUF_MAX_LEN;//设置DMA传输数量<span style="white-space:pre"></span>DMA1_Channel3->CCR |= DMA_CCR1_EN;//使能DMA<span style="white-space:pre"></span><span style="white-space:pre"></span>}}void UART4_IRQHandler(void) //3G{<span style="white-space:pre"></span>if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>//USART_ClearITPendingBit(UART4, USART_IT_RXNE);<span style="white-space:pre"></span>tmp = UART4->SR;<span style="white-space:pre"></span>tmp = UART4->DR;<span style="white-space:pre"></span>serial4.RecvLen = UART_RECV_BUF_MAX_LEN - (u16)DMA2_Channel3->CNDTR;;<span style="white-space:pre"></span>serial4.Status &= ~UART_BUSY_FLAG;<span style="white-space:pre"></span>DMA_Cmd(DMA2_Channel3,DISABLE);<span style="white-space:pre"></span><span style="white-space:pre"></span>DMA2_Channel3->CNDTR = (u16)UART_RECV_BUF_MAX_LEN;<span style="white-space:pre"></span>DMA2_Channel3->CCR |= DMA_CCR1_EN;//使能DMA<span style="white-space:pre"></span>}}void UART5_IRQHandler(void)//外接485,连接云台{<span style="white-space:pre"></span>u8 ch;<span style="white-space:pre"></span>if(USART_GetITStatus(UART5, USART_IT_RXNE) != RESET)//一帧数据接受完才会进入<span style="white-space:pre"></span>{<span style="white-space:pre"></span>USART_ClearITPendingBit(UART5, USART_IT_RXNE);<span style="white-space:pre"></span>ch = UART5->DR;<span style="white-space:pre"></span><span style="white-space:pre"></span>}}
0 0
原创粉丝点击