Air530zGPS.lua 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. --- 模块功能:串口1功能测试
  2. -- @author openLuat
  3. -- @module uart.testUart
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2018.03.27
  7. module(...,package.seeall)
  8. require"utils"
  9. require"pm"
  10. local EnableRMC = "$PCAS03,0,0,0,0,1,0,0,0,0,0,,,0,0*03\r\n"
  11. --[[
  12. 功能定义:
  13. uart按照帧结构接收外围设备的输入,收到正确的指令后,回复ASCII字符串
  14. 帧结构如下:
  15. 帧头:1字节,0x01表示扫描指令,0x02表示控制GPIO命令,0x03表示控制端口命令
  16. 帧体:字节不固定,跟帧头有关
  17. 帧尾:1字节,固定为0xC0
  18. 收到的指令帧头为0x01时,回复"CMD_SCANNER\r\n"给外围设备;例如接收到0x01 0xC0两个字节,就回复"CMD_SCANNER\r\n"
  19. 收到的指令帧头为0x02时,回复"CMD_GPIO\r\n"给外围设备;例如接收到0x02 0xC0两个字节,就回复"CMD_GPIO\r\n"
  20. 收到的指令帧头为0x03时,回复"CMD_PORT\r\n"给外围设备;例如接收到0x03 0xC0两个字节,就回复"CMD_PORT\r\n"
  21. 收到的指令帧头为其余数据时,回复"CMD_ERROR\r\n"给外围设备;例如接收到0x04 0xC0两个字节,就回复"CMD_ERROR\r\n"
  22. ]]
  23. --串口ID,1对应uart1
  24. --如果要修改为uart2,把UART_ID赋值为2即可
  25. local UART_ID = 1
  26. --帧头类型以及帧尾
  27. local CMD_SCANNER,CMD_GPIO,CMD_PORT,FRM_TAIL = 1,2,3,string.char(0xC0)
  28. --串口读到的数据缓冲区
  29. local rdbuf = ""
  30. --[[
  31. 函数名:parse
  32. 功能 :按照帧结构解析处理一条完整的帧数据
  33. 参数 :
  34. data:所有未处理的数据
  35. 返回值:第一个返回值是一条完整帧报文的处理结果,第二个返回值是未处理的数据
  36. ]]
  37. local function parse(data)
  38. if not data then return end
  39. local tail = string.find(data,string.char(0xC0))
  40. if not tail then return false,data end
  41. local cmdtyp = string.byte(data,1)
  42. local body,result = string.sub(data,2,tail-1)
  43. log.info("testUart.parse",data:toHex(),cmdtyp,body:toHex())
  44. if cmdtyp == CMD_SCANNER then
  45. write("CMD_SCANNER")
  46. elseif cmdtyp == CMD_GPIO then
  47. write("CMD_GPIO")
  48. elseif cmdtyp == CMD_PORT then
  49. write("CMD_PORT")
  50. else
  51. write("CMD_ERROR")
  52. end
  53. return true,string.sub(data,tail+1,-1)
  54. end
  55. --[[
  56. 函数名:proc
  57. 功能 :处理从串口读到的数据
  58. 参数 :
  59. data:当前一次从串口读到的数据
  60. 返回值:无
  61. ]]
  62. local function proc(data)
  63. if not data or string.len(data) == 0 then return end
  64. --追加到缓冲区
  65. rdbuf = rdbuf..data
  66. local result,unproc
  67. unproc = rdbuf
  68. --根据帧结构循环解析未处理过的数据
  69. while true do
  70. result,unproc = parse(unproc)
  71. if not unproc or unproc == "" or not result then
  72. break
  73. end
  74. end
  75. rdbuf = unproc or ""
  76. end
  77. -- [2025-08-08 19:39:38.602] [I]-[testUart.read bin] $GNRMC,113938.000,A,3221.43244,N,11922.55915,E,0.29,0.00,080825,,,A,V*04
  78. -- [2025-08-08 19:39:39.610] [I]-[testUart.read bin] $GNRMC,113939.000,A,3221.43246,N,11922.55922,E,0.33,0.00,080825,,,A,V*08
  79. -- [2025-08-08 19:39:40.603] [I]-[testUart.read bin] $GNRMC,113940.000,A,3221.43240,N,11922.55931,E,0.54,0.00,080825,,,A,V*03
  80. -- [2025-08-08 19:39:41.583] [I]-[testUart.read bin] $GNRMC,113941.000,A,3221.43247,N,11922.55928,E,0.00,0.00,080825,,,A,V*0C
  81. -- 定义RMC数据结构(使用Lua表模拟)
  82. local rmc_data = {
  83. time = "", -- 时间
  84. state = "", -- 定位状态
  85. lat = "", -- 纬度
  86. NS = "", -- 南北纬
  87. lng = "", -- 经度
  88. WE = "", -- 东西经
  89. date = "" -- 日期
  90. }
  91. -- 全局变量,模拟接收缓冲区和经纬度存储
  92. local rx_data = ""
  93. local air530_lat = ""
  94. local air530_lng = ""
  95. -- RMC数据解析函数
  96. function AnalysisRMC(pRecRMC)
  97. print("AnalysisRMC")
  98. -- 初始化接收的数据结构
  99. pRecRMC.time = ""
  100. pRecRMC.state = ""
  101. pRecRMC.lat = ""
  102. pRecRMC.NS = ""
  103. pRecRMC.lng = ""
  104. pRecRMC.WE = ""
  105. pRecRMC.date = ""
  106. -- 将字符串按逗号分割成字段表
  107. local fields = {}
  108. for field in string.gmatch(rx_data, "([^,]+)") do
  109. table.insert(fields, field)
  110. end
  111. -- 检查字段数量是否足够
  112. if #fields < 10 then
  113. print("RMC数据格式不正确,字段数量不足")
  114. rx_data = "" -- 清空接收缓存
  115. return
  116. end
  117. -- 解析时间 (第2个字段,索引从1开始)
  118. pRecRMC.time = fields[2] or ""
  119. print("时间: " .. pRecRMC.time)
  120. -- 解析定位状态 (第3个字段)
  121. pRecRMC.state = fields[3] or ""
  122. print("定位状态: " .. pRecRMC.state)
  123. -- 检查定位是否有效
  124. if pRecRMC.state ~= "A" then
  125. print("无效定位信息!")
  126. rx_data = "" -- 清空接收缓存
  127. return
  128. end
  129. -- 解析纬度 (第4个字段)
  130. pRecRMC.lat = fields[4] or ""
  131. print("纬度: " .. pRecRMC.lat)
  132. air530_lat = pRecRMC.lat
  133. -- 解析南北纬 (第5个字段)
  134. pRecRMC.NS = fields[5] or ""
  135. print("南北纬: " .. pRecRMC.NS)
  136. -- 解析经度 (第6个字段)
  137. pRecRMC.lng = fields[6] or ""
  138. print("经度: " .. pRecRMC.lng)
  139. air530_lng = pRecRMC.lng
  140. -- 解析东西经 (第7个字段)
  141. pRecRMC.WE = fields[7] or ""
  142. print("东西经: " .. pRecRMC.WE)
  143. -- 解析日期 (第10个字段)
  144. pRecRMC.date = fields[10] or ""
  145. print("日期: " .. pRecRMC.date)
  146. -- 清空接收缓存
  147. rx_data = ""
  148. print("接收缓存区已清空")
  149. end
  150. -- 示例用法
  151. -- rx_data = "$GNRMC,113941.000,A,3221.43247,N,11922.55928,E,0.00,0.00,080825,,,A,V*0C"
  152. -- AnalysisRMC(rmc_data)
  153. --[[
  154. 函数名:read
  155. 功能 :读取串口接收到的数据
  156. 参数 :无
  157. 返回值:无
  158. ]]
  159. local function read()
  160. local data = ""
  161. --底层core中,串口收到数据时:
  162. --如果接收缓冲区为空,则会以中断方式通知Lua脚本收到了新数据;
  163. --如果接收缓冲器不为空,则不会通知Lua脚本
  164. --所以Lua脚本中收到中断读串口数据时,每次都要把接收缓冲区中的数据全部读出,这样才能保证底层core中的新数据中断上来,此read函数中的while语句中就保证了这一点
  165. while true do
  166. data = uart.read(UART_ID,"*l")
  167. if not data or string.len(data) == 0 then break end
  168. --打开下面的打印会耗时
  169. log.info("testUart.read bin",data)
  170. -- log.info("testUart.read hex",data:toHex())
  171. proc(data)
  172. end
  173. end
  174. --[[
  175. 函数名:write
  176. 功能 :通过串口发送数据
  177. 参数 :
  178. s:要发送的数据
  179. 返回值:无
  180. ]]
  181. function write(s)
  182. log.info("testUart.write",s)
  183. uart.write(UART_ID,s.."\r\n")
  184. end
  185. local function writeOk()
  186. log.info("testUart.writeOk")
  187. end
  188. --保持系统处于唤醒状态,此处只是为了测试需要,所以此模块没有地方调用pm.sleep("testUart")休眠,不会进入低功耗休眠状态
  189. --在开发“要求功耗低”的项目时,一定要想办法保证pm.wake("testUart")后,在不需要串口时调用pm.sleep("testUart")
  190. pm.wake("testUart")
  191. --注册串口的数据接收函数,串口收到数据后,会以中断方式,调用read接口读取数据
  192. uart.on(UART_ID,"receive",read)
  193. --注册串口的数据发送通知函数
  194. uart.on(UART_ID,"sent",writeOk)
  195. --配置并且打开串口
  196. uart.setup(UART_ID,9600,8,uart.PAR_NONE,uart.STOP_1)
  197. --如果需要打开“串口发送数据完成后,通过异步消息通知”的功能,则使用下面的这行setup,注释掉上面的一行setup
  198. --uart.setup(UART_ID,115200,8,uart.PAR_NONE,uart.STOP_1,nil,1)
  199. sys.timerStart(function ()
  200. log.info("像GPS发生命令")
  201. write(EnableRMC)
  202. end, 5000)