您现在的位置是:网站首页> 开发积累

硬件研发技术及实操收集

摘要

硬件研发技术及实操收集

香橙派代替树莓派

Arduino模拟输入(滑动电阻)

软件人员的硬件开发

ESP32休眠典型例子

工控机+IO模块集成方案或工控机带GPIO

使用Arduino和水流传感器进行流速和流量测量

单片机电源解决

Arduino AVR休眠外部终端唤醒

新品 cnc shield v3 雕刻机扩展板 3D打印机 A4988驱动板

ESP32睡眠唤醒

ESP32低功耗模式

电池电量与功耗

如何让Arduino用2颗5号电池运行1年以上--Arduino低功耗




香橙派代替树莓派

安装QT5

sudo apt-get update

sudo apt-get install qt5-default

sudo apt-get install qtcreator

检查安装

orangepi@orangepi:~$ qmake -v

QMake version 3.1

Using Qt version 5.9.5 in /usr/lib/aarch64-linux-gnu 



Arduino模拟输入(滑动电阻)

Arduino所采用的ATmega8微处理器一其有6个模数转换器(ADC,Analog to Digital Converter),每一个模数转换器的精度都是10bit,也就是说能够读取1024(2^10 = 1024)个状态。在Arduino的每一个模拟输入管脚上,电压的变化范畴是从0V到5V,因此Arduino能够感知到的最小电压变化是4.8毫伏(5/1024 = 4.8mV)


压力传感器输出的是标准信号4~20mADC,这个信号是怎样转换成压力值的?在哪里转换的?

首先,这个4~20mA电流要通过一只高精密电阻转换成电压信号。这个电阻可能你的二次仪表中已经有了,也可能需要你自己连接。例如,在4~20mA回路中传入一只250欧的电阻,就可以把电流转换成1~5v的电压。


nalogReference(type)

参数可以为:

DEFAULT:默认5V或3.3V为基准电压。

INTERNAL:在ATmega168和ATmega328上以1.1V为基准电压,以及在ATmega8上以2.56V为基准电压(Mega2560无此选项)

INTERNAL1V1:以1.1V为基准电压(此选项仅针对Mega2560)

INTERNAL2V56:以2.56V为基准电压(此选项仅针对Mega2560)

EXTERNAL:以AREF引脚(0至5V)的电压作为基准电压。

如果我们用

 analogReference(INTERNAL);

调用arduino板子内部1.1V基准,从LM35读取的温度数值会不会得到比原来更精细的温度变化~~~

最终代码:

void setup() {

  Serial.begin(9600);         //使用9600速率进行串口通讯

  analogReference(INTERNAL); //调用板载1.1V基准源

}


void loop() {


  int n = analogRead(A0);    //读取A0口的电压值

  double vol = n * (1.1 / 1024.0*100);   //使用双精度浮点数存储温度数据,温度数据由电压值换算得到

  Serial.println(vol);                   //串口输出温度数据

  delay(1000);                           //等待1秒,控制刷新速度

}



软件人员的硬件开发

如nodemcu的应用

通过图形化控制单片机,植入单片机



ESP32休眠典型例子

/*

 * HelTec Automation(TM) Low_Power test code, witch includ

 * Function summary:

 *

 * - Vext connected to 3.3V via a MOS-FET, the gate pin connected to GPIO21;

 *

 * - OLED display and PE4259(RF switch) use Vext as power supply;

 *

 * - WIFI Kit series V1 don't have Vext control function;

 * 

 * - Basic LoRa Function;

 *

 * - Esp_Deep_Sleep Function;

 * 

 * by lxyzn from HelTec AutoMation, ChengDu, China

 * 

 * www.heltec.cn

 *

 * this project also realess in GitHub:

 * https://github.com/HelTecAutomation/Heltec_ESP32

*/


#include "heltec.h"



#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */

#define TIME_TO_SLEEP  10        /* Time ESP32 will go to sleep (in seconds) */


#define BAND    433E6  //you can set band here directly,e.g. 868E6,915E6




RTC_DATA_ATTR int bootCount = 0;


/*

Method to print the reason by which ESP32

has been awaken from sleep

*/

