串口中断接收与环形缓冲实例(apollo3 blue plus)
#define DEV_UART1 1
#define GPS_POWER_PIN 13
#define GPS_LOG_ENABLE 1
#define MAX_UART1_SIZE 1024
 #define AM_BSP_GPIO_COM_UART1_TX         8
 #define AM_BSP_GPIO_COM_UART1_RX         9
// 定义环形缓冲区结构
 typedef struct 
 {
     uint8_t RxBuffer[MAX_UART1_SIZE];
     volatile uint16_t head;  // 写指针(由中断回调修改)
     volatile uint16_t tail;  // 读指针(由主任务修改)
     uint8_t ready;
 } RingBuffer;
typedef struct
 {
     uint8_t TxBuffer[MAX_UART1_SIZE];
 }uart1_dev_t;
typedef struct
 {
     uint8_t position_flag;
     uint8_t printf_enable;
     uint8_t status;
     char time_hour[6];
     char time_date[6];
     char latitude[17];
     char longitude[17]; 
     float gps_latitude;
     float gps_longitude;
 }Gps_Module_Data;
#include <stdint.h>
 #include <stdio.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include "am_mcu_apollo.h"
 #include "am_bsp.h"
 #include "am_util.h"
 #include <string.h>
 #include "FreeRTOSConfig.h"
 #include "dev_gps.h"
 #include "FreeRTOS.h"
 #include "task.h"
 #include "time.h"
 #include "queue.h" 
 #include "ble_app.h"
void *uart1_dev_Handle;
 uart1_dev_t uart1_dev;
 void *g_pvUART1;
TaskHandle_t gps_task_thread;
Gps_Module_Data gps_module_data;
static RingBuffer uart1_rx = {0};
 //*****************************************************************************
 //
 // Configuration options
 //
 //*****************************************************************************
 const am_hal_gpio_pincfg_t g_AM_BSP_GPIO_COM_UART1_TX =
 {
     .uFuncSel            = AM_HAL_PIN_8_UART1TX,
     .eDriveStrength      = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA
 };
const am_hal_gpio_pincfg_t g_AM_BSP_GPIO_COM_UART1_RX =
 {
     .uFuncSel            = AM_HAL_PIN_9_UART1RX
 };
//*****************************************************************************
 //
 // init uart1 defualt
 //
 //*****************************************************************************
 void dev_uart1_gpio_config_defualt(void)
 {
     g_pvUART1=NULL;
     am_hal_gpio_pinconfig(AM_BSP_GPIO_COM_UART1_TX, g_AM_HAL_GPIO_DISABLE);
        am_hal_gpio_pinconfig(AM_BSP_GPIO_COM_UART1_RX, g_AM_HAL_GPIO_DISABLE);
 }
//*****************************************************************************
 //
 // deinit uart1
 //
 //*****************************************************************************
 void dev_uart1_deinit(void)
 {
     am_hal_uart_tx_flush(g_pvUART1);
     __NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + DEV_UART1));
    am_hal_uart_power_control(g_pvUART1, AM_HAL_SYSCTRL_DEEPSLEEP, false);
     am_hal_uart_deinitialize(g_pvUART1);
    dev_uart1_gpio_config_defualt();
 }
//*****************************************************************************
 //
 // read uart1 data
 //
 //*****************************************************************************
 uint32_t dev_uart1_read_buf(uint8_t *data)
 {
     uint32_t ui32BytesRead;
     
     am_hal_uart_transfer_t sRead =
     {
         .ui32Direction = AM_HAL_UART_READ,
         .pui8Data = data,
         .ui32NumBytes = 23,
         .ui32TimeoutMs = 0,
         .pui32BytesTransferred = &ui32BytesRead,
     };
     
     am_hal_uart_transfer(g_pvUART1, &sRead);
     return ui32BytesRead;
 }
//*****************************************************************************
 //
 // uart1 send data
 //
 //*****************************************************************************
 void dev_uart1_send(uint8_t *data,uint32_t len)
 {
      am_hal_uart_transfer_t sWrite =
        {
           .ui32Direction = AM_HAL_UART_WRITE,
           .pui8Data = data,
           .ui32NumBytes = len,
           .ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
           .pui32BytesTransferred = 0,
        };
      am_hal_uart_transfer(g_pvUART1, &sWrite);
     // am_util_debug_printf("uart send\r\n");
 }
