mbed serial_api模块移植到stm32f107vc(基于st32f1 cube1.4.0)

mbed平台是基于面向对象的c++语言实现的,serial_api是serial类的底层实现(c语言文件)。有些同学可能想在C工程中直接使用serial_api模块(本人就是其中之一,也这么做了,的确比直接调用hal抽象库要好用一些),可惜的是直接将其用在工程中很明显是不行的,至少中断的实现策略就过不去。但是又想用,那么这么办呢?很好办,自己动手修改serial_api及其相关的底层关联c文件(官方叫法“移植”),下面请围观移植过程:


一、移植文件列表

/* 包含引脚映射相关API */

pinmap.h

/* 引脚API实现 */

pinmap.c

/* gpio引脚命名 */

pinnames.h

/* gpio端口命名 */

portnames.h

/*(将serial_api.h修改为serial.h) 串口API */

serial.h

/*(将serial_api.c修改为serial.c)串口API实现 */

serial.c


二、中断解耦实现策略

其实很简单,在serial.c文件中定义一个 UART_HandleTypeDef *huart[5]指针数组,为什么是5呢?因为STM32F1系列MCU最多也就5个物理串口外设。分别保存USART1,USART2,USART3,UART4,UART5的实例句柄,在stm32F1xx_it.c调用中断服务程序是只需要传入对应的句柄即可,例如:

void USART2_IRQHandler(void)

{

HAL_UART_IRQHandler(huart[1]);  

}

在回调函数中则需要加一条判断语句来处理对应的实例数据,如下:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == sensor_serial.Instance){
        sensor_rx_ok = SET;
    }
}


void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == sensor_serial.Instance){
        HAL_UART_Receive_IT(&sensor_serial,(uint8_t *)sensor_rxbuf,64);
    }
}

这种策略在进行串口初始化的时候(调用serial_init()时),实现应用实例与物理串口的绑定,从而实现应用时的解耦。当然,还有另外一种实现策略,就是函数指针,但是这种策略需要对每一个物理串口都实现一组接口,没跟物理串口对应一个id,调用时通过ID来决定执行哪一个中断服务程序。同时这种策略需要重新设定中断向量。


三、pinnames.h

重新定义了引脚名称,使用外设时必须引用这里的引脚名称,否则外设将不能正常使用,切记!切记!,同时,该文件是一个全局文件,不是串口外设的私有文件,后续的I2C,SPI,GPIO,TIM,CAN等都会用到此文件。

/**
  ******************************************************************************
  * File Name          : pinnames.h
  * Description        : 
  ******************************************************************************
  */
#ifndef PIN_NAMES_H
#define PIN_NAMES_H