void print_wakeup_reason(){

  esp_sleep_wakeup_cause_t wakeup_reason;


  wakeup_reason = esp_sleep_get_wakeup_cause();


  switch(wakeup_reason)

  {

    case 1  :

    {

      Serial.println("Wakeup caused by external signal using RTC_IO");

      delay(2);

    } break;

    case 2  :

    {

      Serial.println("Wakeup caused by external signal using RTC_CNTL");

      delay(2);

    } break;

    case 3  :

    {

      Serial.println("Wakeup caused by timer");

      delay(2);

    } break;

    case 4  :

    {

      Serial.println("Wakeup caused by touchpad");

      delay(2);

    } break;

    case 5  :

    {

      Serial.println("Wakeup caused by ULP program");

      delay(2);

    } break;

    default :

    {

      Serial.println("Wakeup was not caused by deep sleep");

      delay(2);

    } break;

  }

}


void setup(){

  //WIFI Kit series V1 not support Vext control

  Heltec.begin(true /*DisplayEnable Enable*/, true /*LoRa Disable*/, true /*Serial Enable*/, true /*PABOOST Enable*/, BAND /*long BAND*/);


  //Increment boot number and print it every reboot

  ++bootCount;

  Serial.println("Boot number: " + String(bootCount));

  delay(2);


  

 


  //Print the wakeup reason for ESP32

  print_wakeup_reason();


  /*

  First we configure the wake up source

  We set our ESP32 to wake up every 5 seconds

  */

  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +

  " Seconds");

  delay(10);


  /*

  Next we decide what all peripherals to shut down/keep on

  By default, ESP32 will automatically power down the peripherals

  not needed by the wakeup source, but if you want to be a poweruser

  this is for you. Read in detail at the API docs

  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html

  Left the line commented as an example of how to configure peripherals.

  The line below turns off all RTC peripherals in deep sleep.

  */

  //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);

  //Serial.println("Configured all RTC Peripherals to be powered down in sleep");


  /*

  Now that we have setup a wake cause and if needed setup the

  peripherals state in deep sleep, we can now start going to

  deep sleep.

  In the case that no wake up sources were provided but deep

  sleep was started, it will sleep forever unless hardware

  reset occurs.

  */

  LoRa.end();

  LoRa.sleep();

  delay(100);

  


  pinMode(5,INPUT);


   pinMode(14,INPUT);

   pinMode(15,INPUT);

   pinMode(16,INPUT);

   pinMode(17,INPUT);

pinMode(18,INPUT);

  pinMode(19,INPUT);


  pinMode(26,INPUT);

  pinMode(27,INPUT);



  delay(100);

  Serial.println("Going to sleep now");

  delay(2);

  esp_deep_sleep_start();

  Serial.println("This will never be printed");

}


void loop(){

  //This is not going to be called

}



使用Arduino和水流传感器进行流速和流量测量

原文

volatile int flow_frequency; // Measures flow sensor pulses

// Calculated litres/hour

float vol = 0.0,l_minute;

unsigned char flowsensor = 2; // Sensor Input

unsigned long currentTime;

unsigned long cloopTime;

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 9);

void flow () // Interrupt function

{

   flow_frequency++;

}

void setup()

{

   pinMode(flowsensor, INPUT);

   digitalWrite(flowsensor, HIGH);

   Serial.begin(9600);

   lcd.begin(16, 2);

   attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING); // Setup Interrupt

   lcd.clear();

   lcd.setCursor(0,0);

   lcd.print("Water Flow Meter");

   lcd.setCursor(0,1);

   lcd.print("Circuit Digest");

   currentTime = millis();

   cloopTime = currentTime;

}

void loop ()

