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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

關于STC8G1K08單片機掉電保存問題。

[復制鏈接]
跳轉到指定樓層
樓主
ID:293079 發(fā)表于 2025-2-28 09:42 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
各位大神幫看一下程序,謝謝。
以下程序功能是實現單獨按鍵控制兩個LED燈,短按切換色溫,長按調節(jié)亮度。掉電保存功能(保存掉電前色溫及亮度)。
可是現在無法實現掉電保存功能。
  1. #include "STC8G.H"
  2. #include <intrins.h>

  3. #define u8  unsigned char
  4. #define u16 unsigned int

  5. // 硬件定義
  6. sbit KEY         = P5^4;    // 按鍵引腳
  7. sbit WHITE_LED   = P3^2;    // 白燈控制引腳
  8. sbit YELLOW_LED  = P3^3;    // 黃燈控制引腳

  9. // EEPROM地址定義
  10. #define EEPROM_BASE 0x0000  // EEPROM基地址

  11. // 全局變量
  12. u8 mode = 0;                // 工作模式(0/1/2)
  13. u8 white_duty = 100;        // 白燈亮度(0 - 100)
  14. u8 yellow_duty = 100;       // 黃燈亮度(0 - 100)
  15. u8 dual_duty = 50;          // 雙燈模式亮度(0 - 100)
  16. u8 pwm_counter = 0;         // PWM計數器

  17. // 按鍵狀態(tài)變量
  18. u16 key_press_time = 0;     // 按鍵計時
  19. bit key_long_flag = 0;      // 長按標志
  20. u16 brightness_update_counter = 0; // 亮度更新計數器
  21. bit brightness_direction = 1; // 亮度調節(jié)方向,1 為增加,0 為減少


  22. u8 EEPROM_Read(u16 addr) {
  23.     u8 readData;
  24.                 EA = 0;  // 關閉中斷
  25.     IAP_CONTR = 0x80;       // 使能IAP
  26.     IAP_CMD = 1;            // 讀命令
  27.     IAP_ADDRH = (u8)(addr >> 8);
  28.     IAP_ADDRL = (u8)addr;
  29.     IAP_TRIG = 0x5A;
  30.     IAP_TRIG = 0xA5;
  31.     readData = IAP_DATA;
  32.     IAP_CONTR = 0;          // 關閉IAP
  33.     EA = 1;  // 恢復中斷
  34.     return readData;
  35. }

  36. void EEPROM_Write(u16 addr, u8 dat) {
  37.     EA = 0;  // 關閉中斷
  38.     IAP_CONTR = 0x80;       // 使能IAP
  39.     IAP_CMD = 2;            // 寫命令
  40.     IAP_ADDRH = (u8)(addr >> 8);
  41.     IAP_ADDRL = (u8)addr;
  42.     IAP_DATA = dat;
  43.     IAP_TRIG = 0x5A;
  44.     IAP_TRIG = 0xA5;
  45.     IAP_CONTR = 0;          // 關閉IAP
  46.     _nop_();
  47.     EA = 1;  // 恢復中斷
  48. }

  49. void EEPROM_Save()
  50. {
  51.     EEPROM_Write(EEPROM_BASE + 0, mode);
  52.     EEPROM_Write(EEPROM_BASE + 1, white_duty);
  53.     EEPROM_Write(EEPROM_BASE + 2, yellow_duty);
  54.     EEPROM_Write(EEPROM_BASE + 3, dual_duty);
  55. }

  56. void EEPROM_Load() {
  57.     u8 temp;
  58.     if ((temp = EEPROM_Read(EEPROM_BASE + 0)) != 0xFF)
  59.                 {
  60.         mode = temp;
  61.     }
  62.     if ((temp = EEPROM_Read(EEPROM_BASE + 1)) != 0xFF)
  63.                 {
  64.         white_duty = temp;
  65.     }
  66.     if ((temp = EEPROM_Read(EEPROM_BASE + 2)) != 0xFF)
  67.                 {
  68.         yellow_duty = temp;
  69.     }
  70.     if ((temp = EEPROM_Read(EEPROM_BASE + 3)) != 0xFF)
  71.                 {
  72.         dual_duty = temp;
  73.     }
  74. }

  75. // 定時器0初始化
  76. void Timer0_Init() {
  77.     AUXR |= 0x80;           // 1T模式
  78.     TMOD &= 0xF0;           // 定時器0模式0
  79.     TL0 = 0x30;             // 25us@24MHz
  80.     TH0 = 0xF3;            
  81.     ET0 = 1;                // 使能中斷
  82.     TR0 = 1;                // 啟動定時器
  83.     EA = 1;                 // 總中斷
  84. }

  85. // PWM輸出控制
  86. void PWM_Update() {
  87.     static u8 pwm_tick = 0;

  88.     if (++pwm_counter >= 20) {           // 0.5ms周期,提高PWM頻率
  89.         pwm_counter = 0;
  90.         pwm_tick = (pwm_tick + 1) % 100;

  91.         switch (mode) {
  92.             case 0:                     // 白燈模式
  93.                 WHITE_LED = (pwm_tick < white_duty);
  94.                 YELLOW_LED = 0;
  95.                 break;
  96.             case 1:                     // 黃燈模式
  97.                 WHITE_LED = 0;
  98.                 YELLOW_LED = (pwm_tick < yellow_duty);
  99.                 break;
  100.             case 2:                     // 雙燈模式
  101.                 WHITE_LED = (pwm_tick < dual_duty);
  102.                 YELLOW_LED = (pwm_tick < dual_duty);
  103.                 break;
  104.         }
  105.     }
  106. }

  107. // 按鍵處理
  108. void Key_Process() {
  109.     if (KEY == 0) {                      // 按鍵按下
  110.         if (key_press_time < 1000) key_press_time++;

  111.         if (key_press_time > 300) {      // 長按判定(300ms)
  112.             key_long_flag = 1;
  113.             brightness_update_counter++;
  114.             // 10000ms / 100 = 100ms ,每100ms更新一次亮度
  115.             if (brightness_update_counter >= 10) {
  116.                 brightness_update_counter = 0;
  117.                 // 亮度調節(jié)
  118.                 switch (mode) {
  119.                     case 0:
  120.                         if (brightness_direction) {
  121.                             if (white_duty < 100) {
  122.                                 white_duty++;
  123.                             } else {
  124.                                 brightness_direction = 0;
  125.                                 white_duty--;
  126.                             }
  127.                         } else {
  128.                             if (white_duty > 0) {
  129.                                 white_duty--;
  130.                             } else {
  131.                                 brightness_direction = 1;
  132.                                 white_duty++;
  133.                             }
  134.                         }
  135.                         break;
  136.                     case 1:
  137.                         if (brightness_direction) {
  138.                             if (yellow_duty < 100) {
  139.                                 yellow_duty++;
  140.                             } else {
  141.                                 brightness_direction = 0;
  142.                                 yellow_duty--;
  143.                             }
  144.                         } else {
  145.                             if (yellow_duty > 0) {
  146.                                 yellow_duty--;
  147.                             } else {
  148.                                 brightness_direction = 1;
  149.                                 yellow_duty++;
  150.                             }
  151.                         }
  152.                         break;
  153.                     case 2:
  154.                         if (brightness_direction) {
  155.                             if (dual_duty < 100) {
  156.                                 dual_duty++;
  157.                             } else {
  158.                                 brightness_direction = 0;
  159.                                 dual_duty--;
  160.                             }
  161.                         } else {
  162.                             if (dual_duty > 0) {
  163.                                 dual_duty--;
  164.                             } else {
  165.                                 brightness_direction = 1;
  166.                                 dual_duty++;
  167.                             }
  168.                         }
  169.                         break;
  170.                 }
  171.                 // 亮度改變后保存數據
  172.                 EEPROM_Save();
  173.             }
  174.         }
  175.     } else {                            // 按鍵釋放
  176.         if (key_press_time > 0) {
  177.             if (!key_long_flag) {        // 短按切換模式
  178.                 u8 prev_mode = mode;
  179.                 mode = (mode + 1) % 3;
  180.                 // 保持前一種色溫的亮度
  181.                 switch (prev_mode) {
  182.                     case 0: // 前一個模式是白燈模式
  183.                         switch (mode) {
  184.                             case 1:
  185.                                 yellow_duty = white_duty;
  186.                                 break;
  187.                             case 2:
  188.                                 dual_duty = white_duty;
  189.                                 break;
  190.                         }
  191.                         break;
  192.                     case 1: // 前一個模式是黃燈模式
  193.                         switch (mode) {
  194.                             case 0:
  195.                                 white_duty = yellow_duty;
  196.                                 break;
  197.                             case 2:
  198.                                 dual_duty = yellow_duty;
  199.                                 break;
  200.                         }
  201.                         break;
  202.                     case 2: // 前一個模式是雙燈模式
  203.                         switch (mode) {
  204.                             case 0:
  205.                                 white_duty = dual_duty;
  206.                                 break;
  207.                             case 1:
  208.                                 yellow_duty = dual_duty;
  209.                                 break;
  210.                         }
  211.                         break;
  212.                 }

  213.                 // 短按切換模式時,保存模式和亮度
  214.                 EEPROM_Save();
  215.             } else {                    // 長按保存亮度
  216.                 EEPROM_Save();
  217.                 key_long_flag = 0;
  218.             }
  219.             key_press_time = 0;
  220.             brightness_update_counter = 0;
  221.         }
  222.     }
  223. }

  224. // 主函數
  225. void main() {
  226.     P3M0 = 0x00;                       
  227.     P3M1 = 0x00;
  228.     P5M0 = 0x00;                       
  229.     P5M1 = 0x00;

  230.     EEPROM_Load();                      // 加載存儲數據
  231.     Timer0_Init();                      // 初始化定時器

  232.     while (1) {
  233.         PWM_Update();                   // 更新PWM輸出
  234.     }
  235. }

  236. // 定時器0中斷服務函數
  237. void timer0_isr() interrupt 1 {
  238.     static u8 key_scan_cnt = 0;

  239.     if (++key_scan_cnt >= 10) {         // 10ms按鍵掃描
  240.         key_scan_cnt = 0;
  241.         Key_Process();
  242.     }
  243. }
復制代碼


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

沙發(fā)
ID:161164 發(fā)表于 2025-2-28 11:36 | 只看該作者
掉電保存要用比較器配合硬件電路的
你有嗎?
回復

使用道具 舉報

板凳
ID:744809 發(fā)表于 2025-2-28 15:58 | 只看該作者
1、保存之前需要進行擦除
2、stc下載的時候,有些型號需要設置eeprom大小
回復

使用道具 舉報

地板
ID:140489 發(fā)表于 2025-2-28 16:28 | 只看該作者
eeprom部分按STC的例程寫吧

  1. void IapIdle()
  2. {
  3.     IAP_CONTR = 0;                              //關閉IAP功能
  4.     IAP_CMD = 0;                                //清除命令寄存器
  5.     IAP_TRIG = 0;                               //清除觸發(fā)寄存器
  6.     IAP_ADDRH = 0x80;                           //將地址設置到非IAP區(qū)域
  7.     IAP_ADDRL = 0;
  8. }

  9. char IapRead(int addr)
  10. {
  11.     char dat;

  12.     IAP_CONTR = 0x80;                           //使能IAP
  13.     IAP_TPS = 12;                               //設置等待參數12MHz
  14.     IAP_CMD = 1;                                //設置IAP讀命令
  15.     IAP_ADDRL = addr;                           //設置IAP低地址
  16.     IAP_ADDRH = addr >> 8;                      //設置IAP高地址
  17.     IAP_TRIG = 0x5a;                            //寫觸發(fā)命令(0x5a)
  18.     IAP_TRIG = 0xa5;                            //寫觸發(fā)命令(0xa5)
  19.     _nop_();
  20.     dat = IAP_DATA;                             //讀IAP數據
  21.     IapIdle();                                  //關閉IAP功能

  22.     return dat;
  23. }

  24. void IapProgram(int addr, char dat)
  25. {
  26.     IAP_CONTR = 0x80;                           //使能IAP
  27.     IAP_TPS = 12;                               //設置等待參數12MHz
  28.     IAP_CMD = 2;                                //設置IAP寫命令
  29.     IAP_ADDRL = addr;                           //設置IAP低地址
  30.     IAP_ADDRH = addr >> 8;                      //設置IAP高地址
  31.     IAP_DATA = dat;                             //寫IAP數據
  32.     IAP_TRIG = 0x5a;                            //寫觸發(fā)命令(0x5a)
  33.     IAP_TRIG = 0xa5;                            //寫觸發(fā)命令(0xa5)
  34.     _nop_();
  35.     IapIdle();                                  //關閉IAP功能
  36. }

  37. void IapErase(int addr)
  38. {
  39.     IAP_CONTR = 0x80;                           //使能IAP
  40.     IAP_TPS = 12;                               //設置等待參數12MHz
  41.     IAP_CMD = 3;                                //設置IAP擦除命令
  42.     IAP_ADDRL = addr;                           //設置IAP低地址
  43.     IAP_ADDRH = addr >> 8;                      //設置IAP高地址
  44.     IAP_TRIG = 0x5a;                            //寫觸發(fā)命令(0x5a)
  45.     IAP_TRIG = 0xa5;                            //寫觸發(fā)命令(0xa5)
  46.     _nop_();                                    //
  47.     IapIdle();                                  //關閉IAP功能
  48. }
復制代碼
回復

使用道具 舉報

5#
ID:235691 發(fā)表于 2025-2-28 16:54 | 只看該作者
STC8G單片機的片上EEPROM程序 - 51單片機  http://www.zg4o1577.cn/bbs/dpj-203901-1.html
回復

使用道具 舉報

6#
ID:57657 發(fā)表于 2025-2-28 22:18 | 只看該作者
掉電保存實際上是低壓保存,有一個LVD低電壓中斷或ADC獲取單片機電壓的比較器中斷,低于電壓視為掉電,需要并聯個大電容。
回復

使用道具 舉報

7#
ID:1133081 發(fā)表于 2025-3-1 08:14 | 只看該作者
初略的看了下樓主的代碼。使用的并不是掉電保存EEPROM模式,但確實也無需使用掉電保存EEPROM模式,使用常規(guī)的EEPROM保存方式即可。樓主采用單健長短按操作,可以采用只要是進入設置模式就開始計時,每次按動鍵計時變量清0,當停止按動達若干時間(通常5~10秒)表示設置結束,即自動將設置的參數保存在EEPROM并退出設置模式。
回復

使用道具 舉報

8#
ID:230500 發(fā)表于 2025-3-1 09:15 | 只看該作者
由于單片機內部的EEPROM有擦寫壽命; 所以不能時時刻刻都在不停的保存數據;其次掉電保存需要額外的外圍硬件電路做配合;一般最簡單的電路就是單片機的供電 與外部供電用二極管隔離;同時加大單片機電源的濾波電容容量 用于掉電后延長單片機的續(xù)航 用來保存數據;再額外用一個IO口配合三極管 來檢測電源是否掉電 ;  一旦檢測到掉電 單片機就執(zhí)行數據保存;

