STM32F103 DMA模式操作UART

本文主要记录UART DMA操作方式,同时对STM32F103 UART驱动抽象出来实现帧数据接收

 

1、MDK工程目录(创建工程方式略)

 


main.c内容如下

运行后的结果是UART收到数据立即通过TX发送出去,同时LED状态反转一次

#include <stdio.h>

#include "stm32f10x.h"
#include "platform.h"

unsigned char led_count = 0;
void LED_Init(void){
    
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void uart_recv_str(UART_TypeDef *p, uint8_t *pbuf, uint16_t len){

    UART_ApiStructure.send_str(p, pbuf, len);
    GPIO_WriteBit(GPIOB, GPIO_Pin_9, (++led_count & 0x01) ? Bit_SET : Bit_RESET);    
}


int main(void){

    LED_Init();
    UART_ApiStructure.config(&UART_TypeDef_param, uart_recv_str);
    UART_ApiStructure.send_str(&UART_TypeDef_param, (uint8_t *)"uart init ok\r\n", 14);
    
    for(;;){}
}

 

uart.h

#ifndef __UART_H
#define __UART_H

typedef void (*pfunc_uart_gpio_init)(void);

/**
* @addtogroup 串口参数定义
* @{
*/

/** UART 数据处理设置 */
typedef struct{

    uint8_t *tx_buf;               /*!< 发送数据缓存 */
    uint8_t *rx_buf;               /*!< 接收数据缓存 */

    uint16_t tx_buf_len_max;       /*!< 发送数据最大缓存空间大小 */
    uint16_t rx_buf_len_max;       /*!< 接收数据最大缓存空间大小 */

    uint16_t rx_tail;               /*!< 接收数据缓存尾标识 */
    uint16_t rx_head;               /*!< 接收数据缓存头标识 */

}UART_UserParam;

/** DMA 参数设置 */
typedef struct{

    uint8_t  irq_tx;                  /*!< 发送通道中断号 */
    uint8_t  irq_rx;                  /*!< 接收通道中断号 */
    DMA_Channel_TypeDef *channel_tx;  /*!< 发送通道 */
    DMA_Channel_TypeDef *channel_rx;  /*!< 接收通道 */

    uint32_t TX_IT_FLAG_TCx;          /*!< 发送完成中断标志 */
    uint32_t RX_IT_FLAG_TCx;          /*!< 接收完成中断标志 */
}DMA_Param;

/** UART 参数设置 */
typedef struct{

    uint32_t baud;                           /*!< 波特率参数 */

    pfunc_uart_gpio_init pfunc_gpio_init;    /*!< 指向串口GPIO初始化函数指针 */
    
    USART_TypeDef* USARTx;                   /*!< 使用串口号 */
    uint8_t USARTx_IRQn;                     /*!< 串口接收中断号 */
    
    DMA_Param *DMAx;                         /*!< DMA参数指针 */

    UART_UserParam *user;                    /*!< UART数据处理指针 */
}UART_TypeDef;

/**
* @}
*/


/**
* @addtogroup API 接口定义
*/
typedef void (*pfunc_uart_rsend_str)(UART_TypeDef *p, uint8_t *pbuf, uint16_t len);
typedef uint8_t (*pfunc_uart_config)(UART_TypeDef *p, pfunc_uart_rsend_str cb);

typedef struct{

    pfunc_uart_config    config;    /*!< 初始化串口 */
    pfunc_uart_rsend_str send_str;  /*!< 发送数据 */
    pfunc_uart_rsend_str recv_cb;   /*!< 接收数据 */
    
}UART_ApiDef;

extern UART_ApiDef UART_ApiStructure;

/**
* @}
*/


#ifdef USE_PRINTF

extern int __printf(const char *fmt, ...);
#else

#define __printf(...)
#endif

#endif

 

uart.c

/**
* @file uart.c USART 驱动程序
*         
* @author T0213-ZH
* @date   2018.06.13 
*/

#include "platform.h"

/**
* @brief 配置USART参数
* @param p: 指向串口参数指针
* @param cb: 用于接收数据回调函数指针
*
* @retval 0-成功,1-已初始过了,2-未设置GPIO初始函数, 3-串口组参数不匹配
*/
static uint8_t uart_init(UART_TypeDef *p, pfunc_uart_rsend_str cb){
    
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;
    DMA_InitTypeDef   DMA_InitStructure;

    //if(g_uart_param) return 1;    

    if(!p->pfunc_gpio_init) return 2;

    if(cb)
        UART_ApiStructure.recv_cb = cb;
    
    //g_uart_param = p;

    p->pfunc_gpio_init();

    if(p->USARTx == USART1){
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); 
        
    }else if(p->USARTx == USART2){
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 
        
    }else if(p->USARTx == USART3){
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); 
        
    }else{ 
        return 3;
    }
    
    USART_InitStructure.USART_BaudRate = p->baud;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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(p->USARTx, &USART_InitStructure);    
    USART_Cmd(p->USARTx, ENABLE);

    USART_ClearFlag(p->USARTx, USART_FLAG_TC);   //注:避免首字符丢掉现象
    USART_ITConfig(p->USARTx, USART_IT_IDLE, ENABLE);


    NVIC_InitStructure.NVIC_IRQChannel = p->USARTx_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_DMACmd(p->USARTx, USART_DMAReq_Tx, ENABLE);
    USART_DMACmd(p->USARTx, USART_DMAReq_Rx, ENABLE);


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    //DMA TX Config
    DMA_DeInit(p->DMAx->channel_tx);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&p->USARTx->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)p->user->tx_buf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = p->user->tx_buf_len_max;
    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_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(p->DMAx->channel_tx, &DMA_InitStructure);
    //DMA_Cmd(p->DMAx->channel_tx, ENABLE)

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitStructure.NVIC_IRQChannel = p->DMAx->irq_tx;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    //DMA RX Config
    DMA_DeInit(p->DMAx->channel_rx);
    DMA_InitStructure.DMA_BufferSize = p->user->rx_buf_len_max;;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)p->user->rx_buf;
    DMA_Init(p->DMAx->channel_rx, &DMA_InitStructure);
    DMA_Cmd(p->DMAx->channel_rx, ENABLE);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitStructure.NVIC_IRQChannel = p->DMAx->irq_rx;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_ITConfig(p->DMAx->channel_tx, DMA_IT_TC, ENABLE);
    DMA_ITConfig(p->DMAx->channel_rx, DMA_IT_TC, ENABLE);    

    return 0;
}