{

   currentTime = millis();

   // Every second, calculate and print litres/hour

   if(currentTime >= (cloopTime + 1000))

   {

    cloopTime = currentTime; // Updates cloopTime

    if(flow_frequency != 0){

      // Pulse frequency (Hz) = 7.5Q, Q is flow rate in L/min.

      l_minute = (flow_frequency / 7.5); // (Pulse frequency x 60 min) / 7.5Q = flowrate in L/hour

      lcd.clear();

      lcd.setCursor(0,0);

      lcd.print("Rate: ");

      lcd.print(l_minute);

      lcd.print(" L/M");

      l_minute = l_minute/60;

      lcd.setCursor(0,1);

      vol = vol +l_minute;

      lcd.print("Vol:");

      lcd.print(vol);

      lcd.print(" L");

      flow_frequency = 0; // Reset Counter

      Serial.print(l_minute, DEC); // Print litres/hour

      Serial.println(" L/Sec");

        }

 else {

      lcd.clear();

      lcd.setCursor(0,0);

      lcd.print("Rate: ");

      lcd.print( flow_frequency );

      lcd.print(" L/M");

      lcd.setCursor(0,1);

      lcd.print("Vol:");

      lcd.print(vol);

      lcd.print(" L");

    }


}

我们将水流传感器连接到管道。如果管道的输出阀关闭,则水流传感器的输出为零(无脉冲)。在Arduino的引脚2上看不到中断信号,并且flow_frequency的计数为零。在这种情况下,在else循环内编写的代码将起作用。

如果管道的输出阀打开,水流过传感器,这又使传感器内的车轮旋转。在这种情况下,我们可以观察到传感器产生的脉冲。这些脉冲将作为对Arduino UNO的中断信号。对于每个中断信号(上升沿),flow_frequency变量的计数将增加一。当前时间和cloopTIme变量可确保每隔一秒钟将flow_frequency的值用于计算流量和体积。计算完成后,将flow_frequency变量设置为零,并从头开始执行整个过程。



单片机电源解决

电脑上的USB接口的输出电压为直流5V,输出电流不大于500毫安,可以用AC转DC模块,或直接一个通用电源,或开关电源


Arduino AVR休眠外部终端唤醒


查看原文

#include <avr/sleep.h>

long tB=0;

void wakeUpNow(){

  tB=millis();

}

void sleepNow()         // here we put the arduino to sleep

{

    /* Now is the time to set the sleep mode. In the Atmega8 datasheet

     * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35

     * there is a list of sleep modes which explains which clocks and

     * wake up sources are available in which sleep modus.

     *

     * In the avr/sleep.h file, the call names of these sleep modus are to be found:

     *

     * The 5 different modes are:

     *     SLEEP_MODE_IDLE         -the least power savings

     *     SLEEP_MODE_ADC

     *     SLEEP_MODE_PWR_SAVE

     *     SLEEP_MODE_STANDBY

     *     SLEEP_MODE_PWR_DOWN     -the most power savings

     *

     * For now, we want as much power savings as possible,

     * so we choose the according sleep modus: SLEEP_MODE_PWR_DOWN

     *

     */  

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

 

    sleep_enable();              // enables the sleep bit in the mcucr register

                                 // so sleep is possible. just a safety pin

 

    /* Now is time to enable a interrupt. we do it here so an

     * accidentally pushed interrupt button doesn't interrupt

     * our running program. if you want to be able to run

     * interrupt code besides the sleep function, place it in

     * setup() for example.

     *

     * In the function call attachInterrupt(A, B, C)

     * A   can be either 0 or 1 for interrupts on pin 2 or 3.  

     *

     * B   Name of a function you want to execute at interrupt for A.

     *

     * C   Trigger mode of the interrupt pin. can be:

     *             LOW        a low level triggers

     *             CHANGE     a change in level triggers

     *             RISING     a rising edge of a level triggers

     *             FALLING    a falling edge of a level triggers

     *

     * In all but the IDLE sleep modes only LOW can be used.

     */


 pinMode(2,INPUT_PULLUP);

    attachInterrupt(digitalPinToInterrupt(2),wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function

                                       // wakeUpNow when pin 2 gets LOW

                                       /* 

    sleep_mode();                // here the device is actually put to sleep!!

                                 // 

    sleep_disable();             // first thing after waking from sleep:

                                 // disable sleep...

    detachInterrupt(0);          // disables interrupt 0 on pin 2 so the

                                 // wakeUpNow code will not be executed

                                 // during normal running time.

    delay(1000);                 // wat 2 sec. so humans can notice the

                                 // interrupt.

                                 // LED to show the interrupt is handled

    digitalWrite (interruptPin, LOW);      // turn off the interrupt LED

 */

 // 进入睡眠模式

  sleep_cpu ();

}


void setup() {

  // put your setup code here, to run once:  

 Serial.begin(9600);

 sleepNow();

}


void loop() {

  // put your main code here, to run repeatedly:

  Serial.print("ok");

  if(millis()-tB>10000 && tB!=0)

  {

    tB=0;

    sleepNow();

  }

}


新品 cnc shield v3 雕刻机扩展板 3D打印机 A4988驱动板

一、 产品介绍

该扩展板可用作雕刻机,3D打印机等的驱动扩展板,一共有4路步进电机驱动模块的插槽,(注意本板子不包含A4988步进电机驱动模块,需要可在本店另购),可驱动4路不进电机,而每一路步进电机都只需要2IO口,也就是说,6IO口就可以很好的管理3个步进电机,使用起来非常的方便,告别传统步进电机操作繁琐。

 

 

二、UNO 与模块IO口对应关系介绍

 

 

步进电机的基本控制需要的引脚,其他引脚是在雕刻机,或3D打印机的时候才用到的,这里我们不作详解,IO对应如上图。

  Arduino UNO----------------------扩展板

    8 ------------------------  EN (步进电机驱动使能端,低电平有效)

-----------------------  Z.DIR(Z轴的方向控制)

-----------------------  Y.DIR(Y轴的方向控制)

-----------------------  X.DIR(X轴的方向控制)

4 ----------------------  Z.STEP(Z轴的步进控制)

3 ----------------------  Y.STEP(Y轴的步进控制)

2 ----------------------  X.STEP(X轴的步进控制)

//下面是简单的步进电机控制程序,

#define EN        8       //步进电机使能端,低电平有效

#define X_DIR     5       //X轴 步进电机方向控制

#define Y_DIR     6       //y轴 步进电机方向控制

#define Z_DIR     7       //z轴 步进电机方向控制

#define X_STP     2       //x轴 步进控制

#define Y_STP     3       //y轴 步进控制

#define Z_STP     4       //z轴 步进控制

/*

//函数:step    功能:控制步进电机方向,步数。

//参数:dir 方向控制, dirPin对应步进电机的DIR引脚,stepperPin 对应步进电机的step引脚, steps 步进的步数

//无返回值

*/

void step(boolean dir, byte dirPin, byte stepperPin, int steps)

{

  digitalWrite(dirPin, dir);

  delay(50);

  for (int i = 0; i < steps; i++) {

    digitalWrite(stepperPin, HIGH);

    delayMicroseconds(800);  

    digitalWrite(stepperPin, LOW);

    delayMicroseconds(800);  

  }

}

void setup(){//将步进电机用到的IO管脚设置成输出

  pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT);

  pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);

  pinMode(Z_DIR, OUTPUT); pinMode(Z_STP, OUTPUT);

  pinMode(EN, OUTPUT);

  digitalWrite(EN, LOW);

}

