標(biāo)題: 有大神幫我改一下單片機代碼嗎? eeprom的按字節(jié)寫入 [打印本頁]

作者: vb2002    時間: 2024-10-22 20:15
標(biāo)題: 有大神幫我改一下單片機代碼嗎? eeprom的按字節(jié)寫入
首先定義一個sbit cap=P32;
P32 連接一個22uf電容,然后接地.,上電后 P32在 0.5秒后,充滿電應(yīng)該是屬于低電平,(P32=0)
在這0.5秒內(nèi),應(yīng)該屬于高電平(P32=1).
那我直接判斷 if(P32==1) 那就寫eeprom(按字節(jié)寫入), 如果P32==0 那就讀取上一次寫的eeprom

這不就實現(xiàn)我的需求了嗎?  按照這個邏輯,我自己寫了一個代碼 .但是老是有問題.

單片機源程序如下:
  1. #include "stc8g.h"
  2. #include "intrins.h"
  3. #include <stdio.h>

  4. #define MAIN_Fosc 11059200UL
  5. #define BRT         (65536 - MAIN_Fosc / 115200 / 4)

  6. typedef unsigned char u8;
  7. typedef unsigned int u16;

  8. u8 dat;                                                //定義eeprom 儲存數(shù)據(jù),但實際好像沒用上
  9. u16 EEPROMId = 0x0020;                                //定義eeprom的地址

  10. sbit cap = P3^2;                                        //p32引腳連電容,接地 做電平判定

  11. void sys_init();                                        //聲明系統(tǒng)初始化配置
  12. void PWM_init(void);                                //聲明pwm

  13. void main()
  14. {               
  15.         unsigned char x;                                 //定義變量x 用于讀取eeprom
  16.         unsigned char y=5;                        //定義變量y用于保存pwm值
  17.         sys_init();                                  //調(diào)用系統(tǒng)配置

  18.           P3M0 = 0x00; P3M1 = 0x00;                //P32 輸出對電容充電
  19.           P5M0 = 0x00; P5M1 = 0x00;                   //pwm 設(shè)置在p55口

  20.         x = IapRead(EEPROMId);                        //讀取的當(dāng)前eeprom 賦值給x        
  21.         
  22.           while(1)
  23.         {         
  24.                 if(cap)                                //如果p32引腳 充電中 p32==1
  25.                 {
  26.                 IapProgram(EEPROMId,y);                //寫地址為0x0020 為 y(以后設(shè)置為switch或者數(shù)組)

  27.                 EEPROMId=EEPROMId+1;                //下次寫eeprom +1  0x0021 ,在下次0x0022 以此類推
  28.                 y=y+1;                                //pwm亮度 數(shù)組+1   (1,15,55,255)
  29.          
  30.                 }
  31.                  CCAP2H=x;                                //把x寫入的值 賦值給pwm

  32.                 if(EEPROMId >= 0X1FE)                                //如果當(dāng)前字節(jié)到達EEPROM末尾,擦除扇區(qū)數(shù)據(jù)
  33.                  {        
  34.                           IapErase(0x0020);                                //擦除扇區(qū)
  35.                  
  36.                         EEPROMId = 0x0020;                        //從頭開始按字節(jié)寫入
  37.                  }
  38.         }
  39. }

  40. void sys_init(void)
  41. {
  42.         P_SW2=0x80;
  43.       PWM_init();
  44.         EA=1;                        //打開總中斷
  45. }


  46. //// 初始化PWM功能 P55 pwm
  47. void PWM_init(void)
  48. {
  49.     P_SW1=0x20;
  50.     CCON = 0x00;
  51.     CMOD = 0x08;
  52.     CL = 0x00;
  53.     CH = 0x00;

  54.     CCAPM2 = 0x42;
  55.     PCA_PWM2 = 0x00;
  56.     CCAP2L = 0x00;                  
  57.     CCAP2H = 0x00;
  58.     CR=1;        
  59. }

  60. void delayms(u16 ms)
  61. {
  62.         unsigned int i;
  63.         do{
  64.                 i = MAIN_Fosc /10000;
  65.                 while(--i);
  66.         }while(--ms);
  67. }

  68. void IapIdle()
  69. {
  70.         IAP_CONTR = 0;                                                 // 關(guān)閉 IAP 功能
  71.         IAP_CMD = 0;                                                         // 清除命令寄存器
  72.         IAP_TRIG = 0;                                                 // 清除觸發(fā)寄存器

  73.         IAP_ADDRH = 0x00;                                        // 清零高地址寄存器
  74.         IAP_ADDRL = 0x00;                                        // 清零低地址寄存器
  75. }

  76. char IapRead(unsigned int addr)
  77. {
  78.         
  79.         char dat;
  80.         IAP_CONTR = 0x80;                                 // 使能 IAP
  81.         IAP_TPS = 12;                                                 // 設(shè)置等待參數(shù) 12MHz
  82.         IAP_CMD = 1;                                                         // 設(shè)置 IAP 讀命令
  83.         IAP_ADDRL = addr;                                 // 設(shè)置 IAP 低地址
  84.         IAP_ADDRH = addr >> 8;                 // 設(shè)置 IAP 高地址
  85.         EA=0;
  86.         _nop_();
  87.         _nop_();        
  88.         IAP_TRIG = 0x5a;                                         // 寫觸發(fā)命令 (0x5a)
  89.         IAP_TRIG = 0xa5;                                         // 寫觸發(fā)命令 (0xa5)
  90.         EA=1;
  91.         _nop_();
  92.         _nop_();
  93.         _nop_();
  94.         _nop_();
  95.         dat = IAP_DATA;                                         // 讀 IAP 數(shù)據(jù)
  96.         IapIdle();                                                                 // 關(guān)閉 IAP 功能
  97.         return dat;

  98. }
  99. void IapProgram(unsigned int addr, char dat)
  100. {

  101.         IAP_CONTR = 0x80;                                 // 使能 IAP
  102.         IAP_TPS = 12;                                                 // 設(shè)置等待參數(shù) 12MHz
  103.         IAP_CMD = 2;                                                        // 設(shè)置 IAP 寫命令
  104.         IAP_ADDRL = addr;                                 // 設(shè)置 IAP 低地址
  105.         IAP_ADDRH = addr >> 8;                 // 設(shè)置 IAP 高地址

  106.         IAP_DATA = dat;                                         // 寫 IAP 數(shù)據(jù)
  107.         EA=0;
  108.         _nop_();
  109.         _nop_();        
  110.         IAP_TRIG = 0x5a;                                         // 寫觸發(fā)命令 (0x5a)
  111.         IAP_TRIG = 0xa5;                                         // 寫觸發(fā)命令 (0xa5)
  112.         EA=1;        
  113.         _nop_();
  114.         _nop_();
  115.         _nop_();
  116.         _nop_();
  117.         IapIdle();                                                                // 關(guān)閉 IAP 功能

  118. }
  119. void IapErase(unsigned int addr)
  120. {

  121.         IAP_CONTR = 0x80;                                 // 使能 IAP
  122.         IAP_TPS = 12;                                                 // 設(shè)置等待參數(shù) 12MHz
  123.         IAP_CMD = 3;                                                         // 設(shè)置 IAP 擦除命令
  124.         IAP_ADDRL = addr;                                 // 設(shè)置 IAP 低地址
  125.         IAP_ADDRH = addr >> 8;                 // 設(shè)置 IAP 高地址

  126.         EA=0;
  127.         _nop_();
  128.         _nop_();        
  129.         IAP_TRIG = 0x5a;                                         // 寫觸發(fā)命令 (0x5a)
  130.         IAP_TRIG = 0xa5;                                         // 寫觸發(fā)命令 (0xa5)
  131.         EA=1;        
  132.         _nop_();
  133.         _nop_();
  134.         _nop_();
  135.         _nop_();
  136.         IapIdle();                                                                 // 關(guān)閉 IAP 功能

  137. }
復(fù)制代碼

作者: npn    時間: 2024-10-22 22:34
字節(jié)讀:可使用unsigned char/int/long code指針匯編成MOVC指令即可訪問,不需要配置EEPROM寄存器,字節(jié)寫將二進制1寫為0且不可逆,必須扇區(qū)擦除才能恢復(fù),沒有字節(jié)擦除,擦除后全部為0xFF(二進制1),一次擦512字節(jié)。
作者: vb2002    時間: 2024-10-22 23:07
npn 發(fā)表于 2024-10-22 22:34
字節(jié)讀:可使用unsigned char/int/long code指針匯編成MOVC指令即可訪問,不需要配置EEPROM寄存器,字節(jié)寫將 ...

可以幫忙完善下我的代碼嗎?
512 個字節(jié),,
從0可以寫,每次小于0.5秒的關(guān),開機,都寫一次新數(shù)據(jù).
寫到510 就擦除這個扇區(qū),然后再從 0 開始寫.
作者: WL0123    時間: 2024-10-23 06:10
P3M0 = 0x00; P3M1 = 0x00;配置是準(zhǔn)雙向高電平,P32 連接一個22uf電容,然后接地,在上電后短暫時間內(nèi)P32電壓由0逐漸上升到接近VCC。從一般意義講,端口電壓小于1/3VCC判斷為低電平,大于2/3VCC判斷為高電平。中間為不確定狀態(tài)(因芯片制造工藝不同,其電氣特性有差異,要以其用戶手冊為準(zhǔn))。樓主以此方法取樣不妥。再者樓主在主循環(huán)中頻繁讀寫EEPROM也是忌諱。通常做法是設(shè)置一個變量,掉電時保存這個變量的數(shù)據(jù)在EEPROM中,再次上電初始化時讀取保存的數(shù)據(jù)賦值這個變量。
作者: dj3365191    時間: 2024-10-23 10:05
上電瞬間是低電平,充滿電后是高電平,你正好理解反了
作者: vb2002    時間: 2024-10-23 12:49
WL0123 發(fā)表于 2024-10-23 06:10
P3M0 = 0x00; P3M1 = 0x00;配置是準(zhǔn)雙向高電平,P32 連接一個22uf電容,然后接地,在上電后短暫時間內(nèi)P32電 ...

