这是以前做过的一个项目,我们理论不多说,直接上代码,根据代码来记录

CO传感器型号为TGS5042,使用STM32L151 ADC采样,计算CO的数值,使用Standby模式。

本文工程源码下载地址

main.c

/********************************************************************************* @file    L151test.c * @author  QZH* @version V1.1.0* @date    16-September-2020* @brief   ******************************************************************************* @attention* for bluesensor  : lower, DHT21* RTC       wake up* stop      模式不会断,唤醒从睡眠的地方* standby   模式,类似于重启* ******************************************************************************* @attention* 2020/12/17* CO传感器,使用L151的ADC直接测量电压* 不需要温湿度* 蓝牙模块为上次使用版本,驱动可以不用改变太大* * 2021/1/21* 1、添加CO计算函数;* 2、ADC数值处理在蓝牙模块唤醒等待的1s中内进行;* 3、实际测试,唤醒工作时间电流约 5.6~ 5.8 mA (程序1300ms左右,实测2S,估算电量可以细算)  ,休眠电流约 6uA,实际休眠电流约 4uA ~ 5uA,开始测试6uA 是因为连接了串口;* 4、初步设置,普通周期 为 5min ,300s 一次,  CO > 40ppm  变成10s 一次;* 5、后续有需要可以 使用后备寄存器  存储检测数据,可以做到检测一定次数再发送;* * *******************************************************************************//* Includes ------------------------------------------------------------------*/
#include "stm32l1xx.h"
#include "delay.h"
#include "gpio.h"
#include "sys.h"
#include "stm32l1xx_clock_config.h"
#include "usart.h"
#include "rtc.h"
#include "blue_common.h"
#include "adc.h"
#include "co.h"/** @addtogroup STM32L1xx_StdPeriph_Examples* @{*/u8 sendtime = 0;/*** @brief  Main program* @param  None* @retval None*/int main(void)
{/*到main()函数这里 SystemInit()已经初始化了,在学习startup_xxxx.s文件里提到过,会调用很早版本的固件库 需要用户自己 SystemInit();*/u16 normal_cycle = 300; u16 quick_cycle = 10;/*把系统时钟放低时钟频率低,功耗低,但是相应的系统速度也肯定慢下来了*/SetHCLKTo8();/*根据系统时钟初始化延时函数*/delay_init(8);/*外设: 依次是串口,ADC,蓝牙模块控制IO*/My_USARTx_Config(USART1,9600);My_USARTx_Config(USART3,9600); Adc_init();blue_control_init();printf("main start!\r\n");#ifdef TESTblue_slp_on;#endifwhile(1){/*芯片唤醒就开始执行自己想做的操作,读取ADC,蓝牙模块发送消息,都在这个函数里面*/blue_setcmd();printf("300ms time for send message...\r\n");delay_ms(300); //这个时间得留给蓝牙发送报文/*根据传感器的数据设置周期,就是RTC唤醒的时间  RTC_Config*/if(sendtime == 0){printf("into normal_cycle  lowerpower mode!\r\n");RTC_Config(normal_cycle);   }else if(sendtime == 1){printf("into quick_cycle  lowerpower mode!\r\n");RTC_Config(quick_cycle);}/*使能自动唤醒功能 */printf("open wakeup!\r\n");RTC_WakeUpCmd(ENABLE);printf("gpio pin set to lowerpower!\r\n");/*进入低功耗前,记得把所有的IO口设置为模拟输入*/gpio_lowpower();printf("get in standby for 5 s!\r\n");Sys_Standby();printf("Standby model won,t go to this place!\r\n");RTC_WakeUpCmd(DISABLE);}
}

唤醒函数RTC_Config

其中有一个关键函数RTC_Config,这个函数的实现ST官方包括网上的例子也很多,当初也是参考了不少demo:

#include "rtc.h"#define LSE_STARTUP_TIMEOUT_Num   0xFFFFF void RTC_Config(uint32_t wakeuptime_s)
{__IO uint32_t lse_waittime = 0;NVIC_InitTypeDef NVIC_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;/* Enable the PWR clock */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);/*!< Allow access to RTC 使能后备寄存器访问*/PWR_RTCAccessCmd(ENABLE);//RESET RTC DomainRCC_RTCResetCmd(ENABLE);RCC_RTCResetCmd(DISABLE);//LSE enable   32.768kRCC_LSEConfig(RCC_LSE_ON);//wait till LSE is readywhile((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)&&(lse_waittime<LSE_STARTUP_TIMEOUT_Num)){lse_waittime++;}/*这里有一段代码是如果外部低速晶振出了问题采用的,用下面这段需要把上面的while语句修改一下ex1:if (timeout == 0) {RCC_LSICmd(ENABLE);while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);} else {RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); }ex2:  //ex2 就是按照上面while一致的方式来进行的if(lse_waittime>=LSE_STARTUP_TIMEOUT_Num){XTUpCounter = 0;RCC_LSICmd(ENABLE);while((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)&&(lse_waittime<LSE_STARTUP_TIMEOUT_Num)){lse_waittime++;}if(XTUpCounter<HSE_STARTUP_TIMEOUT_Num){RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);  //选择内部晶振作为RTC时钟源RTCStateFlag = 2;}else{RTCStateFlag = 0;}   }else{RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//选择外部晶振作为RTC时钟源RTCStateFlag = 1;}*///rtc clock selectRCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//enable rtc clockRCC_RTCCLKCmd(ENABLE);// wait for rtc APB registers synchronisationRTC_WaitForSynchro();/*这里估计可以在后背寄存器保存一定的数据,但是目前这里没有用到// Configure the RTC data register and RTC prescaler 从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎if (RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2) { RTC_InitStructure.RTC_AsynchPrediv = 0x7F;RTC_InitStructure.RTC_SynchPrediv = 0xFF;RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;RTC_Init(&RTC_InitStructure);RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);}RTC_WaitForSynchro();*//*//配置RTC数据寄存器以及时钟分频RTC_InitStructure.RTC_AsynchPrediv = 0X7F;//同步  设置预分频为1S一次RTC_InitStructure.RTC_SynchPrediv = 0XFF; //异步   255  RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;//24小时制//检查RTC初始化 if(RTC_Init(&RTC_InitStructure) == ERROR){while(1);}//Set the date: Thursday January 11th 2018,2018/01/25 星期四RTC_DateStruct.RTC_Year = 0x18;RTC_DateStruct.RTC_Month = RTC_Month_January;RTC_DateStruct.RTC_Date = 0x27;RTC_DateStruct.RTC_WeekDay = RTC_Weekday_Thursday;RTC_SetDate(RTC_Format_BCD, &RTC_DateStruct);//Set the time to 10h 09mn 15s AM ,早上10:09:15RTC_TimeStructure.RTC_H12     = RTC_H12_PM;RTC_TimeStructure.RTC_Hours   = 0x21;RTC_TimeStructure.RTC_Minutes = 0x57;RTC_TimeStructure.RTC_Seconds = 0x33; RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);*///EXIT ConfigEXTI_ClearITPendingBit(EXTI_Line20);EXTI_InitStructure.EXTI_Line = EXTI_Line20;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);//enable the rtc wakeup interruptNVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);//先关闭TRC中断使能// RTC_WakeUpCmd(DISABLE); //rtc wakeup interrupt generation:clock source:RTCDiv_16,//wakeup time base:4sRTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);RTC_SetWakeUpCounter(wakeuptime_s);//清除RTC唤醒中断标志RTC_ClearFlag(RTC_FLAG_WUTF);//enable the wakeup interruptRTC_ITConfig(RTC_IT_WUT, ENABLE);
}void RTC_WKUP_IRQHandler(void)
{if(RTC_GetITStatus(RTC_IT_WUT) != RESET){RTC_ClearITPendingBit(RTC_IT_WUT);EXTI_ClearITPendingBit(EXTI_Line20);}
}

除了上面的rtc.c,当初测试的时候,也针对 系统时钟频率,IO口,ADC配置也进行了测试:

时钟频率

我为什么没有设置更高,更高虽然功耗大,但是运行时间短,相对的功耗不见得比低频率高,这个得看自己的实际需求,不能一概而论。我是直接设置成 8M:

