Ver Fonte

串口驱动完成

樊春春 há 5 meses atrás
pai
commit
99fa4cd321
10 ficheiros alterados com 842 adições e 1 exclusões
  1. 4 0
      app/app_task.c
  2. 157 0
      dev/dev_uart4.c
  3. 52 0
      dev/dev_uart4.h
  4. 203 0
      dev/dev_uart_table.c
  5. 50 0
      dev/dev_uart_table.h
  6. 171 0
      hal/hal_uart.c
  7. 2 1
      hal/hal_uart.h
  8. 136 0
      hal/hal_uart4.c
  9. 64 0
      hal/hal_uart4.h
  10. 3 0
      user/main.c

+ 4 - 0
app/app_task.c

@@ -5,7 +5,9 @@
 #include "cli.h"
 #include "dev_at24cxx.h"
 #include "dev_can.h"
+#include "dev_uart4.h"
 #include "hal_systick.h"
+#include "hal_uart4.h"
 #include "stm32f4xx_tim.h"
 #include <stdint.h>
 #include <stdio.h>
@@ -28,6 +30,7 @@ static uint32_t systick_ms_clock = 0;
 ----------------------------------------*/
 static void app_task_5ms(void)
 {
+    uart_task();
     dev_key_button_task();
     can_process();
     cli_loop();
@@ -188,6 +191,7 @@ void SysTick_Handler(void)
     dev_task_clock();
     dev_systick_decrement();
     dev_systick_increase();
+    uart4_rx_ticks();
     systick_handler();
     jump_boot_time_ctrl();
 }

+ 157 - 0
dev/dev_uart4.c