//*****************************************************************************
 //
 // 注册串口1中断回调函数
 //
 //*****************************************************************************
 void dev_uart1_register(dev_uart1_callback cb)
 {
     uart1_isr_status = cb;
 }
//*****************************************************************************
 //
 // uart1 isr
 //
 //*****************************************************************************
 void am_uart1_isr(void)
 {
     uint32_t ui32Status;
        //
        // Read the masked interrupt status from the UART.
        //
     am_hal_uart_interrupt_status_get(g_pvUART1, &ui32Status, true);
     am_hal_uart_interrupt_clear(g_pvUART1, ui32Status);
     am_hal_uart_interrupt_service(g_pvUART1, ui32Status, 0);
 //    am_util_debug_printf("uart1 isr Status=%d\r\n",ui32Status);    
     if(uart1_isr_status !=NULL)
         uart1_isr_status(ui32Status);
}
void gps_power_gpio_init(void)
 {
     const am_hal_gpio_pincfg_t gps_pin =
     {
         .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA,
         .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL,
         .uFuncSel       = 3            //GPIO功能
     };
     am_hal_gpio_pinconfig(GPS_POWER_PIN, gps_pin);
     am_hal_gpio_output_set(GPS_POWER_PIN);
     gps_module_data.status = 1;
 }
 /*
 **将传入的字符串按照分隔符分隔开,如果两个分隔符中间没数据,返回\0
 **函数返回值为分割之后,后面剩下的数据
 **data:传入的字符串,control:分隔符,out_string:分隔符中间的数据
 */
 char *cut_string(char *data,const char * control,char *out_string)
 {
     char *p1 = NULL;//
     char *p2 = NULL;//
     p1 = strstr(data,control);
     if(p1==NULL)return NULL;
     p2 = strstr(p1+1,control);
     if(p2==NULL)return NULL;
     if((p2-p1)==1)//
     {
         *out_string='\0';
         data = p2;
     }
     else
     {
         memcpy(out_string,p1+1,(int)(p2-p1-1));//
         *(out_string+(p2-p1-1))='\0';
         data = p2;
     }
     return data;
 }
//字符转换浮点数
 static float parse_lat_long(char *str)
 {
     float ll = strtof(str, NULL);
     int deg = ((int)ll) / 100;
     float min = ll - (deg * 100);
     ll = deg + min / 60.0f;
     return ll;
 }
