Temperature acquisition demo

This commit is contained in:
sityliu 2024-04-14 17:59:04 +08:00
parent 3f16c2940c
commit 9874cd49a2
23 changed files with 408 additions and 83 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="C:\ruanjian\anaconda\envs\test_env1" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>

View File

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="C:\ruanjian\anaconda\envs\test_env1" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

109
README.md
View File

@ -1,71 +1,60 @@
## Python项目结构示例
## Python 获取 485 温度传感器数据
### 简介
该仓库为 485 温度传感器数据的获取
### 典型的Python项目的项目结构
运行
```py
myproject/
├── myproject/
│ ├── __init__.py
│ ├── module1.py
│ ├── module2.py
│ └── ...
├── tests/
│ ├── __init__.py
│ ├── test_module1.py
│ ├── test_module2.py
│ └── ...
├── docs/
├── README.md
├── requirements.txt
└── setup.py
```shell
# 安装依赖
pip install -r requirements.txt
# 运行
Python3 run.py
```
- `myproject/`项目的根目录也是Python包的根目录。
- `myproject/__init__.py`:一个空的`__init__.py`文件,用于将`myproject`目录标记为一个Python包。
- `myproject/module1.py`、`myproject/module2.py`等:项目的模块文件,包含项目的核心代码。
- `tests/`:测试目录,包含用于测试项目代码的测试文件。
- `docs/`:文档目录,包含项目的文档文件。
- `README.md`项目的说明文档通常使用Markdown格式编写。
- `requirements.txt`:项目的依赖文件,列出了项目所需的所有依赖包及其版本号。
- `setup.py`项目的安装文件用于将项目打包为可安装的Python包。
这只是一个基本的项目结构示例,实际项目的结构可能会根据具体需求有所不同。
### 项目结构:
### 示例一个典型的flask项目目录结构
```py
myflaskproject/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── views.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── home.html
│ │ └── ...
│ └── static/
│ ├── css/
│ ├── js/
│ └── ...
├── config.py
├── requirements.txt
├── run.py
└── README.md
```
get_485_temperature>tree /f
│ README.md
│ requirements.txt
│ run.py // 程序入口
├─.idea
├─app
│ │ get_temperature.py
│ │ __init__.py
│ │
│ └─__pycache__
│ get_temperature.cpython-38.pyc
__init__.cpython-38.pyc
├─docs
│ NTA8A01 NTC温度传感器设置协议.docx
│ NTA8A01 NTC温度传感器说明书.docx
└─tests
test.py
```
- `app/`:应用程序目录,包含应用程序的核心代码。
- `app/__init__.py`应用程序的初始化文件创建Flask应用对象并配置应用程序。
- `app/models.py`:应用程序的模型文件,包含数据库模型定义。
- `app/views.py`:应用程序的视图文件,包含路由和视图函数的定义。
- `app/templates/`模板目录包含应用程序的HTML模板文件。
- `app/static/`静态文件目录包含应用程序的静态资源文件如CSS、JavaScript等。
- `config.py`:配置文件,包含应用程序的配置信息。
- `requirements.txt`:项目的依赖文件,列出了项目所需的所有依赖包及其版本号。
- `run.py`:应用程序的入口文件,用于启动应用程序。
- `README.md`项目的说明文档通常使用Markdown格式编写。
### 使用设备
https://item.taobao.com/item.htm?id=643781808936
### 设备说明
├─docs
│ NTA8A01 NTC温度传感器设置协议.docx
│ NTA8A01 NTC温度传感器说明书.docx

Binary file not shown.

Binary file not shown.

76
app/get_temperature.py Normal file
View File