#ifdef __cplusplus
extern "C" {
#endif

// See stm32f3xx_hal_gpio.h and stm32f3xx_hal_gpio_ex.h for values of MODE, PUPD and AFNUM
#define STM_PIN_DATA(MODE, PUPD, AFNUM)  ((int)(((AFNUM) << 7) | ((PUPD) << 4) | ((MODE) << 0)))
#define STM_PIN_MODE(X)   (((X) >> 0) & 0x0F)
#define STM_PIN_PUPD(X)   (((X) >> 4) & 0x07)
#define STM_PIN_AFNUM(X)  (((X) >> 7) & 0x0F)
#define STM_MODE_INPUT              (0)
#define STM_MODE_OUTPUT_PP          (1)
#define STM_MODE_OUTPUT_OD          (2)
#define STM_MODE_AF_PP              (3)
#define STM_MODE_AF_OD              (4)
#define STM_MODE_ANALOG             (5)
#define STM_MODE_IT_RISING          (6)
#define STM_MODE_IT_FALLING         (7)
#define STM_MODE_IT_RISING_FALLING  (8)
#define STM_MODE_EVT_RISING         (9)
#define STM_MODE_EVT_FALLING        (10)
#define STM_MODE_EVT_RISING_FALLING (11)
#define STM_MODE_IT_EVT_RESET       (12)

// High nibble = port number (0=A, 1=B, 2=C, 3=D, 4=E, 5=F, 6=G, 7=H)
// Low nibble  = pin number
#define STM_PORT(X) (((uint32_t)(X) >> 4) & 0xF)
#define STM_PIN(X)  ((uint32_t)(X) & 0xF)

typedef enum {
    PIN_INPUT,
    PIN_OUTPUT
} PinDirection;

typedef enum {
    PA_0  = 0x00,
    PA_1  = 0x01,
    PA_2  = 0x02,
    PA_3  = 0x03,
    PA_4  = 0x04,
    PA_5  = 0x05,
    PA_6  = 0x06,
    PA_7  = 0x07,
    PA_8  = 0x08,
    PA_9  = 0x09,
    PA_10 = 0x0A,
    PA_11 = 0x0B,
    PA_12 = 0x0C,
    PA_13 = 0x0D,
    PA_14 = 0x0E,
    PA_15 = 0x0F,

    PB_0  = 0x10,
    PB_1  = 0x11,
    PB_2  = 0x12,
    PB_3  = 0x13,
    PB_4  = 0x14,
    PB_5  = 0x15,
    PB_6  = 0x16,
    PB_7  = 0x17,
    PB_8  = 0x18,
    PB_9  = 0x19,
    PB_10 = 0x1A,
    PB_11 = 0x1B,
    PB_12 = 0x1C,
    PB_13 = 0x1D,
    PB_14 = 0x1E,
    PB_15 = 0x1F,

    PC_0  = 0x20,
    PC_1  = 0x21,
    PC_2  = 0x22,
    PC_3  = 0x23,
    PC_4  = 0x24,
    PC_5  = 0x25,
    PC_6  = 0x26,
    PC_7  = 0x27,
    PC_8  = 0x28,
    PC_9  = 0x29,
    PC_10 = 0x2A,
    PC_11 = 0x2B,
    PC_12 = 0x2C,
    PC_13 = 0x2D,
    PC_14 = 0x2E,
    PC_15 = 0x2F,

    PD_0  = 0x30,
    PD_1  = 0x31,
    PD_2  = 0x32,
    PD_3  = 0x33,
    PD_4  = 0x34,
    PD_5  = 0x35,
    PD_6  = 0x36,
    PD_7  = 0x37,
    PD_8  = 0x38,
    PD_9  = 0x39,
    PD_10 = 0x3A,
    PD_11 = 0x3B,
    PD_12 = 0x3C,
    PD_13 = 0x3D,
    PD_14 = 0x3E,
    PD_15 = 0x3F,
    
    PE_0  = 0x40,
    PE_1  = 0x41,
    PE_2  = 0x42,
    PE_3  = 0x43,
    PE_4  = 0x44,
    PE_5  = 0x45,
    PE_6  = 0x46,
    PE_7  = 0x47,
    PE_8  = 0x48,
    PE_9  = 0x49,
    PE_10 = 0x4A,
    PE_11 = 0x4B,
    PE_12 = 0x4C,
    PE_13 = 0x4D,
    PE_14 = 0x4E,
    PE_15 = 0x4F,
    
    PF_0  = 0x50,
    PF_1  = 0x51,
    PF_2  = 0x52,
    PF_3  = 0x53,
    PF_4  = 0x54,
    PF_5  = 0x55,
    PF_6  = 0x56,
    PF_7  = 0x57,
    PF_8  = 0x58,
    PF_9  = 0x59,
    PF_10 = 0x5A,
    PF_11 = 0x5B,
    PF_12 = 0x5C,
    PF_13 = 0x5D,
    PF_14 = 0x5E,
    PF_15 = 0x5F,
    
    PG_0  = 0x60,
    PG_1  = 0x61,
    PG_2  = 0x62,
    PG_3  = 0x63,
    PG_4  = 0x64,
    PG_5  = 0x65,
    PG_6  = 0x66,
    PG_7  = 0x67,
    PG_8  = 0x68,
    PG_9  = 0x69,
    PG_10 = 0x6A,
    PG_11 = 0x6B,
    PG_12 = 0x6C,
    PG_13 = 0x6D,
    PG_14 = 0x6E,
    PG_15 = 0x6F,
    
    PH_0  = 0x70,
    PH_1  = 0x71,
    PH_2  = 0x72,
    PH_3  = 0x73,
    PH_4  = 0x74,
    PH_5  = 0x75,
    PH_6  = 0x76,
    PH_7  = 0x77,
    PH_8  = 0x78,
    PH_9  = 0x79,
    PH_10 = 0x7A,
    PH_11 = 0x7B,
    PH_12 = 0x7C,
    PH_13 = 0x7D,
    PH_14 = 0x7E,
    PH_15 = 0x7F,

    // Arduino connector namings
    A0          = PA_0,
    A1          = PA_1,
    A2          = PA_4,
    A3          = PB_0,
    A4          = PC_1,
    A5          = PC_0,
    D0          = PA_3,
    D1          = PA_2,
    D2          = PA_10,
    D3          = PB_3,
    D4          = PB_5,
    D5          = PB_4,
    D6          = PB_10,
    D7          = PA_8,
    D8          = PA_9,
    D9          = PC_7,
    D10         = PB_6,
    D11         = PA_7,
    D12         = PA_6,
    D13         = PA_5,
    D14         = PB_9,
    D15         = PB_8,


    // Not connected
    NC = (uint32_t)0xFFFFFFFF
} PinName;



#ifdef __cplusplus
}
#endif

