本帖最后由 聪聪哥哥 于 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); } /** * */ 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); } /** * */ void PMS5003_NVIC_Configuration(void) { //优先级,无优先级分组 // NVIC_SetPriority(PMS5003_USART_IRQ, 0); //UARTx中断使能 NVIC_EnableIRQ(PMS5003_USART_IRQ); } 在串口接收中断中做数据处理,主要代码如下: ///** // * // */ void DealData(void) { EnvirDataMent.uPm25 = Deal_USART_RX_BUF[12]; EnvirDataMent.uPm25 = (EnvirDataMent.uPm25<<8)+Deal_USART_RX_BUF[13]; EnvirDataMent.uPm100 = Deal_USART_RX_BUF[14]; EnvirDataMent.uPm100 = (EnvirDataMent.uPm100<<8)+Deal_USART_RX_BUF[15];
EnvirDataMent.uTemputer = Deal_USART_RX_BUF[24]; EnvirDataMent.uTemputer = (EnvirDataMent.uTemputer<<8)+Deal_USART_RX_BUF[25]; EnvirDataMent.uHumidity = Deal_USART_RX_BUF[26]; EnvirDataMent.uHumidity = (EnvirDataMent.uHumidity<<8)+Deal_USART_RX_BUF[27];
}
三:E32模块模块资料:
该电路只需将模块的TXD 与 RXD 连接到 MCU的RXD和TXD即可。 E32模块是基于SX1278射频芯片的贴片型无线串口模块(TTL电平),透明传输方式,发射功率100MW,工作在410-441MHZ频段,采用LORA扩频技术。 SX1278支持LORA扩频技术,通讯距离远,抗干扰能力强的优势,同时有极强的保密性。模块具有数据加密和压缩功能,模块在空中传输的数据,具有随机性,通过严密的加解密算法,使得数据截获失去意义。而数据压缩功能有概率减小传输时间,减少受干扰的概率,提高可考性和传输效率。 模块的特点功能: 模块的工作参数 模块的指令格式:
主要代码如下:分为串口初始化和串口发送函数 ///** // * // */
void DealData(void) { EnvirDataMent.uPm25 = Deal_USART_RX_BUF[12]; EnvirDataMent.uPm25 = (EnvirDataMent.uPm25<<8)+Deal_USART_RX_BUF[13]; EnvirDataMent.uPm100 = Deal_USART_RX_BUF[14]; EnvirDataMent.uPm100 = (EnvirDataMent.uPm100<<8)+Deal_USART_RX_BUF[15];
EnvirDataMent.uTemputer = Deal_USART_RX_BUF[24]; EnvirDataMent.uTemputer = (EnvirDataMent.uTemputer<<8)+Deal_USART_RX_BUF[25]; EnvirDataMent.uHumidity = Deal_USART_RX_BUF[26]; EnvirDataMent.uHumidity = (EnvirDataMent.uHumidity<<8)+Deal_USART_RX_BUF[27]; } /*工作界面下显示,温度,湿度数据*/ void USART2_E32_SENDDATA(char mode) { char buf[20] = {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); }
/** * @param 无 * @retval 无 */ void OLED_I2C_Start(void) { OLED_W_SDA(1); OLED_W_SCL(1); OLED_W_SDA(0); OLED_W_SCL(0); } /** * @brief I2C停止 * @param 无 * @retval 无 */ void OLED_I2C_Stop(void) { OLED_W_SDA(0); OLED_W_SCL(1); OLED_W_SDA(1); } /** * @brief I2C发送一个字节 * @param Byte 要发送的一个字节 * @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); } /** * @brief OLED写命令 * @param Command 要写入的命令 * @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(); } /** * @brief OLED写数据 * @param Data 要写入的数据 * @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(); } /** * @brief OLED设置光标位置 * @param Y 以左上角为原点,向下方向的坐标,范围:0~7 * @param X 以左上角为原点,向右方向的坐标,范围: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位 } /** * @brief OLED清屏 * @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); } } } /** * @brief OLED显示一个中文 * @param Line 行位置,范围:1~4 * @param Column 列位置,范围:1~15,注意两个汉字的列位置间隔两个位置 比如: OLED_ShowChinese(1,1,0);第一个汉字 OLED_ShowChinese(1,3,1);第二个汉字 * @param Select 从汉字库选择汉字索引 * @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[Select*2]); //显示上半部分内容 } OLED_SetCursor((Line - 1) * 2+1, (Column - 1) * 8); //设置光标位置在上半部分 for (i = 0; i < 16; i++) { OLED_WriteData(OLED_F16x16[Select*2][i+16]); //显示上半部分内容 } } /** * @brief OLED显示一个字符 * @param Line 行位置,范围:1~4 * @param Column 列位置,范围:1~16 * @param Char 要显示的一个字符,范围: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[Char - ' ']); //显示上半部分内容 } OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //设置光标位置在下半部分 for (i = 0; i < 8; i++) { OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //显示下半部分内容 } } /** * @brief OLED显示字符串 * @param Line 起始行位置,范围:1~4 * @param Column 起始列位置,范围:1~16 * @param String 要显示的字符串,范围: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); } } /** * @brief OLED次方函数 * @retval 返回值等于X的Y次方 */ uint32_t OLED_Pow(uint32_t X, uint32_t Y) { uint32_t Result = 1; while (Y--) { Result *= X; } return Result; }
/** * @brief OLED显示数字(十进制,正数) * @param Line 起始行位置,范围:1~4 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:0~4294967295 * @param Length 要显示数字的长度,范围: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'); } }
/** * @brief OLED显示数字(十进制,带符号数) * @param Line 起始行位置,范围:1~4 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:-2147483648~2147483647 * @param Length 要显示数字的长度,范围: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'); } }
/** * @brief OLED显示数字(十六进制,正数) * @param Line 起始行位置,范围:1~4 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:0~0xFFFFFFFF * @param Length 要显示数字的长度,范围: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'); } } }
/** * @brief OLED显示数字(二进制,正数) * @param Line 起始行位置,范围:1~4 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:0~1111 1111 1111 1111 * @param Length 要显示数字的长度,范围: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'); } } /** * @brief OLED初始化 * @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
|