GPS NMEA 0183 4.10协议/GPS Linux串口驱动
? 下圖為GYM-1010-B 北斗導航模塊,同時支持北斗二代 B1、GPS L1 信號,?支持協議 ?NMEA 0183 4.10?版本,默認波特率9600bps,數據位8bit,無校驗位,停止位1bit;默認輸出頻率1HZ
? ??基本上接上天線,供電引腳電壓正常的話,就可以通過串口讀取GPS數據了(GPS芯片會源源不斷的輸出數據)。所以GPS編程最主要的是解析數據,要解析數據就得了解協議格式。北斗導航模塊輸出 6 條 NAME 協議,分別為 GPGGA、GPGLL、GPGSA、GPGSV、GPRMC 和 GPVTG 等 6 條協議。
?一、下面詳細學習這六種不同的輸出協議的數據格式。
(1)?$GPGGA?(GPS定位信息)
? 協議格式:
? 樣例數據:
? 協議格式詳細分析:
(2)?$GPGLL?(地理定位信息)
? 協議格式:
? 樣例數據:
? 協議格式詳細分析:
(3)?$GPGSA?(當前衛星信息)
? 協議格式:
? 樣例數據:
? 協議格式詳細分析:
(4)?$GPGSV(可見衛星信息)
? 協議格式:
? 樣例數據:
??需要注意的是這里的樣例數據有2條,這是因為當前可見衛星一共有7個,但是每條語句最多包括四顆衛星的信息,所以分成了2條語句。每顆衛星的信息有四個數據項,即:<4>(衛星編號)、<5>(衛星仰角)、<6>(衛星方位角)、<7>(信噪比)。
? 協議格式詳細分析(只分析第1條樣例數據語句):
(5)?$GPRMC(最簡定位信息)
? 協議格式:
? 樣例數據:
? 協議格式詳細分析:
(6)?$GPVTG(地面速度信息)
? 協議格式:
? 樣例數據:
? 協議格式詳細分析:
??有了上面對NMEA0183協議的詳細學習,剩下的就是串口編程了。無論是通過單片機,還是Windows/WinCE/Linux系統,編寫串口程序把這些數據讀取到都是比較容易的,剩下就是通過c++那些查找算法函數,或者MFC?CString字符串的相關函數進行解析就OK了。
二、Linux串口驅動分析設計
A、核心數據結構
??串口驅動有3個核心數據結構,它們都定義在<#include linux/serial_core.h>
? ?1、uart_driver
? ?uart_driver包含了串口設備名、串口驅動名、主次設備號、串口控制臺(可選)等信息,還封裝了tty_driver(底層串口驅動無需關心tty_driver)。
? ?2、uart_port
uart_port用于描述串口端口的I/O端口或I/O內存地址、FIFO大小、端口類型、串口時鐘等信息。實際上,一個uart_port實例對應一個串口設備.
? ?struct uart_port {
? ? spinlock_t ? ? ? ? ? ? lock; ? ? ? ? ? /* 串口端口鎖 */
? ? unsigned int ? ? ? ? ? iobase; ? ? ? ? /* IO端口基地址 */
? ? unsigned char __iomem *membase; ? ? ? ?/* IO內存基地址,經映射(如ioremap)后的IO內存虛擬基地址 */
? ? unsigned int ? ? ? ? ? irq; ? ? ? ? ? ?/* 中斷號 */
? ? unsigned int ? ? ? ? ? uartclk; ? ? ? ?/* 串口時鐘 */
? ? unsigned int ? ? ? ? ? fifosize; ? ? ? /* 串口FIFO緩沖大小 */
? ? unsigned char ? ? ? ? ?x_char; ? ? ? ? /* xon/xoff字符 */
? ? unsigned char ? ? ? ? ?regshift; ? ? ? /* 寄存器位移 */
? ? unsigned char ? ? ? ? ?iotype; ? ? ? ? /* IO訪問方式 */
? ? unsigned char ? ? ? ? ?unused1;
#define UPIO_PORT ? ? ? ?(0) ? ? ? ? ? ? ? /* IO端口 */
#define UPIO_HUB6 ? ? ? ?(1)
#define UPIO_MEM ? ? ? ? (2) ? ? ? ? ? ? ? /* IO內存 */
#define UPIO_MEM32 ? ? ? (3)
#define UPIO_AU ? ? ? ? ?(4) ? ? ? ? ? ? ? /* Au1x00 type IO */
#define UPIO_TSI ? ? ? ? (5) ? ? ? ? ? ? ? /* Tsi108/109 type IO */
#define UPIO_DWAPB ? ? ? (6) ? ? ? ? ? ? ? /* DesignWare APB UART */
#define UPIO_RM9000 ? ? ?(7) ? ? ? ? ? ? ? /* RM9000 type IO */
? ? unsigned int ? ? ? ?read_status_mask; ?/* 關心的Rx error status */
? ? unsigned int ? ? ? ?ignore_status_mask;/* 忽略的Rx error status */
? ? struct uart_info ? ? ?*info; ? ? ? ? ? /* pointer to parent info */
? ? struct uart_icount ? ? icount; ? ? ? ? /* 計數器 */
? ? struct console ? ? ? ?*cons; ? ? ? ? ? /* console結構體 */
#ifdef CONFIG_SERIAL_CORE_CONSOLE
? ? unsigned long ? ? ? ? sysrq; ? ? ? ? ? /* sysrq timeout */
#endif
? ? upf_t ? ? ? ? ? ? ? ? flags;
#define UPF_FOURPORT ? ? ? ? ((__force upf_t) (1 << 1))
#define UPF_SAK ? ? ? ? ? ? ?((__force upf_t) (1 << 2))
#define UPF_SPD_MASK ? ? ? ? ((__force upf_t) (0x1030))
#define UPF_SPD_HI ? ? ? ? ? ((__force upf_t) (0x0010))
#define UPF_SPD_VHI ? ? ? ? ?((__force upf_t) (0x0020))
#define UPF_SPD_CUST ? ? ? ? ((__force upf_t) (0x0030))
#define UPF_SPD_SHI ? ? ? ? ?((__force upf_t) (0x1000))
#define UPF_SPD_WARP ? ? ? ? ((__force upf_t) (0x1010))
#define UPF_SKIP_TEST ? ? ? ?((__force upf_t) (1 << 6))
#define UPF_AUTO_IRQ ? ? ? ? ((__force upf_t) (1 << 7))
#define UPF_HARDPPS_CD ? ? ? ((__force upf_t) (1 << 11))
#define UPF_LOW_LATENCY ? ? ?((__force upf_t) (1 << 13))
#define UPF_BUGGY_UART ? ? ? ((__force upf_t) (1 << 14))
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
#define UPF_CONS_FLOW ? ? ? ?((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ? ? ? ?((__force upf_t) (1 << 24))
#define UPF_BOOT_AUTOCONF ? ?((__force upf_t) (1 << 28))
#define UPF_FIXED_PORT ? ? ? ((__force upf_t) (1 << 29))
#define UPF_DEAD ? ? ? ? ? ? ((__force upf_t) (1 << 30))
#define UPF_IOREMAP ? ? ? ? ?((__force upf_t) (1 << 31))
#define UPF_CHANGE_MASK ? ? ?((__force upf_t) (0x17fff))
#define UPF_USR_MASK ? ? ? ? ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
? ? unsigned int ? ? ? ? ? ? mctrl; ? ? ? ?/* 當前的moden設置 */
? ? unsigned int ? ? ? ? ? ? timeout; ? ? ?/* character-based timeout */ ? ? ? ?
? ? unsigned int ? ? ? ? ? ? type; ? ? ? ? /* 端口類型 */
? ? const struct uart_ops ? *ops; ? ? ? ? ?/* 串口端口操作函數集 */
? ? unsigned int ? ? ? ? ? ? custom_divisor;
? ? unsigned int ? ? ? ? ? ? line; ? ? ? ? /* 端口索引 */
? ? resource_size_t ? ? ? ? ?mapbase; ? ? ?/* IO內存物理基地址,可用于ioremap */
? ? struct device ? ? ? ? ? *dev; ? ? ? ? ?/* 父設備 */
? ? unsigned char ? ? ? ? ? ?hub6; ? ? ? ? /* this should be in the 8250 driver */
? ? unsigned char ? ? ? ? ? ?suspended;
? ? unsigned char ? ? ? ? ? ?unused[2];
? ? void ? ? ? ? ? ? ? ? ? ?*private_data; /* 端口私有數據,一般為platform數據指針 */
};
? ?uart_iconut為串口信息計數器,包含了發送字符計數、接收字符計數等。在串口的發送中斷處理函數和接收中斷處理函數中,我們需要管理這些計數。
struct?uart_icount?{
????__u32????cts;
????__u32????dsr;
????__u32????rng;
????__u32????dcd;
????__u32????rx;??????/*?發送字符計數 */
????__u32????tx;??????/*?接受字符計數 */
????__u32????frame;???/*?幀錯誤計數 */
????__u32????overrun;?/*?Rx FIFO溢出計數 */
????__u32????parity;??/*?幀校驗錯誤計數 */
????__u32????brk;?????/*?break計數 */
????__u32????buf_overrun;
};
?
uart_info有兩個成員在底層串口驅動會用到:xmit和tty。用戶空間程序通過串口發送數據時,上層驅動將用戶數據保存在xmit;而串口發送中斷處理函數就是通過xmit獲取到用戶數據并將它們發送出去。串口接收中斷處理函數需要通過tty將接收到的數據傳遞給行規則層。
?
/* uart_info實例僅在串口端口打開時有效,它可能在串口關閉時被串口核心層釋放。因此,在使用uart_port的uart_info成員時必須保證串口已打開。底層驅動和核心層驅動都可以修改uart_info實例。
?* This is the state information which is only valid when the port
?* is open; it may be freed by the core driver once the device has
?* been closed. Either the low level driver or the core can modify
?* stuff here.
?*/
struct?uart_info?{
????struct?tty_struct?????*tty;
????struct?circ_buf????????xmit;
????uif_t????????????????? flags;
/*
?* Definitions for info->flags. These are _private_ to serial_core, and
?* are specific to this structure. They may be queried by low level drivers.
?*/
#define?UIF_CHECK_CD????????((__force uif_t)?(1?<<?25))
#define?UIF_CTS_FLOW????????((__force uif_t)?(1?<<?26))
#define?UIF_NORMAL_ACTIVE????((__force uif_t)?(1?<<?29))
#define?UIF_INITIALIZED????????((__force uif_t)?(1?<<?31))
#define?UIF_SUSPENDED????????((__force uif_t)?(1?<<?30))
????int???????????????????? blocked_open;
????struct?tasklet_struct???tlet;
????wait_queue_head_t?????? open_wait;
????wait_queue_head_t?????? delta_msr_wait;
};
3、uart_ops
uart_ops涵蓋了串口驅動可對串口設備進行的所有操作。
/*
?* This structure describes all the operations that can be
?* done on the physical hardware.
?*/
struct uart_ops {
? ? unsigned int (*tx_empty)(struct uart_port *); /* 串口的Tx FIFO緩存是否為空 */
? ? void ? ? ? ? (*set_mctrl)(struct uart_port *, unsigned int mctrl); /* 設置串口modem控制 */
? ? unsigned int (*get_mctrl)(struct uart_port *); /* 獲取串口modem控制 */
? ? void ? ? ? ? (*stop_tx)(struct uart_port *); /* 禁止串口發送數據 */
? ? void ? ? ? ? (*start_tx)(struct uart_port *); /* 使能串口發送數據 */
? ? void ? ? ? ? (*send_xchar)(struct uart_port *, char ch);/* 發送xChar */
? ? void ? ? ? ? (*stop_rx)(struct uart_port *); /* 禁止串口接收數據 */
? ? void ? ? ? ? (*enable_ms)(struct uart_port *); /* 使能modem的狀態信號 */
? ? void ? ? ? ? (*break_ctl)(struct uart_port *, int ctl); /* 設置break信號 */
? ? int ? ? ? ? ?(*startup)(struct uart_port *); /* 啟動串口,應用程序打開串口設備文件時,該函數會被調用 */
? ? void ? ? ? ? (*shutdown)(struct uart_port *); /* 關閉串口,應用程序關閉串口設備文件時,該函數會被調用 */
? ? void ? ? ? ? (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios*old); /* 設置串口參數 */
? ? void ? ? ? ? (*pm)(struct uart_port *, unsigned int state,
? ? ? ? ? ? ?unsigned int oldstate); /* 串口電源管理 */
? ? int ? ? ? ? ?(*set_wake)(struct uart_port *, unsigned int state); /* ?*/
? ? const char ?*(*type)(struct uart_port *); /* 返回一描述串口類型的字符串 */
? ? void ? ? ? ? (*release_port)(struct uart_port *); /* 釋放串口已申請的IO端口/IO內存資源,必要時還需iounmap */
? ? int ? ? ? ? ?(*request_port)(struct uart_port *); /* 申請必要的IO端口/IO內存資源,必要時還可以重新映射串口端口 */
? ? void ? ? ? ? (*config_port)(struct uart_port *, int); /* 執行串口所需的自動配置 */
? ? int ? ? ? ? ?(*verify_port)(struct uart_port *, struct serial_struct *); /* 核實新串口的信息 */
? ? int ? ? ? ? ?(*ioctl)(struct uart_port *, unsigned int, unsigned long); /* IO控制 */
};
B、串口驅動API
? 1、uart_register_driver
?/* 功能: ? ?uart_register_driver用于將串口驅動uart_driver注冊到內核(串口核心層)中,通常在模塊初始化函數調用該函數。 * 參數 drv:要注冊的uart_driver * 返回值: ?成功,返回0;否則返回錯誤碼 */ int uart_register_driver(struct uart_driver *drv); 2、uart_unregister_driver
?/* 功能: ? ?uart_unregister_driver用于注銷我們已注冊的uart_driver,通常在模塊卸載函數調用該函數 * 參數 drv:要注銷的uart_driver * 返回值: ?成功,返回0;否則返回錯誤碼 */ void uart_unregister_driver(struct uart_driver *drv); 3、uart_add_one_port
?/* 功能: ? ?uart_add_one_port用于為串口驅動添加一個串口端口,通常在探測到設備后(驅動的設備probe方法)調用該函數 * 參數 drv:串口驅動 * ? ? ?port:要添加的串口端口 * 返回值: ?成功,返回0;否則返回錯誤碼 */ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port); 4、uart_remove_one_port
?/* 功能: ? ? uart_remove_one_port用于刪除一個已添加到串口驅動中的串口端口,通常在驅動卸載時調用該函數 * 參數 drv: 串口驅動 * ? ? ?port: 要刪除的串口端口 * 返回值: ? 成功,返回0;否則返回錯誤碼 */ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port);
5、uart_write_wakeup
?/* 功能: ? ? uart_write_wakeup喚醒上層因向串口端口寫數據而阻塞的進程,通常在串口發送中斷處理函數中調用該函數 * 參數 port:需要喚醒寫阻塞進程的串口端口 */ void uart_write_wakeup(struct uart_port *port); 6、uart_suspend_port
?/* 功能: ? ? uart_suspend_port用于掛起特定的串口端口 * 參數 drv: 要掛起的串口端口所屬的串口驅動 * ? ? ?port:要掛起的串口端口 * 返回值: ? 成功返回0;否則返回錯誤碼 */ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port); 7、uart_resume_port
?/* 功能: ? ? uart_resume_port用于恢復某一已掛起的串口 * 參數 drv: 要恢復的串口端口所屬的串口驅動 * ? ? ?port:要恢復的串口端口 * 返回值: ? 成功返回0;否則返回錯誤碼 */ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) 8、uart_get_baud_rate
?/* 功能: ? ? ? ?uart_get_baud_rate通過解碼termios結構體來獲取指定串口的波特率 * 參數 port: ?要獲取波特率的串口端口 * ? ? termios:當前期望的termios配置(包含串口波特率) * ? ? old: ? ?以前的termios配置,可以為NULL * ? ? min: ? ?可接受的最小波特率 * ? ? max: ? ?可接受的最大波特率 * 返回值: ? ? 串口的波特率 */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max);
9、uart_get_divisor
?/* 功能: ? ? uart_get_divisor用于計算某一波特率的串口時鐘分頻數(串口波特率除數) * 參數 port:要計算時鐘分頻數的串口端口 * ? ? ?baud:期望的波特率 *返回值: ? ?串口時鐘分頻數 */ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
10、uart_update_timeout
?/* 功能: ? ? ?uart_update_timeout用于更新(設置)串口FIFO超時時間 * 參數 port: 要更新超時時間的串口端口 * ? ? cflag:termios結構體的cflag值 * ? ? baud: 串口的波特率 */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud); 11、uart_match_port
?/* 功能:uart_match_port用于判斷兩串口端口是否為同一端口 * 參數 port1、port2:要判斷的串口端口 * 返回值:不同返回0;否則返回非0 */ int uart_match_port(struct uart_port *port1, struct uart_port *port2);
12、uart_console_write
?/* 功能: ? ? ? ?uart_console_write用于向串口端口寫一控制臺信息 * 參數 port: ? ?要寫信息的串口端口 * ? ? s: ? ? ? 要寫的信息 * ? ? count: ? 信息的大小 * ? ? putchar: 用于向串口端口寫字符的函數,該函數函數有兩個參數:串口端口和要寫的字符 */ void uart_console_write(struct uart_port *port, const char *s, unsigned int count, void (*putchar)(struct uart_port *, int))
三、針對 GYM-1010-B 串口的編寫?
該串口驅動例子是我針對海思 Hi3516?處理器的串口2(uart2)獨立開發的。該驅動將串口看作平臺(platform)設備。platform可以看作一偽總線,用于將集成于片上系統的輕量級設備與Linux設備驅動模型聯系到一起,它包含以下兩部分(有關platform的聲明都在#include <linux/platform_device.h>,具體實現在drivers/base/platform.c): 1、platform設備。我們需要為每個設備定義一個platform_device實例
? ? ??struct platform_device { const char ? ? ?*name; ? ? ? ? /* 設備名 */ int ? ? ? ? ? ? ?id; ? ? ? ? ? /* 設備的id號 */ struct device ? ?dev; ? ? ? ? ?/* 其對應的device */ u32 ? ? ? ? ? ? ?num_resources;/* 該設備用有的資源數 */ struct resource *resource; ? ? /* 資源數組 */ };
? 為我們的設備創建platform_device實例有兩種方法:填充一個platform_device結構體后用platform_device_register(一次注冊一個)或platform_add_devices(一次可以注冊多個platform設備)將platform_device注冊到內核;更簡單的是使用platform_device_register_simple來建立并注冊我們的platform_device。
? ??2、platform驅動。platform設備由platform驅動進行管理。當設備加入到系統中時,platform_driver的probe方法會被調用來見對應的設備添加或者注冊到內核;當設備從系統中移除時,platform_driver的remove方法會被調用來做一些清理工作,如移除該設備的一些實例、注銷一些已注冊到系統中去的東西。
? ? ??struct platform_driver {
? ? int ?(*probe)(struct platform_device *);
? ? int ?(*remove)(struct platform_device *);
? ? void (*shutdown)(struct platform_device *);
? ? int ?(*suspend)(struct platform_device *, pm_message_t state);
? ? int ?(*suspend_late)(struct platform_device *, pm_message_t state);
? ? int ?(*resume_early)(struct platform_device *);
? ? int ?(*resume)(struct platform_device *);
? ? struct device_driver driver;
};
更詳細platform資料可參考其他資料,略。。。。。。。。。。
下面是串口驅動例子和其GPS測試程序源碼 .....
總結
以上是生活随笔為你收集整理的GPS NMEA 0183 4.10协议/GPS Linux串口驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 招行的享定存规则
- 下一篇: 农行卡状态异常解除方法 可以先拨打客服电