@ -0,0 +1,76 @@
#!/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File : get_temperature.py
# Time 2024/4/14 下午 4:23
# Modify sityliu
# Author :蓝陌
# version python 3.8
# Description获取温度485通信
"""
import serial
import time
print("Hello,World!")
# 打开串口
port = "COM7"
baud = 9600
timeout = 1
try:
ser = serial.Serial(port=port, baudrate=baud, bytesize=8,parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1)
if ser.isOpen():
print("Port is open")
except:
print("请检查串口是否被占用;或者串口出现异常!")
exit()
# crc16 算法
def crc16(data: bytes) -> int:
crc = 0xFFFF
for b in data:
cur_byte = 0xFF & b
for _ in range(0, 8):
if (crc & 0x0001) ^ (cur_byte & 0x0001):
crc = (crc >> 1) ^ 0xA001
else:
crc >>= 1
cur_byte >>= 1
return ((crc & 0xFF) << 8) | (crc >> 8)
# 判断高位
def highest_bit(hex_num):
bin_num = bin(int(hex_num, 16))[2:]
return '1' if bin_num[0] == '1' else '0'
# 组建读写串口信息
# 发送帧地址为101 03 00 00 00 01 84 0A
# 返回帧RX01 03 02 01 F2 38 51
sed_msg = bytearray([0x01, 0x03, 0x00, 0x00, 0x00, 0x01])
crc = crc16(sed_msg)
crc = "{:04x}".format(crc)
sendbytes = bytes.fromhex(crc)
sed_msg = sed_msg + sendbytes
print("发送帧:",sed_msg)
def run():
# 读取和解析串口数据
while True:
ser.write(bytes(sed_msg))
time.sleep(0.1)
recbytes = ser.readline()
hex_list = [hex(b)[2:] for b in recbytes]
hex_data = hex_list[3] + hex_list[4]
tes = highest_bit(hex_data)
if highest_bit(hex_data) == '1':
if int(hex_data,16) / 10 >= 6280:
print("温度探头断开或出现异常,请检查!!!")
exit()
else:
print("检测到的温度:", int(hex_data, 16) / 10)
else:
# 负温度
print("检测到的温度:", (int(hex_data, 16) - 65536) / 10)

View File

View File

View File

View File

View File

View File

@ -1,3 +0,0 @@
class Config:
SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False

Binary file not shown.

Binary file not shown.

View File

View File

@ -1,3 +1,3 @@
-i https://pypi.tuna.tsinghua.edu.cn/simple
Flask
Flask-RESTful
pyserial
modbus-tk

5
run.py
View File

@ -1,4 +1,5 @@
from app import app
from app import get_temperature
if __name__ == '__main__':
app.run()
get_temperature.run()

View File

270
tests/test.py Normal file
View File

@ -0,0 +1,270 @@
# -*- coding: utf-8 -*-
import struct
import serial
import time
import modbus_tk
from modbus_tk import modbus_rtu
print("Hello,world!")
'''
在Python中读取485数据的过程可以分为以下几个步骤
创建Serial对象使用Python的serial库创建一个Serial对象用于与485设备进行通信
打开串口使用Serial对象的open()方法打开串口建立与485设备的连接
配置串口参数设置串口的波特率数据位停止位校验位等参数
读取数据使用Serial对象的read()方法读取485设备发送的数据
解析数据根据实际需求对读取到的数据进行解析和处理
关闭串口使用Serial对象的close()方法关闭串口连接'''
# 02:06:44.552→发 01 06 00 00 00 01 48 0A
# 02:06:51.794→发 01 06 00 00 00 00 89 CA
# 02:06:56.833→发 01 06 00 01 00 01 19 CA
# 02:06:58.360→发 01 06 00 01 00 00 D8 0A
# 01 04 00 00 00 01 31 CA
# 打开串口
# port = "COM7"
# baud = 38400
# timeout = 1
# ser = serial.Serial(port=port, baudrate=baud, bytesize=8,parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1)
# if ser.isOpen():
# print("Port is open")
# print(ser)
# # # 构建串口数据(发布和接收)
# # msg = "01 04 00 00 00 01 31 CA"
# # 发送帧 01 04 00 00 00 03 B0 OB
# # 站号 01
# # 功能码 04
# # 起始地址: 00 00=0X0000起始地址=0
# # 寄存器数: 00 03=0X0003寄存器数=3
# # CRC校验 B0 OB低字节在前高字节在后
# def crc16(data: bytes):
# crc = 0xFFFF
# for pos in data:
# crc ^= pos
# for i in range(8):
# if ((crc & 1) != 0):
# crc >>= 1
# crc ^= 0xA001
# else:
# crc >>= 1
# return ((crc & 0xff) << 8) + (crc >> 8)
# # 示例
# data = bytearray([0x01, 0x03, 0x00, 0x00, 0x00, 0x02])
# print(data)
# crc = crc16(data)
# crc = "{:04x}".format(crc)
# print(crc)
# # 010400000003B0OB
# msg = "010300000002"
# msg1 = msg + crc
# sendbytes = bytes.fromhex(msg1)
# data_to_send = [0x01, 0x06, 0x00, 0x00, 0x00, 0x01, 0x48, 0x0A]
# data_to_send2 = [0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0xCA]
# read_aisle1 = [0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x31, 0xCA]
# ser.write(bytes(data_to_send))
# time.sleep(0.2)
# buffer_data = ser.in_waiting
# return_data = ser.read(buffer_data)
# # address = ser.read(1) # 站号
# # function_code = ser.read(1) # 功能码
# # data_length = ser.read(2) # 起始地址
# # humidity = ser.read(2) # 读取数据2字节
# # crc1 = ser.read(2) # 读取CRC校验2字节
# # humidity_value = int.from_bytes(temperature, byteorder='big')
# print(return_data)
# # print(address, function_code, data_length, humidity, crc1)
# # print(crc1)
# return_data2 = ser.read(ser.in_waiting)
# print(return_data2)
# time.sleep(1)
# ser.write(bytes(data_to_send2))
# 98--27
CRC_HI = [
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
]
CRC_LO = [
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,0x04,
0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8,
0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10,
0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C,
0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0,
0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C,
0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54,
0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98,
0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,0x40
]
def CRC_16(str, usDataLen):
uchCRCHi = 0xFF # high byte of CRC initialized
uchCRCLo = 0xFF # low byte of CRC initialized
while usDataLen > 0: # pass through message buffer
uIndex = uchCRCHi ^ str[0] # calculate the CRC
uchCRCHi = uchCRCLo ^ CRC_HI[uIndex]
uchCRCLo = CRC_LO[uIndex]
str = str[1:]
usDataLen -= 1
return (uchCRCHi << 8) | uchCRCLo
def calc_crc16(string):
data = bytearray.fromhex(string)
# logging.info(type(data))
crc = 0xFFFF
for pos in data:
crc ^= pos
for i in range(8):
if ((crc & 1) != 0):
crc >>= 1
crc ^= 0xA001
else:
crc >>= 1
return ((crc & 0xff) << 8) + (crc >> 8)
# 485温度
'''
温度读取指令
01 03 00 00 00 01 84 0A
'''
port = "COM7"
baud = 9600
timeout = 1
ser = serial.Serial(port=port, baudrate=baud, bytesize=8,parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1)
if ser.isOpen():
print("Port is open")
print(ser)
# def crc16(data: bytes):
# crc = 0xFFFF
# for pos in data:
# crc ^= pos
# for i in range(8):
# if ((crc & 1) != 0):
# crc >>= 1
# crc ^= 0xA001
# else:
# crc >>= 1
# return ((crc & 0xff) << 8) + (crc >> 8)
def crc16(data: bytes) -> int:
crc = 0xFFFF
for b in data:
cur_byte = 0xFF & b
for _ in range(0, 8):
if (crc & 0x0001) ^ (cur_byte & 0x0001):
crc = (crc >> 1) ^ 0xA001
else:
crc >>= 1
cur_byte >>= 1
return ((crc & 0xFF) << 8) | (crc >> 8)
# 示例
# 01 03 00 00 00 01 84 0A
data = bytearray([0x01, 0x03, 0x00, 0x00, 0x00, 0x01])
print(data)
crc = crc16(data)
crc = "{:04x}".format(crc)
print(crc)
# 010400000003B0OB
msg = "010300000001"
msg1 = msg + crc
sendbytes = bytes.fromhex(msg1)
data_to_send = [0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A]
while(1):
ser.write(bytes(sendbytes))
time.sleep(0.1)
recbytes = ser.readline()
# return_data2 = ser.read(ser.in_waiting)
print(recbytes)
templist = list(recbytes)
# mode = templist[2]
# light = int(templist[3])
# left_time_low = float(templist[5])/16
print(templist)
# time.sleep(1)
# unsigned int CRC_16(unsigned char *str,unsigned int usDataLen)
# {
# unsigned char uchCRCHi = 0xFF ; /* high byte of CRC initialized */
# unsigned char uchCRCLo = 0xFF ; /* low byte of CRC initialized */
# unsigned uIndex ; /* will index into CRC lookup table */
# while (usDataLen--)/* pass through message buffer */
# {
# uIndex = uchCRCHi ^ *str++ ; /* calculate the CRC */
# uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
# uchCRCLo = auchCRCLo[uIndex] ;
# }
# return (uchCRCHi << 8 | uchCRCLo) ;
# }
# def CRC_16(str, usDataLen):
# uchCRCHi = 0xFF # high byte of CRC initialized
# uchCRCLo = 0xFF # low byte of CRC initialized
# while usDataLen > 0: # pass through message buffer
# uIndex = uchCRCHi ^ str[0] # calculate the CRC
# uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex]
# uchCRCLo = auchCRCLo[uIndex]
# str = str[1:]
# usDataLen -= 1
# return (uchCRCHi << 8) | uchCRCLo
# def crc_16(data: bytes) -> int:
# crc_hi = 0xFF
# crc_lo = 0xFF
# for byte in data:
# index = crc_hi ^ byte
# crc_hi = crc_lo ^ CRC_HI[index]
# crc_lo = CRC_LO[index]
# return (crc_hi << 8) | crc_lo

View File

@ -1,13 +0,0 @@
import unittest
from app import app
class UserTestCase(unittest.TestCase):
def setUp(self):
self.app = app.test_client()
def test_get_user(self):
response = self.app.get('/users/1')
data = response.get_json()
self.assertEqual(response.status_code, 200)
self.assertEqual(data['username'], 'john')
self.assertEqual(data['email'], 'john@example.com')

View File

@ -1 +0,0 @@
print("Hello World!")