#endif

四、pinmap.h

定义了一个map结构体,以及引脚映射的外部API。同pinnames.h,该文件也是一个全局文件。
/**
  ******************************************************************************
  * File Name          : pinmap.h
  * Description        : 
  ******************************************************************************
  */

#ifndef _PIN_MAP_H
#define _PIN_MAP_H




/* 与mbed的pinmap结构有些不同 ,主意区别 */
typedef struct{
    uint32_t    pin;            /* 外设引脚,必须使用pinnames.h中定义的引脚名称 */
    uint32_t    pin_port;       /* 引脚端口基地址,例如:GPIOB_BASE */       
    uint32_t    peripheral;     /* 外设基地址,例如:USART1_BASE */
    uint32_t    remap;          /* 引脚重映射 */
    uint32_t    mode;           /* 引脚输入输出模式 */
    uint32_t    pupd;           /* 上下拉电阻 */
}pinmap_t; 

/* 引脚配置函数 */
void     pinmap_pinout(uint32_t pin,const pinmap_t *map);

/* 引脚端口合并 */
uint32_t pinmap_merge(uint32_t a,uint32_t b);

/* 查找引脚对应的外设,返回外设基地址 */
uint32_t pinmap_find_peripheral(uint32_t pin,const pinmap_t *map);

/* 调用 pinmap_find_peripheral,返回外设地址 */
uint32_t pinmap_peripheral(uint32_t pin,const pinmap_t *map);


#endif

五、pinmap.c

pinmap.h对应的接口实现文件。

/**
  ******************************************************************************
  * File Name          : pinmap.c
  * Description        : 
  ******************************************************************************
  */

#include "stm32f1xx.h"
#include "pinmap.h"
#include "pinnames.h"
#include "ierror.h"
#include "iassert.h"

/* private function *******************************************/
static void pin_function(const pinmap_t *map);
static void set_gpio_clock(const pinmap_t *map);


void pinmap_pinout(uint32_t pin, const pinmap_t *map) {
    if (pin == NC)
        return;

    while (map->pin != NC) {
        if (map->pin == pin) {
            pin_function(map);
            return;
        }
        map++;
    }
    error("could not pinout");
}

