之前有过一篇文章,不过那个只支持1个串口,而stm32f103大容量有5个串口,写这一篇的目的正是为了支持所有串口,可通过宏定义USE_USARTx进行设置使用串口的情况。关于基础部分,主要是原理的讲解可参考:https://blog.csdn.net/qq_40831436/article/details/115071656?spm=1001.2014.3001.5501
串口初始化讲解
初始化说明:5个串口并非所有串口都支持DMA传输,由下表所知,只有串口1-4具备DMA,而串口5无,所以,本程序中,串口1-4接收数据使用DMA传输,而串口5使用接收字节中断。 以下以串口1初始化为例:通过宏定义USE_USART1条件编译串口1初始化
#if USE_USART1
USARTx_Var_Init(&U1RxBuff,&g_U1RxFra);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USARTx_AFPP_GPIO_Config(USART1TX_GPIO_CLK,USART1TX_GPIO_PORT,USART1TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART1RX_GPIO_CLK,USART1RX_GPIO_PORT,USART1RX_GPIO_Pin);
USARTx_WorkMode_Config(USART1,115200,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
USARTx_NVIC_Config(USART1_IRQn,1,1);
USART_ClearITPendingBit(USART1,USART_IT_IDLE);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
USART_Cmd(USART1, ENABLE);
USARTx_RxDMA_Config(USART1,DMA1_Channel5,RCC_AHBPeriph_DMA1,(USART1_BASE+0x04),(uint32_t)U1RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
通过初始化之后,串口1接收缓冲区为:U1RxBuff.rxarr,即通过USARTx_RxDMA_Config函数进行配置。 而U1RxBuff定义如下:
#if USE_USART1
_USARTxRXBUFF U1RxBuff;
_FRAMEATTRI g_U1RxFra;
#endif
同样是通过条件编译,每个串口具备独立的串口接收缓冲区,互不干涉。
串口接收讲解
接收具备两种情况,一种是USART1-4,DMA接收,不用CPU干预,只需等待接收完成,进入空闲中断。而在空闲中断中的处理如下: 1、得到当前帧写入的结束地址 pRxBuff->wp; 2、将当前帧的起始地址 rp 赋值给帧记录队列 rpx进行记录 3、将当前帧的结束地址 wp 赋值给帧记录队列 wpx 进行记录 4、帧记录队列+1,等待前台处理数据 5、将 wp 赋值给 rp,一边记录下一个帧
static void USARTx_IDLE_IRQ(USART_TypeDef * pUSARTx,DMA_Channel_TypeDef* DMAy_Channelx,_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
uint16_t trnum=0;
pUSARTx->SR;
pUSARTx->DR;
if(DMAy_Channelx->CNDTR == 0)
{
trnum = UxRXBUFFSIZE;
}
else
{
trnum = DMAy_Channelx->CNDTR&0xffff;
}
pRxBuff->wp = UxRXBUFFSIZE-trnum;
pUxRxFra->fraddr[pUxRxFra->nextfra].rpx = pRxBuff->rp;
pUxRxFra->fraddr[pUxRxFra->nextfra].wpx = pRxBuff->wp;
pUxRxFra->nextfra = (pUxRxFra->nextfra+1)%FRADDRMAX;
pRxBuff->rp = pRxBuff->wp;
}
之后再空闲中断中调用 USARTxIDLE_IRQ()–调用–>USARTx_IDLE_IRQ()
void USARTxIDLE_IRQ(uint8_t Com_USARTx)
{
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
USARTx_IDLE_IRQ(USART1,USART1_RxDMA_CHANNEL,&U1RxBuff,&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
USARTx_IDLE_IRQ(USART2,USART2_RxDMA_CHANNEL,&U2RxBuff,&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
USARTx_IDLE_IRQ(USART3,USART3_RxDMA_CHANNEL,&U3RxBuff,&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
USARTx_IDLE_IRQ(UART4,USART4_RxDMA_CHANNEL,&U4RxBuff,&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
UART5_IDLE_IRQ(&U5RxBuff,&g_U5RxFra);
break;
#endif
default:
break;
}
}
接收的第二种情况是无DMA接收,需要CPU进行干预,则通过利用串口接收中断: 串口接收字节数据处理如下:
static void USART5_RXNE_IRQ(_USARTxRXBUFF *pRxBuff)
{
pRxBuff->rxarr[pRxBuff->wp] = USART_ReceiveData(UART5);
pRxBuff->wp = (pRxBuff->wp+1)%UxRXBUFFSIZE;
}
在串口接收中断中通过调用 USART5RXNE_IRQ()–调用–>USART5_RXNE_IRQ()接收数据。
void USART5RXNE_IRQ(void)
{
USART_ClearITPendingBit(UART5,USART_IT_RXNE);
USART5_RXNE_IRQ(&U5RxBuff);
}
对于无DMA的空闲中断中调用的函数处理如下:
static void UART5_IDLE_IRQ(_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
UART5->SR;
UART5->DR;
pUxRxFra->fraddr[pUxRxFra->nextfra].rpx = pRxBuff->rp;
pUxRxFra->fraddr[pUxRxFra->nextfra].wpx = pRxBuff->wp;
pUxRxFra->nextfra = (pUxRxFra->nextfra+1)%FRADDRMAX;
pRxBuff->rp = pRxBuff->wp;
}
在中断中调用情况如下:
#if USE_USART1
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART1);
}
}
#endif
#if USE_USART2
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART2);
}
}
#endif
#if USE_USART3
void USART3_IRQHandler(void)
{
if(USART_GetITStatus(USART3,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART3);
}
}
#endif
#if USE_USART4
void UART4_IRQHandler(void)
{
if(USART_GetITStatus(UART4,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART4);
}
}
#endif
#if USE_USART5
void UART5_IRQHandler(void)
{
if(USART_GetITStatus(UART5,USART_IT_RXNE)!=RESET)
{
USART5RXNE_IRQ();
}
if(USART_GetITStatus(UART5,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART5);
}
}
#endif
数据读取讲解
数据读取可参考先前文章,先判断是否有新的数据帧产生,即通过 currfra与 nextfra两个变量进行记录,其中nextfra变量在串口空闲中断中会+1,而当当前帧数据被应用层取出时:currfra+1。当currfra == nextfra时,说明所有的数据帧都已读取完毕。 从串口接收缓冲区中读取当前处理帧数据主要分为两种情况 一种是rpx<wpx,直接读取即可; 一种是wpx<rpx,说明接收时发生了接收缓冲区队列翻转情况,需要先读取:第一部分为rpx-(UxRXBUFFSIZE-1)的数据,第二部分为0-wpx的数据。
static uint8_t GetAFraFromUxRxBuff(uint8_t *pbuff,uint8_t *psize,_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxFra)
{
uint8_t rtflg=0;
uint16_t fralen=0;
if(pUxFra->currfra != pUxFra->nextfra)
{
if(pUxFra->fraddr[pUxFra->currfra].rpx<pUxFra->fraddr[pUxFra->currfra].wpx)
{
fralen = pUxFra->fraddr[pUxFra->currfra].wpx-pUxFra->fraddr[pUxFra->currfra].rpx;
for((*psize)=0;(*psize)<fralen;(*psize)++)
{
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx+(*psize)];
}
pUxFra->fraddr[pUxFra->currfra].rpx=pUxFra->fraddr[pUxFra->currfra].wpx;
}
else
{
for((*psize)=0;pUxFra->fraddr[pUxFra->currfra].rpx<UxRXBUFFSIZE;pUxFra->fraddr[pUxFra->currfra].rpx++)
{
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx];
(*psize)++;
}
pUxFra->fraddr[pUxFra->currfra].rpx = 0;
while(pUxFra->fraddr[pUxFra->currfra].rpx<pUxFra->fraddr[pUxFra->currfra].wpx)
{
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx];
(*psize)++;
pUxFra->fraddr[pUxFra->currfra].rpx++;
}
}
pUxFra->currfra = (pUxFra->currfra+1)%FRADDRMAX;
rtflg = 1;
}
return rtflg;
}
而应用层实际调用函数为:GetAFraFromComx()–调用–>GetAFraFromUxRxBuff()
uint8_t GetAFraFromComx(uint8_t Com_USARTx,uint8_t *pbuff,uint8_t *psize)
{
uint8_t rtflg=0;
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U1RxBuff,&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U2RxBuff,&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U3RxBuff,&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U4RxBuff,&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U5RxBuff,&g_U5RxFra);
break;
#endif
default:
break;
}
return rtflg;
}
而判断是否有新的未处理的数据帧可通过以下函数,(一般在OS中才使用本函数),裸机可直接通过调用GetAFraFromComx()函数判断。
static uint8_t JudgeUxFrameDataNum(_FRAMEATTRI *pUxFra)
{
uint8_t rtflg=0;
if(pUxFra->currfra != pUxFra->nextfra)
{
rtflg = 1;
}
else
{
rtflg = 0;
}
return rtflg;
}
uint8_t JudgeUxFraIsNull(uint8_t Com_USARTx)
{
uint8_t rtflg=0;
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
rtflg = JudgeUxFrameDataNum(&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
rtflg = JudgeUxFrameDataNum(&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
rtflg = JudgeUxFrameDataNum(&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
rtflg = JudgeUxFrameDataNum(&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
rtflg = JudgeUxFrameDataNum(&g_U5RxFra);
break;
#endif
default:
break;
}
return rtflg;
}
使用说明
简单使用本库只需知道一下宏定义与调用以下几个函数即可。 一、宏定义: 想要使用哪个串口只需将 USE_USARTx 宏定义为1即可 而要是使用中断优先级分组则将 NeedSet_NVICprio 宏定义为1,默认分组2
#define USE_USART1 1
#define USE_USART2 1
#define USE_USART3 1
#define USE_USART4 1
#define USE_USART5 1
#define NeedSet_NVICprio 1
二、使用函数说明:
void USARTx_Config(void);
void USARTxIDLE_IRQ(uint8_t Com_USARTx);
void USART5RXNE_IRQ(void);
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num);
uint8_t GetAFraFromComx(uint8_t Com_USARTx,uint8_t *pbuff,uint8_t *psize);
uint8_t JudgeUxFraIsNull(uint8_t Com_USARTx);
完整代码
bsp_usart_dma.h
#ifndef __USARTDMA_H
#define __USARTDMA_H
#include "stm32f10x.h"
#include <stdio.h>
#define USE_USART1 0
#define USE_USART2 1
#define USE_USART3 0
#define USE_USART4 0
#define USE_USART5 0
#define NeedSet_NVICprio 1
#define Com_USART1 1
#define Com_USART2 2
#define Com_USART3 3
#define Com_USART4 4
#define Com_USART5 5
#ifdef USE_USART1
#define USART1TX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART1TX_GPIO_PORT GPIOA
#define USART1TX_GPIO_Pin GPIO_Pin_9
#define USART1RX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART1RX_GPIO_PORT GPIOA
#define USART1RX_GPIO_Pin GPIO_Pin_10
#define USART1_RxDMA_CHANNEL DMA1_Channel5
#endif
#ifdef USE_USART2
#define USART2TX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART2TX_GPIO_PORT GPIOA
#define USART2TX_GPIO_Pin GPIO_Pin_2
#define USART2RX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART2RX_GPIO_PORT GPIOA
#define USART2RX_GPIO_Pin GPIO_Pin_3
#define USART2_RxDMA_CHANNEL DMA1_Channel6
#endif
#ifdef USE_USART3
#define USART3TX_GPIO_CLK RCC_APB2Periph_GPIOB
#define USART3TX_GPIO_PORT GPIOB
#define USART3TX_GPIO_Pin GPIO_Pin_10
#define USART3RX_GPIO_CLK RCC_APB2Periph_GPIOB
#define USART3RX_GPIO_PORT GPIOB
#define USART3RX_GPIO_Pin GPIO_Pin_11
#define USART3_RxDMA_CHANNEL DMA1_Channel3
#endif
#ifdef USE_USART4
#define USART4TX_GPIO_CLK RCC_APB2Periph_GPIOC
#define USART4TX_GPIO_PORT GPIOC
#define USART4TX_GPIO_Pin GPIO_Pin_10
#define USART4RX_GPIO_CLK RCC_APB2Periph_GPIOC
#define USART4RX_GPIO_PORT GPIOC
#define USART4RX_GPIO_Pin GPIO_Pin_11
#define USART4_RxDMA_CHANNEL DMA2_Channel3
#endif
#ifdef USE_USART5
#define USART5TX_GPIO_CLK RCC_APB2Periph_GPIOC
#define USART5TX_GPIO_PORT GPIOC
#define USART5TX_GPIO_Pin GPIO_Pin_12
#define USART5RX_GPIO_CLK RCC_APB2Periph_GPIOD
#define USART5RX_GPIO_PORT GPIOD
#define USART5RX_GPIO_Pin GPIO_Pin_2
#endif
#define UxRXBUFFSIZE 512
typedef struct __USARTxRXBUFF
{
uint16_t wp;
uint16_t rp;
uint8_t rxarr[UxRXBUFFSIZE];
}_USARTxRXBUFF;
typedef struct __FRAMEADDR
{
uint16_t wpx;
uint16_t rpx;
}_FRAMEADDR;
#define FRADDRMAX 10
typedef struct __FRAMEATTRI
{
_FRAMEADDR fraddr[FRADDRMAX];
uint8_t currfra;
uint8_t nextfra;
}_FRAMEATTRI;
void USARTx_Config(void);
void USARTxIDLE_IRQ(uint8_t Com_USARTx);
void USART5RXNE_IRQ(void);
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num);
uint8_t GetAFraFromComx(uint8_t Com_USARTx,uint8_t *pbuff,uint8_t *psize);
uint8_t JudgeUxFraIsNull(uint8_t Com_USARTx);
#endif
bsp_usart_dma.c
#include "bsp_usart_dma.h"
#if USE_USART1
_USARTxRXBUFF U1RxBuff;
_FRAMEATTRI g_U1RxFra;
#endif
#if USE_USART2
_USARTxRXBUFF U2RxBuff;
_FRAMEATTRI g_U2RxFra;
#endif
#if USE_USART3
_USARTxRXBUFF U3RxBuff;
_FRAMEATTRI g_U3RxFra;
#endif
#if USE_USART4
_USARTxRXBUFF U4RxBuff;
_FRAMEATTRI g_U4RxFra;
#endif
#if USE_USART5
_USARTxRXBUFF U5RxBuff;
_FRAMEATTRI g_U5RxFra;
#endif
static void USARTx_Var_Init(_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
pRxBuff->rp = 0;
pRxBuff->wp = 0;
pUxRxFra->currfra = 0;
pUxRxFra->nextfra = 0;
}
static void USARTx_NVIC_Config(uint8_t usartx_irqn,uint8_t preeprio,uint8_t subprio)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = usartx_irqn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preeprio;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
static void USARTx_AFPP_GPIO_Config(uint32_t RCC_APB2Periph,GPIO_TypeDef* GPIOx,uint16_t GPIO_Pinx)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pinx;
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
static void USARTx_FloatIN_GPIO_Config(uint32_t RCC_APB2Periph,GPIO_TypeDef* GPIOx,uint16_t GPIO_Pinx)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pinx;
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
static void USARTx_WorkMode_Config(USART_TypeDef* USARTx,uint32_t BaudRate,uint16_t WordLength,uint16_t StopBits,uint16_t Parity)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = BaudRate;
USART_InitStructure.USART_WordLength = WordLength;
USART_InitStructure.USART_StopBits = StopBits;
USART_InitStructure.USART_Parity = Parity ;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USARTx, &USART_InitStructure);
}
static void USARTx_RxDMA_Config(USART_TypeDef* USARTx,DMA_Channel_TypeDef* DMAy_Channelx,uint32_t RCC_DMAx,\
uint32_t PeriBsAddr,uint32_t MemBsAddr,uint32_t buffsize,uint32_t prio)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_DMAx, ENABLE);
DMA_InitStructure.DMA_PeripheralBaseAddr = PeriBsAddr;
DMA_InitStructure.DMA_MemoryBaseAddr = MemBsAddr;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = buffsize;
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_Circular ;
DMA_InitStructure.DMA_Priority = prio;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMAy_Channelx, &DMA_InitStructure);
DMA_Cmd (DMAy_Channelx,ENABLE);
USART_DMACmd(USARTx,USART_DMAReq_Rx,ENABLE);
}
void USARTx_Config(void)
{
#if NeedSet_NVICprio
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
#endif
#if USE_USART1
USARTx_Var_Init(&U1RxBuff,&g_U1RxFra);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USARTx_AFPP_GPIO_Config(USART1TX_GPIO_CLK,USART1TX_GPIO_PORT,USART1TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART1RX_GPIO_CLK,USART1RX_GPIO_PORT,USART1RX_GPIO_Pin);
USARTx_WorkMode_Config(USART1,115200,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
USARTx_NVIC_Config(USART1_IRQn,1,1);
USART_ClearITPendingBit(USART1,USART_IT_IDLE);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
USART_Cmd(USART1, ENABLE);
USARTx_RxDMA_Config(USART1,DMA1_Channel5,RCC_AHBPeriph_DMA1,(USART1_BASE+0x04),(uint32_t)U1RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART2
USARTx_Var_Init(&U2RxBuff,&g_U2RxFra);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
USARTx_AFPP_GPIO_Config(USART2TX_GPIO_CLK,USART2TX_GPIO_PORT,USART2TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART2RX_GPIO_CLK,USART2RX_GPIO_PORT,USART2RX_GPIO_Pin);
USARTx_WorkMode_Config(USART2,115200,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
USARTx_NVIC_Config(USART2_IRQn,1,1);
USART_ClearITPendingBit(USART2,USART_IT_IDLE);
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
USART_Cmd(USART2, ENABLE);
USARTx_RxDMA_Config(USART2,DMA1_Channel6,RCC_AHBPeriph_DMA1,(USART2_BASE+0x04),(uint32_t)U2RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART3
USARTx_Var_Init(&U3RxBuff,&g_U3RxFra);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
USARTx_AFPP_GPIO_Config(USART3TX_GPIO_CLK,USART3TX_GPIO_PORT,USART3TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART3RX_GPIO_CLK,USART3RX_GPIO_PORT,USART3RX_GPIO_Pin);
USARTx_WorkMode_Config(USART3,115200,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
USARTx_NVIC_Config(USART3_IRQn,1,1);
USART_ClearITPendingBit(USART3,USART_IT_IDLE);
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);
USART_Cmd(USART3, ENABLE);
USARTx_RxDMA_Config(USART3,DMA1_Channel3,RCC_AHBPeriph_DMA1,(USART3_BASE+0x04),(uint32_t)U3RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART4
USARTx_Var_Init(&U4RxBuff,&g_U4RxFra);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
USARTx_AFPP_GPIO_Config(USART4TX_GPIO_CLK,USART4TX_GPIO_PORT,USART4TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART4RX_GPIO_CLK,USART4RX_GPIO_PORT,USART4RX_GPIO_Pin);
USARTx_WorkMode_Config(UART4,115200,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
USARTx_NVIC_Config(UART4_IRQn,1,1);
USART_ClearITPendingBit(UART4,USART_IT_IDLE);
USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);
USART_Cmd(UART4, ENABLE);
USARTx_RxDMA_Config(UART4,DMA2_Channel3,RCC_AHBPeriph_DMA2,(UART4_BASE+0x04),(uint32_t)U4RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART5
USARTx_Var_Init(&U5RxBuff,&g_U5RxFra);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
USARTx_AFPP_GPIO_Config(USART5TX_GPIO_CLK,USART5TX_GPIO_PORT,USART5TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART5RX_GPIO_CLK,USART5RX_GPIO_PORT,USART5RX_GPIO_Pin);
USARTx_WorkMode_Config(UART5,115200,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
USARTx_NVIC_Config(UART5_IRQn,1,1);
USART_ClearITPendingBit(UART5,USART_IT_RXNE);
USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);
USART_ClearITPendingBit(UART5,USART_IT_IDLE);
USART_ITConfig(UART5, USART_IT_IDLE, ENABLE);
USART_Cmd(UART5, ENABLE);
#endif
}
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
USART_SendData(pUSARTx,ch);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i;
for(i=0; i<num; i++)
{
Usart_SendByte(pUSARTx,array[i]);
}
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
temp_h = (ch&0XFF00)>>8;
temp_l = ch&0XFF;
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
static void USARTx_IDLE_IRQ(USART_TypeDef * pUSARTx,DMA_Channel_TypeDef* DMAy_Channelx,_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
uint16_t trnum=0;
pUSARTx->SR;
pUSARTx->DR;
if(DMAy_Channelx->CNDTR == 0)
{
trnum = UxRXBUFFSIZE;
}
else
{
trnum = DMAy_Channelx->CNDTR&0xffff;
}
pRxBuff->wp = UxRXBUFFSIZE-trnum;
pUxRxFra->fraddr[pUxRxFra->nextfra].rpx = pRxBuff->rp;
pUxRxFra->fraddr[pUxRxFra->nextfra].wpx = pRxBuff->wp;
pUxRxFra->nextfra = (pUxRxFra->nextfra+1)%FRADDRMAX;
pRxBuff->rp = pRxBuff->wp;
}
#if USE_USART5
static void USART5_RXNE_IRQ(_USARTxRXBUFF *pRxBuff)
{
pRxBuff->rxarr[pRxBuff->wp] = USART_ReceiveData(UART5);
pRxBuff->wp = (pRxBuff->wp+1)%UxRXBUFFSIZE;
}
static void UART5_IDLE_IRQ(_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
UART5->SR;
UART5->DR;
pUxRxFra->fraddr[pUxRxFra->nextfra].rpx = pRxBuff->rp;
pUxRxFra->fraddr[pUxRxFra->nextfra].wpx = pRxBuff->wp;
pUxRxFra->nextfra = (pUxRxFra->nextfra+1)%FRADDRMAX;
pRxBuff->rp = pRxBuff->wp;
}
void USART5RXNE_IRQ(void)
{
USART_ClearITPendingBit(UART5,USART_IT_RXNE);
USART5_RXNE_IRQ(&U5RxBuff);
}
#endif
void USARTxIDLE_IRQ(uint8_t Com_USARTx)
{
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
USARTx_IDLE_IRQ(USART1,USART1_RxDMA_CHANNEL,&U1RxBuff,&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
USARTx_IDLE_IRQ(USART2,USART2_RxDMA_CHANNEL,&U2RxBuff,&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
USARTx_IDLE_IRQ(USART3,USART3_RxDMA_CHANNEL,&U3RxBuff,&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
USARTx_IDLE_IRQ(UART4,USART4_RxDMA_CHANNEL,&U4RxBuff,&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
UART5_IDLE_IRQ(&U5RxBuff,&g_U5RxFra);
break;
#endif
default:
break;
}
}
static uint8_t GetAFraFromUxRxBuff(uint8_t *pbuff,uint8_t *psize,_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxFra)
{
uint8_t rtflg=0;
uint16_t fralen=0;
if(pUxFra->currfra != pUxFra->nextfra)
{
if(pUxFra->fraddr[pUxFra->currfra].rpx<pUxFra->fraddr[pUxFra->currfra].wpx)
{
fralen = pUxFra->fraddr[pUxFra->currfra].wpx-pUxFra->fraddr[pUxFra->currfra].rpx;
for((*psize)=0;(*psize)<fralen;(*psize)++)
{
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx+(*psize)];
}
pUxFra->fraddr[pUxFra->currfra].rpx=pUxFra->fraddr[pUxFra->currfra].wpx;
}
else
{
for((*psize)=0;pUxFra->fraddr[pUxFra->currfra].rpx<UxRXBUFFSIZE;pUxFra->fraddr[pUxFra->currfra].rpx++)
{
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx];
(*psize)++;
}
pUxFra->fraddr[pUxFra->currfra].rpx = 0;
while(pUxFra->fraddr[pUxFra->currfra].rpx<pUxFra->fraddr[pUxFra->currfra].wpx)
{
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx];
(*psize)++;
pUxFra->fraddr[pUxFra->currfra].rpx++;
}
}
pUxFra->currfra = (pUxFra->currfra+1)%FRADDRMAX;
rtflg = 1;
}
return rtflg;
}
static uint8_t JudgeUxFrameDataNum(_FRAMEATTRI *pUxFra)
{
uint8_t rtflg=0;
if(pUxFra->currfra != pUxFra->nextfra)
{
rtflg = 1;
}
else
{
rtflg = 0;
}
return rtflg;
}
uint8_t GetAFraFromComx(uint8_t Com_USARTx,uint8_t *pbuff,uint8_t *psize)
{
uint8_t rtflg=0;
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U1RxBuff,&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U2RxBuff,&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U3RxBuff,&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U4RxBuff,&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U5RxBuff,&g_U5RxFra);
break;
#endif
default:
break;
}
return rtflg;
}
uint8_t JudgeUxFraIsNull(uint8_t Com_USARTx)
{
uint8_t rtflg=0;
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
rtflg = JudgeUxFrameDataNum(&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
rtflg = JudgeUxFrameDataNum(&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
rtflg = JudgeUxFrameDataNum(&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
rtflg = JudgeUxFrameDataNum(&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
rtflg = JudgeUxFrameDataNum(&g_U5RxFra);
break;
#endif
default:
break;
}
return rtflg;
}
中断服务函数中:
#if USE_USART1
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART1);
}
}
#endif
#if USE_USART2
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART2);
}
}
#endif
#if USE_USART3
void USART3_IRQHandler(void)
{
if(USART_GetITStatus(USART3,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART3);
}
}
#endif
#if USE_USART4
void UART4_IRQHandler(void)
{
if(USART_GetITStatus(UART4,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART4);
}
}
#endif
#if USE_USART5
void UART5_IRQHandler(void)
{
if(USART_GetITStatus(UART5,USART_IT_RXNE)!=RESET)
{
USART5RXNE_IRQ();
}
if(USART_GetITStatus(UART5,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART5);
}
}
#endif
main测试函数:
uint8_t parr[100],psize;
int main(void)
{
BSP_Init();
SysTick_Config(SystemCoreClock / 1000);
while(1)
{
if(GetAFraFromComx(Com_USART1,parr,&psize))
{
if(psize != 0)
{
Usart_SendArray(USART1,parr,psize);
}
}
if(GetAFraFromComx(Com_USART2,parr,&psize))
{
if(psize != 0)
{
Usart_SendArray(USART2,parr,psize);
}
}
if(GetAFraFromComx(Com_USART3,parr,&psize))
{
if(psize != 0)
{
Usart_SendArray(USART3,parr,psize);
}
}
if(GetAFraFromComx(Com_USART4,parr,&psize))
{
if(psize != 0)
{
Usart_SendArray(UART4,parr,psize);
}
}
if(GetAFraFromComx(Com_USART5,parr,&psize))
{
if(psize != 0)
{
Usart_SendArray(UART5,parr,psize);
}
}
}
}
兴起再写DMA发送队列
题外话
以上的都是会产生空闲中断的数据帧格式,如果数据帧无空闲,而是通过帧头帧尾判断的话,以下代码为串口接收处理参考。 通过帧头帧尾判断数据帧,无需配置空闲中断,而在串口接收中断中调用:
void USART1RXNE_IRQ(void)
{
static uint8_t afracnt=0;
uint8_t ch;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
afracnt++;
ch = USART_ReceiveData(DEBUG_USARTx)&0xff;
RxBuff.rxarr[RxBuff.wp] = ch;
RxBuff.wp=(RxBuff.wp+1)%RXBUFFSIZE;
if((ch == 0xf5)||(afracnt==50))
{
afracnt = 0;
g_Fra.fraddr[g_Fra.nextfra].rpx = RxBuff.rp;
g_Fra.fraddr[g_Fra.nextfra].wpx = RxBuff.wp;
g_Fra.nextfra = (g_Fra.nextfra+1)%FRADDRMAX;
RxBuff.rp = RxBuff.wp;
}
}
中断中为:
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)
{
USART1RXNE_IRQ();
}
if ( USART_GetITStatus( USART1, USART_IT_IDLE ) != RESET )
{
}
}
其余与上述一致。
|