本帖最后由 lugl4313820 于 2021-12-19 22:49 编辑
昨天实现在MQTT的数据发布,今天实现了stm32F103C8T6用DS18B20采集温度,通过EC-01-Kit发布数据,用python编写展示程序。
1、18B20是常用的数字温度计传感器,也是单片机经常使用的温度计,我这里直接移值正点原子的18B20驱动库。
18B20.h
#ifndef __DS18B20_H
#define __DS18B20_H
#include "sys.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//DS18B20驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/12
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//IO方向设置 这里使用了PA0,原来的库是用PE11的,更改过来还是费了一翻周折,翻看了寄存器的资料
#define DS18B20_IO_IN() {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=8;}
#define DS18B20_IO_OUT() {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=3;}
////IO操作函数
#define DS18B20_DQ_OUT PAout(0) //数据端口 PA0
#define DS18B20_DQ_IN PAin(0) //数据端口 PA0
u8 DS18B20_Init(void);//初始化DS18B20
short DS18B20_Get_Temp(void);//获取温度
void DS18B20_Start(void);//开始温度转换
void DS18B20_Write_Byte(u8 dat);//写入一个字节
u8 DS18B20_Read_Byte(void);//读出一个字节
u8 DS18B20_Read_Bit(void);//读出一个位
u8 DS18B20_Check(void);//检测是否存在DS18B20
void DS18B20_Rst(void);//复位DS18B20
#endif
ds18B20.c
#include "ds18b20.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//DS18B20驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/12
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//复位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //SET PG11 OUTPUT
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us
DS18B20_DQ_OUT=1; //DQ=1
delay_us(15); //15US
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN(); //SET PG11 INPUT
while (DS18B20_DQ_IN&&retry<200)
{
retry++;
delay_us(1);
};
if(retry>=200)return 1;
else retry=0;
while (!DS18B20_DQ_IN&&retry<240)
{
retry++;
delay_us(1);
};
if(retry>=240)return 1;
return 0;
}
//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void)
{
u8 data;
DS18B20_IO_OUT(); //SET PG11 OUTPUT
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN(); //SET PG11 INPUT
delay_us(12);
if(DS18B20_DQ_IN)data=1;
else data=0;
delay_us(50);
return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void)
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT(); //SET PG11 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
DS18B20_DQ_OUT=0; // Write 1
delay_us(2);
DS18B20_DQ_OUT=1;
delay_us(60);
}
else
{
DS18B20_DQ_OUT=0; // Write 0
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
//开始温度转换
void DS18B20_Start(void)
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // skip rom
DS18B20_Write_Byte(0x44); // convert
}
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); //使能PORTG口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PORTG.11 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_SetBits(GPIOG,GPIO_Pin_11); //输出1
DS18B20_Rst();
return DS18B20_Check();
}
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // skip rom
DS18B20_Write_Byte(0xbe); // convert
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0; //温度为负
}else temp=1; //温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL; //获得底八位
tem=(float)tem*0.625; //转换
if(temp)return tem; //返回温度值
else return -tem;
}
拿到18B20驱动下,在主程序里直接引用并采集就行了:
主程序更改如下:
main.c
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "EC616S.h"
#include "mqtt.h"
#include "tsensor.h"
#include "ds18b20.h"
/************************************************
ALIENTEK战舰STM32开发板实验4
串口实验
技术支持:www.openedv.com
淘宝店铺:http://eboard.taobao.com
关注微信公众平台微信号:"正点原子",免费获取STM32资料。
广州市星翼电子科技有限公司
作者:正点原子 @ALIENTEK
************************************************/
int main(void)
{
u16 t;
double temp;
short temp_ds18b20;
u16 len;
char cData[40];
u16 times=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
EC616S_Init(9600); //command serial
LED_Init(); //LED端口初始化
//KEY_Init(); //初始化与按键连接的硬件接口
//T_Adc_Init(); //ADC初始化
DS18B20_Init();
EC616S_lugl_MQTTClient_connect();
while(1)
{
temp_ds18b20=DS18B20_Get_Temp(); //得到温度值
printf("18b20温度为:%d\r\n",temp_ds18b20);
sprintf(cData,"{\"value\":\"%d\"}", temp_ds18b20);
EC616S_lugl_MQTTClient_Test(cData);
delay_ms(500);
}
}
串口监视助手显示为:发布数据正常返回OK。
上位机软件用pyqt5开发:
man.py程序为:
# encoding: utf-8
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLCDNumber, QVBoxLayout,QLabel
from PyQt5.QtCore import QTimer, QDateTime
from PyQt5.QtGui import QFont
import paho.mqtt.client as mqtt
import time
import json
host = "host_name"
port = 1883
username = 'user_name'
password = 'pwd'
mqttClient = mqtt.Client(protocol=3) # 定义mqtt对象
temp_d = {'value': 0}
# noinspection PyUnusedLocal
def on_connect(client, userdata, flags, rc):
print("连接成功" + "Connected with result code " + str(rc))
# noinspection PyUnusedLocal
def on_message(client, userdata, msg): # 接收非图片数据
if msg.topic == "topic/1":
try:
s = msg.payload.decode("utf-8")
tab = json.loads(s)
temp_d['value'] = int(tab['value'])/10
except Exception as e:
print(str(e))
# noinspection PyUnusedLocal
def on_subscribe(client, userdata, mid, granted_qos):
print("消息订阅成功")
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.resize(600, 600)
self.lcd_1 = QLCDNumber(self) # 1
self.lcd_1.setDigitCount(5)
self.lcd_1.display(20.5)
self.label = QLabel(self)
self.label.setFixedWidth(600)
self.label.move(150, 200)
self.v_layout = QVBoxLayout()
self.v_layout.addWidget(self.lcd_1)
self.v_layout.addWidget(self.label)
self.setLayout(self.v_layout)
timer = QTimer(self)
# mqtt配置初始化
mqttClient.username_pw_set("admin", "password")
mqttClient.on_connect = on_connect # 连接递归
mqttClient.on_subscribe = on_subscribe # 订阅递归
mqttClient.on_message = on_message # 消息递归
mqttClient.username_pw_set(username, password=password)
mqttClient.connect(host=host, port=port, keepalive=60) # 订阅频道
time.sleep(0.02)
# 动态显示时间在label上
timer.timeout.connect(self.showtime)
timer.start()
# 订阅消息
mqttClient.subscribe(topic="topic/+", qos=0)
mqttClient.loop_start()
def showtime(self):
datetime = QDateTime.currentDateTime()
text = datetime.toString()
self.label.setText(text)
self.label.setFont(QFont("Roman times", 12, QFont.Bold))
self.lcd_1.display(temp_d['value'])
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
实现的效果为:
经过这几天的学习NB-IoT的使用,感觉这块板子上手快,易用性,稳定性也挺好。
如果哪位老板想用于生产环境,我这里再加完善,可以先快的出成品。下一步准备手机实现温度展示。
用E4A写了一个手机的界面,有点丑,也是实现基本功能吧,很想找个美工美化一下。