void pin_function(const pinmap_t *map)
{
    I_ASSERT(map->pin != NC);
    
    /* enable AFIO clock */
    set_gpio_clock(map);
    __HAL_RCC_AFIO_CLK_ENABLE();
    
    /* configure alternate function */
    if(map->remap>0){
        switch(map->remap){
        case AFIO_MAPR_SPI1_REMAP:
            __HAL_AFIO_REMAP_SPI1_ENABLE();
            break;
        case AFIO_MAPR_I2C1_REMAP:
            __HAL_AFIO_REMAP_I2C1_ENABLE();
            break;
        case AFIO_MAPR_USART1_REMAP:
            __HAL_AFIO_REMAP_USART1_ENABLE();
            break;
        case AFIO_MAPR_USART2_REMAP:
            __HAL_AFIO_REMAP_USART2_ENABLE();
            break;
        case AFIO_MAPR_USART3_REMAP_FULLREMAP:
            __HAL_AFIO_REMAP_USART3_ENABLE();
            break;
        case AFIO_MAPR_USART3_REMAP_PARTIALREMAP:
            __HAL_AFIO_REMAP_USART3_PARTIAL();
            break;
        case AFIO_MAPR_TIM1_REMAP_PARTIALREMAP:
            __HAL_AFIO_REMAP_TIM1_PARTIAL();
            break;
        case AFIO_MAPR_TIM1_REMAP_FULLREMAP:
            __HAL_AFIO_REMAP_TIM1_ENABLE();
            break;
        case AFIO_MAPR_TIM2_REMAP_PARTIALREMAP1:
            __HAL_AFIO_REMAP_TIM2_PARTIAL_1();
            break;
        case AFIO_MAPR_TIM2_REMAP_PARTIALREMAP2:
            __HAL_AFIO_REMAP_TIM2_PARTIAL_2();
            break;
        case AFIO_MAPR_TIM2_REMAP_FULLREMAP:
            __HAL_AFIO_REMAP_TIM2_ENABLE();
            break;
        case AFIO_MAPR_TIM3_REMAP_PARTIALREMAP:
            __HAL_AFIO_REMAP_TIM3_PARTIAL();
            break;
        case AFIO_MAPR_TIM3_REMAP_FULLREMAP:
            __HAL_AFIO_REMAP_TIM3_ENABLE();
            break;
        case AFIO_MAPR_TIM4_REMAP:
            __HAL_AFIO_REMAP_TIM4_ENABLE();
            break;
        default:
            break;
        }
    }
    
    GPIO_InitTypeDef        gpio_initstruct;
    gpio_initstruct.Pin     = (uint32_t)(1<<(map->pin & 0xF));
    gpio_initstruct.Mode    = map->mode;
    gpio_initstruct.Pull    = map->pupd;
    gpio_initstruct.Speed   = GPIO_SPEED_HIGH;
    HAL_GPIO_Init((GPIO_TypeDef *)map->pin_port,&gpio_initstruct);
    
    if((map->pin == PA_13) || (map->pin == PA_14))
       __HAL_AFIO_REMAP_SWJ_DISABLE();              /* JTAG-DP Disabled and SW-DP Disabled */
    
    if((map->pin == PA_15) || (map->pin == PB_3))
        __HAL_AFIO_REMAP_SWJ_NOJTAG();              /* JTAG-DP Disabled and SW-DP enabled */
    
    
}

void set_gpio_clock(const pinmap_t *map)
{
    if(map == NULL)
        return;
    
    switch(map->pin_port){
    case GPIOA_BASE:
        __GPIOA_CLK_ENABLE();
        break;
    case GPIOB_BASE:
        __GPIOB_CLK_ENABLE();
        break;
    case GPIOC_BASE:
        __GPIOC_CLK_ENABLE();
        break;
    case GPIOD_BASE:
        __GPIOD_CLK_ENABLE();
        break;
    case GPIOE_BASE:
        __GPIOE_CLK_ENABLE();
        break;
    default:
        error("Pinmap error: wrong port number.");
        break;
    }
}

uint32_t pinmap_merge(uint32_t a,uint32_t b)
{
    // both are the same (inc both NC)
    if (a == b)
        return a;

    // one (or both) is not connected
    if (a == (uint32_t)NC)
        return b;
    if (b == (uint32_t)NC)
        return a;

    // mis-match error case
    error("pinmap mis-match");
    return (uint32_t)NC;    
}


uint32_t pinmap_find_peripheral(uint32_t pin,const pinmap_t *map)
{
    while(map->pin != NC){
        if(map->pin == pin)
            return map->peripheral;
        
        map++;
    }
    return (uint32_t)NC;
}


uint32_t pinmap_peripheral(uint32_t pin,const pinmap_t *map)
{
    uint32_t  peripheral = (uint32_t)NC;
    
    if(pin == NC)
        return (uint32_t)NC;
    
    peripheral = pinmap_find_peripheral(pin,map);
    if((uint32_t)NC == peripheral)
        error("pinmap not found for peripheral");
    return peripheral;
}

六、serial.h

包含了通用的串口操作api,没有对数据接收和发送进行封装,使用hal uart库的接收发送API。

/**
  ******************************************************************************
  * File Name          : serial.h
  * Description        : 
  ******************************************************************************
  */

#ifndef  _SERIAL_H
#define  _SERIAL_H


/* inlcude *********************************/
#include "stm32f1xx.h"

typedef enum{
    UART_1 = (uint32_t)USART1_BASE,
    UART_2 = (uint32_t)USART2_BASE,
    UART_3 = (uint32_t)USART3_BASE,
    UART_4 = (uint32_t)UART4_BASE,
    UART_5 = (uint32_t)UART5_BASE
}UART_NAME;



/**
  * 实际使用接口时的调用顺序:
  * 首先调用serial_init进行默认初始化
  * 其次调用serial_baud设定波特率
  * 再次调用serial_format格式化串口参数
  * 最后调用serial_irq_set配置NVIC全局中断并使能外部中断
  * */
 
void serial_init(UART_HandleTypeDef *handle,uint32_t tx,uint32_t rx);
void serial_free(UART_HandleTypeDef *huart);
void serial_baud(UART_HandleTypeDef *huart,uint32_t baud);
void serial_format(UART_HandleTypeDef *huart,uint32_t data_bits,uint32_t parity,uint32_t stop_bits);
void serial_irq_set(UART_HandleTypeDef *huart,uint32_t preempt_prio,uint32_t sub_prio);
void serial_irq_enable(UART_HandleTypeDef *huart);
void serial_irq_disable(UART_HandleTypeDef *huart);



#endif

七、serial.c

串口api的实现源文件。

/**
  ******************************************************************************
  * File Name          : serial.c
  * Description        : 
  ******************************************************************************
  */

#include "serial.h"
#include "pinmap.h"
#include "pinnames.h"
#include "portnames.h"
#include "ierror.h"
#include "iassert.h"

/* private function */
static void init_uart(UART_HandleTypeDef *huart,uint32_t tx,uint32_t rx);

/* variable ************************************************/
/* 外设引脚映射表,每一个外设都会有这么1个静态映射表与之对应 */
/* 串口发送引脚TX映射表 */
const static pinmap_t   UART_TX_TAB[]= {
    {PA_9, GPIOA_BASE,UART_1,0,GPIO_MODE_AF_PP,GPIO_NOPULL},
    {PB_6, GPIOB_BASE,UART_1,AFIO_MAPR_USART1_REMAP,GPIO_MODE_AF_PP,GPIO_NOPULL},
    {PA_2, GPIOA_BASE,UART_2,0,GPIO_MODE_AF_PP,GPIO_NOPULL},
    {PD_5, GPIOD_BASE,UART_2,AFIO_MAPR_USART2_REMAP,GPIO_MODE_AF_PP,GPIO_NOPULL},
    {PB_10,GPIOB_BASE,UART_3,0},    
    {PD_8, GPIOD_BASE,UART_3,AFIO_MAPR_USART3_REMAP_FULLREMAP,GPIO_MODE_AF_PP,GPIO_NOPULL},       /* 全部重映射 */ 
    {PC_10,GPIOC_BASE,UART_4,0,GPIO_MODE_AF_PP,GPIO_NOPULL}, 
    {PC_12,GPIOC_BASE,UART_5,0,GPIO_MODE_AF_PP,GPIO_NOPULL},
    {NC,   NC,        NC,    0,NC,             NC}
};