void loop(){

  step(false, X_DIR, X_STP, 200); //X轴电机 反转1圈,200步为一圈

  step(false, Y_DIR, Y_STP, 200); //y轴电机 反转1圈,200步为一圈

  step(false, Z_DIR, Z_STP, 200); //z轴电机 反转1圈,200步为一圈

  delay(1000);

  step(true, X_DIR, X_STP, 200); //X轴电机 正转1圈,200步为一圈

  step(true, Y_DIR, Y_STP, 200); //y轴电机 正转1圈,200步为一圈

  step(true, Z_DIR, Z_STP, 200); //z轴电机 正转1圈,200步为一圈

  delay(1000);

}

 

实验现象:步进电机反转一圈,停顿1秒,再正传一圈,如此循环。

值得注意的是:在接插A4988模块的时候注意不要插反,步进电机接线方式是:

2A ,2B 为一组(红,绿), 1A,1B为一组(蓝,黄)想改变方向,改变其中一组的位置即可,比如2A,与2B交换。


ESP32睡眠唤醒

进入休眠后定时器唤醒

esp_sleep_enable_timer_wakeup(20000000);

参数:

定时时间,单位μ秒, 类型uint64_t, 所以定时时间要在584942年以内

例子:

#include <Arduino.h>

#include <esp_sleep.h>


RTC_DATA_ATTR int bootCount = 0;


void setup()

{

  Serial.begin(115200);

  Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);

  delay(5000);

  esp_sleep_enable_timer_wakeup(20000000);

  Serial.println(esp_sleep_get_wakeup_cause());

}


void loop()

{

  Serial.println("ESP32 will sleep now!");

  delay(100);

  esp_deep_sleep_start();

}