總結下來有三種方案; 第一種是做外部掉電檢測;通過檢測掉電后保存數據
第二種是 通過你的按鍵做數據保存; 如果操作了按鍵, 同時新舊數據有不一樣,說明有命令修改;操作完按鍵后, 把新數據刷新保存到EEPROM
第三種,使用FRAM鐵電存儲器; 幾乎可以無限制的擦寫壽命;
回復

使用道具 舉報

9#
ID:230500 發(fā)表于 2025-3-1 09:23 | 只看該作者
另外;你的程序有問題; 你仔細看下STC的例程; 單片機自帶的EEPROM,寫數據之前需要先整個扇區(qū)擦除后才能寫; 下面這一段是你的程序沒有做擦除處理; 直接就開始寫數據了;
void EEPROM_Save()
{
    EEPROM_Write(EEPROM_BASE + 0, mode);
    EEPROM_Write(EEPROM_BASE + 1, white_duty);
    EEPROM_Write(EEPROM_BASE + 2, yellow_duty);
    EEPROM_Write(EEPROM_BASE + 3, dual_duty);
}
回復

使用道具 舉報

10#
ID:195666 發(fā)表于 2025-3-1 14:11 | 只看該作者
1、先判斷能不能存儲成功;
2、判斷掉電檢測是否成功;
3、將這2個功能聯調成功。
回復

