基于CW32F030开发板设计的环境检测系统(带无线监测功能)
本帖最后由 聪聪哥哥 于 2024-6-17 10:36 编辑基于CW32F030开发板设计的环境检测系统前言:一:开发板介绍:CW32F030CxTx StartKit 评估板为用户提供一种经济且灵活的方式使用 CW32F030CxTx 芯片构建系统原型。可进行性能、功耗、功能等各方面快速验证。
CW32F030CxTx StartKit 评估板需要搭配 CW-DAPLINK 调试器一起使用。
CW32F030CxTx StartKit 评估板带有 CW32F030 StartKit 软件包及 CW32F030-StdPeriph-Lib 固件库和例程。
CW32F030CxTx StartKit 评估板板载资源介绍:• CW32F030CxTx 微控制器(ARM® Cortex®-M0+ 最高主频 64MHz),LQFP48 封装,64K 字节 FLASH,8K 字节 RAM
• 3 颗 LED:
- 电源指示灯(LED3),用户指示灯(LED1,LED2)
• 三个轻触开关:
- 复位轻触开关(S3),用户轻触开关(S1,S2)
• USB 转串口芯片(CH340N)
• FLASH 芯片(W25Q64JVSSIQ)
• EEPROM 芯片(CW24C02AD)
• 板载接口:
- Mini USB 接口(串口通信,USB 供电)
- 下载器调试接口
- 所有 GPIO 口通过排针引出
• 多种方式供电:USB VBUS 供电,3.3V 供电(LD1117AS33TR),外接 1.65V ~ 5.5V 供电
• CW32F030-StdPeriph-Lib 软件包提供全面免费的固件库和例程
• 支持多种集成开发环境,IAR™,Keil®
使用开发环境:KEIL5.28A,调试器使用:自制的DAP调试器(实测很好用)
二:PM5003T颗粒物传感器模块资料:2.1:PM5003T颗粒物传感器产品介绍:PMS5003T 是一款可以同时监测空气中颗粒物浓度及温湿度的二合一传感器。其中颗粒物浓度的监测基于激光散射原理,可连续采集并计算单位体积内空气中不 同粒径的悬浮颗粒物个数,即颗粒物浓度分布,进而换算成为质量浓度。传感器同时内嵌瑞士生产的温湿度一体检测芯片。颗粒物浓度数值及温度、湿度合并以通用数字接口形式输出。本传感器可嵌入各种与空气质量监测和改善相关的仪器设备,为其提供及时准确的环境参数。工作原理:本传感器采用激光散射原理。即令激光照射在空气中的悬浮颗粒物上产生散射, 同时在某一特定角度收集散射光,得到散射光强随时间变化的曲线。进而微处理 器利用基于米氏(MIE)理论的算法,得出颗粒物的等效粒径及单位体积内不同 粒径的颗粒物数量。2.2:硬件接口定义:输出结果:1. 主要输出为单位体积内各浓度颗粒物质量以及个数,其中颗粒物个数的单位 体积为 0.1 升,质量浓度单位为:微克/立方米。 2. 输出分为主动输出和被动输出两种状态。传感器上电后默认状态为主动输出, 即传感器主动向主机发送串行数据,时间间隔为 200~800ms,空气中颗粒物 浓度越高,时间间隔越短。主动输出又分为两种模式:平稳模式和快速模式。 在空气中颗粒物浓度变化较小时,传感器输出为平稳模式,即每三次输出同样的一组数值,实际数据更新周期约为 2s。当空气中颗粒物浓度变化较大时, 传感器输出自动切换为快速模式,每次输出都是新的数值,实际数据更新周 期为 200~800ms。3. 温湿度输出:输出吸入传感器内部的采样空气温度及湿度。典型电路连接方式:2.3电路设计应注意:1. PMS5003T 需要 5V 供电,这是因为风机需要 5V 驱动。但其他数据通讯和控 制管脚均需要 3.3V 作为高电平。因此与之连接通讯的主板 MCU 应为 3.3V 供 电。如果主板 MCU 为 5V 供电,则在通讯线(RXD、TXD)和控制线(SET、 RESET)上应当加入电平转换芯片或电路。 2. SET 和 RESET 内部有上拉电阻,如果不使用,则应悬空。 3. PIN7 和 PIN8 为程序内部调试用,应用电路中应使其悬空。 4. 应用休眠功能时应注意:休眠时风扇停止工作,而风扇重新启动需要至少 30秒的稳定时间,因此为获得准确的数据,休眠唤醒后传感器工作时间不应低于 30秒。附:主要代码如下:分为串口初始化和串口接收函数
void PMS5003_GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; //UART TX RX 复用 PMS5003_USART_AFTX; PMS5003_USART_AFRX; GPIO_InitStructure.Pins = PMS5003_USART_TX_GPIO_PIN; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; GPIO_Init(PMS5003_USART_TX_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pins = PMS5003_USART_RX_GPIO_PIN; GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP; GPIO_Init(PMS5003_USART_TX_GPIO_PORT, &GPIO_InitStructure);}/** * @brief 配置UART * */void PMS5003_UART_Configuration(void){ USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = PMS5003_USART_BaudRate; USART_InitStructure.USART_Over = USART_Over_16; USART_InitStructure.USART_Source = USART_Source_PCLK; USART_InitStructure.USART_UclkFreq = PMS5003_USART_UclkFreq; USART_InitStructure.USART_StartBit = USART_StartBit_FE; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No ; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(PMS5003_USARTx, &USART_InitStructure); //使能UARTx RX中断 USART_ITConfig(PMS5003_USARTx, USART_IT_RC, ENABLE);}/** * @brief 配置NVIC * */void PMS5003_NVIC_Configuration(void){ //优先级,无优先级分组// NVIC_SetPriority(PMS5003_USART_IRQ, 0); //UARTx中断使能 NVIC_EnableIRQ(PMS5003_USART_IRQ);}在串口接收中断中做数据处理,主要代码如下:///**// * @brief 处理串口3 接收到的数据// *// */void DealData(void) { EnvirDataMent.uPm25 = Deal_USART_RX_BUF; EnvirDataMent.uPm25 = (EnvirDataMent.uPm25<<8)+Deal_USART_RX_BUF; EnvirDataMent.uPm100 = Deal_USART_RX_BUF; EnvirDataMent.uPm100 = (EnvirDataMent.uPm100<<8)+Deal_USART_RX_BUF;
EnvirDataMent.uTemputer = Deal_USART_RX_BUF; EnvirDataMent.uTemputer = (EnvirDataMent.uTemputer<<8)+Deal_USART_RX_BUF; EnvirDataMent.uHumidity = Deal_USART_RX_BUF; EnvirDataMent.uHumidity = (EnvirDataMent.uHumidity<<8)+Deal_USART_RX_BUF;
}
三:E32模块模块资料:
该电路只需将模块的TXD 与 RXD 连接到 MCU的RXD和TXD即可。E32模块是基于SX1278射频芯片的贴片型无线串口模块(TTL电平),透明传输方式,发射功率100MW,工作在410-441MHZ频段,采用LORA扩频技术。SX1278支持LORA扩频技术,通讯距离远,抗干扰能力强的优势,同时有极强的保密性。模块具有数据加密和压缩功能,模块在空中传输的数据,具有随机性,通过严密的加解密算法,使得数据截获失去意义。而数据压缩功能有概率减小传输时间,减少受干扰的概率,提高可考性和传输效率。模块的特点功能:模块的工作参数模块的指令格式:
主要代码如下:分为串口初始化和串口发送函数///**// * @brief 处理串口3 接收到的数据// *// */
void DealData(void) { EnvirDataMent.uPm25 = Deal_USART_RX_BUF; EnvirDataMent.uPm25 = (EnvirDataMent.uPm25<<8)+Deal_USART_RX_BUF; EnvirDataMent.uPm100 = Deal_USART_RX_BUF; EnvirDataMent.uPm100 = (EnvirDataMent.uPm100<<8)+Deal_USART_RX_BUF;
EnvirDataMent.uTemputer = Deal_USART_RX_BUF; EnvirDataMent.uTemputer = (EnvirDataMent.uTemputer<<8)+Deal_USART_RX_BUF; EnvirDataMent.uHumidity = Deal_USART_RX_BUF; EnvirDataMent.uHumidity = (EnvirDataMent.uHumidity<<8)+Deal_USART_RX_BUF;}/*工作界面下显示,温度,湿度数据*/void USART2_E32_SENDDATA(char mode){ char buf = {0}; switch (mode) { case 0 : E32_USART_SendString(CW_UART2,"温度值:"); sprintf(buf," %4.1f ℃",EnvirDataMent.uTemputer/10.0);
E32_USART_SendString(CW_UART2,buf); break ;
case 1 : E32_USART_SendString(CW_UART2,"湿度值"); sprintf(buf," %4.1f%% ",EnvirDataMent.uHumidity/10.0); E32_USART_SendString(CW_UART2,buf); break ; case 2 : E32_USART_SendString(CW_UART2,"PM值");
sprintf(buf," %4.1f ",EnvirDataMent.uPm25/10.0); E32_USART_SendString(CW_UART2,buf); break ; default : break ; }}四:OLED模块模块资料:4.1:OLED 简介: OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。因为具备轻薄、省电等特性,因此从 2003 年开始,这种显示设备在 MP3 播放器上得到了广泛应用,而对于同属数码类产品的 DC 与手机,此前只是在一些展会上展示过采用 OLED 屏幕的工程样品。自 2007 年后,寿命得 到很大提高,具备了许多 LCD 不可比拟的优势。GND:电源地 VCC:2.2V~5.5V SCL(D0):CLK 时钟 (高电平 2.2V~5.5V) SDA(D1):MOSI 数据(高电平 2.2V~5.5V) RST:复位(高电平 2.2V~5.5V) D/C:数据/命令(高电平 2.2V~5.5V) 兼容 3.3V 和 5V 控制芯片的 I/O 电平(无需任何设置,直接兼容)。实物图片4.2:汉字显示方法:需要使用软件做自己的字库
IIC驱动部分/*引脚配置*/#define OLED_W_SCL(x) GPIO_WritePin(CW_GPIOA, GPIO_PIN_1, (GPIO_PinState)(x))#define OLED_W_SDA(x) GPIO_WritePin(CW_GPIOA, GPIO_PIN_0, (GPIO_PinState)(x))
/*引脚初始化*/void OLED_I2C_Init(void){ __RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.IT=GPIO_IT_NONE; GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pins=GPIO_PIN_1 | GPIO_PIN_0; GPIO_InitStruct.Speed=GPIO_SPEED_LOW; GPIO_Init(CW_GPIOA, &GPIO_InitStruct); GPIO_WritePin(CW_GPIOA,GPIO_PIN_1 | GPIO_PIN_0,GPIO_Pin_SET);
OLED_W_SCL(1); OLED_W_SDA(1);}
/*** @briefI2C开始* @param无* @retval 无*/void OLED_I2C_Start(void){ OLED_W_SDA(1); OLED_W_SCL(1); OLED_W_SDA(0); OLED_W_SCL(0);}/*** @briefI2C停止* @param无* @retval 无*/void OLED_I2C_Stop(void){ OLED_W_SDA(0); OLED_W_SCL(1); OLED_W_SDA(1);}/*** @briefI2C发送一个字节* @paramByte 要发送的一个字节* @retval 无*/void OLED_I2C_SendByte(uint8_t Byte){ uint8_t i; for (i = 0; i < 8; i++) { if(Byte & (0x80 >> i)) OLED_W_SDA(1); else OLED_W_SDA(0); OLED_W_SCL(1); OLED_W_SCL(0); } OLED_W_SCL(1); //额外的一个时钟,不处理应答信号 OLED_W_SCL(0);}/*** @briefOLED写命令* @paramCommand 要写入的命令* @retval 无*/void OLED_WriteCommand(uint8_t Command){ OLED_I2C_Start(); OLED_I2C_SendByte(0x78); //从机地址 OLED_I2C_SendByte(0x00); //写命令 OLED_I2C_SendByte(Command); OLED_I2C_Stop();}/*** @briefOLED写数据* @paramData 要写入的数据* @retval 无*/void OLED_WriteData(uint8_t Data){ OLED_I2C_Start(); OLED_I2C_SendByte(0x78); //从机地址 OLED_I2C_SendByte(0x40); //写数据 OLED_I2C_SendByte(Data); OLED_I2C_Stop();}/*** @briefOLED设置光标位置* @paramY 以左上角为原点,向下方向的坐标,范围:0~7* @paramX 以左上角为原点,向右方向的坐标,范围:0~127* @retval 无*/void OLED_SetCursor(uint8_t Y, uint8_t X){ OLED_WriteCommand(0xB0 | Y); //设置Y位置 OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //设置X位置低4位 OLED_WriteCommand(0x00 | (X & 0x0F)); //设置X位置高4位}/*** @briefOLED清屏* @param无* @retval 无*/void OLED_Clear(void){ uint8_t i, j; for (j = 0; j < 8; j++) { OLED_SetCursor(j, 0); for(i = 0; i < 128; i++) { OLED_WriteData(0x00); } }}/*** @briefOLED显示一个中文* @paramLine 行位置,范围:1~4* @paramColumn 列位置,范围:1~15,注意两个汉字的列位置间隔两个位置 比如: OLED_ShowChinese(1,1,0);第一个汉字 OLED_ShowChinese(1,3,1);第二个汉字* @paramSelect 从汉字库选择汉字索引* @retval 无*/void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t Select){ uint8_t i; OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分 for (i = 0; i < 16; i++) { OLED_WriteData(OLED_F16x16); //显示上半部分内容 } OLED_SetCursor((Line - 1) * 2+1, (Column - 1) * 8); //设置光标位置在上半部分 for (i = 0; i < 16; i++) { OLED_WriteData(OLED_F16x16); //显示上半部分内容 }}/*** @briefOLED显示一个字符* @paramLine 行位置,范围:1~4* @paramColumn 列位置,范围:1~16* @paramChar 要显示的一个字符,范围:ASCII可见字符* @retval 无*/void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char){ uint8_t i; OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分 for (i = 0; i < 8; i++) { OLED_WriteData(OLED_F8x16); //显示上半部分内容 } OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //设置光标位置在下半部分 for (i = 0; i < 8; i++) { OLED_WriteData(OLED_F8x16); //显示下半部分内容 }}/*** @briefOLED显示字符串* @paramLine 起始行位置,范围:1~4* @paramColumn 起始列位置,范围:1~16* @paramString 要显示的字符串,范围:ASCII可见字符* @retval 无*/void OLED_ShowString(uint8_t Line, uint8_t Column, char *String){ uint8_t i; for (i = 0; String != '\0'; i++) { OLED_ShowChar(Line, Column + i, String); }}/*** @briefOLED次方函数* @retval 返回值等于X的Y次方*/uint32_t OLED_Pow(uint32_t X, uint32_t Y){ uint32_t Result = 1; while (Y--) { Result *= X; } return Result;}
/*** @briefOLED显示数字(十进制,正数)* @paramLine 起始行位置,范围:1~4* @paramColumn 起始列位置,范围:1~16* @paramNumber 要显示的数字,范围:0~4294967295* @paramLength 要显示数字的长度,范围:1~10* @retval 无*/void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length){ uint8_t i; for (i = 0; i < Length; i++) { OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0'); }}
/*** @briefOLED显示数字(十进制,带符号数)* @paramLine 起始行位置,范围:1~4* @paramColumn 起始列位置,范围:1~16* @paramNumber 要显示的数字,范围:-2147483648~2147483647* @paramLength 要显示数字的长度,范围:1~10* @retval 无*/void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length){ uint8_t i; uint32_t Number1; if (Number >= 0) { OLED_ShowChar(Line, Column, ' '); Number1 = Number; } else { OLED_ShowChar(Line, Column, '-'); Number1 = -Number; } for (i = 0; i < Length; i++) { OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0'); }}
/*** @briefOLED显示数字(十六进制,正数)* @paramLine 起始行位置,范围:1~4* @paramColumn 起始列位置,范围:1~16* @paramNumber 要显示的数字,范围:0~0xFFFFFFFF* @paramLength 要显示数字的长度,范围:1~8* @retval 无*/void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length){ uint8_t i, SingleNumber; for (i = 0; i < Length; i++) { SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16; if (SingleNumber < 10) { OLED_ShowChar(Line, Column + i, SingleNumber + '0'); } else { OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A'); } }}
/*** @briefOLED显示数字(二进制,正数)* @paramLine 起始行位置,范围:1~4* @paramColumn 起始列位置,范围:1~16* @paramNumber 要显示的数字,范围:0~1111 1111 1111 1111* @paramLength 要显示数字的长度,范围:1~16* @retval 无*/void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length){ uint8_t i; for (i = 0; i < Length; i++) { OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0'); }}/*** @briefOLED初始化* @param无* @retval 无*/void OLED_Init(void){ uint32_t i, j;
for (i = 0; i < 1000; i++) //上电延时 { for (j = 0; j < 1000; j++); }
OLED_I2C_Init(); //端口初始化
OLED_WriteCommand(0xAE); //关闭显示
OLED_WriteCommand(0xD5); //设置显示时钟分频比/振荡器频率 OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); //设置多路复用率 OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); //设置显示偏移 OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); //设置显示开始行
OLED_WriteCommand(0xA1); //设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); //设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //设置COM引脚硬件配置 OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); //设置对比度控制 OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); //设置预充电周期 OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); //设置VCOMH取消选择级别 OLED_WriteCommand(0x30);
OLED_WriteCommand(0xA4); //设置整个显示打开/关闭
OLED_WriteCommand(0xA6); //设置正常/倒转显示
OLED_WriteCommand(0x8D); //设置充电泵 OLED_WriteCommand(0x14);
OLED_WriteCommand(0xAF); //开启显示
OLED_Clear(); //OLED清屏}
显示部分:
五:CW32F030C8拓展板实现的主要功能:
实物图片如下:
B站视频链接如下,感兴趣的可以移步去看下,感谢!!!!!https://www.bilibili.com/video/BV1B1VLevEuT/?spm_id_from=333.999.0.0&vd_source=fb5a6d1a3332aab1989e0f3e24f2afc1
感觉空气净化器也就当时那啥主持人制作了个关于雾霾的视频,然后就火起来了,现在又淡出人们生活了 huquanz711 发表于 2024-6-17 07:47
感觉空气净化器也就当时那啥主持人制作了个关于雾霾的视频,然后就火起来了,现在又淡出人们生活了...
嗯,这个也就是可以监控空气的PM数据什么的 雾霾也看在什么地方测试 trucyw 发表于 2024-6-17 08:24
雾霾也看在什么地方测试
模块是可以读取的,那个PM2.5 数值就是 显示的颗粒数 多挺好的,不过室内PM2.5检测一般都不太理想,CW这个板子太丑 很好 模块请问链接能发一下嘛? 具体是哪一个i 楼主这是设计的PCB板嘛? OKAKAKO 发表于 2024-6-21 21:05
楼主这是设计的PCB板嘛?
是的,绘制了一个拓展板 输出分为主动输出和被动输出两种状态
页:
[1]