进入休眠后被RTC_GPIO唤醒 (引脚唤醒方式一)

首先,并不是每个GPIO都是RTC_GPIO, 详见下表

1.png

2.png

注意: 我们填写的GPIO引脚号是真正的引脚号 不是其RTC_GPIO编号


 esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);

#include <Arduino.h>

#include <esp_sleep.h>


RTC_DATA_ATTR int bootCount = 0;


void setup()

{

  Serial.begin(115200);

  Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);

  esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);

  Serial.printf("the wakeup reason is :%d\r\n", esp_sleep_get_wakeup_cause());

}


void loop()

{

  delay(3000);

  Serial.println("ESP32 will sleep now!");

  delay(100);

  esp_deep_sleep_start();

}

进入休眠后被RTC_CNTL唤醒 (引脚唤醒方式二)

思考一个问题, 如果我们有8个GPIO引脚想唤醒ESP32, 难道要用上一节的方法操作8遍吗?

当然不是, 我们可以直接操作引脚集合, (我们用一个mask片选想操作的引脚,然后这些引脚都具有了唤醒ESP32的能力)

我们可以设置这些引脚是 每个都能触发(每个葫芦娃都能自己去救爷爷), 还是一起共同发力才能触发(集齐七龙珠??)

esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);

参数:


mask :

1.png

如: 我们想让 32 33 35 39触发, 这样计算mask

1.png

注意: 我们不要使用 37 38


mode: 触发方式 可选:

ESP_EXT1_WAKEUP_ALL_LOW : 全都置低时触发唤醒

ESP_EXT1_WAKEUP_ANY_HIGH : 任意置高时触发唤醒

1.png

进入休眠后被触摸按键唤醒

值得注意的是,

  • 触摸按键唤醒所需deepsleep电流要大于 按键和定时器
  • 必须写触摸回调函数, 否则无用

#include <Arduino.h>

#include <esp_sleep.h>


RTC_DATA_ATTR int bootCount = 0;

RTC_DATA_ATTR int BTN_Pin_BITMASK = 0;



void callbackPin2()

{

  Serial.println("T2 weak ESP32 up");

}


void setup()

{

  Serial.begin(115200);

  Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);

  esp_sleep_enable_touchpad_wakeup();

  Serial.printf("the wakeup reason is :%d\r\n", esp_sleep_get_wakeup_cause());

  touchAttachInterrupt(2,callbackPin2,40);

}


void loop()

{

  delay(3000);

  Serial.println("ESP32 will sleep now!");

  delay(100);

  esp_deep_sleep_start();

}



ESP32低功耗模式

玩转 ESP32 + Arduino (十七) deepsleep深睡眠模式

字数 1,002阅读 2,540



一. 关于UPL协处理器的概念

ESP32 有强大的超低功耗协处理器 (ULP co-processor)

ULP 协处理器是一个功耗极低的协处理器设备,无论主 CPU 是处于正常运行模式还是 Deep-sleep 模式,ULP 协处理器都可以独立运行。超低功耗协处理器的补充使得 ESP32 能够胜任一些对低功耗要求较高的应用场合。

ULP 协处理器的主要特性有:

采用 8 MHz 频率和 8 KB 内存
内建 ADC 和 I2C 接口
支持正常模式和 Deep-sleep 模式
可唤醒主 CPU 或向主 CPU 发送中断
能够访问主 CPU 的外围设备、内部传感器及 RTC 寄存器

鉴于以上的特性,ULP 协处理器能够在消耗较低电流的情况下,完成 ADC 采样,进行 I2C Sensor 的读写,驱动 RTC GPIO 口动作,可以在某些超低功耗场景中完全替代主 CPU。

重要的: ULP是ESP32做出优秀低功耗产品的关键

但是致命的: ULP只能用汇编????????

参考文档: https://blog.csdn.net/espressif/article/details/79131076

二. 理解了ULP之后, 让我们看一下ESP32的工作模式

可以看到ESP32在深睡眠模式下可以启动或停止ULP协处理器

三. ESP32 deepsleep模式唤醒方式及关键API

唤醒方式:

  • 定时器唤醒
  • 两种引脚唤醒方式
  • 触摸按键唤醒
  • ULP唤醒

1. 开始进入深睡眠: esp_deep_sleep_start();

esp_deep_sleep_start();

2. 获取esp32被唤醒的原因 esp_deep_sleep_get_wakeup_cause();

这是一个ESP-IDF的原生方法, 如果我们想用, 需要引入头文件

#include <esp_sleep.h>

注意:#include <esp_deep_sleep.h>即将被弃用, 所以不要再用这个头文件了

Serial.println(esp_deep_sleep_get_wakeup_cause());

返回: 被唤醒原因码:

原因码对应原因说明
0ESP_SLEEP_WAKEUP_UNDEFINED没有定义被唤醒的原因(第一次启动时会报)
2ESP_SLEEP_WAKEUP_EXT0被RTC_GPIO唤醒
3ESP_SLEEP_WAKEUP_EXT1被RTC_CNTL引脚集合的变化唤醒
4ESP_SLEEP_WAKEUP_TIMER被ESP的定时器唤醒
5ESP_SLEEP_WAKEUP_TOUCHPAD被触摸唤醒
6ESP_SLEEP_WAKEUP_ULP被ULP唤醒
7ESP_SLEEP_WAKEUP_GPIO被GPIO唤醒(仅限轻睡眠模式light sleep)
8ESP_SLEEP_WAKEUP_UART被串口唤醒(仅限轻睡眠模式light sleep)

3. 设置具体的唤醒源请看下面的相关章节

四. RTC memory

ESP32有8KB的RTC存储器
在RTC memory里的变量不会因为deepsleep被清除, 创建方法:

RTC_DATA_ATTR int bootCount = 0;

注意, RTC memory会被硬件reset清除

五. 进入休眠后定时器唤醒

esp_sleep_enable_timer_wakeup(20000000);

参数:

  • 定时时间,单位μ秒, 类型uint64_t, 所以定时时间要在584942年以内??????

例子:

#include <Arduino.h>#include <esp_sleep.h>RTC_DATA_ATTR int bootCount = 0;void setup(){
  Serial.begin(115200);
  Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);
  delay(5000);
  esp_sleep_enable_timer_wakeup(20000000);
  Serial.println(esp_sleep_get_wakeup_cause());}void loop(){
  Serial.println("ESP32 will sleep now!");
  delay(100);
  esp_deep_sleep_start();}

六. 进入休眠后被RTC_GPIO唤醒 (引脚唤醒方式一)

首先,并不是每个GPIO都是RTC_GPIO, 详见下表

注意: 我们填写的GPIO引脚号是真正的引脚号 不是其RTC_GPIO编号

  esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);
#include <Arduino.h>#include <esp_sleep.h>RTC_DATA_ATTR int bootCount = 0;void setup(){
  Serial.begin(115200);
  Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);
  Serial.printf("the wakeup reason is :%d\r\n", esp_sleep_get_wakeup_cause());}void loop(){
  delay(3000);
  Serial.println("ESP32 will sleep now!");
  delay(100);
  esp_deep_sleep_start();}

七. 进入休眠后被RTC_CNTL唤醒 (引脚唤醒方式二)

思考一个问题, 如果我们有8个GPIO引脚想唤醒ESP32, 难道要用上一节的方法操作8遍吗?

当然不是, 我们可以直接操作引脚集合, (我们用一个mask片选想操作的引脚,然后这些引脚都具有了唤醒ESP32的能力)

我们可以设置这些引脚是 每个都能触发(每个葫芦娃都能自己去救爷爷), 还是一起共同发力才能触发(集齐七龙珠??)

esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);

参数:

  • mask :

如: 我们想让 32 33 35 39触发, 这样计算mask

注意: 我们不要使用 37 38

  • mode: 触发方式 可选:
    • ESP_EXT1_WAKEUP_ALL_LOW : 全都置低时触发唤醒
    • ESP_EXT1_WAKEUP_ANY_HIGH : 任意置高时触发唤醒

八. 进入休眠后被触摸按键唤醒

值得注意的是,

  • 触摸按键唤醒所需deepsleep电流要大于 按键和定时器
  • 必须写触摸回调函数, 否则无用