/**
* @brief 发送数据接口
* @param p: 指向发送数据缓存指针
* @param len: 数据长度
*
* @retval none
*/
static void uart_send_str(UART_TypeDef *p, uint8_t *pbuf, uint16_t len){

  if(!len) return;

uint16_t i;
for(i=0; i<len; i++){ p->user->tx_buf[i] = *pbuf++; } while(DMA_GetFlagStatus(p->DMAx->TX_IT_FLAG_TCx) == SET); DMA_SetCurrDataCounter(p->DMAx->channel_tx, len); DMA_Cmd(p->DMAx->channel_tx, ENABLE); } /** * @brief 接收数据接口,中断触发 * * @retval none */ static void uart_recv_len(UART_TypeDef *p){ p->user->rx_head = p->user->rx_buf_len_max - DMA_GetCurrDataCounter(p->DMAx->channel_rx); if(p->user->rx_tail != p->user->rx_head){ uint16_t i = 0; uint8_t buf[p->user->rx_buf_len_max]; uint16_t head = p->user->rx_head; do{ buf[i++] = p->user->rx_buf[p->user->rx_tail++]; if(p->user->rx_tail == p->user->rx_buf_len_max) p->user->rx_tail = 0; }while(p->user->rx_tail != head); if(UART_ApiStructure.recv_cb){ UART_ApiStructure.recv_cb(p, buf, i); } //uart_send_str(buf, i); } } /** * @brief UART 接口函数 */ UART_ApiDef UART_ApiStructure = { .config = uart_init, /*!< 指向串口参数配置接口函数指针 */ .send_str = uart_send_str, /*!< 指向串口发送字符串接口函数指针 */ .recv_cb = 0, }; void uart_tx_irq(UART_TypeDef *p){ if(DMA_GetITStatus(p->DMAx->TX_IT_FLAG_TCx) == SET){ DMA_Cmd(p->DMAx->channel_tx, DISABLE); DMA_ClearITPendingBit(p->DMAx->TX_IT_FLAG_TCx); } } void uart_rx_irq(UART_TypeDef *p){ if(DMA_GetITStatus(p->DMAx->RX_IT_FLAG_TCx) == SET){ DMA_ClearITPendingBit(p->DMAx->RX_IT_FLAG_TCx); } } void uart_irq(UART_TypeDef *p){ if(USART_GetITStatus(p->USARTx, USART_IT_IDLE) != RESET){ USART_ReceiveData(p->USARTx); USART_ClearITPendingBit(p->USARTx, USART_IT_IDLE); uart_recv_len(p); } } #ifdef USE_PRINTF int __fputc(unsigned char ch, unsigned char *f){ /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(USART1, (uint8_t) ch); /* Loop until the end of transmission */ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {} return ch; } #endif

 

platform.c

#include "platform.h"

extern void uart_tx_irq(UART_TypeDef *p);
extern void uart_rx_irq(UART_TypeDef *p);
extern void uart_irq(UART_TypeDef *p); 

void USART_GpioInit(void){
    
    GPIO_InitTypeDef GPIO_InitStructure;    

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);    
}

/**
* @addtogroup 
* @{
*/
#define UART_TX_BUF_MAX (256)
#define UART_RX_BUF_MAX (256)

uint8_t uart_tx_buf[UART_TX_BUF_MAX];
uint8_t uart_rx_buf[UART_RX_BUF_MAX];


DMA_Param dma_param = {
    .irq_tx = DMA1_Channel4_IRQn,    
    .irq_rx = DMA1_Channel5_IRQn,    
    .channel_tx = DMA1_Channel4,     
    .channel_rx = DMA1_Channel5,     

    .TX_IT_FLAG_TCx = DMA1_IT_TC4,   
    .RX_IT_FLAG_TCx = DMA1_IT_TC5,   
};

/** UART  */
UART_UserParam uart_param = {
    .tx_buf = uart_tx_buf,            
    .rx_buf = uart_rx_buf,            
    .tx_buf_len_max = UART_TX_BUF_MAX,
    .rx_buf_len_max = UART_RX_BUF_MAX,
    .rx_tail = 0,                     
    .rx_head = 0,                     
};

/** UART */
UART_TypeDef UART_TypeDef_param = {
     
    .baud = 115200,                      
    .pfunc_gpio_init = USART_GpioInit,   
    .USARTx = USART1,                    
    .USARTx_IRQn = USART1_IRQn,          

    .DMAx = &dma_param,                  

    .user = &uart_param,                 
};

void DMA1_Channel4_IRQHandler(void){
    uart_tx_irq(&UART_TypeDef_param);
}

void DMA1_Channel5_IRQHandler(void){
     uart_rx_irq(&UART_TypeDef_param);
}

void USART1_IRQHandler(void){
    uart_irq(&UART_TypeDef_param);
}

/**
* @}
*/

 

posted @ 2018-11-07 15:55  不在+年华  阅读(4451)  评论(1编辑  收藏  举报