/* 串口发送引脚RX映射表 */
const static pinmap_t   UART_RX_TAB[]= {
    {PA_10,GPIOA_BASE,UART_1,0,GPIO_MODE_INPUT,GPIO_NOPULL},
    {PB_7, GPIOB_BASE,UART_1,AFIO_MAPR_USART1_REMAP,GPIO_MODE_INPUT,GPIO_NOPULL},
    {PA_3, GPIOA_BASE,UART_2,0,GPIO_MODE_INPUT,GPIO_NOPULL},
    {PD_6, GPIOD_BASE,UART_2,AFIO_MAPR_USART2_REMAP,GPIO_MODE_INPUT,GPIO_NOPULL},
    {PB_11,GPIOB_BASE,UART_3,0,GPIO_MODE_INPUT,GPIO_NOPULL},
    {PD_9, GPIOD_BASE,UART_3,AFIO_MAPR_USART3_REMAP,GPIO_MODE_INPUT,GPIO_NOPULL},
    {PC_11,GPIOC_BASE,UART_4,0,GPIO_MODE_INPUT,GPIO_NOPULL},
    {PD_2, GPIOD_BASE,UART_5,0,GPIO_MODE_INPUT,GPIO_NOPULL},
    {NC,   NC,        NC,    0,NC,             NC}
};

/* 保存串口实例句柄,用于中断服务程序 */
UART_HandleTypeDef  *huart[5] = {NULL,NULL,NULL,NULL,NULL};




/*****************************************************************************/
void serial_init(UART_HandleTypeDef *handle,uint32_t tx,uint32_t rx)
{
    UART_NAME uart = (UART_NAME)NC;
    UART_NAME uart_tx = (UART_NAME)pinmap_peripheral(tx,UART_TX_TAB);
    UART_NAME uart_rx = (UART_NAME)pinmap_peripheral(rx,UART_RX_TAB);
    
    uart = (UART_NAME)pinmap_merge(uart_tx,uart_rx);
    I_ASSERT(uart != (UART_NAME)NC);
    
    handle->Instance = (USART_TypeDef *)uart;
    
    /* enable clock */
    if(uart == UART_1){
        __HAL_RCC_USART1_CLK_ENABLE();
        huart[0] = handle;
    }
    
    if(uart == UART_2){
        __HAL_RCC_USART2_CLK_ENABLE();
        huart[1] = handle;
    }
    
    if(uart == UART_3){
        __HAL_RCC_USART3_CLK_ENABLE();
        huart[2] = handle;
    }
    
    if(uart == UART_4){
        __HAL_RCC_UART4_CLK_ENABLE();
        huart[3] = handle;
    }
    
    if(uart == UART_5){
        __HAL_RCC_UART5_CLK_ENABLE();
        huart[4] = handle;
    }
        
    pinmap_pinout(tx,UART_TX_TAB);
    pinmap_pinout(rx,UART_RX_TAB);
    
    init_uart(handle,tx,rx);
}