可以幫忙完善下嗎?

作者: vb2002    時間: 2024-10-23 12:49
dj3365191 發(fā)表于 2024-10-23 10:05
上電瞬間是低電平,充滿電后是高電平,你正好理解反了

可以幫忙完善下代碼嗎?
作者: zhuls    時間: 2024-10-23 16:41
如果是“上電后 P32在 0.5秒后,充滿電應(yīng)該是屬于低電平”,充滿電后應(yīng)是高電平的才對吧?
作者: vb2002    時間: 2024-10-24 10:19
關(guān)鍵是eeprom單字節(jié)寫入.
這個沒問題

作者: xiaobendan001    時間: 2024-10-25 10:24
0.5秒關(guān)機再開機,開機后充電,此時單片機不一定能復(fù)位完成,關(guān)機后0.5秒,此時電容的電未必能放完。再開機不一定能及時復(fù)位并開始運行你的代碼。搞不懂為啥要這么操作。
作者: 188610329    時間: 2024-10-25 20:54
你是那個要做手電筒的吧? 你的思路是不是搞錯了?
正確的思路應(yīng)該是:
給單片機提供足夠大的電容,確保單片機在 0.5S 內(nèi)不會被完全放電,當(dāng)單片機檢測到“斷電”這個信號之后,給標(biāo)志位F0置位1,然后設(shè)置 0.5秒的定時換醒后 休眠。 0.5秒后休眠喚醒 把F0清0繼續(xù)休眠。如果0.5秒內(nèi)被來電喚醒,因為標(biāo)志F0 為1 則模式增加1,同時跟新 Eeprom.  如果 0.5秒后被喚新,或者,時間很長徹底掉電了,重新上電,因為F0都為0 則 讀取Eeprom 數(shù)據(jù),繼續(xù)使用,原來的模式。
作者: WL0123    時間: 2024-10-26 06:30
vb2002 發(fā)表于 2024-10-23 12:49
可以幫忙完善下嗎?

首先要明確表明你的需求是什么,才能提供有效的解決方案。
作者: vb2002    時間: 2024-10-29 23:36
188610329 發(fā)表于 2024-10-25 20:54
你是那個要做手電筒的吧? 你的思路是不是搞錯了?
正確的思路應(yīng)該是:
給單片機提供足夠大的電容,確保 ...

手電功能上已經(jīng)搞定了,
現(xiàn)在就是每次都是寫 1字節(jié),然后擦除整個扇區(qū),
覺得這樣太浪費了,eeprom壽命怕頂不住多久,
想弄成 每次讀一字節(jié),寫一字節(jié),寫完 512或者 1024,2048,再擦除扇區(qū),再從頭開始寫




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1