//$GNRMC,100512.000,A,2232.3339,N,11401.5394,E,0.49,83.03,1 A * 54
 static uint8_t gps_get_latitude_and_longitude(char *data)
 {
     char string[15]={0};
     char *aaa = NULL;
     uint8_t cnt = 0;
     char *p1=NULL,*p2=NULL;
     uint8_t ret = 0,valid = 0;
     
     if(((p1=strstr(data,"RMC"))!=NULL)&&((p2=strstr(p1,"*"))!=NULL)&&(p2-p1<100))
     {
         aaa = p1;
         while(aaa!=NULL)
         {
             cnt++;
             aaa=cut_string(aaa,",",string);
             if(aaa==NULL)break;
            if(cnt == 1)//UTC(Coordinated Universal Time)时间,hhmmss(时分秒
             {
                 memset(gps_module_data.time_hour,0,sizeof(gps_module_data.time_hour));
                 if((string[0]!=0)&&(strstr(string,".")!=NULL))
                 {
                     memcpy(gps_module_data.time_hour,string,6);
                 }
                 else
                 {
                     break;
                 }
             }
            else if((cnt == 2)&&(string[0]!=0))
             {
                 //am_util_debug_printf("valid 0:%d",string[0]);
                 if(string[0] == 'A')
                     {
                     //    gps_module_data.position_flag = 1;
                         valid = 1;
                     }
                 else 
                     {
                     //    gps_module_data.position_flag = 0;
                         valid = 0;
                     }
             }
          else if(cnt == 3)//纬度
             {
                 memset(gps_module_data.latitude,0,sizeof(gps_module_data.latitude));
                 if((string[0]!=0)&&(strstr(string,".")!=NULL))
                 {
                     memcpy(gps_module_data.latitude+3,string,strlen(string));
                 }
                 else
                 {
                     break;
                 }
             }
             else if(cnt == 4)//N   S
             {
                 if(string[0] == 'S')
                 {
                     gps_module_data.latitude[0] = string[0];
                     gps_module_data.latitude[1] = ':';
                     gps_module_data.latitude[2] = '-';
                     if(GPS_LOG_ENABLE)am_util_debug_printf("latitude:%s\n",gps_module_data.latitude);
                 //    gps_module_data.gps_latitude = parse_lat_long(&gps_module_data.latitude[2]);
                 //    if(GPS_LOG_ENABLE)am_util_debug_printf("gps-latitude:%lf\n",gps_module_data.gps_latitude);
                 }
                 else if(string[0] == 'N')
                 {
                     gps_module_data.latitude[0] = string[0];
                     gps_module_data.latitude[1] = ':';
                     gps_module_data.latitude[2] = '0';
                     if(GPS_LOG_ENABLE)am_util_debug_printf("latitude:%s\n",gps_module_data.latitude);
                 //    gps_module_data.gps_latitude = parse_lat_long(&gps_module_data.latitude[2]);
                 //    if(GPS_LOG_ENABLE)am_util_debug_printf("gps-latitude:%lf\n",gps_module_data.gps_latitude);
                 }
                 else
                 {
                     break;
                 }
             }
             else if(cnt == 5)//经度
             {
                 memset(gps_module_data.longitude,0,sizeof(gps_module_data.longitude));
                 if((string[0]!=0)&&(strstr(string,".")!=NULL))
                 {
                     memcpy(gps_module_data.longitude+3,string,strlen(string));
                 }
                 else
                 {
                     break;
                 }
             }
             else if(cnt == 6)//W   E
             {
                 if(string[0] == 'W')
                 {
                     gps_module_data.longitude[0] = string[0];
                     gps_module_data.longitude[1] = ':';
                     gps_module_data.longitude[2] = '-';
                     if(GPS_LOG_ENABLE)am_util_debug_printf("longitude:%s\n",gps_module_data.longitude);
                 //    gps_module_data.gps_longitude = parse_lat_long(&gps_module_data.longitude[2]);
                 //    if(GPS_LOG_ENABLE)am_util_debug_printf("gps-longitude:%lf\n",gps_module_data.gps_longitude);
                 }
                 else if(string[0] == 'E')
                 {
                     gps_module_data.longitude[0] = string[0];
                     gps_module_data.longitude[1] = ':';
                     gps_module_data.longitude[2] = '0';
                     if(GPS_LOG_ENABLE)am_util_debug_printf("longitude:%s\n",gps_module_data.longitude);
                 //    gps_module_data.gps_longitude = parse_lat_long(&gps_module_data.longitude[2]);
                 //    if(GPS_LOG_ENABLE)am_util_debug_printf("gps-longitude:%lf\n",gps_module_data.gps_longitude);
                 }
                 else
                 {
                     break;
                 }
             }
             else if(cnt == 7)//地面速率
             {    
                 
             }
             else if(cnt == 8)//地面航向
             {
                 
             }
            else if(cnt == 9)//UTC日期,ddmmyy(日月年)格式
             {
                 memset(gps_module_data.time_date,0,sizeof(gps_module_data.time_date));
                 if(string[0]!=0)
                 {
                     memcpy(gps_module_data.time_date,string,6);
                     struct tm lt;        //C标准库time.h 
                     int timezone = 0;
                    lt.tm_mday = (gps_module_data.time_date[0] - '0')*10 + (gps_module_data.time_date[1] - '0');
                     lt.tm_mon = (gps_module_data.time_date[2] - '0')*10 + (gps_module_data.time_date[3] - '0');
                     lt.tm_year = (gps_module_data.time_date[4] - '0')*10 + (gps_module_data.time_date[5] - '0');
                    lt.tm_hour = (gps_module_data.time_hour[0] - '0')*10 + (gps_module_data.time_hour[1] - '0');
                     lt.tm_min = (gps_module_data.time_hour[2] - '0')*10 + (gps_module_data.time_hour[3] - '0');
                     lt.tm_sec = (gps_module_data.time_hour[4] - '0')*10 + (gps_module_data.time_hour[5] - '0');
                     
                 //    gps time:211122095858
                     if(GPS_LOG_ENABLE)am_util_debug_printf("cclk:%d-%d-%d %d:%d:%d\n",lt.tm_mday,lt.tm_mon,lt.tm_year,lt.tm_hour,lt.tm_min,lt.tm_sec);
                     lt.tm_year = lt.tm_year + 100;
                     lt.tm_mon = lt.tm_mon - 1;
                     work.current_time = mktime(<)-(timezone/4*3600);
                     am_util_debug_printf("current_time : %lld",work.current_time);    //北京时间
                     
                     if(valid)
                     {
                         gps_module_data.gps_latitude = parse_lat_long(&gps_module_data.latitude[2]);
                         if(GPS_LOG_ENABLE)am_util_debug_printf("gps-latitude:%f\n",gps_module_data.gps_latitude);
                         
                         gps_module_data.gps_longitude = parse_lat_long(&gps_module_data.longitude[2]);
                         if(GPS_LOG_ENABLE)am_util_debug_printf("gps-longitude:%f\n",gps_module_data.gps_longitude);
                        if(gps_module_data.position_flag == 0)
                             {
                                 gps_module_data.position_flag = 1;
                                 am_util_debug_printf("gps valid report\n");
                             }
                         ret = 1;
                     }
                 }
             }
         }
     }
    return ret;
 }