使用道具 舉報

11#
ID:293079 發(fā)表于 2025-3-1 14:24 | 只看該作者
lkc8210 發(fā)表于 2025-2-28 11:36
掉電保存要用比較器配合硬件電路的
你有嗎?

謝謝您建議。已經解決啦。這部分是沒有的。發(fā)現可以不需要。
回復

使用道具 舉報

12#
ID:293079 發(fā)表于 2025-3-1 14:24 | 只看該作者
123156fsadf 發(fā)表于 2025-2-28 15:58
1、保存之前需要進行擦除
2、stc下載的時候,有些型號需要設置eeprom大小

謝謝建議,已經解決啦。
回復

使用道具 舉報

13#
ID:293079 發(fā)表于 2025-3-1 14:25 | 只看該作者
lids 發(fā)表于 2025-2-28 16:28
eeprom部分按STC的例程寫吧

謝謝建議,已經解決啦。
回復

使用道具 舉報

14#
ID:293079 發(fā)表于 2025-3-1 14:25 | 只看該作者
a399288395 發(fā)表于 2025-3-1 09:15
由于單片機內部的EEPROM有擦寫壽命; 所以不能時時刻刻都在不停的保存數據;其次掉電保存需要額外的外圍硬 ...

謝謝建議,已經解決啦。
回復

使用道具 舉報

15#
ID:293079 發(fā)表于 2025-3-1 14:25 | 只看該作者
a399288395 發(fā)表于 2025-3-1 09:23
另外;你的程序有問題; 你仔細看下STC的例程; 單片機自帶的EEPROM,寫數據之前需要先整個扇區(qū)擦除后才能 ...

謝謝建議,已經解決啦。
回復

使用道具 舉報

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

本版積分規(guī)則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 在线观看av网站永久 | 国产中文字幕在线 | 999精彩视频 | 色综合色综合色综合 | 亚洲天堂精品久久 | 欧美精品福利 | 亚洲成人免费电影 | 亚洲日本一区二区三区四区 | 久久精品69 | 国产在线精品一区二区 | 国产精品久久二区 | 精品九九九 | 精品国产精品三级精品av网址 | 福利精品 | 一级黄色影片在线观看 | 日韩国产在线 | 日韩欧美在线视频 | 91国内精品 | 成人永久免费视频 | 亚洲国产精品久久久久秋霞不卡 | 在线看片网站 | 九九免费在线视频 | 91精品国产自产在线老师啪 | 本地毛片 | 欧美午夜精品 | 观看av| 欧美激情精品久久久久久 | 欧美一区二区三区精品免费 | 久草视频观看 | 精品视频在线一区 | 97超碰人人草 | 国产成都精品91一区二区三 | 龙珠z在线观看 | 在线资源视频 | www.99热.com| 97精品超碰一区二区三区 | 欧美极品视频在线观看 | 自拍偷拍亚洲一区 | 免费毛片www com cn | 日本亚洲欧美 | 亚洲精品综合 |