tfcard_app.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. --[[
  2. @module onewire_multi_app
  3. @summary OneWire多DS18B20温度传感器应用演示模块(带切换功能)
  4. @version 002.002.000
  5. @date 2025.11.25
  6. @author 王棚嶙嶙
  7. @usage
  8. 本模块演示多DS18B20温度传感器的完整功能:
  9. 1. 多传感器切换控制
  10. 2. 电源管理(GPIO控制)
  11. 3. 按键切换传感器
  12. 4. 多路温度同时监测
  13. 5. 使用引脚复用功能(pins.setup)
  14. ]]
  15. log.info("onewire_multi_app", "多传感器模块版本: 002.002.000")
  16. -- 设置所有GPIO引脚电压为3.3V,确保DS18B20传感器正常供电
  17. pm.ioVol(pm.IOVOL_ALL_GPIO, 3300)
  18. -- GPIO2和GPIO31控制电源,确保DS18B20供电正常
  19. gpio.setup(2, 1) -- GPIO2输出高电平
  20. gpio.setup(31, 1) -- GPIO31输出高电平
  21. -- 传感器配置
  22. local sensor_config = {
  23. {pin = 2, channel = 0, name = "GPIO2(默认)"}, -- GPIO2使用通道0
  24. {pin = 54, channel = 3, name = "引脚54(复用)"} -- 引脚54使用通道3
  25. }
  26. local current_sensor = 1 -- 当前使用的传感器索引
  27. -- DS18B20命令定义
  28. local CMD_CONVERT_T = 0x44 -- 温度转换命令
  29. local CMD_READ_SCRATCHPAD = 0xBE -- 读取暂存器命令
  30. local CMD_SKIP_ROM = 0xCC -- 跳过ROM命令
  31. -- 全局状态变量
  32. local task_running = false
  33. local switch_pressed = false
  34. -- CRC8校验函数
  35. local function crc8_check(data)
  36. if not data or #data == 0 then
  37. return false
  38. end
  39. local crc = 0
  40. for i = 1, #data - 1 do
  41. crc = crc ~ data:byte(i)
  42. for j = 1, 8 do
  43. if crc & 0x01 then
  44. crc = (crc >> 1) ~ 0x8C
  45. else
  46. crc = crc >> 1
  47. end
  48. end
  49. end
  50. return crc == data:byte(#data)
  51. end
  52. -- 计算温度值
  53. local function calculate_temperature(data)
  54. if not data or #data < 2 then
  55. log.warn("onewire_multi_app", "温度数据无效或长度不足")
  56. return nil
  57. end
  58. local temp_raw = data:byte(1) + (data:byte(2) * 256)
  59. if temp_raw > 32767 then
  60. temp_raw = temp_raw - 65536
  61. end
  62. local temperature = temp_raw * 0.0625
  63. if temperature < -55.0 or temperature > 125.0 then
  64. log.warn("onewire_multi_app", "温度值超出有效范围:", temperature)
  65. return nil
  66. end
  67. return temperature
  68. end
  69. -- 电源控制函数
  70. local function power_control(on)
  71. log.info("onewire_multi_app", "电源控制:", on and "开启" or "关闭")
  72. if on then
  73. sys.wait(100) -- 等待电源稳定
  74. end
  75. return true
  76. end
  77. -- 初始化指定传感器
  78. local function init_sensor(sensor_idx)
  79. local config = sensor_config[sensor_idx]
  80. log.info("onewire_multi_app", "初始化传感器:", config.name, "引脚:", config.pin, "通道:", config.channel)
  81. if config.pin == 54 then
  82. pins.setup(config.pin, "ONEWIRE")
  83. log.info("onewire_multi_app", "配置引脚54为ONEWIRE复用功能")
  84. end
  85. onewire.init(config.channel)
  86. onewire.timing(config.channel, false, 0, 480, 70, 70, 410, 70, 10, 10, 15, 70)
  87. log.info("onewire_multi_app", "传感器初始化完成:", config.name)
  88. return config.channel
  89. end
  90. -- 检测DS18B20设备是否存在
  91. local function detect_ds18b20_device(channel)
  92. local present = onewire.reset(channel, true)
  93. if present then
  94. log.info("onewire_multi_app", "通道", channel, "检测到DS18B20设备")
  95. else
  96. log.warn("onewire_multi_app", "通道", channel, "未检测到DS18B20设备")
  97. end
  98. return present
  99. end
  100. -- 初始化OneWire总线
  101. local function init_onewire_bus(channel)
  102. log.info("onewire_multi_app", "初始化OneWire总线,通道:", channel)
  103. onewire.init(channel)
  104. onewire.timing(channel, false, 0, 480, 70, 70, 410, 70, 10, 10, 15, 70)
  105. log.info("onewire_multi_app", "OneWire总线初始化完成,通道:", channel)
  106. return true
  107. end
  108. -- 读取DS18B20温度
  109. local function read_ds18b20_temperature(channel)
  110. log.info("onewire_multi_app", "读取DS18B20温度,通道:", channel)
  111. local tbuff = zbuff.create(2)
  112. local rbuff = zbuff.create(9)
  113. local present = onewire.reset(channel, true)
  114. if not present then
  115. log.warn("onewire_multi_app", "通道", channel, "设备未响应")
  116. return nil
  117. end
  118. tbuff:set(0, CMD_SKIP_ROM)
  119. tbuff:set(1, CMD_CONVERT_T)
  120. local succ = onewire.tx(channel, tbuff, 0, 2, false, true, true)
  121. if not succ then
  122. log.warn("onewire_multi_app", "通道", channel, "发送温度转换命令失败")
  123. return nil
  124. end
  125. log.info("onewire_multi_app", "等待温度转换完成...")
  126. sys.wait(750)
  127. local succ = onewire.reset(channel, true)
  128. if not succ then
  129. log.warn("onewire_multi_app", "通道", channel, "读取时设备未响应")
  130. return nil
  131. end
  132. tbuff:set(0, CMD_SKIP_ROM)
  133. tbuff:set(1, CMD_READ_SCRATCHPAD)
  134. succ = onewire.tx(channel, tbuff, 0, 2, false, true, true)
  135. if not succ then
  136. log.warn("onewire_multi_app", "通道", channel, "发送读取命令失败")
  137. return nil
  138. end
  139. rbuff:resize(9)
  140. local succ, rx_len = onewire.rx(channel, 9, nil, rbuff, 0, false, false, false)
  141. if not succ or rx_len ~= 9 then
  142. log.warn("onewire_multi_app", "通道", channel, "温度数据接收失败,长度:", rx_len or 0)
  143. return nil
  144. end
  145. local crc8c = crypto.crc8(rbuff:query(0,8), 0x31, 0, true)
  146. if crc8c == rbuff[8] then
  147. local temp_low = rbuff[0]
  148. local temp_high = rbuff[1]
  149. local temp_raw = temp_low + (temp_high * 256)
  150. if temp_raw > 32767 then
  151. temp_raw = temp_raw - 65536
  152. end
  153. local temperature = temp_raw * 0.0625
  154. if temperature >= -55.0 and temperature <= 125.0 then
  155. log.info("onewire_multi_app", "温度读取成功,通道", channel, ":", string.format("%.2f°C", temperature))
  156. return temperature
  157. else
  158. log.warn("onewire_multi_app", "温度值超出有效范围:", temperature)
  159. return nil
  160. end
  161. else
  162. log.warn("onewire_multi_app", "CRC校验失败,期望:", string.format("0x%02X", crc8c),
  163. "实际:", string.format("0x%02X", rbuff[8]))
  164. return nil
  165. end
  166. end
  167. -- 切换传感器
  168. local function switch_onewire_sensor()
  169. log.info("onewire_multi_app", "切换传感器...")
  170. local old_config = sensor_config[current_sensor]
  171. onewire.deinit(old_config.channel)
  172. current_sensor = (current_sensor % #sensor_config) + 1
  173. local new_config = sensor_config[current_sensor]
  174. local channel = init_sensor(current_sensor)
  175. log.info("onewire_multi_app", "切换到传感器:", new_config.name, "通道:", channel)
  176. return channel
  177. end
  178. -- 初始化硬件
  179. local function init_hardware()
  180. log.info("onewire_multi_app", "初始化硬件配置...")
  181. gpio.setup(gpio.PWR_KEY, function()
  182. switch_pressed = true
  183. log.info("onewire_multi_app", "切换按键被按下")
  184. end, gpio.PULLUP, gpio.RISING)
  185. local channel = init_sensor(current_sensor)
  186. local detected = detect_ds18b20_device(channel)
  187. if not detected then
  188. log.warn("onewire_multi_app", "第一个传感器未检测到,尝试第二个传感器...")
  189. current_sensor = 2
  190. channel = init_sensor(current_sensor)
  191. detected = detect_ds18b20_device(channel)
  192. end
  193. log.info("onewire_multi_app", "硬件初始化完成")
  194. log.info("onewire_multi_app", "当前使用传感器:", sensor_config[current_sensor].name)
  195. return detected
  196. end
  197. -- 演示OneWire初始化功能
  198. local function demonstrate_onewire_init()
  199. log.info("demo", "=== 1. 多通道onewire.init()演示 ===")
  200. for i, config in ipairs(sensor_config) do
  201. log.info("demo", "初始化通道", config.channel, "对应引脚", config.pin, config.name)
  202. onewire.init(config.channel)
  203. end
  204. log.info("demo", "OneWire初始化演示完成")
  205. end
  206. -- 演示时序配置功能
  207. local function demonstrate_onewire_timing()
  208. log.info("demo", "=== 2. 多通道onewire.timing()演示 ===")
  209. for i, config in ipairs(sensor_config) do
  210. log.info("demo", "配置通道", config.channel, "的DS18B20标准时序")
  211. onewire.timing(config.channel, false, 0, 480, 70, 70, 410, 70, 10, 10, 15, 70)
  212. end
  213. log.info("demo", "时序配置演示完成")
  214. end
  215. -- 演示设备检测功能
  216. local function demonstrate_device_detection()
  217. log.info("demo", "=== 3. 多通道设备检测演示 ===")
  218. for i, config in ipairs(sensor_config) do
  219. local present = onewire.reset(config.channel, true)
  220. log.info("demo", "通道", config.channel, config.name, "检测状态:", present and "检测到设备" or "未检测到设备")
  221. end
  222. log.info("demo", "设备检测演示完成")
  223. end
  224. -- 演示电源控制功能
  225. local function demonstrate_power_control()
  226. log.info("demo", "=== 4. 电源控制演示 ===")
  227. power_control(true)
  228. power_control(false)
  229. log.info("demo", "电源控制演示完成")
  230. end
  231. -- 演示传感器切换功能
  232. local function demonstrate_sensor_switching()
  233. log.info("demo", "=== 5. 传感器切换功能演示 ===")
  234. local original_sensor = current_sensor
  235. for i = 1, #sensor_config do
  236. local channel = switch_onewire_sensor()
  237. local detected = detect_ds18b20_device(channel)
  238. log.info("demo", "切换到传感器", current_sensor, "检测状态:", detected and "成功" or "失败")
  239. sys.wait(500)
  240. end
  241. current_sensor = original_sensor
  242. init_sensor(current_sensor)
  243. log.info("demo", "传感器切换演示完成,恢复原始传感器")
  244. end
  245. -- 演示位操作功能
  246. local function demonstrate_bit_operations()
  247. log.info("demo", "=== 6. 位操作功能演示 ===")
  248. for i, config in ipairs(sensor_config) do
  249. onewire.bit(config.channel, 1)
  250. log.info("demo", "通道", config.channel, "发送位: 1")
  251. local bit_value = onewire.bit(config.channel)
  252. log.info("demo", "通道", config.channel, "读取位值:", bit_value)
  253. end
  254. log.info("demo", "位操作演示完成")
  255. end
  256. -- 演示调试模式功能
  257. local function demonstrate_debug_mode()
  258. log.info("demo", "=== 7. 调试模式演示 ===")
  259. log.info("demo", "调试模式当前状态: 关闭(可通过取消注释开启)")
  260. -- for i, config in ipairs(sensor_config) do
  261. -- onewire.debug(config.channel, true)
  262. -- log.info("demo", "开启通道", config.channel, "的调试模式")
  263. -- end
  264. log.info("demo", "调试模式演示完成")
  265. end
  266. -- 演示资源释放功能
  267. local function demonstrate_resource_cleanup()
  268. log.info("demo", "=== 8. 资源释放演示 ===")
  269. for i, config in ipairs(sensor_config) do
  270. onewire.deinit(config.channel)
  271. log.info("demo", "释放通道", config.channel, "的资源")
  272. end
  273. log.info("demo", "资源释放演示完成")
  274. -- 重新初始化所有通道
  275. for i, config in ipairs(sensor_config) do
  276. init_sensor(i)
  277. end
  278. end
  279. -- 演示多传感器OneWire API接口
  280. local function demonstrate_multi_onewire_apis()
  281. log.info("onewire_multi_app", "开始演示多传感器OneWire API接口...")
  282. demonstrate_onewire_init()
  283. demonstrate_onewire_timing()
  284. demonstrate_device_detection()
  285. demonstrate_power_control()
  286. demonstrate_sensor_switching()
  287. demonstrate_bit_operations()
  288. demonstrate_debug_mode()
  289. demonstrate_resource_cleanup()
  290. log.info("onewire_multi_app", "多传感器API演示完成")
  291. end
  292. -- 多传感器应用主函数
  293. local function multi_sensor_app_main()
  294. log.info("onewire_multi_app", "启动多传感器应用")
  295. if not init_hardware() then
  296. log.error("onewire_multi_app", "所有传感器都未检测到,请检查硬件连接")
  297. log.warn("onewire_multi_app", "硬件连接提示:")
  298. log.warn("onewire_multi_app", "1. 传感器1连接GPIO2 (默认OneWire功能)")
  299. log.warn("onewire_multi_app", "2. 传感器2连接引脚54 (复用为GPIO3/ONEWIRE)")
  300. log.warn("onewire_multi_app", "3. 确保GPIO31/GPIO2已设置为高电平供电")
  301. return
  302. end
  303. task_running = true
  304. log.info("onewire_multi_app", "开始多传感器连续监测...")
  305. log.info("onewire_multi_app", "按PWR_KEY按键可切换传感器")
  306. while task_running do
  307. if switch_pressed then
  308. switch_pressed = false
  309. switch_onewire_sensor()
  310. end
  311. local config = sensor_config[current_sensor]
  312. local temperature = read_ds18b20_temperature(config.channel)
  313. if temperature then
  314. log.info("onewire_multi_app",
  315. "传感器" .. current_sensor .. "(" .. config.name .. "):",
  316. string.format("%.2f°C", temperature))
  317. else
  318. log.warn("onewire_multi_app", "传感器" .. current_sensor .. "读取失败")
  319. end
  320. sys.wait(1000)
  321. end
  322. for i, config in ipairs(sensor_config) do
  323. onewire.deinit(config.channel)
  324. end
  325. log.info("onewire_multi_app", "多传感器应用结束")
  326. end
  327. -- 启动多传感器应用任务
  328. local function start_multi_sensor_app()
  329. sys.taskInit(function()
  330. demonstrate_multi_onewire_apis()
  331. multi_sensor_app_main()
  332. end)
  333. end
  334. -- 模块初始化函数
  335. local function init_module()
  336. log.info("onewire_multi_app", "多传感器应用模块初始化")
  337. start_multi_sensor_app()
  338. end
  339. -- 启动模块
  340. init_module()
  341. log.info("onewire_multi_app", "多传感器应用模块加载完成")