久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 489|回復: 15
打印 上一主題 下一主題
收起左側

SRAM中的變量,進入掉電真的不變?

  [復制鏈接]
跳轉到指定樓層
樓主
ID:1155837 發表于 2025-7-4 21:17 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
最近學完C語言,在做手持風扇主板,我使用了一個數組和一個計數器讀取預設好的檔位值,然后賦值給CCAP寄存器,實現改變占空比。
const unsigned char ccapvalues[] = {0x38, 0x33, 0x2E, 0x25, 0x20, 0x16, 0x10, 0x00};
unsigned char ccapcounter;

我讀手冊時,看到一句話:時鐘停振模式下,CPU 和全部的外設均停止工作,但 SRAM 和 XRAM 中的數據是一直維持不變的。
看到這句話之后,我想既然如此,那我這個計數器的值就不需要保存到eeprom了,畢竟我是軟關機,單片機不會完全掉電。
然而當我寫完代碼之后,實際測試發現,CCAP計數器在從睡眠恢復之后,無論怎么設置都恢復到0。
即使是嘗試將該UCHAR用idata和_at_命令固定在ram中的某個位置,它也會恢復到0。
這似乎不對?不是說進入掉電模式SRAM中的數據不會變嗎?由于怎么改代碼都得不到正確的結果,我索性就去嘗試eeprom讀寫了
在看過手冊之后,寫了一段EEPROM的讀寫函數,我按照原來的思路,把eeprom讀取函數放在了SLEEP函數中,喚醒后執行的地方。
void SLEEP(void){
//其他代碼
EEPROM_WRITE(ccapcounter);//把計數器的值寫入
PCON = 0X02;
/////////////////喚醒后從這里執行/////////////////
//其他代碼
EEPROM_READ();//讀取EEPROM,賦值給計數器
}
但是這么嘗試之后,依然無法觀察到從睡眠中喚醒計數器值不會被重置。
最后搞的我都開始懷疑我寫的代碼了,直接復制手冊里的代碼之后,發現還是不行,于是我就想著寫一段用于驗證eeprom讀寫功能的代碼
http://www.stcaimcu.com/thread-18923-1-1.html
不負我所望,在這個代碼中,成功驗證了我寫的EEPROM讀寫代碼是完全正確的,既然可以正確讀寫,那又為什么計數器值還是被歸零呢?我開始懷疑是不是代碼其他部分把計數器值重置了。
檢查之后也沒有發現有哪里會把計數器給重置。
但是我看著睡眠函數里面的讀取位置,我突然想到,我在主循環里再執行一遍讀取行不行?說做就做,我用了一個用于初始化計數器值的bit量。
bit initccapcounter = 0;
void main(){
//其他代碼
while(1){
        if(!initccapcounter){
        initccapcounter = 1;
        EEPROM_READ();

}
結果還真實現了喚醒后計數器不歸零的功能。
然后經過查證之后,發現是在執行完SLEEP函數之后,單片機會從復位向量地址重新執行程序,也就是變量可能在這里重新被初始化了!
也就是說,在我這個場景下,相當于是剛執行完EEPROM_READ,剛給計數器賦了值,然后你程序就把這個值清空了,所以才表現出了“沒有讀取成功的現象”!
但是我對這個問題也是一知半解,我不知道為什么我不不論是不給變量初值,還是用_at_把變量定位到IDATA,都沒用,不過既然EEPROM已經成功了,我就不在乎這些試過的方案了。
到此為止,總算是解決了變量會被歸零的問題。
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:879809 發表于 2025-7-5 18:43 | 只看該作者
你需要修改startup.a51這個文件。
回復

使用道具 舉報

板凳
ID:1137639 發表于 2025-7-6 00:24 | 只看該作者
在手持風扇主板開發中,你遇到的計數器在睡眠模式恢復后歸零的問題,本質上是對單片機睡眠模式與程序執行機制理解偏差導致的。盡管數據手冊表明SRAM在時鐘停振模式下能維持數據,但程序從睡眠喚醒后并非從斷點繼續執行,而是會從復位向量地址重新啟動,這會導致全局變量和靜態變量按編譯設定的初始值重新初始化(如`ccapcounter`默認歸零),即便用`_at_`命令定位到IDATA也無法改變這一初始化邏輯,因為變量初始化是程序啟動階段的固有流程。  你最初嘗試將EEPROM讀寫放在`SLEEP`函數中,誤以為喚醒后能直接沿用寫入的值,但實際程序重啟后會先執行初始化代碼,此時EEPROM讀取的時機滯后于變量初始化,導致新值被初始值覆蓋。而將`EEPROM_READ()`放在主循環的條件判斷中(通過`initccapcounter`標記避免重復讀取),確保了程序重啟后首次進入主循環時立即用EEPROM數據覆蓋默認初始化值,從而實現了計數器狀態的保持,這是利用程序執行順序解決了初始化與數據恢復的時序沖突問題。  此案例揭示了單片機睡眠模式下的關鍵要點:睡眠喚醒本質是一次程序重啟,變量會按編譯規則重新初始化,SRAM數據維持特性僅適用于未被程序主動修改的場景。因此,涉及狀態保持的應用需在程序啟動流程中優先完成非易失性數據(如EEPROM)的讀取,以覆蓋默認初始化值,而非依賴SRAM的被動數據維持機制。這也驗證了嵌入式系統開發中“程序執行流程控制”與“硬件特性利用”需協同設計的重要性。
回復

使用道具 舉報

地板
ID:384109 發表于 2025-7-6 10:22 | 只看該作者
你這是什么單片機啊,休眠喚醒跟復位操作一個效果,那還要休眠干什么,直接斷電不就好了
回復

使用道具 舉報

5#
ID:604453 發表于 2025-7-6 13:32 | 只看該作者
進入休眠模式不變,掉電斷電會丟失的。
回復

使用道具 舉報

6#
ID:1133081 發表于 2025-7-6 14:55 | 只看該作者
樓主說的問題根本不存在,是樓主沒有設置好PCON寄存器。這是用STC8H3K48S2在官方例程基礎上改寫的測試程序,喚醒后的num值就是休眠前的值。
  1. #include <STC8H.H>
  2. #include "intrins.h"

  3. #define IDL             0x01                    //PCON.0
  4. #define PD              0x02                    //PCON.1
  5. #define uint unsigned int
  6. #define uchar unsigned char

  7. uchar code table[]={
  8.         0x3f,0x06,0x5b,0x4f,
  9.         0x66,0x6d,0x7d,0x07,
  10.         0x7f,0x6f,0x77,0x7c,
  11.         0x39,0x5e,0x79,0x71};
  12. uchar data dis_buf[8];

  13. uchar i;
  14. uint j;
  15. uint num=9990;
  16. void Delay1ms(void)        //@11.0592MHz
  17. {
  18.         unsigned char data i, j;

  19.         i = 15;
  20.         j = 90;
  21.         do
  22.         {
  23.                 while (--j);
  24.         } while (--i);
  25. }


  26. void main()
  27. {
  28.         P0M0 = 0x00;
  29.         P0M1 = 0x00;
  30.         P1M0 = 0x00;
  31.         P1M1 = 0x00;
  32.         P2M0 = 0x00;
  33.         P2M1 = 0x00;
  34.         P3M0 = 0x00;
  35.         P3M1 = 0x00;
  36.         P4M0 = 0x00;
  37.         P4M1 = 0x00;
  38.         P5M0 = 0x00;
  39.         P5M1 = 0x00;
  40.        
  41.         EX0 = 1;                                    //使能INT0中斷,用于喚醒MCU
  42.         EA = 1;

  43.         while (1)
  44.         {
  45.                 dis_buf[0]=table[num/1000%10];
  46.                 dis_buf[1]=table[num/100%10];
  47.                 dis_buf[2]=table[num/10%10];
  48.                 dis_buf[3]=table[num%10];
  49.                 P0=0x00;
  50.                 P2&=0xf0;
  51.                 P2|=~(0x01<<i);
  52.                 P0=dis_buf[i];
  53.                 i=++i%4;
  54.                 if(++j>=1000)
  55.                 {
  56.                         j=0;
  57.                         if(++num>9999)num=0;
  58.                 }
  59.                 if(!P33)//key
  60.                 {
  61.                         P0=0xff;
  62.                         P2=0xff;
  63.                         _nop_();
  64.                         _nop_();
  65.                         _nop_();
  66.                         _nop_();
  67. //                        PCON = IDL;                                 //MCU進入IDLE模式
  68.                         PCON = PD;                                  //MCU進入掉電模式
  69.                         _nop_();
  70.                         _nop_();
  71.                         _nop_();
  72.                         _nop_();
  73.                 }
  74.                 Delay1ms();
  75.         }
  76. }

  77. void INT0_Isr() interrupt 0//P3.2
  78. {
  79. //    外部中斷喚醒                                 //測試端口
  80. }
復制代碼
回復

使用道具 舉報

7#
ID:1155837 發表于 2025-7-8 23:57 | 只看該作者
rundstedt 發表于 2025-7-5 18:43
你需要修改startup.a51這個文件。

改了,添加了一個清空ram區域的跳過程序,比如初始化到0x30就跳過到0x31繼續,把這個char值用_at_定在0x30,但沒成功
回復

使用道具 舉報

8#
ID:1155837 發表于 2025-7-9 00:14 | 只看該作者
WL0123 發表于 2025-7-6 14:55
樓主說的問題根本不存在,是樓主沒有設置好PCON寄存器。這是用STC8H3K48S2在官方例程基礎上改寫的測試程序 ...

你這里用到了一個uint num=9990,這樣初始化就是9990,和我的情況是不一樣的,我如果寫成uchar ccapcounter=7,那會不會從現在歸零的情況0變成7?我認為樓上的回復有道理,我應該修改start A51這個文件,防止喚醒后變量被重新初始化。
回復

使用道具 舉報

9#
ID:1155837 發表于 2025-7-9 00:16 | 只看該作者
lzuoxin 發表于 2025-7-6 13:32
進入休眠模式不變,掉電斷電會丟失的。

51掉電模式就是休眠模式,翻譯的問題,這個模式下cpu和片內外設都斷電,但ram不會斷電,可以保持數據。
回復

使用道具 舉報

10#
ID:1155837 發表于 2025-7-9 00:19 | 只看該作者
WL0123 發表于 2025-7-6 14:55
樓主說的問題根本不存在,是樓主沒有設置好PCON寄存器。這是用STC8H3K48S2在官方例程基礎上改寫的測試程序 ...

不過你這里先讓CPU進入IDLE,再進入PD的方案,我會試試的,我現在是直接進入PD
回復

使用道具 舉報

11#
ID:1133081 發表于 2025-7-9 10:27 | 只看該作者
千早愛音愛玩51 發表于 2025-7-9 00:14
你這里用到了一個uint num=9990,這樣初始化就是9990,和我的情況是不一樣的,我如果寫成uchar ccapcount ...

初始化num可以是4位任意數,設9990只不過是驗證一下溢出后歸0,與數據能不能保持毫無關聯。
回復

使用道具 舉報

12#
ID:1034262 發表于 2025-7-9 11:21 | 只看該作者
如果是STC的MCU,則進入掉電(睡眠)模式,只要電源正常供給,則內部所有的寄存器、內存數據都保持原樣,包括所有的IO設置和輸出都不改變。如果你發現改變了,則請檢查電源、程序。
回復

使用道具 舉報

13#
ID:879348 發表于 2025-7-9 11:46 | 只看該作者
你對單片機理解不夠深刻,51不存在這個問題,STM32有一種休眠模式才是重新運行
回復

使用道具 舉報

14#
ID:230500 發表于 2025-7-16 08:10 | 只看該作者
只是DIY玩還是準備商用, 商用 不需要單片機; 有專門的單芯片;可以做按鍵換擋和鋰電池充放電;成本比單片機低得多;  如果是DIY;像STC 51 單片機 有掉電模式和低功耗模式; 不管哪種模式,存儲器中的數據都不會丟失;保持掉電前的狀態。
回復

使用道具 舉報

15#
ID:401564 發表于 2025-7-16 12:39 | 只看該作者
1,SRAM在休眠后喚醒,在不掉電的情況下,它的值是不變的
2,我認為CCAP的值也是不變的,可能是你程序的問題
3,在這個應用中,沒有必要用到EEPROM,有種沒苦硬吃的感覺
4,14#已經說過了,如果是產品,用不到8051單片機的,有專門風扇芯片,如果是要更高級的功能,比如電量顯示,支持快充之類的,可以用一個OTP單片機,那玩意便宜
回復

使用道具 舉報

16#
ID:1156607 發表于 2025-7-19 18:57 | 只看該作者
只要芯片電源引腳有電,SRAM的值不會掉的
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 色激情网 | 一区二区三区在线观看视频 | 欧美精品www | av黄色片 | 国产乱淫av片免费 | 国产精品久久网 | 亚洲免费黄色 | 国产精品视频免费在线观看 | 清清草视频 | 闷骚老干部cao个爽 欧美区一区二 | 久久怡红院 | 成人9ⅰ免费影视网站 | 国产黄a三级三级三级看三级男男 | 欧美网站在线观看 | 国产综合亚洲精品一区二 | 日韩欧美中文字幕在线观看 | 国产中文在线观看 | 欧美精品黄色 | 老司机免费福利视频 | 成人激情视频在线观看 | 一级特黄妇女高潮 | 五月婷婷综合激情 | 欧美精品日韩 | 97精品在线 | 97精品视频在线观看 | 成人涩涩 | 久久久久久久影院 | 中文字幕丰满人伦在线 | 中文字幕一区二区三区视频 | 午夜黄色大片 | 青草av在线| 亚洲第一毛片 | 日本精品国产 | 在线观看二区 | a视频在线免费观看 | 99一区二区 | 中文字幕网址在线 | 亚洲免费婷婷 | 久操精品| 国产精品久久一区 | 欧美精品网 |