【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)

JW01

网上买的JW01模块,二十六块,买贵了。看到最便宜有九块钱的(运费十块),心疼。。。避雷了兄弟们,看到二十六块的JW01别买。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_第1张图片

这个模块它是1秒钟检测一次CO2然后通过串口来传输结果,并且还自带了数据检测,感觉还是不错的,这里记录一下。

商家提供的资料我看了,演示视频不能说是保教包会吧也算得上是聊胜于无了。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_第2张图片

唯一有用的就是芯片手册了,不过芯片手册这个文件夹里也就几张图片。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_第3张图片

还好JW01本身就简单,通过这几张图片我们也能大概知道是怎么使用。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_第4张图片

可以知道JW01是通过UART来传输数据的,波特率9600,数据位8位,停止位1位,无校验,就是最普通的设置。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_第5张图片

从上图可以知道JW01发送的串口数据流格式,一共是6个字节。

第一个字节是固定的2C,我们后面通过这个来使得获取的数据位对齐。

第二和第三个字节可以通过公式来得到检测到的CO2浓度。

然后第四和第五个字节好像也是固定的,是0x03和0xFF。

最后一个字节是校验位,也就是前五个字节加起来(要转为8位的数据格式,例如uint8_t)等于第六个字节的时候,我们得到的数据才是正确的。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_第6张图片

还有一点要注意的就是JW01的输出口(TXD)是5V的(这个和供电的电压有关,如果给3.3V供电的话那么就不需要考虑这些了),而我们的单片机大概率是3.3V,因此要电平转换。

不过很幸运,我们STM32F103的USART1的RXD是可以接收5V电压的,因此不需要转换。

如上图所示,IO口有标注FT的引脚即是可以接受5V电压的。但是我们STM32F103的USART2就不能接受5V电压的,因此我们就使用USART1这样比较省事。

STM32F103通过JW01获取CO2浓度

所以我们只需要把对应的口接到STM32F103的引脚上就行。

因为JW01需要5V供电,因此我将ST-Link的5V接出来供5V电了,经我实测,STM32F103的3.3V似乎也可以带得动JW01,不过预热速度会比5V稍慢一些。

并且我们只需要接收JW01的信息而不需要给它发送数据,因此我们甚至可以不配置STM32F103的TXD,只需要配置RXD即可,不过代码里我还是配置上了(因为用的是之前配置USART的代码)。

接下来的讲解配合我下面的代码食用。

我们首先先正常配置USART,可以参考我之前的文章。

由于我们是需要接收数据,因此需要打开接收数据的中断,中断优先级随便配一个就行。

因为JW01固定发送的是6字节的数据,因此我们使用容量为6个uint8_t的数组来存放数据。

在中断函数里,我们按照接收的顺序去把收到的数据放入数组里,但是要多一个判断,只有当我们准备存放在数值的第一位并且此时接收的数据为0x2C的时候(参考前文的数据包格式),我们才真正接收此数据,否则我们就一直卡在准备接受第一位数据的状态。

JW01的发送速率是一秒发一次。也就是说正常情况下我们数组里的数据是一秒更新一次。

接收之后我们显示检测的数据,CO2的浓度为数组第二个元素乘上256再加上数值第三个元素,单位为ppm。

并且之前也说了,六个字节的最后一个字节是校验位,前五个字节加起来要等于第六个字节,需要注意的是在比较的时候需要将比较结果转换为8个bit的数据,这样才能正确比较。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

void JW01_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能外设时钟
    
    GPIO_InitTypeDef GPIO_Init_Struct;
    GPIO_Init_Struct.GPIO_Mode=GPIO_Mode_AF_PP;                      //TXD为复用推挽输出
    GPIO_Init_Struct.GPIO_Pin=GPIO_Pin_9;                            //9号为TXD
    GPIO_Init_Struct.GPIO_Speed=GPIO_Speed_50MHz;                    //这个随意
    GPIO_Init(GPIOA,&GPIO_Init_Struct);
    
    GPIO_Init_Struct.GPIO_Mode=GPIO_Mode_IN_FLOATING;                //RXD为浮空输入
    GPIO_Init_Struct.GPIO_Pin=GPIO_Pin_10;                           //10号为RXD
    GPIO_Init(GPIOA,&GPIO_Init_Struct);                              
    
    USART_InitTypeDef Usart_Init_Struct;
    Usart_Init_Struct.USART_BaudRate=9600;                                      //波特率
    Usart_Init_Struct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //无硬件控制流
    Usart_Init_Struct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;                   //收发模式
    Usart_Init_Struct.USART_Parity=USART_Parity_No;                             //无校验
    Usart_Init_Struct.USART_StopBits=USART_StopBits_1;                          //停止位1位
    Usart_Init_Struct.USART_WordLength=USART_WordLength_8b;                     //数据位8位
    USART_Init(USART1,&Usart_Init_Struct);
    
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);                                //开启接收中断
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                             //NVIC中断配置
    NVIC_InitTypeDef nitd;
    nitd.NVIC_IRQChannel=USART1_IRQn;
    nitd.NVIC_IRQChannelCmd=ENABLE;
    nitd.NVIC_IRQChannelPreemptionPriority=2;
    nitd.NVIC_IRQChannelSubPriority=2;
    NVIC_Init(&nitd);
    
    USART_Cmd(USART1,ENABLE);
}

uint8_t CO2_Data[6];                                        //存放接收到的数据包

void USART1_IRQHandler(void){
    static uint8_t index=0;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
        CO2_Data[index]=USART_ReceiveData(USART1);
        if(index==0&&CO2_Data[index]!=0x2C){                //固定数据包的开头
            return;
        }else{
            if(++index>=6) index=0;
        }
        USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);    //清除数据接收标志位
    }
}

int main(void){
    OLED_Init();
    JW01_Init();
    OLED_ShowString(1,1,"Hello World");
    OLED_ShowString(2,1,"CO2 is ");
    while(1){
        if(CO2_Data[5]==(uint8_t)(CO2_Data[0]+CO2_Data[1]+CO2_Data[2]+CO2_Data[3]+CO2_Data[4])){
            OLED_ShowNum(2,8,CO2_Data[1]*256+CO2_Data[2],5);
        }else{
            OLED_ShowString(2,8,"ERROR");
        }
        OLED_ShowHexNum(3,1,CO2_Data[0],2);
        OLED_ShowHexNum(3,4,CO2_Data[1],2);
        OLED_ShowHexNum(3,7,CO2_Data[2],2);
        OLED_ShowHexNum(4,1,CO2_Data[3],2);
        OLED_ShowHexNum(4,4,CO2_Data[4],2);
        OLED_ShowHexNum(4,7,CO2_Data[5],2);
    }
}

效果演示

上面代码涉及的OLED的驱动代码用的是b站江科大自化协的,没有OLED的小伙伴可以使用串口通信打印到电脑的串口助手上,不过只能用USART2了。因为JW01用了USART1。

接线方面的话就是把JW01的TXD接到GPIOA的10号引脚。

然后ST-Link的5V接出来给JW01供电,JW01的GND也和STM32共地(因为供电源一样)。

【STM32F103】JW01-CO2-V2.2二氧化碳检测模块(USART)_第7张图片

你可能感兴趣的:(STM32F103,stm32,嵌入式硬件,单片机,mcu)