/*把系统时钟放低时钟频率低,功耗低,但是相应的系统速度也肯定慢下来了*/SetHCLKTo8();/*根据系统时钟初始化延时函数*/delay_init(8);

IO口

IO口用到的不多,最后休眠前有一个gpio_lowpower()函数如下:

void gpio_lowpower(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;   GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_9|GPIO_Pin_10;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;GPIO_Init(GPIOB, &GPIO_InitStructure);
}

ADC

ADC配置其实和F103一样,固件库的配置都是一样的,这个也是从别的地方复制一下,这个配置其实网上很多,我记得我最初看到还是在正点原子的F103系列教程demo里面看到的,基本就是一样:

#include "adc.h"void Adc_init(void)
{ GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;/*----------------- ADC1 configuration with DMA enabled --------------------*//* Enable the HSI oscillator */RCC_HSICmd(ENABLE);/* Enable GPIOA clock */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);/* Configure PA.1 (ADC Channe1) in analog mode */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA, &GPIO_InitStructure);/* Check that HSI oscillator is ready */while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div1;ADC_CommonInit(&ADC_CommonInitStructure);/* Enable ADC1 clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);/* ADC1 configuration */ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  //需要连续读10次,所以开启ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfConversion = 1;ADC_Init(ADC1, &ADC_InitStructure);ADC_TempSensorVrefintCmd(ENABLE);/* ADC1 regular channel18 configuration */ ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_48Cycles);   /* Enable ADC1 */ADC_Cmd(ADC1, ENABLE);/* Wait until the ADC1 is ready */while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET){          }           ADC_SoftwareStartConv(ADC1); }//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{//设置指定ADC的规则组通道,一个序列,采样时间ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_48Cycles );    //ADC1,ADC通道,采样时间为239.5周期                   ADC_SoftwareStartConv(ADC1);        //使能指定的ADC1的软件转换启动功能    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}u16 Get_Adc_Average(u8 ch,u8 times)
{u32 temp_val=0;u8 t;for(t=0;t<times;t++){temp_val+=Get_Adc(ch);delay_ms(5);}return temp_val/times;
}

TGS5042传感器

TGS5042解析代码在这里就不贴出来,因为如果做其他产品这个部分也没有必要知道,我自己也只是为了做个记录,国外的传感器,价格比较贵,而且这个传感器有些年头了,传感器的更新还是比较快的,估计以后也用得少。

蓝牙模块

蓝牙模块使用的是 深圳云里物里 的 MS50SFB 模块,是nRF52832的内核,因为是别人的固件,所以产品在蓝牙模块通讯处理部分还是有改进空间的,可以自己使用 nRF52832 模块进行设计,然后程序执行的时间,功耗,可以得到进一步控制。

产品最终

唤醒工作时间电流约 5.6~ 5.8 mA ,2s左右。

产品实际运行时间2S,主要是因为和蓝牙模块的通讯 和 预留发送蓝牙报文的时间,一般至少预留蓝牙模块发送 2个周期以上的报文,以确保产品周期播报的稳定性,这也是根据自己的实际需求,如果休眠时间过长,可以多放点周期,如果本来周期就短,唤醒工作时间可以缩短 。

休眠电流约 4uA ~ 5uA。(以上电流是在3.6V电池供电环境下)