static void init_uart(UART_HandleTypeDef *huart,uint32_t tx,uint32_t rx)
{
    huart->Init.BaudRate    = 9600;
    huart->Init.WordLength  = UART_WORDLENGTH_8B;
    huart->Init.StopBits    = UART_STOPBITS_1;
    huart->Init.Parity      = UART_PARITY_NONE;
    huart->Init.HwFlowCtl   = UART_HWCONTROL_NONE;
    huart->Init.OverSampling = UART_OVERSAMPLING_16;
    
    if(rx == NC){
        huart->Init.Mode    = UART_MODE_TX;
    }else if(tx == NC){
        huart->Init.Mode    = UART_MODE_RX;
    }else{
        huart->Init.Mode    = UART_MODE_TX_RX;
    }
    
    HAL_UART_Init(huart);
}


void serial_free(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        __USART1_FORCE_RESET();
        __USART1_RELEASE_RESET();
        __USART1_CLK_DISABLE();
        HAL_NVIC_DisableIRQ(USART1_IRQn);
    }
    
    if(huart->Instance == USART2){
        __USART2_FORCE_RESET();
        __USART2_RELEASE_RESET();
        __USART2_CLK_DISABLE();
        HAL_NVIC_DisableIRQ(USART2_IRQn);
    }
    
    if(huart->Instance == USART3){
        __USART3_FORCE_RESET();
        __USART3_RELEASE_RESET();
        __USART3_CLK_DISABLE();
        HAL_NVIC_DisableIRQ(USART3_IRQn);
    }
    
    if(huart->Instance == UART4){
        __UART4_FORCE_RESET();
        __UART4_RELEASE_RESET();
        __UART4_CLK_DISABLE();
        HAL_NVIC_DisableIRQ(UART4_IRQn);
    }
    
    if(huart->Instance == UART5){
        __UART5_FORCE_RESET();
        __UART5_RELEASE_RESET();
        __UART5_CLK_DISABLE();
        HAL_NVIC_DisableIRQ(UART5_IRQn);
    }
}


void serial_baud(UART_HandleTypeDef *huart,uint32_t baud)
{
    huart->Init.BaudRate = baud;
    HAL_UART_Init(huart);
}

void serial_format(UART_HandleTypeDef *huart,uint32_t data_bits,uint32_t parity,uint32_t stop_bits)
{
    huart->Init.WordLength  = data_bits;
    huart->Init.Parity      = parity;
    huart->Init.StopBits    = stop_bits;
    HAL_UART_Init(huart);
}

void serial_irq_set(UART_HandleTypeDef *huart,uint32_t preempt_prio,uint32_t sub_prio)
{
    IRQn_Type irq;
    
    if(huart->Instance == USART1)
        irq = USART1_IRQn;
    
    if(huart->Instance == USART2)
        irq = USART2_IRQn;
    
    if(huart->Instance == USART3)
        irq = USART3_IRQn;
    
    if(huart->Instance == UART4)
        irq = UART4_IRQn;
    
    if(huart->Instance == UART5)
        irq = UART5_IRQn;
    
    HAL_NVIC_SetPriority(irq,preempt_prio,sub_prio);
    HAL_NVIC_EnableIRQ(irq);
	//NVIC_SetVector(
}

void serial_irq_enable(UART_HandleTypeDef *huart)
{
    IRQn_Type irq;
    
    if(huart->Instance == USART1)
        irq = USART1_IRQn;
    
    if(huart->Instance == USART2)
        irq = USART2_IRQn;
    
    if(huart->Instance == USART3)
        irq = USART3_IRQn;
    
    if(huart->Instance == UART4)
        irq = UART4_IRQn;
    
    if(huart->Instance == UART5)
        irq = UART5_IRQn;
    
    HAL_NVIC_EnableIRQ(irq);
}


void serial_irq_disable(UART_HandleTypeDef *huart)
{
    IRQn_Type irq;
    
    if(huart->Instance == USART1)
        irq = USART1_IRQn;
    
    if(huart->Instance == USART2)
        irq = USART2_IRQn;
    
    if(huart->Instance == USART3)
        irq = USART3_IRQn;
    
    if(huart->Instance == UART4)
        irq = UART4_IRQn;
    
    if(huart->Instance == UART5)
        irq = UART5_IRQn;
    
    HAL_NVIC_DisableIRQ(irq);
}