void open_gps(void)
 {
     gps_module_data.status = 1;
     gps_module_data.position_flag = 0;
     am_hal_gpio_output_set(GPS_POWER_PIN);
     vTaskResume(gps_task_thread);
     am_util_debug_printf("gps task resume\n");
 }
void close_gps(void)
 {
     if(gps_module_data.printf_enable == 1)return;
     gps_module_data.status = 0;
     gps_module_data.position_flag = 0;
     am_hal_gpio_output_clear(GPS_POWER_PIN);
     vTaskSuspend(gps_task_thread);    //挂起UDP任务,直到解除挂起,
    am_util_debug_printf("gps task suspend\n");
 }
 //  获取可读数据量 添加环形缓冲区辅助函数
 uint32_t RingBuffer_Available(RingBuffer *rb)
 {
     uint32_t head = rb->head;
     uint32_t tail = rb->tail;
    if (head >= tail) return (head - tail);
     return (MAX_UART1_SIZE - tail + head);
 }
 // 读取数据(在主任务中调用,带临界区保护)
 uint8_t RingBuffer_Get(RingBuffer *rb)
 {
     __disable_irq();
     if (rb->tail == rb->head) 
     {
         __enable_irq();
         return 0;  // 无数据
     }
     uint8_t data = rb->RxBuffer[rb->tail];
     rb->tail = (rb->tail + 1) % MAX_UART1_SIZE;
     __enable_irq();
     return data;
 }
// 修改后的环形缓冲区写入函数(适配实际硬件)
 static void RingBuffer_Put(RingBuffer *rb, uint8_t data)
 {
     uint32_t next_head = (rb->head + 1) % MAX_UART1_SIZE;
     
     // 当缓冲区未满时写入
     if (next_head != rb->tail) 
     {
         rb->RxBuffer[rb->head] = data;
         rb->head = next_head;
     }
     if (next_head == rb->tail)
     {
         am_util_debug_printf("--uart1 rx over--\n");// 处理缓冲区满的情况
     }
 }