@@ -0,0 +1,157 @@
+#include "dev_uart4.h"
+#include "dev_uart_table.h"
+#include "hal_uart4.h"
+#include "queue.h"
+#include <stdint.h>
+#include <time.h>
+
+uint8_t port_cmd_first(uart_type *p_data)
+{
+    if (p_data->rx_len > 3)
+        return 0;
+
+    if (p_data->rx[2] != 0x04)
+        return 0;
+
+    p_data->device_type = p_data->rx[1];
+
+    p_data->tx_len = 10;
+
+    p_data->tx[0] = 0x01;
+
+    p_data->tx[1] = 0x03;
+
+    return 1;
+}
+
+uint8_t port_cmd_read(uart_type *p_data)
+{
+    uint8_t len  = 0;
+    uint8_t addr = 0;
+    // len_check
+    if (p_data->rx_len > 6)
+        return 0;
+
+    // cec_check
+    // if (p_data->rx[p_data->rx_len - 1] != cec8(p_data->rx, p_data->rx_len -1));
+
+    p_data->device_type = p_data->rx[1];
+
+    addr = (p_data->rx[3] << 8) | p_data->rx[2];
+    len  = p_data->rx[4];
+
+    if (0 == get_regist_value(p_data, addr, len))
+    {
+        return 0;
+    }
+
+    p_data->tx_len = len + 5;
+
+    p_data->tx[0]                  = 0x02;
+    p_data->tx[1]                  = p_data->rx[2];
+    p_data->tx[2]                  = p_data->rx[3];
+    p_data->tx[3]                  = p_data->rx[4];
+    p_data->tx[p_data->tx_len - 1] = 0x99; // cec8(p_data->tx, p_data->tx_len - 1)
+
+    return 1;
+}
+
+uint8_t port_cmd_write(uart_type *p_data)
+{
+    uint8_t len  = 0;
+    uint8_t addr = 0;
+    // len_check
+    if (p_data->rx_len != (p_data->rx[4] + 6))
+        return 0;
+
+    // cec_check
+    // if (p_data->rx[p_data->rx_len - 1] != cec8(p_data->rx, p_data->rx_len -1));
+
+    p_data->device_type = p_data->rx[1];
+
+    addr = (p_data->rx[3] << 8) | p_data->rx[2];
+    len  = p_data->rx[4];
+
+    if (1 == set_regist_value(p_data, addr, len))
+    {
+        p_data->tx[1] = 0x00;
+    }
+    else
+    {
+        p_data->tx[1] = 0xFF;
+    }
+
+    p_data->tx_len = 3;
+    // cmd
+    p_data->tx[0] = 0x03;
+    p_data->tx[2] = 0x99; // cec8(p_data->tx, p_data->tx_len - 1)
+
+    return 1;
+}
+
+const com_protocol_type com_protocol_table[] = {
+
+    {0x01, port_cmd_first},
+    {0x02, port_cmd_read},
+    {0x03, port_cmd_write},
+};
+
+void uart4_conn_check(void)
+{
+    static uint16_t count = 0;
+
+    if (uart_msg.disconnect_flg)
+    {
+        count += 10;
+        if (count >= 3000)
+        {
+            count                = 3000;
+            uart_msg.device_type = 0;
+        }
+    }
+    else
+    {
+        if (uart_msg.device_type == 0x02)
+        {
+            count = 0;
+        }
+    }
+}
+
+uint8_t uart_receive_analysis(uart_type *p_data)
+{
+    uint8_t i, len;
+
+    len = UART_ARR_SIZE(com_protocol_table);
+
+    for (i = 0; i < len; i++)
+    {
+
+        if ((p_data->rx[0] == com_protocol_table[i].cmd) && (com_protocol_table[i].p_func != NULL))
+        {
+            if (1 == com_protocol_table[i].p_func(p_data))
+            {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+void uart_task(void)
+{
+
+    if (uart_msg.rx_finished_flg)
+    {
+        uart_msg.rx_finished_flg = 0;
+        uart_msg.rx_len          = uart_msg.rx_count_u8;
+        uart_msg.rx_count_u8     = 0;
+
+        if (1 == uart_receive_analysis(&uart_msg))
+        {
+            uart4_start_send(&uart_msg);
+        }
+    }
+
+    uart4_conn_check();
+}

+ 52 - 0
dev/dev_uart4.h

@@ -0,0 +1,52 @@
+#ifndef __DEV_UART4_H
+#define __DEV_UART4_H
+
+#include "hal_uart4.h"
+#include <stdint.h>
+#ifdef __cplusplus
+extern 'C'
+{
+#endif
+#ifdef __DEV_UART4_H_GLOBAL
+#define __DEV_UART4_H_EXTERN
+#else
+#define __DEV_UART4_H_EXTERN extern
+#endif
+
+/************************************************************************************************
+ *                                          Version                                              *
+ ************************************************************************************************/
+
+/************************************************************************************************
+ *                                          How to use                                           *
+ ************************************************************************************************/
+
+/************************************************************************************************
+ *                                          Enable config                                         *
+ ************************************************************************************************/
+
+/************************************************************************************************
+ *                                          Includes                                             *
+ ************************************************************************************************/
+
+/************************************************************************************************
+ *                                          Defines                                              *
+ ************************************************************************************************/
+#define UART_ARR_SIZE(a) sizeof(a) / sizeof((a)[0])
+
+    typedef struct
+    {
+        uint8_t cmd;
+        uint8_t (*p_func)(uart_type *data);
+    } com_protocol_type;
+
+    void uart_task(void);
+
+/************************************************************************************************
+ *                                          Defines                                              *
+ ************************************************************************************************/
+#ifdef __cplusplus
+};
+#endif
+
+#endif // __DEV_UART4_H

+ 203 - 0
dev/dev_uart_table.c

@@ -0,0 +1,203 @@
+
+
+#include "dev_uart_table.h"
+#include "dev_can.h"
+#include "hal_uart4.h"
+#include <stdint.h>
+
+static void read_1000(uint8_t memoft, uint8_t *data, uint8_t *read_bytes)
+{
+
+    uint8_t size = 0;
+    switch (memoft)
+    {
+    case 0:
+        data[0] = 0x12;
+        data[1] = 0x13;
+        size    = 2;
+        break;
+    case 1:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 2:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 3:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 4:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 5:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 6:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 7:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    }
+
+    *read_bytes += size;
+}
+
+static void read_1100(uint8_t memoft, uint8_t *data, uint8_t *read_bytes)
+{
+
+    uint8_t size = 0;
+    switch (memoft)
+    {
+    case 0:
+        data[0] = 0x12;
+        data[1] = 0x13;
+        size    = 2;
+        break;
+    case 1:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 2:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 3:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 4:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 5:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 6:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    case 7:
+        data[0] = 0x14;
+        size    = 1;
+        break;
+    }
+
+    *read_bytes += size;
+}
+
+const regist_read_type mem_read_table[] = {
+    {0x1000, read_1000},
+    {0x1100, read_1100},
+};
+
+uint8_t     aa = 0;
+uint8_t     bb = 0;
+uint8_t     cc = 0;
+static void write_1000(uint8_t memoft, uint8_t *data, uint8_t *read_bytes)
+{
+
+    uint8_t size = 0;
+    switch (memoft)
+    {
+    case 0:
+        aa   = data[0];
+        bb   = data[1];
+        size = 2;
+        break;
+    case 1:
+        cc   = data[0];
+        size = 1;
+        break;
+    }
+
+    *read_bytes += size;
+}
+
+const regist_read_type mem_write_table[] = {
+    {0x1000, write_1000},
+};
+
+uint8_t get_regist_value(uart_type *p_data, uint8_t mem_start_addr, uint8_t read_len)
+{
+    uint8_t  len, i;
+    uint8_t  cur_len      = 0;
+    uint8_t  mem_addr_oft = 0;
+    uint16_t mem_addr     = 0;
+    uint8_t *ptr          = 0;
+
+    mem_addr_oft = (uint8_t)(mem_start_addr & 0x000F);
+    mem_addr     = mem_start_addr & 0xFFF0;
+    len          = read_len;
+    ptr          = &p_data->tx[4];
+
+    for (i = 0; i < ARR_SIZE(mem_read_table); i++)
+    {
+        if ((mem_addr = mem_read_table[i].addr) && mem_read_table[i].p_func != 0)
+        {
+            do
+            {
+                mem_read_table[i].p_func(mem_addr_oft++, &ptr[cur_len], &cur_len);
+            } while ((cur_len < len) && (mem_addr_oft < 16));
+
+            if (cur_len > len)
+            {
+                return 0;
+            }
+            else if (cur_len < len)
+            {
+                mem_addr     = mem_addr + mem_addr_oft & 0xFFF0;
+                mem_addr_oft = 0;
+            }
+            else
+            {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+uint8_t set_regist_value(uart_type *p_data, uint8_t mem_start_addr, uint8_t read_len)
+{
+    uint8_t  len, i;
+    uint8_t  cur_len      = 0;
+    uint8_t  mem_addr_oft = 0;
+    uint16_t mem_addr     = 0;
+    uint8_t *ptr          = 0;
+
+    mem_addr_oft = (uint8_t)(mem_start_addr & 0x000F);
+    mem_addr     = mem_start_addr & 0xFFF0;
+    len          = read_len;
+    ptr          = &p_data->rx[5];
+
+    for (i = 0; i < ARR_SIZE(mem_write_table); i++)
+    {
+        if ((mem_addr = mem_write_table[i].addr) && mem_write_table[i].p_func != 0)
+        {
+            do
+            {
+                mem_write_table[i].p_func(mem_addr_oft++, &ptr[cur_len], &cur_len);
+            } while ((cur_len < len) && mem_addr_oft < 17);
+
+            if ((mem_addr_oft >= 17) || (cur_len != len))
+            {
+                return 0;
+            }
+            else
+            {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}

+ 50 - 0
dev/dev_uart_table.h

@@ -0,0 +1,50 @@
+#ifndef __DEV──UART──TABLE_H
+#define __DEV──UART──TABLE_H
+
+#include "hal_uart4.h"
+#include <stdint.h>
+#ifdef __cplusplus
+extern 'C'
+{
+#endif
+#ifdef __DEV──UART──TABLE_H_GLOBAL
+#define __DEV──UART──TABLE_H_EXTERN
+#else
+#define __DEV──UART──TABLE_H_EXTERN extern
+#endif
+
+    /************************************************************************************************
+     *                                          Version                                              *
+     ************************************************************************************************/
+
+    /************************************************************************************************
+     *                                          How to use                                           *
+     ************************************************************************************************/
+
+    /************************************************************************************************
+     *                                          Enable config                                         *
+     ************************************************************************************************/
+
+    /************************************************************************************************
+     *                                          Includes                                             *
+     ************************************************************************************************/
+
+    /************************************************************************************************
+     *                                          Defines                                              *
+     ************************************************************************************************/
+    typedef struct
+    {
+        uint16_t addr;
+        void (*p_func)(uint8_t memoft, uint8_t *data, uint8_t *read_bytes);
+    } regist_read_type;
+
+    uint8_t get_regist_value(uart_type * p_data, uint8_t mem_start_addr, uint8_t read_len);
+    uint8_t set_regist_value(uart_type * p_data, uint8_t mem_start_addr, uint8_t read_len);
+/************************************************************************************************
+ *                                          Defines                                              *
+ ************************************************************************************************/
+#ifdef __cplusplus
+};
+#endif
+
+#endif // __DEV──UART──TABLE_H

+ 171 - 0
hal/hal_uart.c

@@ -1,6 +1,7 @@
 #include "hal_uart.h"
 #include "stm32f4xx.h"
 // #include <stdint.h>
+#include <stdint.h>
 #include <sys/unistd.h>
 
 static uint8_t usart1_tx_buf[256];
@@ -9,6 +10,9 @@ static uint8_t usart1_rx_buf[256];
 static uint8_t usart2_tx_buf[256];
 static uint8_t usart2_rx_buf[256];
 
+static uint8_t usart3_tx_buf[256];
+static uint8_t usart3_rx_buf[256];
+
 #define HAL_UART1_TX_PORT   GPIOA
 #define HAL_UART1_TX_PIN    GPIO_Pin_9
 #define HAL_UART1_TX_SOURCE GPIO_PinSource9
@@ -23,6 +27,13 @@ static uint8_t usart2_rx_buf[256];
 #define HAL_UART2_RX_PIN    GPIO_Pin_3
 #define HAL_UART2_RX_SOURCE GPIO_PinSource3
 
+#define HAL_UART3_TX_PORT   GPIOB
+#define HAL_UART3_TX_PIN    GPIO_Pin_10
+#define HAL_UART3_TX_SOURCE GPIO_PinSource2
+#define HAL_UART3_RX_PORT   GPIOB
+#define HAL_UART3_RX_PIN    GPIO_Pin_11
+#define HAL_UART3_RX_SOURCE GPIO_PinSource3
+
 int usart1_snd_tx_cnt = 0;
 
 // 加入以下代码,支持printf函数,而不需要选择use MicroLIB
@@ -221,6 +232,37 @@ static void usart2_deconfig(void)
 {
 }
 
+static void usart3_config(void)
+{
+    GPIO_InitTypeDef GPIO_StructInit;
+    NVIC_InitTypeDef NVIC_InitStructure;
+    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
+
+    GPIO_StructInit.GPIO_Mode  = GPIO_Mode_AF;
+    GPIO_StructInit.GPIO_OType = GPIO_OType_PP;
+    GPIO_StructInit.GPIO_Speed = GPIO_Speed_100MHz;
+    GPIO_StructInit.GPIO_PuPd  = GPIO_PuPd_UP;
+    GPIO_StructInit.GPIO_Pin   = HAL_UART3_TX_PIN;
+    GPIO_PinAFConfig(HAL_UART3_TX_PORT, HAL_UART3_TX_SOURCE, GPIO_AF_USART3);
+    GPIO_Init(HAL_UART3_TX_PORT, &GPIO_StructInit);
+
+    GPIO_StructInit.GPIO_Pin = HAL_UART3_RX_PIN;
+    GPIO_PinAFConfig(HAL_UART3_RX_PORT, HAL_UART3_RX_SOURCE, GPIO_AF_USART3);
+    GPIO_Init(HAL_UART3_RX_PORT, &GPIO_StructInit);
+
+    // Usart1 NVIC 配置
+    NVIC_InitStructure.NVIC_IRQChannel                   = USART3_IRQn; // 串口1中断通道
+    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;           // 抢占优先级
+    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;           // 子优先级
+    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;      // IRQ通道使能
+    NVIC_Init(&NVIC_InitStructure);
+}
+
+static void usart3_deconfig(void)
+{
+}
+
 usart_context_t usart1_context = {
     USART1,
     usart1_tx_buf,
@@ -251,6 +293,21 @@ usart_context_t usart2_context = {
     usart2_config,
     usart2_deconfig};
 
+usart_context_t usart3_context = {
+    USART3,
+    usart3_tx_buf,
+    sizeof(usart3_tx_buf),
+    0,
+    0,
+    0,
+    usart3_rx_buf,
+    sizeof(usart3_rx_buf),
+    0,
+    0,
+    0,
+    usart3_config,
+    usart3_deconfig};
+
 void usart_config_init(usart_context_t *p_usart_content, uint32_t band_rate)
 {
     p_usart_content->config();
@@ -290,6 +347,115 @@ void usart_send(usart_context_t *p_usart_content, const void *_send_buf, const u
         ;
 }
 
+int32_t usart_read_until_char(usart_context_t *p_usart_content, char c)
+{
+    uint32_t i;
+
+    for (i = p_usart_content->rx_rd; i < p_usart_content->rx_wr; i++)
+    {
+        if (p_usart_content->rx_buf[i % p_usart_content->rx_buf_size] == c)
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+// read until memory
+// return:第一次出现mem位置, -1 没找到
+int32_t usart_read_until_mem(usart_context_t *p_usart_content, char *mem, int len)
+{
+    int32_t i, j, pos;
+
+    for (i = p_usart_content->rx_rd; i < p_usart_content->rx_wr; i++)
+    {
+        // overflow
+        for (j = 0; j < len; j++)
+        {
+            pos = i + j;
+            if (p_usart_content->rx_buf[pos % p_usart_content->rx_buf_size] != mem[j])
+            {
+                break;
+            }
+        }
+        // 找到内存快
+        if (j == len)
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+// read ble format 04 FC code len data
+// return 满足format条件结束位置, -1 没找到
+int32_t usart_read_ble_format(usart_context_t *p_usart_content)
+{
+    uint16_t rx_wr = p_usart_content->rx_wr;
+    uint16_t rx_rd = p_usart_content->rx_rd;
+
+    if (rx_wr < rx_rd)
+    {
+        rx_wr += p_usart_content->rx_buf_size;
+    }
+
+    if (rx_wr - rx_rd < 4)
+    {
+        return -1;
+    }
+
+    // 第一次开机跳过特殊桢处理 00 04,跳过00
+    if (p_usart_content->rx_buf[rx_rd % p_usart_content->rx_buf_size] == 0x00 || p_usart_content->rx_buf[(rx_rd + 1) % p_usart_content->rx_buf_size] == 0x04)
+    {
+        p_usart_content->rx_rd++;
+        p_usart_content->rx_rd %= p_usart_content->rx_buf_size;
+        return -4;
+    }
+
+    if (p_usart_content->rx_buf[rx_rd % p_usart_content->rx_buf_size] != 0x04 || p_usart_content->rx_buf[(rx_rd + 1) % p_usart_content->rx_buf_size] != 0xFC)
+    {
+        return -2;
+    }
+
+    // 蓝牙长度不够
+    if (rx_wr - rx_rd < p_usart_content->rx_buf[(rx_rd + 3) % p_usart_content->rx_buf_size] + 4)
+    {
+        return -3;
+    }
+    return p_usart_content->rx_buf[(rx_rd + 3) % p_usart_content->rx_buf_size] + 4;
+}
+
+int32_t usart_copy_data(usart_context_t *p_usart_content, int rlen, char *data)
+{
+    int32_t i, p;
+
+    // 拷贝rlen + 1个数据
+    for (i = 0; i < rlen; i++)
+    {
+        p       = (p_usart_content->rx_rd + i) % p_usart_content->rx_buf_size;
+        data[i] = p_usart_content->rx_buf[p];
+    }
+
+    return 0;
+}
+
+int32_t usart_read_update(usart_context_t *p_usart_content, int rlen, char *data)
+{
+    int32_t i, p;
+
+    // 拷贝rlen + 1个数据
+    for (i = 0; i < rlen; i++)
+    {
+        p       = (p_usart_content->rx_rd + i) % p_usart_content->rx_buf_size;
+        data[i] = p_usart_content->rx_buf[p];
+    }
+
+    // 指定pos下一个位置
+    // return p_usart_content->rx_rd = (p_usart_content->rx_rd + rlen) % p_usart_content->rx_buf_size;
+    p = p_usart_content->rx_rd = (p_usart_content->rx_rd + rlen) % p_usart_content->rx_buf_size;
+    return p;
+}
+
 void usart_send_it(usart_context_t *p_usart_content, const void *_send_buf, const uint16_t send_count)
 {
     const uint8_t *send_buf = (const uint8_t *)_send_buf;
@@ -417,4 +583,9 @@ void USART1_IRQHandler(void)
 void USART2_IRQHandler(void)
 {
     usart_it(&usart2_context);
+}
+
+void USART3_IRQHandler(void)
+{
+    usart_it(&usart3_context);
 }

+ 2 - 1
hal/hal_uart.h

@@ -27,7 +27,7 @@ void    usart_config_deinit(usart_context_t *p_usart_content);
 void    usart_send_it(usart_context_t *p_usart_content, const void *_send_buf, const uint16_t send_count);
 void    usart_wait_send_finished(usart_context_t *p_usart_content);
 int32_t usart_read_until_char(usart_context_t *p_usart_content, char c);
-int32_t usart_read_until_mem(usart_context_t *p_usart_content, char mem, int len);
+int32_t usart_read_until_mem(usart_context_t *p_usart_content, char *mem, int len);
 int32_t usart_read_ble_format(usart_context_t *p_usart_content);
 int32_t usart_read_update(usart_context_t *p_usart_content, int rlen, char *data);
 int32_t usart_read_drop(usart_context_t *p_usart_content);
@@ -39,4 +39,5 @@ void    u_log(char *arg, ...);
 
 extern usart_context_t usart1_context;
 extern usart_context_t usart2_context;
+extern usart_context_t usart3_context;
 #endif

+ 136 - 0
hal/hal_uart4.c

@@ -0,0 +1,136 @@
+#include "hal_uart4.h"
+#include "queue.h"
+#include "stm32f4xx.h"
+#include "stm32f4xx_gpio.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_usart.h"
+
+uart_type uart_msg = {
+    .rx_count_u8        = 0,
+    .tx_count_u8        = 0,
+    .rx_finished_flg    = 0,
+    .disconnect_flg     = 0,
+    .rx_over_time       = 5,
+    .rx_over_time_count = 0xFF,
+    .disconnect_count   = 0,
+};
+
+void hal_uart4_init(void)
+{
+    GPIO_InitTypeDef GPIO_StructInit;
+    NVIC_InitTypeDef NVIC_InitStructure;
+    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
+
+    GPIO_StructInit.GPIO_Mode  = GPIO_Mode_AF;
+    GPIO_StructInit.GPIO_OType = GPIO_OType_PP;
+    GPIO_StructInit.GPIO_Speed = GPIO_Speed_100MHz;
+    GPIO_StructInit.GPIO_PuPd  = GPIO_PuPd_UP;
+    GPIO_StructInit.GPIO_Pin   = GPIO_Pin_10;
+    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);
+    GPIO_Init(GPIOC, &GPIO_StructInit);
+
+    GPIO_StructInit.GPIO_Pin = GPIO_Pin_11;
+    // GPIO_StructInit.GPIO_Mode  = GPIO_Mode_AF;
+    // GPIO_StructInit.GPIO_OType = GPIO_OType_PP;
+    // GPIO_StructInit.GPIO_Speed = GPIO_Speed_100MHz;
+    // GPIO_StructInit.GPIO_PuPd  = GPIO_PuPd_NOPULL;
+    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);
+    GPIO_Init(GPIOC, &GPIO_StructInit);
+
+    NVIC_InitStructure.NVIC_IRQChannel                   = UART4_IRQn; // 串口1中断通道
+    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;          // 抢占优先级
+    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;          // 子优先级
+    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;     // IRQ通道使能
+    NVIC_Init(&NVIC_InitStructure);
+
+    USART_InitTypeDef USART_InitStructure;
+    USART_InitStructure.USART_BaudRate            = 115200;
+    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(UART4, &USART_InitStructure); // 初始化串口
+
+    USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
+
+    USART_Cmd(UART4, ENABLE); // 使能串口
+}
+
+void UART4_IRQHandler(void)
+{
+    // 接收中断处理
+    if (RESET != USART_GetITStatus(UART4, USART_IT_RXNE))
+    {
+        USART_ClearITPendingBit(UART4, USART_IT_RXNE);
+
+        uart_msg.rx_over_time_count = 0;
+        uart_msg.disconnect_count   = 0;
+        uart_msg.disconnect_flg     = 0;
+
+        if (uart_msg.rx_count_u8 >= RX_TX_BUF_LEN)
+        {
+            uart_msg.rx_count_u8 = 0;
+        }
+
+        uart_msg.rx[uart_msg.rx_count_u8++] = USART_ReceiveData(UART4);
+    }
+
+    // 发送中断处理
+    if (RESET != USART_GetITStatus(UART4, USART_IT_TXE))
+    {
+        USART_ClearITPendingBit(UART4, USART_IT_TXE);
+
+        USART_SendData(UART4, uart_msg.tx[uart_msg.tx_count_u8++]);
+
+        if (uart_msg.tx_count_u8 >= uart_msg.tx_len)
+        {
+            USART_ITConfig(UART4, USART_IT_TXE, DISABLE);
+            USART_ITConfig(UART4, USART_IT_TC, ENABLE);
+        }
+    }
+
+    // 发送完成中断
+    if (RESET != USART_GetITStatus(UART4, USART_IT_TC))
+    {
+        USART_ClearITPendingBit(UART4, USART_IT_TC);
+
+        USART_ITConfig(UART4, USART_IT_TC, DISABLE);
+        USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
+    }
+
+    // 发送错误
+    if (RESET != USART_GetITStatus(UART4, USART_IT_ORE))
+        USART_ClearITPendingBit(UART4, USART_IT_ORE);
+}
+
+void uart4_rx_ticks(void)
+{
+    if (uart_msg.rx_over_time_count != 0xFF)
+    {
+        if (++uart_msg.rx_over_time_count >= uart_msg.rx_over_time)
+        {
+            uart_msg.rx_over_time_count = 0xFF;
+            uart_msg.rx_finished_flg    = 1;
+        }
+    }
+
+    if (uart_msg.disconnect_count != 0xFFFF)
+    {
+        if (++uart_msg.disconnect_count >= 2500) // 5000ms
+        {
+            uart_msg.disconnect_count = 0xFFFF;
+            uart_msg.disconnect_flg   = 1;
+        }
+    }
+}
+
+void uart4_start_send(uart_type *p_msg)
+{
+    p_msg->tx_count_u8 = 0;
+
+    USART_ITConfig(UART4, USART_IT_RXNE, DISABLE);
+    USART_SendData(UART4, p_msg->tx[p_msg->tx_count_u8++]);
+    USART_ITConfig(UART4, USART_IT_TXE, ENABLE);
+}

+ 64 - 0
hal/hal_uart4.h

@@ -0,0 +1,64 @@
+#ifndef __HAL_UART4_H
+#define __HAL_UART4_H
+
+#include <stdint.h>
+#ifdef __cplusplus
+extern 'C'
+{
+#endif
+#ifdef __HAL_UART4_H_GLOBAL
+#define __HAL_UART4_H_EXTERN
+#else
+#define __HAL_UART4_H_EXTERN extern
+#endif
+
+    /************************************************************************************************
+     *                                          Version                                              *
+     ************************************************************************************************/
+
+    /************************************************************************************************
+     *                                          How to use                                           *
+     ************************************************************************************************/
+
+    /************************************************************************************************
+     *                                          Enable config                                         *
+     ************************************************************************************************/
+
+    /************************************************************************************************
+     *                                          Includes                                             *
+     ************************************************************************************************/
+#include "stm32f4xx.h"
+    /************************************************************************************************
+     *                                          Defines                                              *
+     ************************************************************************************************/
+#define RX_TX_BUF_LEN (50)
+
+    typedef struct
+    {
+        uint8_t  rx[RX_TX_BUF_LEN];
+        uint8_t  tx[RX_TX_BUF_LEN];
+        uint8_t  rx_len;
+        uint8_t  tx_len;
+        uint8_t  rx_count_u8;
+        uint8_t  tx_count_u8;
+        uint8_t  device_type;
+        uint8_t  rx_finished_flg;
+        uint8_t  disconnect_flg;
+        uint8_t  rx_over_time;
+        uint8_t  rx_over_time_count;
+        uint16_t disconnect_count;
+    } uart_type;
+
+    extern uart_type uart_msg;
+
+    void hal_uart4_init(void);
+    void uart4_rx_ticks(void);
+    void uart4_start_send(uart_type * p_msg);
+/************************************************************************************************
+ *                                          Defines                                              *
+ ************************************************************************************************/
+#ifdef __cplusplus
+};
+#endif
+
+#endif // __HAL_UART4_H

+ 3 - 0
user/main.c

@@ -6,6 +6,7 @@
 #include "hal_can.h"
 #include "hal_conf.h"
 #include "hal_pwm.h"
+#include "hal_uart4.h"
 #include "misc.h"
 
 #define APP_FLASH_OFFSET 0x8000
@@ -26,6 +27,8 @@ int main(void)
     dev_can_network_init();
     usart_config_init(&usart1_context, 115200);
     usart_config_init(&usart2_context, 9600);
+    usart_config_init(&usart3_context, 115200);
+    hal_uart4_init();
     ble_init();
     hal_i2c1_init();
     dev_key_button_init();