八、test.c

1个应用实例。

#include "stm32f1xx_hal.h"
#include "pinnames.h"



/* serial                  */
#define  SENSOR_SERIAL_TX                  PD_5
#define  SENSOR_SERIAL_RX                  PD_6


/* public variable ***********************************************************/
UART_HandleTypeDef sensor_serial;
uint8_t  sensor_txbuf[64]={0};
uint8_t  sensor_rxbuf[64]={0};
int32_t  sensor_conc = -1;
uint8_t sensor_rx_ok = RESET;



/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);


int main(void)
{

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();
  
  /* 初始化串口 */
    serial_init(&sensor_serial,SENSOR_SERIAL_TX,SENSOR_SERIAL_RX);
    serial_irq_set(&sensor_serial,1,0);
    HAL_UART_Receive_IT(&sensor_serial,(uint8_t *)sensor_rxbuf,64);


  while (1)
  {
    if(sensor_rx_ok == SET)
    {
        sensor_rx_ok = RESET;
    }
  }

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV5;
  RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
  RCC_OscInitStruct.Prediv1Source = RCC_PREDIV1_SOURCE_PLL2;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4;
  RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL2_ON;
  RCC_OscInitStruct.PLL2.PLL2MUL = RCC_PLL2_MUL8;
  RCC_OscInitStruct.PLL2.HSEPrediv2Value = RCC_HSE_PREDIV2_DIV5;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  __HAL_RCC_PLLI2S_ENABLE();

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}

/* usart callback function *********************************************/

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == sensor_serial.Instance){
        sensor_rx_ok = SET;
    }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == sensor_serial.Instance){
        HAL_UART_Receive_IT(&sensor_serial,(uint8_t *)sensor_rxbuf,64);
    } 	
    
}

九、stm hal库串口驱动的一个问题

使用stm32 hal抽象库的同学都会碰到1个问题,就是在使用串口中断接收数据的时候,当设定的缓冲区大小和接收字节大小不一致时就会导致串口错误(缓冲区大小是接收字节大小的整数倍除外),溢出错误无限循环。举个例子:rxbuf【20】,接收大小11,第一次接收正常,第二次接收就会出错了。
一般应用协议的长度肯定不是固定长度的,所以使用官方库肯定会出问题。那么,怎么办呢,长度不固定,协议肯定会有一个结束符,一般都会以\r\n结束。本人的做法是修改stm32f1xx_hal_uart.c中的下面这个静态函数,代码中红色部分:
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
  uint16_t* tmp;
  uint32_t tmp_state = 0;
  
  tmp_state = huart->State; 
  if((tmp_state == HAL_UART_STATE_BUSY_RX) || (tmp_state == HAL_UART_STATE_BUSY_TX_RX))
  {
    if(huart->Init.WordLength == UART_WORDLENGTH_9B)
    {
      tmp = (uint16_t*) huart->pRxBuffPtr;
      if(huart->Init.Parity == UART_PARITY_NONE)
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
        huart->pRxBuffPtr += 2;
      }
      else
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
        huart->pRxBuffPtr += 1;
      }
    }
    else
    {
      if(huart->Init.Parity == UART_PARITY_NONE)
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
      }
      else
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
      }
    }


 //   if(--huart->RxXferCount == 0)
    if(*(huart->pRxBuffPtr-1) == '\n')

    {
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);


      /* Check if a transmit process is ongoing or not */
      if(huart->State == HAL_UART_STATE_BUSY_TX_RX) 
      {
        huart->State = HAL_UART_STATE_BUSY_TX;
      }
      else
      {
        /* Disable the UART Parity Error Interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_PE);


        /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);


        huart->State = HAL_UART_STATE_READY;
      }
      HAL_UART_RxCpltCallback(huart);


      return HAL_OK;
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}


如此这般,只要你得缓冲区足够大,就不会有问题!





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值