//*****************************************************************************
 //
 // 串口1回调函数处理
 //
 //*****************************************************************************
 void uart1_dev_receiver_handle(uint32_t ui32Status)
 {
     //am_util_debug_printf("reveier ui32Status=%d\r\n",ui32Status);
  if (ui32Status & (AM_HAL_UART_INT_RX_TMOUT | AM_HAL_UART_INT_RX))
     {
         uint32_t i,totallen, ui32BytesRead = 0;
         uint8_t temp_buf[64];  
        ui32BytesRead = dev_uart1_read_buf(temp_buf);    //每次最多读23个字节
         totallen = ui32BytesRead;
         // 将数据写入环形缓冲区
         for (i = 0; i < ui32BytesRead; i++)
         {
             RingBuffer_Put(&uart1_rx, temp_buf[i]);
         }
         //am_util_debug_printf("uart rx:%d\n",totallen);
         if (ui32Status & (AM_HAL_UART_INT_RX_TMOUT))
         {
              ui32BytesRead = dev_uart1_read_buf(temp_buf);
             totallen += ui32BytesRead;
             // 将数据写入环形缓冲区
             for (i = 0; i < ui32BytesRead; i++)
             {
                 RingBuffer_Put(&uart1_rx, temp_buf[i]);
             }            
             //am_util_debug_printf("uart1:%d %s\r\n",totallen, uart1_rx.RxBuffer);
             //am_util_debug_printf("uart tmout:%d\n",totallen);
         }
         uart1_rx.ready = true;
    }
  
 }
 //*****************************************************************************
 //
 // init uart
 //
 //*****************************************************************************
 void  dev_uart1_init(void)
 {
     am_hal_uart_config_t sUartConfig =
     {
         //
         // Standard UART settings: 115200-8-N-1
         //
         .ui32BaudRate    = 115200,
         .ui32DataBits    = AM_HAL_UART_DATA_BITS_8,
         .ui32Parity      = AM_HAL_UART_PARITY_NONE,
         .ui32StopBits    = AM_HAL_UART_ONE_STOP_BIT,
         .ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
        //
         // Set TX and RX FIFOs to interrupt at three-quarters full.
         //
         .ui32FifoLevels = (AM_HAL_UART_TX_FIFO_3_4 |
                            AM_HAL_UART_RX_FIFO_3_4),
        //
         // This code will use the standard interrupt handling for UART TX, but
         // we will have a custom routine for UART RX.
         //
         .pui8TxBuffer = uart1_dev.TxBuffer,
         .ui32TxBufferSize = MAX_UART1_SIZE,
           .pui8RxBuffer = 0,
         .ui32RxBufferSize = 0,
     };
    am_hal_uart_initialize(DEV_UART1, &g_pvUART1);
     am_hal_uart_power_control(g_pvUART1, AM_HAL_SYSCTRL_WAKE, false);
     am_hal_uart_configure(g_pvUART1, &sUartConfig);
     //hl_dev_uart_gpio_config(g_pvUART1,config->ui32module);
     am_hal_gpio_pinconfig(AM_BSP_GPIO_COM_UART1_TX, g_AM_BSP_GPIO_COM_UART1_TX);
     am_hal_gpio_pinconfig(AM_BSP_GPIO_COM_UART1_RX, g_AM_BSP_GPIO_COM_UART1_RX);
     //
     // Make sure to enable the interrupts for RX, since the HAL doesn't already
     // know we intend to use them.
     //
     NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + DEV_UART1));
     NVIC_SetPriority(UART0_IRQn+DEV_UART1, NVIC_configMAX_SYSCALL_INTERRUPT_PRIORITY);
     am_hal_uart_interrupt_enable(g_pvUART1, (AM_HAL_UART_INT_RX |
                                  AM_HAL_UART_INT_RX_TMOUT));
    dev_uart1_register(uart1_dev_receiver_handle);
     am_util_debug_printf("uart1 init:\r\n");
 }
//*****************************************************************************
 //
 //initial setup for the gps task.
 //
 //*****************************************************************************
 void gps_task(void *pvParameters)
{
     char data[1024] = {0};
     uint16_t i, len;
     uint16_t available;
     
     gps_power_gpio_init();
     dev_uart1_init();
     am_util_debug_printf("gps init\n");
     
     while (1) 
         {            
             if(uart1_rx.ready)    //20ms,230 BITS
                 {
                     // Read data from the UART 
                     available = RingBuffer_Available(&uart1_rx);
                    if(available > 0)
                     {
                         len = available > MAX_UART1_SIZE ? MAX_UART1_SIZE : available;
             
                         // 读取数据到临时缓冲区
                         for (i = 0; i < len; i++)
                         {
                             data[i] = RingBuffer_Get(&uart1_rx);
                         }
                     
                     //    if(gps_module_data.printf_enable)
                     //    {
                             am_util_debug_printf("rec:%d,%s\r\n",len,data);
                     //    }
                         if(strstr(data,"RMC")!=NULL)
                         {
                             gps_get_latitude_and_longitude(data);
                             //gps_connect_flag = 1;
                         }            
                         memset(data,0,sizeof(data));
                     }
                     uart1_rx.ready = false;
                 }            
             else vTaskDelay(20 / portTICK_PERIOD_MS);        //115200 BITS/S 20ms,230 BITS
         }
 }
