您的位置:首页 > 其它

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

2015-04-14 11:02 471 查看
<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_1

extern 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;
b2c1
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>}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  stm32 usart 收发 dma