#include <Arduino.h>#include <esp_sleep.h>RTC_DATA_ATTR int bootCount = 0;RTC_DATA_ATTR int BTN_Pin_BITMASK = 0;void callbackPin2(){
  Serial.println("T2 weak ESP32 up");}void setup(){
  Serial.begin(115200);
  Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);
  esp_sleep_enable_touchpad_wakeup();
  Serial.printf("the wakeup reason is :%d\r\n", esp_sleep_get_wakeup_cause());
  touchAttachInterrupt(2,callbackPin2,40);}void loop(){
  delay(3000);
  Serial.println("ESP32 will sleep now!");
  delay(100);
  esp_deep_sleep_start();}

九. 被ULP唤醒

这个要做一个专门的ULP专题




电池电量与功耗

一个3000mAH,额定电压5V的电池给一个功耗2.5W,电压5V的用电设备供电,它理论的使用时长为:

I=P/U=>2.5w/5v=>0.5A=>500MA

3000mAh,就是3000MA电流可以放电一小时,

3000/500=6小时

如何让Arduino用2颗5号电池运行1年以上--Arduino低功耗


LD工作室(mylife1213) · 2016-01-11 18:11

如何让Arduino用2颗5号电池运行1年以上--Arduino低功耗

本文转自极客工坊:

如果你想把arduino avr类的开发项目用来便携式设置上,不管商业还是个人DIY,那么你头一个要对付的问题就是设备功耗!

我测试atmega328p(大部分arduino 都是基于这个处理器) 最小系统下(16Mhz)运行功耗是10ma,那么如果不对处理器进行任何节电处理的话一块手机1500mah的电池只能不间断运行 1500/10/24=6.5天 ,这个还是在没有任何外围元器件的情况下的运行时间! 

现在物联网非常火,那么物联网正常情况是需要多个节点进行数据采集,然后上报给主机进行联网操作,或者接收主机命令进行对其他电器的操作. 那个问题就出现了,很多时候数据采集的地方是没有电源的,比如外置气象数据采集,这个时候就需要采集设备可以使用电池来驱动,而且不能频繁的更换电池!这就需要用到处理器的节电方案!

下面我将介绍ATMEGA328P的节电解决方案.

328P有8种节电设置,分别是:

 

空闲模式

当SM2..0 为000 时, SLEEP 指令将使MCU 进入空闲模式。在此模式下,CPU 停止运行,而SPI、USART、模拟比较器、ADC、两线串行接口、定时器/ 计数器、看门狗和中断系统继续工作。这个睡眠模式只停止了clkCPU 和clkFLASH,其他时钟则继续工作。象定时器溢出与USART 传输完成等内外部中断都可以唤醒MCU。如果不需要从模拟比较器中断唤醒MCU,为了减少功耗,可以切断比较器的电源。方法是置位模拟比较器控

制和状态寄存器ACSR 的ACD。如果ADC 使能,进入此模式后将自动启动一次转换。

 

ADC 噪声抑制模式

当SM2..0 为001 时, SLEEP 指令将使MCU 进入噪声抑制模式。在此模式下,CPU 停止运行,而ADC、外部中断、两线接口地址配置、定时器/ 计数器2 和看门狗继续工作。这个睡眠模式只停止了clkI/O、clkCPU 和clkFLASH,其他时钟则继续工作。此模式提高了ADC 的噪声环境,使得转换精度更高。ADC 使能的时候,进入此模式将自动启动一次AD 转换。ADC 转换结束中断、外部复位、看门狗复位、BOD 复位、两线接口地址匹配中断、定时器/ 计数器2 中断、SPM/EEPROM 准备好中断、外部电平中断INT0 或INT1,或外部中断INT2 可以将MCU 从ADC 噪声抑制模式唤醒。

 

掉电模式

当SM2..0 为010 时, SLEEP 指令将使MCU 进入掉电模式。在此模式下,外部晶体停振,而外部中断、两线接口地址匹配及看门狗(如果使能的话)继续工作。只有外部复

位、看门狗复位、BOD 复位、两线接口地址匹配中断、外部电平中断INT0 或INT1,或

外部中断INT2 可以使MCU 脱离掉电模式。这个睡眠模式停止了所有的时钟,只有异步

模块可以继续工作。

 

省电模式

当SM2..0 为011 时, SLEEP 指令将使MCU 进入省电模式。这一模式与掉电模式只有一点不同:

