随着智能家居与物联网技术的迅速发展,人们对于生活品质的追求日益提升,家庭宠物养护也逐渐智能化、精细化。观赏鱼作为广受欢迎的宠物之一,其饲养环境的维护成为了众多养鱼爱好者的关注焦点。传统的观赏鱼缸管理依赖人工监测与调节,不仅费时费力,还难以实现精准控制,尤其是在快节奏的现代生活中,忙碌的主人常常难以及时发现并处理水质恶化、水温异常等问题,这直接影响到鱼类的健康与观赏性。
本项目通过集成先进的传感技术和远程控制功能,为观赏鱼提供一个稳定、健康的生态环境,同时让养鱼爱好者能够便捷地监控和管理鱼缸状态。
该项目的核心在于利用高性能的STM32F103RCT6微控制器作为主控单元,结合多种高精度传感器(包括浑浊度、温度、光敏及氨气传感器)实时监测水质、水温和光照条件,实现对鱼缸环境的全方位监控。通过智能化算法判断各项指标是否处于适宜范围,并据此自动调整增氧泵、加热设备及照明系统的运行,保证鱼缸环境的最优化。
项目采用了BC26 NBIOT模块,借助低功耗广域网技术,将鱼缸的实时数据上传至腾讯云IoT物联网平台。这一设计使得用户可以通过定制的微信小程序远程监控鱼缸状态,随时随地查看水质、水温、光照强度等关键参数,并根据需要远程调控设备工作模式与参数设定,如调整增氧泵的工作周期、设定水温阈值等,真正实现了观赏鱼缸管理的智能化与远程化。
本项目的开发满足现代家庭及商业场所对高效、智能宠物养护的需求,通过技术创新推动宠物养护方式的变革,提升养鱼体验。
(1)水质监测与警示:通过搭载的水质浑浊度传感器,系统能够实时监测鱼缸中的水质情况。一旦检测到水质浑浊度超过预设的最大安全值,系统将自动触发LED灯显示红色,提示用户需要更换或净化水质。若水质良好,则LED灯呈现绿色,给予安心指示。
(2)智能温控系统:集成的防水式DS18B20温度传感器持续监控水温变化。当水温降至预设的最低温度限制以下时,系统自动激活加热棒,维持鱼缸内水温恒定,确保鱼类生活在适宜的温度环境中。
(3)光照自动调节:光敏传感器BH1750监测环境光线强度,当自然光线不足,低于设定阈值时,系统自动开启内置的LED照明系统,为鱼缸内的生物提供必要的光照,促进其健康成长并增强观赏效果。
(4)氨气监测与环境优化:MQ137氨气传感器负责监测鱼缸内的氨气浓度,氨气是影响鱼类健康的主要有害物质之一。一旦检测到氨气超标,系统同样会亮起红色警示灯,提示用户需要采取措施改善硝化环境,保持水质清洁。
(5)自动增氧功能:系统支持用户通过微信小程序设定增氧泵的开启时间间隔,确保鱼缸内氧气充足,维持良好的水体含氧量,促进鱼类活跃度和生长。
(6)远程监控与控制:所有监测数据(水质、水温、光照强度)通过NBIOT模块实时传输至腾讯云IoT平台,用户可通过专属的微信小程序远程查看这些数据,实时了解鱼缸环境状态,并能远程调整各项设备的工作参数,如调整水温设定值、增氧泵工作计划等,实现远程智能管理。
(7)灵活的控制模式:微信小程序提供多种控制模式,包括自动模式、手动模式等,用户可根据实际情况自由切换,既可享受全自动化管理带来的便利,也能在需要时手动介入调整。
(1)主控模块:
(2)传感器模块:
(2)执行器模块:
(3)通信模块:
(4)用户交互模块:
(5)云服务与数据分析模块:
(1)感知层:
(2)控制层:
(3)通信层:
(4)云服务层:
(5)应用层:
主控CPU采用STM32F103RCT6,这颗芯片包括48 KB SRAM、256 KB Flash、2个基本定时器、4个通用定时器、2个高级定时器、51个通用IO口、5个串口、2个DMA控制器、3个SPI、2个I2C、1个USB、1个CAN、3个12位ADC、1个12位DAC、1个SDIO接口,芯片属于大容量类型,配置较高,整体符合硬件选型设计。当前选择的这款开发板自带了一个1.4寸的TFT-LCD彩屏,可以显示当前传感器数据以及一些运行状态信息。
测温采用DS18B20,DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。
DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。
主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。
TDS (Total Dissolved Solids)、中文名总溶解固体、又称溶解性固体、又称溶解性固体总量、表明1升水肿容有多少毫克溶解性固体、一般来说、TDS值越高、表示水中含有溶解物越多、水就越不洁净、虽然在特定情况下TDS并不能有效反映水质的情况、但作为一种可快速检测的参数、TDS目前还可以作为有效的在水质情况反映参数来作为参考。常用的TDS检测设备为TDS笔、虽然价格低廉、简单易用、但不能把数据传给控制系统、做长时间的在线监测、并做水质状况分析、使用专门的仪器、虽然能传数据、精度也高、但价格很贵、为此这款TDS传感器模块、即插即用、使用简单方便、测量用的激励源采用交流信号、可有效防止探头极化、延长探头寿命的同时、也增加了输出信号的稳定性、TDS探头为防水探头、可长期侵入水中测量、该产品可以应用于生活用水、水培等领域的水质检测、有了这个传感器、可轻松DIY–套TDS检测仪了、轻松检测水的洁净程度。
用来控制鱼缸加热。
地址:https://cloud.tencent.com/
微信扫描即可快速登录,然后选择产品,物联网,选择物联网开发平台。
链接: https://console.cloud.tencent.com/iotexplorer
第一次进去需要实名认证,认证成功就可以进去了。
点击项目名称,进入产品开发页面。
产品品类选择自定义产品品类。
点击产品名称,进入设备配置页面。
选择自定义品类。
- 上传腾讯云-微信小程序通信数据的属性值:
- ds18b20_max 温度阀值 读写权限 整型
- adc_hp_max 水质阀值 读写权限 整型
- time_food 增氧间隔 读写权限 整型
- auto_mode 控制模式 读写权限 布尔类型
- water_hp 水质 只读权限 整型
- temp_data 水温 只读权限 浮点数类型
- BH1750 光强 只读权限 整型
- MQ135 氨气 只读权限 整型
- oxygen_sw 增氧控制 读写权限 布尔类型
- heat_sw 加热控制 读写权限 布尔类型
- led_sw 照明灯控制 读写权限 布尔类型
-
下面就继续添加(按照),前面的流程。
然后翻到最下面,点击下一步。
设备开发页面有一个主题列表。可以了解到当前的主题信息。
当前项目需要用到的就是下面的两个主题。
- $thing/up/property/2ZYN8YF7CM/${deviceName} 发布 属性上报
- $thing/up/property/2ZYN8YF7CM/${deviceName} 订阅 属性下发与属性上报响应
-
这个页面不需要做什么,直接点击下一步即可。
设置信息: 根据自己设备情况自己设置即可。
根据需要配置。
根据自己的样式进行调整。
可以根据自己喜欢的图标进行设置。
创建完成。
设备的二维码: (打开微信小程序,搜索 腾讯连连,打开腾讯连连,扫描下面的二维码就可以绑定设备了—这个是有有效时间范围的,过期了需要登录重新获取二维码)
设备信息:
- 产品密匙:WCk1aGDvGyg34+KolnKMqw==
- 产品ID:2ZYN8YF7CM
-
下面也有MQTT三元组的信息。
如果除了小程序之外,还想使用手机APP,可以配置手机APP页面。
配置步骤和上面的微信程序一样。
MQTT协议介绍:https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html
- 目前物联网通信支持 MQTT 标准协议接入(兼容3.1.1版本协议),具体的协议请参见 MQTT 3.1.1 协议文档。
- 和标准 MQTT 区别
-
- 1. 支持 MQTT 的 PUB、SUB、PING、PONG、CONNECT、DISCONNECT、UNSUB 等报文。
- 2. 支持 cleanSession。
- 3. 不支持 will、retain msg。
- 4. 不支持 QOS2。
-
就像我们登录QQ、登录微信需要账号密码一样,设备登录物联网平台也需要类似的东西。
官方文档地址: https://cloud.tencent.com/document/product/634/32546
生成密匙直接使用python代码获取:
- #!/usr/bin/python
- # -*- coding: UTF-8 -*-
- import base64
- import hashlib
- import hmac
- import random
- import string
- import time
- import sys
- # 生成指定长度的随机字符串
- def RandomConnid(length):
- return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
- # 生成接入物联网通信平台需要的各参数
- def IotHmac(productID, devicename, devicePsk):
- # 1. 生成 connid 为一个随机字符串,方便后台定位问题
- connid = RandomConnid(5)
- # 2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串
- # 将当前时间往后推迟5年
- expiry = int(time.time()) + 5 * 365 * 24 * 60 * 60
- # 3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}
- clientid = "{}{}".format(productID, devicename)
- # 4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}
- username = "{};12010126;{};{}".format(clientid, connid, expiry)
- # 5. 对 username 进行签名,生成token
- secret_key = devicePsk.encode('utf-8') # convert to bytes
- data_to_sign = username.encode('utf-8') # convert to bytes
- secret_key = base64.b64decode(secret_key) # this is still bytes
- token = hmac.new(secret_key, data_to_sign, digestmod=hashlib.sha256).hexdigest()
- # 6. 根据物联网通信平台规则生成 password 字段
- password = "{};{}".format(token, "hmacsha256")
- return {
- "clientid" : clientid,
- "username" : username,
- "password" : password
- }
- if __name__ == '__main__':
- # 参数分别填入: 产品ID,设备名称,设备密匙
- print(IotHmac("2ZYN8YF7CM","dev1","WCk1aGDvGyg34+KolnKMqw=="))
-
-
上面python的代码需要填入的参数从下面截图里获取:
运行得到的结果:
安装Python,设置好环境变量,打开控制台终端,在命令行上运行代码:python get_pass.py
得到一下结果。
- {'clientid': '2ZYN8YF7CMdev1', 'username': '2ZYN8YF7CMdev1;12010126;HULWJ;1705853339', 'password': '26725d9cf937e3d054cc51fa91338d81ddebc072ae1fa65c564a068d8bb3e0c7;hmacsha256'}
-
总结:
- clientid: 2ZYN8YF7CMdev1
- username: 2ZYN8YF7CMdev1;12010126;HULWJ;1705853339
- password: 26725d9cf937e3d054cc51fa91338d81ddebc072ae1fa65c564a068d8bb3e0c7;hmacsha256
-
如果设备端想要得到APP页面的按钮状态就需要订阅属性下发和属性上报的响应,主题格式就是这样的:
主题订阅:
- $thing/up/property/2ZYN8YF7CM/dev1
-
主题发布:
- $thing/down/property/2ZYN8YF7CM/dev1
-
设备端向APP页面上报属性时,需要上传具体的数据,数据流的格式如下:
官方文档: https://cloud.tencent.com/document/product/1081/34916
上传的格式就是自己创建产品时,添加的功能属性。
按下面的JSON格式进行组合:
- {"method":"report","clientToken":"123","params":{"ds18b20_max":20,"adc_hp_max":20,"time_food":5,"auto_mode":1,"water_hp":80,"temp_data":12.5,"BH1750":300,"MQ135":20,"oxygen_sw":1,"heat_sw":0,"led_sw":0}}
-
官方文档: https://cloud.tencent.com/document/product/634/32546
域名格式:<产品ID>.iotcloud.tencentdevices.com
- 2ZYN8YF7CM.iotcloud.tencentdevices.com
-
**得到域名对应的IP地址: ** 175.178.30.200
为了方便测试,先使用MQTT客户端软件模拟硬件设备登录服务器。
- IP地址:175.178.30.200
- 端口号:1883
- 客户端ID: 2ZYN8YF7CMdev1
- 用户名: 2ZYN8YF7CMdev1;12010126;HULWJ;1705853339
- 密码: 26725d9cf937e3d054cc51fa91338d81ddebc072ae1fa65c564a068d8bb3e0c7;hmacsha256
- 订阅主题: $thing/down/property/2ZYN8YF7CM/dev1
- 发布主题: $thing/up/property/2ZYN8YF7CM/dev1
- 发布数据格式:
- {"method":"report","clientToken":"123","params":{"ds18b20_max":20,"adc_hp_max":20,"time_food":5,"auto_mode":1,"water_hp":80,"temp_data":12.5,"BH1750":300,"MQ135":20,"oxygen_sw":1,"heat_sw":0,"led_sw":0}}
-
依次填入参数之后,点击订阅主题、发布主题。
发布主题之后,会收到服务器下发的回应消息,表示消息已经上传成功。
在设备调试页面,可以看到设备已经在线了:
打开设备页面,就能看到设备上传的数据:
还能看历史数据: 可以看最近3天的数据。
打开腾讯连连微信小程序绑定设备,就可以看到设备的数据了。
步骤如下:
打开微信,找到小程序。
右上角搜索,腾讯连接。
然后打开腾讯连连,添加设备,扫描设备的二维码。
打开设备二维码页面。
添加成功。 点击左下角关注公众号,可以第一时间收到设备的动态消息。
到此,腾讯物联网云平台部署完成。
点击微信小程序里面的按钮可以看到设备端收到对应的控制信息。
- len:129,Data:$$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322mbXir::5NMCGSjgp","params":{"ds18b20_max":21}}
- len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530388538MKtZG::67Y#YRmFN","params":{"time_food":6}}
- len:128,Data:$$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322sDtoc::EnQpzyukd","params":{"adc_hp_max":22}}
- len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530388538PaAHn::@KgWjdE1V","params":{"auto_mode":0}}
- len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530388538XYQqA::WsGV4K0uo","params":{"auto_mode":1}}
- len:127,Data:$$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559fdKIy::addUie4XDm","params":{"oxygen_sw":0}}
- len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559OmPZY::vkCb-o5o%","params":{"oxygen_sw":1}}
- len:124,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559GCZHF::o3Zg6m9sEq","params":{"heat_sw":1}}
- len:123,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322DuDjB::CgY5$Gx8Z","params":{"heat_sw":0}}
- len:123,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559opcLp::MdJWtA8ai7","params":{"led_sw":1}}
- len:122,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322SZvJM::GYX7QT$T#","params":{"led_sw":0}}
-
- 硬件连接方式:
-
- 【1】 TFT 1.44 寸彩屏接线
- GND 电源地
- VCC 接5V或3.3v电源
- SCL 接PC8(SCL)
- SDA 接PC9(SDA)
- RST 接PC10
- DC 接PB7
- CS 接PB8
- BL 接PB11
-
- 【2】BC26-NBIOT模块
- PA2(TX)--RXD 模块接收脚
- PA3(RX)--TXD 模块发送脚
- GND---GND 地
- VCC---VCC 电源(5.0V)
-
- 【3】DS18B20温度传感器
- VCC--VCC
- GND---GND
- DAT---PB3
-
- 【4】鱼缸加热棒--继电器控制
- GND----GND
- VCC---3.3V
- OUT---PB4
-
- 【5】增氧泵--继电器控制
- GND----GND
- VCC---3.3V
- OUT---PC11
-
- 【6】水质传感器(ADC通道1)
- VCC--->5V
- GND--->GND
- DAT--->PA1
-
- 【7】氨气采集传感器(ADC通道4)
- VCC--->5V
- GND--->GND
- DAT--->PA4
-
-
- 【8】板载LED灯接线
- LED1---PA8
- LED2---PD2 (被串口占用)
-
-
- 【9】板载按键接线
- K0---PA0
- K1---PC5
- K2---PA15
-
- 【10】LED指示灯
- LED1--PA5 红色灯--表示报警异常
- LED2--PA6 绿色灯--表示系统正常
- LED3--PA7 白色灯--照明
-
-
- 【11】环境光检测检测:BH1750数字传感器
- SDA-----PB5
- SCL-----PB6
- GND---GND 地
- VCC---VCC 电源(3.3V~5.0V)
-
-
- #include "hal_uart.h"
- #include "stm32f0xx_usart.h"
-
- //接收串口数据的回调函数
- static void (*halUartOnIRQ)(unsigned char byte) = 0;
-
- static void halUartGpioInit(void);
- static void halUartParamInit(unsigned long baudrate);
- static void halUartIRQInit(void);
-
- /*
- * 串口通信初始化
- *
- * @param baudrate - 串口通信波特率
- */
- void halUartInit(unsigned long baudrate)
- {
- halUartGpioInit();
-
- halUartParamInit(baudrate);
-
- halUartIRQInit();
- }
-
- /*
- * 注册接收串口数据的回调函数
- *
- * @param onIRQ - 回调函数,接收到串口数据时自动调用此函数
- */
- void halUartSetIRQCallback(void (*onIRQ)(unsigned char byte))
- {
- halUartOnIRQ = onIRQ;
- }
-
- /*
- * 向串口发送信息
- *
- * @param buf - 待发送的信息的存储地址
- * @param len - 待发送的信息的数据长度
- */
- void halUartWrite(const unsigned char *buf, unsigned int len)
- {
- for (unsigned int i = 0; i < len; i++) {
- USART_SendData(USART1, buf[i]);
- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
- }
- }
-
- /*
- * 初始化串口通信相关的GPIO
- */
- void halUartGpioInit()
- {
- //配置结构体
- GPIO_InitTypeDef uart1Tx;
- GPIO_InitTypeDef uart1Rx;
-
- /* TX */
- uart1Tx.GPIO_Pin = GPIO_Pin_9,//PA9作为TX
- uart1Tx.GPIO_Speed = GPIO_Speed_10MHz,//通信频率
- uart1Tx.GPIO_Mode = GPIO_Mode_AF,
- uart1Tx.GPIO_PuPd = GPIO_PuPd_NOPULL,
-
- /* RX */
- uart1Rx.GPIO_Pin = GPIO_Pin_10,//PA10作为RX
- uart1Rx.GPIO_Speed = GPIO_Speed_10MHz,//通信频率
- uart1Rx.GPIO_Mode = GPIO_Mode_AF,
- uart1Rx.GPIO_PuPd = GPIO_PuPd_NOPULL,
-
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
-
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
-
- GPIO_Init(GPIOA, &uart1Tx);
- GPIO_Init(GPIOA, &uart1Rx);
- }
-
- /*
- * 初始化串口通信配置
- * @param baudrate - 串口通信波特率
- */
- void halUartParamInit(unsigned long baudrate)
- {
- USART_InitTypeDef uartConfig;
-
- uartConfig.USART_BaudRate = baudrate;
- uartConfig.USART_WordLength = USART_WordLength_8b;
- uartConfig.USART_Parity = USART_Parity_No;
- uartConfig.USART_StopBits = USART_StopBits_1;
- uartConfig.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- uartConfig.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
-
- USART_Init(USART1, &uartConfig);
- USART_Cmd(USART1, ENABLE);
- }
-
- /*
- * 初始化串口通信的中断请求
- */
- void halUartIRQInit()
- {
- NVIC_InitTypeDef uartNVIC;
-
- uartNVIC.NVIC_IRQChannel = USART1_IRQn;
- uartNVIC.NVIC_IRQChannelPriority = 0;
- uartNVIC.NVIC_IRQChannelCmd = ENABLE;
-
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
- USART_ITConfig(USART1, USART_IT_TC, ENABLE);
-
- NVIC_Init(&uartNVIC);
- }
-
- /*
- * 串口通信中断处理函数。当串口接收到数据时,便会自动产生中断并执行此函数
- */
- void USART1_IRQHandler(void)
- {
- unsigned char byte = 0;
-
- if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
- byte = USART_ReceiveData(USART1); // Auto to clear RXNE flag when read!
-
- if (halUartOnIRQ != 0) halUartOnIRQ(byte);
- }
- else USART_ClearFlag(USART1,USART_FLAG_TC);
- }
-
- #include "hal_adc.h"
-
- #include "stm32f0xx_adc.h"
-
- /*
- * ADC初始化
- */
- void halAdcInit()
- {
- GPIO_InitTypeDef gpioCfg;
- ADC_InitTypeDef adcCfg;
-
- /* PA0 */
- gpioCfg.GPIO_Pin = GPIO_Pin_1;
- gpioCfg.GPIO_Mode = GPIO_Mode_AN;
- gpioCfg.GPIO_PuPd = GPIO_PuPd_NOPULL;
-
- ADC_StructInit(&adcCfg);
- adcCfg.ADC_Resolution = ADC_Resolution_8b;
- adcCfg.ADC_ContinuousConvMode = DISABLE;
- adcCfg.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
- adcCfg.ADC_DataAlign = ADC_DataAlign_Right;
- adcCfg.ADC_ScanDirection = ADC_ScanDirection_Backward;
-
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
-
- RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4);
-
- ADC_DeInit(ADC1);
-
- GPIO_Init(GPIOA, &gpioCfg);
-
- ADC_Init(ADC1, &adcCfg);
-
- /* Convert the ADC1 Vref with 55.5 Cycles as sampling time */
- ADC_ChannelConfig(ADC1, ADC_Channel_1, ADC_SampleTime_55_5Cycles);
-
- ADC_GetCalibrationFactor(ADC1);
- ADC_DMACmd(ADC1, ENABLE);
-
- ADC_Cmd(ADC1, ENABLE);
-
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));
-
- ADC_StartOfConversion(ADC1);
- }
-
- /*
- *读取ADC值
- *
- *@return ADC值
- */
- unsigned int halAdcRead()
- {
- ADC_StartOfConversion(ADC1);
-
- while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
-
- return ADC_GetConversionValue(ADC1);
- }
-
- #include "hal_oled12864.h"
- #include "font_v_8x16.h"
- #include "hal_lcd_spi.h"
-
- #include "hal_system.h"
-
- #include "stm32f0xx_gpio.h"
-
- typedef unsigned char uint8;
- typedef unsigned short uint16;
-
- static void halOLED12864Reset(void);
- static void halOLED12864ChipInit(void);
- static void halOLED12864SetPosition(uint8 page, uint8 x);
-
- static void halOLEDShowChar8x16(uint16 x, uint16 page, uint8 ch);
-
- void halOLED12864Init(void)
- {
- /* Init SPI-GPIO */
- halLcdSpiInit();
-
- /* Init Chip */
- halOLED12864ChipInit();
-
- /* Setting */
- halOLED12864ClearScreen();
- halOLED12864SetPosition(0,0);
- }
-
- void halOLED12864ClearScreen(void)
- {
- uint8 page, x;
-
- for (page = 0; page < HAL_OLED12864_PAGE; page++) {
- halLcdSpiTxCmd(0xb0 + page);
- halLcdSpiTxCmd(0x01);
- halLcdSpiTxCmd(0x10);
-
- for (x = 0; x < HAL_OLED12864_X; x++) halLcdSpiTxData(0);
- }
- }
-
- void halOLED12864ShowX16(uint8 line, uint8 column, const uint8 *str)
- {
- if (!str || line > 3) return;
-
- uint8 page = line * 2; // 2 page per line
- const uint8 *ptext = str; // text
-
- /* Show text */
- while(*ptext != 0) {
- /* ASCII Code: 0~127 */
- if((*ptext) < 128) {
- /* End of line */
- if((column + 8) > HAL_OLED12864_X) return;
-
- /* Show 8x16 ASCII Char. */
- halOLEDShowChar8x16(column, page, *ptext);
- column += 8;
-
- ptext++;
- }
- } /* while(*ptext != 0) */
- }
-
- static void halOLED12864Reset(void)
- {
- #ifdef STM32F030x8
- /* RST: PA12 */
- GPIO_InitTypeDef lcdGPIO;
-
- lcdGPIO.GPIO_Mode = GPIO_Mode_OUT;
- lcdGPIO.GPIO_Speed = GPIO_Speed_2MHz;
- lcdGPIO.GPIO_Pin = GPIO_Pin_12;
-
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
-
- GPIO_Init(GPIOA, &lcdGPIO);
-
- /* Reset OLED12864 */
- GPIO_ResetBits(GPIOA, GPIO_Pin_12);
-
- halSystemDelayUs(60000);
-
- GPIO_SetBits(GPIOA, GPIO_Pin_12);
- #else
- /* RST: PA3 */
- GPIO_InitTypeDef lcdGPIO;
-
- lcdGPIO.GPIO_Mode = GPIO_Mode_OUT;
- lcdGPIO.GPIO_Speed = GPIO_Speed_2MHz;
- lcdGPIO.GPIO_Pin = GPIO_Pin_3;
-
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
-
- GPIO_Init(GPIOA, &lcdGPIO);
-
- /* Reset OLED12864 */
- GPIO_ResetBits(GPIOA, GPIO_Pin_3);
-
- halSystemDelayUs(60000);
-
- GPIO_SetBits(GPIOA, GPIO_Pin_3);
- #endif
- }
-
- static void halOLED12864ChipInit(void)
- {
- halOLED12864Reset();
-
- halLcdSpiTxCmd(0xae); // --turn off oled panel
- halLcdSpiTxCmd(0x00); // ---set low column address
- halLcdSpiTxCmd(0x10); // ---set high column address
- halLcdSpiTxCmd(0x40); // --set start line address Set Mapping
- // RAM Display Start Line (0x00~0x3F)
- halLcdSpiTxCmd(0x81); // --set contrast control register
- halLcdSpiTxCmd(0xcf); // --Set SEG Output Current Brightness
- halLcdSpiTxCmd(0xa1); // --Set SEG/Column Mapping
- halLcdSpiTxCmd(0xc8); // --Set COM/Row Scan Direction
- halLcdSpiTxCmd(0xa6); // --set normal display
- halLcdSpiTxCmd(0xa8); // --set multiplex ratio(1 to 64)
- halLcdSpiTxCmd(0x3f); // --1/64 duty
- halLcdSpiTxCmd(0xd3); // --set display offset Shift Mapping RAM
- // Counter(0x00~0x3F)
- halLcdSpiTxCmd(0x00); // --not offset
- halLcdSpiTxCmd(0xd5); // --set display clock divide
- // ratio/oscillator oscillator frequency
- halLcdSpiTxCmd(0x80); // --set divide ratio, Set Clock as 100
- // Frames/Sec
- halLcdSpiTxCmd(0xd9); // --set pre-charge period
- halLcdSpiTxCmd(0xf1); // --Set Pre-Charge as 15 Clocks & Discharge
- // as 1 Clock
- halLcdSpiTxCmd(0xda); // --set com pins hardware configuration
- halLcdSpiTxCmd(0x12);
- halLcdSpiTxCmd(0xdb); // --set vcomh
- halLcdSpiTxCmd(0x40); // --Set VCOM Deselect Level
- halLcdSpiTxCmd(0x20); // --Set Page Addressing Mode (0x00/0x01/0x02)
- halLcdSpiTxCmd(0x02); //
- halLcdSpiTxCmd(0x8d); // --set Charge Pump enable/disable
- halLcdSpiTxCmd(0x14); // --set(0x10) disable
- halLcdSpiTxCmd(0xa4); // --Disable Entire Display On (0xa4/0xa5)
- halLcdSpiTxCmd(0xa6); // --Disable Inverse Display On (0xa6/a7)
- halLcdSpiTxCmd(0xaf); // --turn on oled panel
- }
-
- static void halOLED12864SetPosition(uint8 page, uint8 x)
- {
- halLcdSpiTxCmd( 0xb0 + page );
- halLcdSpiTxCmd( ((x&0xf0)>>4)|0x10 );
- halLcdSpiTxCmd( (x&0x0f)|0x01 );
- }
-
- static void halOLEDShowChar8x16(uint16 x, uint16 page, uint8 ch)
- {
- uint16 charIndex;
-
- /* index of font table, height: 16 */
- if(ch > 32) charIndex = (ch - 32) * 16;
- else charIndex = 0;
-
- /* Set first page */
- halOLED12864SetPosition(page, x);
- for (uint8 j = 0; j < 8; j++) halLcdSpiTxData( FONT_TABLE_8x16[charIndex + j] );
-
- /* Set second page */
- halOLED12864SetPosition(page + 1, x);
- for (uint8 j = 0; j < 8; j++) halLcdSpiTxData( FONT_TABLE_8x16[charIndex + j + 8] );
- }
-
第一步接上之后,串口调试助手选择波特率为115200,勾选软件上的发送新行选项。发送AT过去,正常模块会返回OK。
只有收到了OK,才表示模块工作正常。
- 【1】查询模块是否正常
- AT
-
- OK
-
-
- 【2】获取卡号,查询卡是否插好
- AT+CIMI
-
- 460041052911195
-
- OK
-
-
- 【3】激活网络
- AT+CGATT=1
-
- OK
-
-
- 【4】获取网络激活状态
- AT+CGATT?
-
- +CGATT: 1
-
- OK
-
-
- 【5】查询网络质量
- AT+CSQ
-
- +CSQ: 26,0
-
- OK
-
- 【6】 检查网络状态
- AT+CEREG=? //
- +CEREG: 0,1 //找网成功
- OK
-
如果需要使用GPS定位就开,不需要使用就不用管。
使用GPS定位还需要将模块上的GPS天线接好,否则也是没有信号的。
官方文档:
- 【1】激活GPS,要等一段时间
- AT+QGNSSC=1
-
- OK
-
-
- 【2】查询激活状态,1表示成功激活
- AT+QGNSSC?
-
- +QGNSSC: 1
-
- OK
-
-
- 【3】获取一次GPS定位语句
- AT+QGNSSRD="NMEA/RMC"
- +QGNSSRD: $GNRMC,120715.00,A,3150.78179,N,11711.93433,E,0.000,,310818,,,A,V*19
- OK
-
下面通过BC26模块的AT指令连接MQTT服务器(OneNet),上传数据测试。
官方文档: