0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

武汉芯源CW32L031实现超远距离超低耗无线采集

华仔的编程随笔 来源:华仔的编程随笔 作者:华仔的编程随笔 2023-06-30 16:03 次阅读

CW32L031实现低功耗温湿度

硬件环境】

  1. CW32L031C8开发板
  2. SHT30温湿度传感器
  3. E31-TTL-50无线串口模块

【开发板环境】

Ubuntu20.0.4

【代码编辑器】

VSCODE ssh远程

【编译器】

arm-none-eabi-gcc

【工程包】

Cw32l031_gcc工程包

【工程概述】

本工程的核心分为sht30数据采集后,经无线串口模块发送给上位机,利用自动唤醒模块休眠指定时长后再次唤醒系统进行数据采集。

【初略原理图】

image.png

【程序流程图】

image.png

【主要代码】

  1. 自动唤醒定时器(AWT) 包含一个 16bit 向下计数器,并由一个可编程预分频器驱动。AWT 可选 5 种计数时钟源,可工作于定时模式或计数模式。当计数器时钟源为 LSE 或 LSI 时,AWT 可在深度休眠模式下保持运行,下溢出中断可唤醒 MCU 回到运行模式。具体配置代码如下:
void Init_awt_power(void)

{

    AWT_TimeCntInitTypeDef AWT_TimeCntInitStruct = {0};

    RCC_APBPeriphClk_Enable2(RCC_APB2_PERIPH_AWT, ENABLE);  //Open AWT Clk

    RCC_SystemCoreClockUpdate( RCC_Sysctrl_GetHClkFreq() );

    RCC_LSI_Enable();

 

    

    AWT_TimeCntStructInit( &AWT_TimeCntInitStruct );

    AWT_TimeCntInitStruct.AWT_ClkSource = AWT_CLKSOURCE_LSI;

    AWT_TimeCntInitStruct.AWT_Prescaler = AWT_PRS_DIV32768;

    AWT_TimeCntInitStruct.AWT_Mode = AWT_MODE_TIMECNT;

    AWT_TimeCntInitStruct.AWT_Period = 120;

    AWT_TimeCntInit(&AWT_TimeCntInitStruct);

 

    __disable_irq();

    NVIC_EnableIRQ(AWT_IRQn);

    __enable_irq();

    //使能AWT下溢出中断

    AWT_ITConfig(AWT_IT_UD, ENABLE);

    AWT_Cmd(ENABLE);

 

    //DeepSleep唤醒时,保持原系统时钟来源

    RCC_WAKEUPCLK_Config(RCC_SYSCTRL_WAKEUPCLKDIS);

 

    

}
  1. 软件IIC的配置,这里使用软件模拟实现。具体代码如下:
#include "myiic.h"

 

#define  I2C1_SCL_GPIO_PORT       CW_GPIOB

#define  I2C1_SCL_GPIO_PIN        GPIO_PIN_10   

#define  I2C1_SDA_GPIO_PORT       CW_GPIOB

#define  I2C1_SDA_GPIO_PIN        GPIO_PIN_11  

 

void delay_us(uint32_t us)

{

    while(us--)

    {

        __NOP();

        __NOP();

        __NOP();

        __NOP();

        __NOP();

    }

    

}

 

void IIC_Init(void)

{

      //配置PB10 为输出

    //使能GPIOB时钟

    CW_SYSCTRL- >AHBEN_f.GPIOB  = 1;

    //配置PB10 为输出

    CW_GPIOB- >ANALOG_f.PIN10 = 0; //设置 GPIOx_ANALOG.PINy 为 0,将端口配置为数字功能;

    CW_GPIOB- >DIR_f.PIN10 = 0;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;

    CW_GPIOB- >OPENDRAIN_f.PIN10 = 0;  //0:推挽输出

    CW_GPIOB- >ODR_f.PIN10 = 1;

    

    CW_GPIOB- >ANALOG_f.PIN11 = 0; //设置 GPIOx_ANALOG.PINy 为 0,将端口配置为数字功能;

    CW_GPIOB- >DIR_f.PIN11 = 0;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;

    CW_GPIOB- >OPENDRAIN_f.PIN11 = 0;  //0:推挽输出

    CW_GPIOB- >ODR_f.PIN11 = 1;

        

}

                                                                                                             

//IO方向设置(SDA)

/*********xxxxxxxxxxxxxx*************/

void SDA_IN()  

{ 

    CW_GPIOB- >DIR_f.PIN11 = 1;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;

}

 

void SDA_OUT()

{ 

  CW_GPIOB- >DIR_f.PIN11 = 0;    //设置 GPIOx_DIR.PINy 为 0,将端口配置成输出;

    CW_GPIOB- >OPENDRAIN_f.PIN11 = 0;  //0:推挽输出

}

 

//产生IIC起始信号

void IIC_Start(void)

{

    SDA_OUT();     //sda线输出

    IIC_SDA=1;        

    IIC_SCL=1;

    delay_us(4);

    IIC_SDA=0;//START:when CLK is high,DATA change form high to low 

    delay_us(4);

    IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 

}   

 

//产生IIC停止信号

void IIC_Stop(void)

{

    SDA_OUT();//sda线输出

    IIC_SCL=0;

    IIC_SDA=0;//STOP:when CLK is high DATA change form low to high

    delay_us(4);

    IIC_SCL=1; 

    IIC_SDA=1;//发送I2C总线结束信号

    delay_us(4);                                

}

 

//等待应答信号到来

//返回值:1,接收应答失败

//        0,接收应答成功

/*********xxxx修改超时时间************/

uint8_t IIC_Wait_Ack(void)

{

    uint8_t ucErrTime=0;

    SDA_IN();      //SDA设置为输入  

    IIC_SDA=1;delay_us(3);     

    IIC_SCL=1;delay_us(3);   

    while(READ_SDA)

    {

        ucErrTime++;

        if(ucErrTime >250)

        {

            //printf("超时\\n");

            IIC_Stop();

            return 1;

        }

    }

    IIC_SCL=0;//时钟输出0      

    return 0;  

} 

 

//产生ACK应答

void IIC_Ack(void)

{

    IIC_SCL=0;

    SDA_OUT();

    IIC_SDA=0;

    delay_us(2);

    IIC_SCL=1;

    delay_us(2);

    IIC_SCL=0;

}

 

//不产生ACK应答          

void IIC_NAck(void)

{

    IIC_SCL=0;

    SDA_OUT();

    IIC_SDA=1;

    delay_us(2);

    IIC_SCL=1;

    delay_us(2);

    IIC_SCL=0;

}           

 

//IIC发送一个字节

//返回从机有无应答

//1,有应答

//0,无应答           

void IIC_Send_Byte(uint8_t txd)

{                        

    uint8_t t;   

        SDA_OUT();      

    IIC_SCL=0;//拉低时钟开始数据传输

    for(t=0;t< 8;t++)

    {              

        if((txd&0x80) >>7)

            IIC_SDA=1;

        else

            IIC_SDA=0;

        txd< <=1;      

        delay_us(2);   //对TEA5767这三个延时都是必须的

        IIC_SCL=1;

        delay_us(2); 

        IIC_SCL=0;  

        delay_us(2);

    }    

}     

 

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   

uint8_t IIC_Read_Byte(unsigned char ack)

{

    unsigned char i,receive=0;

    SDA_IN();//SDA设置为输入

  for(i=0;i< 8;i++ )

    {

        IIC_SCL=0; 

        delay_us(100);

            IIC_SCL=1;

        receive< <=1;

        if(READ_SDA) receive++;   

        delay_us(100); 

    }                    

    if (!ack)

        IIC_NAck();//发送nACK

    else

        IIC_Ack(); //发送ACK   

    return receive;

}
  1. SHT30的采集程序如下:
#include "sht30.h"

#include "myiic.h"

 

#define POLYNOMIAL_CXDZ 0x31 // X^8 + X^5 + X^4 + 1

//SHT3X CRC校验

unsigned char SHT3X_CRC(uint8_t *data, uint8_t len)

{

    unsigned char bit;        // bit mask

    unsigned char crc = 0xFF; // calculated checksum

    unsigned char byteCtr;    // byte counter

 

    // calculates 8-Bit checksum with given polynomial @GZCXDZ

    for(byteCtr = 0; byteCtr < len; byteCtr++) {

            crc ^= (data[byteCtr]);

            for(bit = 8; bit > 0; --bit) {

                    if(crc & 0x80) {

                            crc = (crc < < 1) ^ POLYNOMIAL_CXDZ;

                    }  else {

                            crc = (crc < < 1);

                    }

            }

    }

  return crc;

}

 

//SHT30命令函数

//addr:表示产品的序号,因为SHT30使用IIC总线的话一条线上可以挂两个

void SHT30_CMD(uint16_t cmd)

{

    IIC_Start();

    IIC_Send_Byte(SHT30_ADDR+0);  //发送设备地址,写寄存器

    IIC_Wait_Ack();

    IIC_Send_Byte((cmd >>8)&0xff); //MSB

 

    IIC_Wait_Ack();

    IIC_Send_Byte(cmd&0xff); //LSB

 

    IIC_Wait_Ack();

    IIC_Stop();

    SysTickDelay(50);//命令发完后需要等待20ms以上才能读写

}



//SHT30读取温湿度

//temp:温度,-400~1250,实际温度=temp/10,分辨率0.1℃,精度±0.3℃

//humi:湿度,0~1000,实际湿度=humi/10,分辨率0.1%rh,精度±3

//返回0成功,1失败

uint8_t SHT30_Read_Humiture(int *temp,uint16_t *humi)

{

    uint8_t buff[6];

    

    SHT30_CMD(SHT30_READ_HUMITURE);//读温湿度命令

    

    IIC_Start();

    IIC_Send_Byte(SHT30_ADDR+1); //发送设备地址,读寄存器

    IIC_Wait_Ack();

    buff[0]=IIC_Read_Byte(1);//继续读,给应答

    buff[1]=IIC_Read_Byte(1);//继续读,给应答

    buff[2]=IIC_Read_Byte(1);//继续读,给应答

    buff[3]=IIC_Read_Byte(1);//继续读,给应答

    buff[4]=IIC_Read_Byte(1);//继续读,给应答

    buff[5]=IIC_Read_Byte(0);//不继续给停止应答

    IIC_Stop();

 

    

    //printf("buff=%d,%d,%d,%d,%d,%d\\r\\n",buff[0],buff[1],buff[2],buff[3],buff[4],buff[5]);

    //CRC校验

    if(SHT3X_CRC(&buff[0],2)==buff[2] && SHT3X_CRC(&buff[3],2)==buff[5])

    {

 

        *temp=(-45+(175.0*((buff[0]< < 8)+buff[1])/65535.0))*10;

        *humi=10*100*((buff[3]< < 8)+buff[4])/65535.0;

        if(*temp >1250) *temp=1250;

        else if(*temp< -400) *temp=-400;

        return 0;

    }

    else return 1;  

    

}

 

//SHT30初始化

void SHT30_Init()

{

    IIC_Init();

}
  1. 在主程序中,我们首先对串口、IIC、AWT、SHT30进行初始化,然后进入采集程序,实现的代码如下:
int main(void)

{

    int t[6];

    uint16_t h[6];

    E31_UART_Init();

    SHT30_Init();

    USART_ITConfig(CW_UART1, USART_IT_RC, ENABLE);

    Init_awt_power();

    InitTick(24000000ul); //初始化SysTick

    // 开启两线调试接口

    RCC_SWDIO_Config(RCC_SYSCTRL_SWDIOEN);

    while (1)

    {

        SHT30_Read_Humiture(t,h);

        e31_send(t[0],h[0]);

        enter_lowpower();

        exit_lowpower();

    }

 

    return 0;

}

【程序效果】

模块采集的数据,在上位机的串口助手上接收到以16进制数据发送的温湿度数据。

image.png

上位机根据具体的需要再进行解析、判断或者分发。

【功耗测试】

此工程以合宙的IoT Power来采集功率耗数据,并做出基本的分析,具体效果如下图:

image.png

从上面的数据我们可以看出,待机电流为7.5微安左右,在每两分钟启用一次数据上报,最在工作电流为46.5mA,平均电流为110uA,平均功率为362微瓦。可以推算一下,1000mAH的电池可以持续供电100天左右。如果我们采用在温湿度正常的范围内缓存,每一个小时做一次数据上传,那么预计可以延长30倍的工作时间,那就是10年左右的待机。

【讨论】

CW32L031具有超低功耗的出色性能,此实验的意义验证了在电池供电的环境下,可以持续的工作数年的可能。433M无线超远距离无线转输模块可以提供长达5公里(空旷)数据传输,广泛适用于智慧农业等野外的数据持续采集。也可以把温湿度传感器更改为土壤湿度、门禁等传感器,实现无线报警等功能。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 传感器
    +关注

    关注

    2545

    文章

    50439

    浏览量

    750972
  • 定时器
    +关注

    关注

    23

    文章

    3231

    浏览量

    114316
  • 编辑器
    +关注

    关注

    1

    文章

    800

    浏览量

    31049
  • 无线采集
    +关注

    关注

    0

    文章

    22

    浏览量

    7967
  • 武汉芯源
    +关注

    关注

    1

    文章

    65

    浏览量

    235
收藏 人收藏

    评论

    相关推荐

    首创ubuntu下cw32l031的vscode+gcc工程创建、下载、调试

    首创在ubuntu下面用vscode实现cw32l031的gcc工程创建、编译、下载与调试
    的头像 发表于 06-25 21:49 2.4w次阅读
    首创ubuntu下<b class='flag-5'>cw32l031</b>的vscode+gcc工程创建、下载、调试

    【Ubuntu VSCODE+GCC】CW32L031实现printf工程

    CW32L031在ubuntu系统下面实现GCC,驱动UART,实现printf工程
    的头像 发表于 06-28 17:07 1001次阅读
    【Ubuntu VSCODE+GCC】<b class='flag-5'>CW32L031</b><b class='flag-5'>实现</b>printf工程

    Ubuntu VSCODE+GCC】CW32L031驱动sht30

    CW32L031在ubuntu下面,使用VSCODE+gcc实现对sht30温湿计的驱动
    的头像 发表于 06-28 17:12 2.4w次阅读
    Ubuntu VSCODE+GCC】<b class='flag-5'>CW32L031</b>驱动sht30

    NRF24L01+PA+LNA 无线远距离2.4G模块

    本帖最后由 eehome 于 2013-1-5 10:09 编辑 NRF24L01+PA+LNA 无线远距离2.4G模块250K的速率下,空旷地的
    发表于 04-11 10:16

    NRF24L01+PA+LNA 无线远距离2.4G模块250K的速率下

    NRF24L01+PA+LNA 无线远距离2.4G模块250K的速率下,空旷地的距离为1100米左右,1M的速率下,空旷地的
    发表于 05-17 15:00

    远距离无线模块APC810

    `采用SEMTECH新的LORA的无线扩频芯片SI1278,采用扩频调制和高效纠错编码,集成的APC810模块,经过一级放大,功耗推到500毫瓦,在5K速率下,空旷距离能达5公里,非常适合
    发表于 02-03 12:03

    武汉】IAR Embedded Workbench®集成开发环境已全面支持武汉CW32 MCU系列

    版本起,IAR将全面支持武汉CW32F030系列、CW32F003系列、CW32L083系
    发表于 06-14 14:54

    【产品介绍】32位低功耗MCU CW32L031系列产品介绍

    Cortex-M0+低功耗MCU CW32L031系列型号展示武汉半导体32位低功耗CW32L031系列集成了主频可达48MHz的ARM
    发表于 09-16 10:30

    持续深耕物联网领域,武汉半导体发布Sub-1G系列产品CW32W031

    武汉半导体持续深耕物联网领域,继推出蓝牙系列芯片CW32R030后,再次推出Sub-1G系列产品CW32W031。该产品是基于
    发表于 01-05 13:35

    ubuntu下面用vscdoe实现CW32L031的工程创建、编译、下载与调试

    目前官方提供CW32L083只提供了MDK、IAR下的固件库、启动文件。我有过成功CW32L083的项目移植的经验,现在成功的把CW32L031的工程移植到ubuntu下面,实现了VS
    发表于 06-25 21:13

    CW32L031产品介绍

    CW32L031是一款基于eFlash的单芯片低功耗微控制器,集成了ARM®Cortex®-M0+ 核心,主频高达48MHz,高速嵌入式存储器(高达64KB的FLASH和 高达8K字节的SRAM
    发表于 09-14 06:02

    CW32L031微控制器数据手册

    CW32L031 是基于 eFlash 的单芯片低功耗微控制器,集成了主频高达 48MHz 的 ARM® Cortex®-M0+ 内核、高速嵌入式存储器(多至 64K 字节 FLASH 和多至 8K
    发表于 09-14 08:26

    CW32L031 StartKit软件包

    CW32L031 StartKit 软件包
    发表于 09-15 07:58

    【产品介绍】32位低功耗MCU CW32L031系列产品介绍

    Cortex-M0+低功耗MCUCW32L031系列型号展示武汉半导体32位低功耗CW32L031系列集成了主频可达48MHz的ARMC
    的头像 发表于 09-16 10:42 1383次阅读
    【产品介绍】32位低功耗MCU <b class='flag-5'>CW32L031</b>系列产品介绍

    持续深耕物联网领域,武汉半导体发布Sub-1G系列产品CW32W031

    武汉半导体持续深耕物联网领域,继推出蓝牙系列芯片CW32R030后,再次推出Sub-1G系列产品CW32W031。该产品是基于
    的头像 发表于 01-05 13:36 902次阅读
    持续深耕物联网领域,<b class='flag-5'>武汉</b><b class='flag-5'>芯</b><b class='flag-5'>源</b>半导体发布Sub-1G系列产品<b class='flag-5'>CW32W031</b>