STM32L151低功耗项目笔记(CO传感器TGS5042)相关推荐

  1. 初出茅庐的小李第113篇博客项目笔记之机智云智能浇花器实战(2)-基础Demo实现

    初出茅庐的小李第112篇博客项目笔记之机智云智能浇花器实战(1)-基础Demo实现 接(1) 继电器实现 继电器原理图 继电器采用的是5V继电器,控制端是RELAY-1 继电器代码实现 #includ ...

  2. 【STM32】ESP8266 WiFi模块实时上报温湿度及控制LED灯项目笔记

    ESP8266 WiFi模块实时上报温湿度及控制LED灯项目笔记 一.ESP8266模块 1.模块介绍 2.AT指令介绍 2.硬件连接 二.串口转发及调试 1.串口转发流程 2.串口转发程序实现 ST ...

  3. 《BI项目笔记》用Excel2013连接和浏览OLAP多维数据集

    <BI项目笔记>用Excel2013连接和浏览OLAP多维数据集 原文:<BI项目笔记>用Excel2013连接和浏览OLAP多维数据集 用Excel2013连接和浏览OLAP ...

  4. 《BI项目笔记》创建标准维度、维度自定义层次结构

    原文:<BI项目笔记>创建标准维度.维度自定义层次结构

  5. 【Andorid X 项目笔记】动态设置ViewPager的Adapter问题(2)

    由于没有找到嵌套FragmentActivity的方法,只好打算用不同的FragmentPagerAdapter来动态切换ViewPager的,如下: /**      * 首页切换的三个界面     ...

  6. stm32f103 低功耗调试笔记 低功耗模式下一直有个800多uA的电流

    最新在做一个低功耗项目 ,用到stm32f103芯片,用到的stop模式和standby模式. 因 stop 只比 standby 模式多1-3uA,最终选用了 stop 模式.下面是官方文档中对几种 ...

  7. 《BI项目笔记》数据源视图设置

    原文:<BI项目笔记>数据源视图设置 目的 数据源视图是物理源数据库和分析维度与多维数据集之间的逻辑数据模型.在创建数据源视图时,需要在源数据库中指定包含创建维度和多维数据集所需要的数据表 ...

  8. 【Andorid X 项目笔记】禁用ListView的Fling功能(1)

    前言 新的项目正在紧张开发中,初步估计2个月时间开发完成第一版,我负责Android端开发,由于不便过早公布,本系列将命名为"X项目笔记",并于项目结束后最终公布名称.本系列主要记 ...

  9. AppFuse项目笔记(1)

    AppFuse项目笔记(1) 一.Appfuse简介 Appfuse是Matt Raible 开发的一个指导性的入门级J2EE框架,它对如何集成流行的Spring.Hibernate.ibatis.s ...

最新文章

  1. 2017年最受欢迎的10个编程挑战网站
  2. 1、C语言面试笔试---变量定义和声明
  3. 朴素的串模式匹配(C语言实现)【串模式匹配】
  4. SAP物料帐下修改物料的价格
  5. Spring5参考指南:SpringAOP简介
  6. x264 编码数配置
  7. CSS的一些常用知识点
  8. python自学路线及教程_python如何学习:最全学习路线
  9. android 360度环拍,Android 4.2系统360度全景图拍摄试玩
  10. Netty8# Netty之ByteBuf初探
  11. 计算机用户删除文件找回,电脑上删除的文件如何找回 业内人士分享小技巧
  12. 虚拟服务器的密码忘记了,虚拟平台管理术:忘记 ESXi 主机的 root 密码该怎么办?...
  13. 解决python使用猴子补丁时引入ssl错误
  14. android patch app,AndroidN,O 加载到patch 以后重启app crash了.
  15. SpringBoot 默认数据库连接池 HikariCP
  16. android时间24小时,安卓时间显示TextClock显示日期时间,24小时制和12小时制(自定义...
  17. For 循环优化,提升效率
  18. Docker容器启动参数大全与详细说明
  19. sql 中or与in的查询效率对比
  20. 工程(二)——DeeplabV3+语义分割训练自制数据集

热门文章

  1. Python到底有多强?双十一的时候带你领略它的强大之处!
  2. 2021年化工自动化控制仪表最新解析及化工自动化控制仪表复审模拟考试
  3. c罗说什么语言,世界足坛:语言不通,怎能仗剑天涯
  4. 能够在乱世中_三国时期难得一遇的天才,在乱世中能够从容自若,智慧不输诸葛亮...
  5. Microsoft Office 2021(预览版)
  6. go语言字符串换行_Go语言字符串高效拼接(一)
  7. 主流操作系统及其优缺点
  8. 沪上首个千人区块链产业峰会!POW'ER 2020上海峰会首日精华实录
  9. Alibaba后台4年,跳槽字节,艰难4面技术,成功砍下开发岗offer
  10. 集群、负载均衡、分布式 简介