如果定时器/ 计数器2 为异步驱动,即寄存器ASSR 的AS2 置位,则定时器/ 计数器2 在睡眠时继续运行。除了掉电模式的唤醒方式,定时器/ 计数器2 的溢出中断和比较匹配中断也可以将MCU 从休眠方式唤醒,只要TIMSK 使能了这些中断,而且SREG 的全局中

断使能位I 置位。如果异步定时器不是异步驱动的,建议使用掉电模式,而不是省电模式。因为在省电模式下,若AS2 为0,则MCU 唤醒后异步定时器的寄存器数值是没有定义的。这个睡眠模式停止了除clkASY 以外所有的时钟,只有异步模块可以继续工作。

 

Standby 模式

当SM2..0 为110 时, SLEEP 指令将使MCU 进入Standby 模式。这一模式与掉电模式唯一的不同之处在于振荡器继续工作。其唤醒时间只需要6 个时钟周期。

 

扩展Standby 模式

当SM2..0 为111 时, SLEEP 指令将使MCU 进入扩展的Standby 模式。这一模式与省掉电模式唯一的不同之处在于振荡器继续工作。其唤醒时间只需要6 个时钟周期。

 

下图是各个模式下关闭的模块

 

 

那么我们正常使用的是掉电模式,在掉电模式下328p测试耗电1ua,这是什么概念,2颗5号电池在处理器没有进行其他操作的情况下可以工作79年!

当然了,我们不可能让处理器就这样一直待机不做其他事情,我们需要定期唤醒328P,让他处理事情,比如采集温湿度,PM2.5数据发送给主机.那么如何唤醒呢? 答案是在掉电模式下你只能通过外部中断和看门狗来唤醒328P,外部中断唤醒需要外围电路,我们优先选择WDT看门狗进行唤醒.这里的看门狗不是你们知道的只有重启328P的功能!他也可以配置成中断事件! "ISR(WDT_vect) "中断函数,通过看门狗我们就可以在不添加外围元件的情况设置唤醒时间了!

 

下面看实例:

 

#include <avr/sleep.h>

#include <avr/wdt.h>

 

volatile byte data=0;

 

void setup() {

  pinMode(13,OUTPUT);

  setup_watchdog(9);

// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms

// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec

  ACSR |=_BV(ACD);//OFF ACD

  ADCSRA=0;//OFF ADC

  Sleep_avr();//Sleep_Mode

}

 

void loop() {

 

if(data>=7){

  data=0;

//-------------------------------

   digitalWrite(13,HIGH);

  delay(100);                      //此处是到达设置唤醒时间允许的程序

  digitalWrite(13,LOW);

//--------------------------------    

Sleep_avr();

}

else {

  Sleep_avr();  //Continue Sleep

}

 

}

 

//Sleep mode is activated

void setup_watchdog(int ii) {

 

  byte bb;

 

  if (ii > 9 ) ii=9;

  bb=ii & 7;

  if (ii > 7) bb|= (1<<5);

  bb|= (1<<WDCE);

  MCUSR &= ~(1<<WDRF);

  // start timed sequence

  WDTCSR |= (1<<WDCE) | (1<<WDE);

  // set new watchdog timeout value

  WDTCSR = bb;

  WDTCSR |= _BV(WDIE);

}

//WDT interrupt

ISR(WDT_vect) {

  ++data;

// wdt_reset();

}

void Sleep_avr(){

  set_sleep_mode(SLEEP_MODE_PWR_DOWN  ); // sleep mode is set here

  sleep_enable();

  sleep_mode();                        // System sleeps here

}

这是一个配置成56秒唤醒一次对5号端口设置高电平100ms的程序,其中if(data>=7)是data(看门狗)超时大于7次就唤醒CPU进行高电平100ms的函数,看门狗超时时间已设置成8秒,你可以调节if(data>=7)设置成你想要的唤醒时间!

通过这样的节电设置以后这个程序可以运行至少几年!

要改变唤醒时间是改这个函数:

if(data>=7) 

函数里面7的意思是有7次看门狗8秒超时复位.比如你要设置24秒那就写if(data>=3)

公式是:3*8=24

如果喜欢观看类似科技新奇事物,以及了解创客圈最新资讯,或者您对Arduino有所耳闻,可以关注我们微信公众号,一定会带给您最新的资讯,最实用的教程,以及创客最新的玩意。





























上一篇:开发相关软件使用

下一篇:开源库收集

Top