高精度簡易電子稱第二步——低功耗測試


雖然這個稱做出來的樣子不是便攜式,外觀有些簡陋(自己用木頭架子搭起來的),但是對於使用兩節3.7V的18650的鋰電池供電來說,還是需要設計一下低功耗的。

稱的使用頻率不高,不能讓觸摸屏一直亮着,也不能讓單片機一直處於工作狀態,那樣也太不節能、太不綠色了。

 

一、STM32低功耗設計

查閱stm32參考手冊,可以看到低功耗有以下三種:

 

我想要的效果是在稱上沒有放任何東西的時候,如果持續30秒沒有放置,立即進入低功耗模式,但是SRAM和寄存器中的數據不要丟失,在這個基礎上,功耗盡量小就可以了

對比上面的模式說明,我需要進入的是停止模式。

停止模式是在Cortex™-M3的深睡眠模式基礎上結合了外設的時鍾控制機制,在停止模式下電壓
調節器可運行在正常或低功耗模式。此時在1.8V供電區域的的所有時鍾都被停止, PLLHSI
HSE RC振盪器的功能被禁止, SRAM和寄存器內容被保留下來。

關鍵的一點是在停止模式下,所有的I/O引腳都保持它們在運行模式時的狀態。 

 確定了進入的是停止模式,那么如何才能進入停止模式呢?

 

其實這么多操作,ST全都給我們封裝在了一個庫函數中:void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)

具體內容是:

void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
{
  uint32_t tmpreg = 0;
  /* Check the parameters */
  assert_param(IS_PWR_REGULATOR(PWR_Regulator));
  assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));
  
  /* Select the regulator state in STOP mode ---------------------------------*/
  tmpreg = PWR->CR;
  /* Clear PDDS and LPDS bits */
  tmpreg &= CR_DS_MASK;
  /* Set LPDS bit according to PWR_Regulator value */
  tmpreg |= PWR_Regulator;
  /* Store the new value */
  PWR->CR = tmpreg;
  /* Set SLEEPDEEP bit of Cortex System Control Register */
  SCB->SCR |= SCB_SCR_SLEEPDEEP;
  
  /* Select STOP mode entry --------------------------------------------------*/
  if(PWR_STOPEntry == PWR_STOPEntry_WFI)
  {   
    /* Request Wait For Interrupt */
    __WFI();
  }
  else
  {
    /* Request Wait For Event */
    __WFE();
  }
  
  /* Reset SLEEPDEEP bit of Cortex System Control Register */
  SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);  
}

我們只需要在需要低功耗的時候,調用這個函數就行了。

但是我們要選擇自己需要喚醒時的方式——中斷WFI(wait for interrupt)  or  事件WFE(wait for event)

這兩個有點繞:事件是中斷的觸發源,開放了對應的中斷屏蔽位,則事件可以觸發相應的中斷。在STM32中,中斷與事件不是等價的,一個中斷肯定對應一個事件,但一個事件不一定對應一個中斷。

比如我想要使用外部按鍵喚醒停止中的STM32,那么需要把按鍵引腳映射在了外部中斷線上,然后對應的上面配置成中斷喚醒方式:

PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);

在按鍵的中斷函數中配置退出低功耗時的操作即可。

void EXTI15_10_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line15) != RESET) //確保是否產生了EXTI Line中斷
    {
        Restart_From_Low_Power();                                            //停機喚醒后需要啟動HSE    

        EXTI_ClearITPendingBit(EXTI_Line15);     //清除中斷標志位
    }
}

關於退出時的操作,參考手冊上說:

HSI時鍾是板子上的8M晶振提供的,而我們使用的是72M的時鍾,所以還需要重新配置一下時鍾:

    //啟動並配置stm32
    ErrorStatus HSEStartUpStatus;
   //使能 HSE
   RCC_HSEConfig(RCC_HSE_ON);

   //等待 HSE 准備就緒
   HSEStartUpStatus = RCC_WaitForHSEStartUp();

   if(HSEStartUpStatus == SUCCESS)
   {
         //使能 PLL
         RCC_PLLCmd(ENABLE);

         //等待 PLL 准備就緒
         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
         {
         }

         //選擇PLL作為系統時鍾源 
         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

         //等待PLL被選擇為系統時鍾源
         while(RCC_GetSYSCLKSource() != 0x08)
         {
         }
   }

 

二、觸摸屏低功耗設計

 使用的是HMI串口屏,一個指令即刻讓屏幕進入sleep模式

//HMI息屏
void HMI_Sleep_Mode(void)
{
    sprintf(buf,"sleep=1");
    HMI_Send_String(buf);
    Delay_ms(20);
}

 

三、CS1237低功耗設計

 還是查看芯片手冊:

void CS1237_power_down(void)
{
    SCLK_1;
    CS1237_delay_us(100);
    SCLK_1;
    CS1237_delay_us(100);
}

//cs1237重新喚醒,SCLK回到低電平並保持10us
void CS1237_restart(void)
{
    SCLK_0;
    CS1237_delay_us(20);
}

 

四、進入低功耗的判斷

一開始考慮使用定時器定時對比讀出的重量數據,如果數據在30s內沒有變化並且一直小於1g,則進入低功耗模式,但是又怕定時器的中斷正好發生在CS1237的讀寫過程中,

這樣會打斷時序,造成讀數誤差

我看了一下我程序主循環循環一次的用時,大概在0.2s左右,其實這個也能當做一個基准,因為每次循環的時間都是差不多的。

那么我可以每循環一次就進行一次數據對比,每滿足上面的情況就+1,當循環計數150次的時候,進入低功耗。否則清零計數。

這樣每次進入低功耗的時間其實都是相差無幾,而且節省了一個定時器。運用循環體本身的時間作為計時標志。

        //下面是關於進入低功耗的判斷
        // 仿真發現在沒有收到觸摸屏的按下時,循環一次的時間大致為4s,這樣省去了一個定時器,避免了中斷
        low_power_weight_1 = now_weight;
        if((low_power_weight_1 < 1) && ((low_power_weight_1-low_power_weight_2 < 1) || (low_power_weight_2-low_power_weight_1 < 1)))
        {
            low_power_num++;
        }
        else
        {
            low_power_num = 0;
            low_power_weight_2 = low_power_weight_1;
        }
        
        //重量低於1g並且在40秒內沒有變化,即開始進入低功耗
        if(low_power_num >= 80)
        {
            //計數清零,准備下一次的計數
            low_power_num = 0;
            //蜂鳴器首先響用來提示
            Beep_Warning_Slowly(3);        
            //進入低功耗
            Low_Power_Mode();
        }

 

參考資料:

https://www.cnblogs.com/yangguang-it/p/7441756.html

https://www.jianshu.com/p/540fff36fcc0

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM