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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

C語言數據分拆存儲后讀出不正確

  [復制鏈接]
跳轉到指定樓層
樓主
ID:965189 發表于 2023-9-7 21:54 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
之前用這個方法將16位數分拆為8位數后存儲到片內,然后再讀出來顯示的時候“ 一部分 ”數據變了,也有一些是正確的。向各位請教正確的分拆和合并方法。
uint shu;                               //定義16位變量

IapErase(0x0000);                   //扇區擦除
IapProgram(0x0000,shu>>8);  //保存數據高8位
IapProgram(0x0001,shu);        //保存數據低8位

shu=IapRead(0x0000)<<8|IapRead(0x0001); //讀出保存的數據
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:213173 發表于 2023-9-8 07:34 | 只看該作者
上述代碼表面看沒有問題,易出錯可能是受中斷干擾或放在不恰當的位置,亦或相關讀寫的函數體有問題。
回復

使用道具 舉報

板凳
ID:123289 發表于 2023-9-8 08:32 | 只看該作者
試試 = 高位*256 + 低位
回復

使用道具 舉報

地板
ID:1079566 發表于 2023-9-8 09:33 | 只看該作者
uint 如果真是16位的話,應該沒錯。

或者,你可以考慮union
union
{
    unsigned shor int i;
    unsigned char x[2];
}shu;

寫讀 shu.x[0],shu.x[1], 用整體時,shu.i

}
回復

使用道具 舉報

5#
ID:384109 發表于 2023-9-8 10:38 | 只看該作者
看看錯誤和正確數據的規律,讀出數據合并時分開兩步走
回復

使用道具 舉報

6#
ID:69038 發表于 2023-9-8 10:51 | 只看該作者
shu=(IapRead(0x0000)<<8)|(IapRead(0x0001)); //讀出保存的數據,這樣有試過嗎?
回復

使用道具 舉報

7#
ID:965189 發表于 2023-9-8 15:52 | 只看該作者
wulin 發表于 2023-9-8 07:34
上述代碼表面看沒有問題,易出錯可能是受中斷干擾或放在不恰當的位置,亦或相關讀寫的函數體有問題。

我在擦除前關中斷
EA=0;
IapErase(0x0000);

完成寫入后再恢復中斷
回復

使用道具 舉報

8#
ID:965189 發表于 2023-9-8 15:55 | 只看該作者
yzwzfyz 發表于 2023-9-8 08:32
試試 = 高位*256 + 低位

這方法也試過,不行。以前用24C02的時候用過這個方法是可以的。今次試過不行。
回復

使用道具 舉報

9#
ID:965189 發表于 2023-9-8 15:58 | 只看該作者
ZSJM 發表于 2023-9-8 09:33
uint 如果真是16位的話,應該沒錯。

或者,你可以考慮union

這個未試過。謝謝你的建議,找時間試一下
回復

使用道具 舉報

10#
ID:965189 發表于 2023-9-8 15:59 | 只看該作者
zhuls 發表于 2023-9-8 10:51
shu=(IapRead(0x0000)

這個試過了,問題依舊。
回復

使用道具 舉報

11#
ID:1040201 發表于 2023-9-8 16:23 | 只看該作者
&0xff取低8位
回復

使用道具 舉報

12#
ID:1059013 發表于 2023-9-8 16:34 | 只看該作者
應該是第三行錯了,16位shu存入8位的話,自動四舍五入,其實存的還是高8位
回復

使用道具 舉報

13#
ID:883242 發表于 2023-9-8 16:37 | 只看該作者
  1. uint16_t shu;
  2. uint8_t *p;
  3. p=&shu;
  4. IapProgram(0x0000,*p++);
  5. IapProgram(0x0001,*p++);
  6. p=&shu;
  7. IapRead(0x0000,*p++); IapRead(0x0001,*p++);
復制代碼
回復

使用道具 舉報

14#
ID:213173 發表于 2023-9-8 17:10 | 只看該作者
君工創 發表于 2023-9-8 15:52
我在擦除前關中斷
EA=0;
IapErase(0x0000);

這是一款掉電中斷數據保存EEPROM的測試程序,非常可靠,相關代碼可以參考。
//測試環境:TX-1C實驗板,MCU型號IAP15W4K58S4,系統時鐘11.0592MHz
//注意:測試本示例時,需在ISP下載時將低壓復位功能和低壓時禁止EEPROM操作關閉
  1. #include <STC15F2K60S2.H>
  2. #include <intrins.h>                                //庫頭文件
  3. #define uint unsigned int                         //宏定義數據類型uint
  4. #define uchar unsigned char                 //宏定義數據類型uchar
  5. //宏定義ISP的操作命令
  6. #define CMD_IDLE    0               //空閑模式
  7. #define CMD_READ    1               //IAP字節讀命令
  8. #define CMD_PROGRAM 2               //IAP字節編程命令
  9. #define CMD_ERASE   3               //IAP扇區擦除命令
  10. #define ENABLE_IAP  0x82            //CPU的等待時間
  11. #define IAP_ADDRESS 0x0800                        //測試地址
  12. sbit duan=P2^6;
  13. sbit wein=P2^7;

  14. //順序共陰極數碼管段碼表,段碼a-h順序接PX0-PX7
  15. uchar code table[]={//共陰數碼管段碼"0~f-."
  16.                 0x3f,0x06,0x5b,0x4f,
  17.                 0x66,0x6d,0x7d,0x07,
  18.                 0x7f,0x6f,0x77,0x7c,
  19.                 0x39,0x5e,0x79,0x71,0x40,0x80};
  20. uchar data dis_buf[8];                //緩存數組
  21. uint num,sec;
  22. uchar i;

  23. void Timer0Init();                                        //定時器初始化聲明
  24. void IapIdle();                                                //關閉IAP/EEPROM
  25. uchar IapReadByte(uint addr);                //讀取EEPROM數據
  26. void IapProgramByte(uint addr, uchar dat);//寫入EEPROM數據
  27. void IapEraseSector(uint addr);                //擦除EEPROM數據

  28. void main()                                                       
  29. {
  30.         P0M0 = 0x00;
  31.         P0M1 = 0x00;
  32.         P1M0 = 0x00;
  33.         P1M1 = 0x00;
  34.         P2M0 = 0x00;
  35.         P2M1 = 0x00;
  36.         P3M0 = 0x00;
  37.         P3M1 = 0x00;
  38.         P4M0 = 0x00;
  39.         P4M1 = 0x00;
  40.         P5M0 = 0x00;
  41.         P5M1 = 0x00;
  42.         P6M0 = 0x00;
  43.         P6M1 = 0x00;
  44.         P7M0 = 0x00;
  45.         P7M1 = 0x00;
  46.         sec=IapReadByte(IAP_ADDRESS)<<8|IapReadByte(IAP_ADDRESS+1);//讀取保存的數據 用時11.75us
  47.         if(sec==0xffff)//如果沒有保存數據
  48.                 sec=0;//變量為0
  49.         else IapEraseSector(IAP_ADDRESS);//擦除數據,為下次掉電保存數據做準備

  50.         PCON &= 0xDF;//清0掉電標志
  51.         ELVD = 1;//開低壓中斷
  52.         EA   = 1;//開總中斷

  53.         Timer0Init();//初始化定時器

  54.         while(1)
  55.         {
  56.                 if(TF0)//查詢T0中斷請求標志
  57.                 {               
  58.                         TF0=0;//T0中斷請求標志清0
  59.                         if(++num>=1000)//1秒
  60.                         {
  61.                                 num=0;                               
  62.                                 sec++;
  63.                         }
  64.                         dis_buf[0]=table[sec/10000%10];
  65.                         dis_buf[1]=table[sec/1000%10];
  66.                         dis_buf[2]=table[sec/100%10];
  67.                         dis_buf[3]=table[sec/10%10];
  68.                         dis_buf[4]=table[sec%10];

  69.                         P0=0x00;duan=1;duan=0;
  70.                         P0=~(0x01<<i);wein=1;wein=0;
  71.                         P0=dis_buf[i];duan=1;duan=0;
  72.                         i=++i%5;
  73.                 }
  74.         }
  75. }

  76. void Timer0Init(void)        //1毫秒@11.0592MHz
  77. {
  78.         AUXR |= 0x80;                //定時器時鐘1T模式
  79.         TMOD &= 0xF0;                //設置定時器模式
  80.         TL0 = 0xCD;                        //設置定時初始值
  81.         TH0 = 0xD4;                        //設置定時初始值
  82.         TF0 = 0;                        //清除TF0標志
  83.         TR0 = 1;                        //定時器0開始計時
  84. }


  85. /*----------------------------
  86.         關閉IAP功能
  87. ----------------------------*/
  88. void IapIdle()
  89. {
  90.     IAP_CONTR = 0;                  //關閉IAP功能
  91.     IAP_CMD = 0;                    //清除命令寄存器
  92.     IAP_TRIG = 0;                   //清除觸發寄存器
  93.     IAP_ADDRH = 0x80;               //將地址設置到非IAP區域
  94.     IAP_ADDRL = 0;
  95. }
  96. /*----------------------------
  97. 從ISP/IAP/EEPROM區域讀取一字節
  98. ----------------------------*/
  99. uchar IapReadByte(uint addr)
  100. {
  101.     uchar dat;                       //數據緩沖區

  102.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  103.     IAP_CMD = CMD_READ;             //設置IAP命令
  104.     IAP_ADDRL = addr;               //設置IAP低地址
  105.     IAP_ADDRH = addr >> 8;          //設置IAP高地址
  106.     IAP_TRIG = 0x5a;                //寫觸發命令(0x5a)
  107.     IAP_TRIG = 0xa5;                //寫觸發命令(0xa5)
  108.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  109.     dat = IAP_DATA;                 //讀ISP/IAP/EEPROM數據
  110.     IapIdle();                      //關閉IAP功能
  111.     return dat;                     //返回
  112. }
  113. /*-------------------------------
  114. 寫一字節數據到ISP/IAP/EEPROM區域
  115. --------------------------------*/
  116. void IapProgramByte(uint addr, uchar dat)
  117. {
  118.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  119.     IAP_CMD = CMD_PROGRAM;          //設置IAP命令
  120.     IAP_ADDRL = addr;               //設置IAP低地址
  121.     IAP_ADDRH = addr >> 8;          //設置IAP高地址
  122.     IAP_DATA = dat;                 //寫ISP/IAP/EEPROM數據
  123.     IAP_TRIG = 0x5a;                //寫觸發命令(0x5a)
  124.     IAP_TRIG = 0xa5;                //寫觸發命令(0xa5)
  125.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  126.     IapIdle();                      //關閉IAP功能
  127. }
  128. /*----------------------------
  129. ISP/IAP/EEPROM扇區擦除
  130. ----------------------------*/
  131. void IapEraseSector(uint addr)
  132. {
  133.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  134.     IAP_CMD = CMD_ERASE;            //設置IAP命令
  135.     IAP_ADDRL = addr;               //設置IAP低地址
  136.     IAP_ADDRH = addr >> 8;          //設置IAP高地址
  137.     IAP_TRIG = 0x5a;                //寫觸發命令(0x5a)
  138.     IAP_TRIG = 0xa5;                //寫觸發命令(0xa5)
  139.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  140.     IapIdle();                      //關閉IAP功能
  141. }
  142. void PowerLost() interrupt 6                //剩余電量從中斷開始到完全斷電2.5ms
  143. {
  144.         EA = 0;                                                //關閉總中斷
  145.         P0M1 = 0xff;                                //所有端口高阻用時2.75us
  146.         P1M1 = 0xff;
  147.         P2M1 = 0xff;
  148.         P3M1 = 0xff;
  149.         P4M1 = 0xff;
  150.         P5M1 = 0xff;
  151.         P6M1 = 0xff;
  152.         P7M1 = 0xff;
  153.         IapProgramByte(IAP_ADDRESS,sec>>8);//寫數據高8位到EEPROM
  154.         IapProgramByte(IAP_ADDRESS+1,sec);//寫數據低8位到EEPROM  寫兩個字節用時215.25us

  155.         while((PCON & 0x20) != 0)         //復查低壓標志
  156.         {
  157.                 PCON &= 0xDF;                  //清除低壓標志
  158.                 _nop_();               
  159.                 _nop_();                            //坐等掉電
  160.         }
  161.         IAP_CONTR = 0x20;                 //發現是誤報,重啟單片機,恢復正常工作
復制代碼
回復

使用道具 舉報

15#
ID:965189 發表于 2023-9-8 22:41 | 只看該作者
fishafish 發表于 2023-9-8 16:34
應該是第三行錯了,16位shu存入8位的話,自動四舍五入,其實存的還是高8位

這個講法有可能,因為某些數會錯,而一些數不會錯。
回復

使用道具 舉報

16#
ID:965189 發表于 2023-9-8 23:01 | 只看該作者

請教大俠,這一行,IapRead(0x0000,*p++); IapRead(0x0001,*p++);
讀出數據不是讀出來重新組合到shu嗎?為什么又讀到內存里了。
回復

使用道具 舉報

17#
ID:491577 發表于 2023-9-8 23:29 | 只看該作者
數據溢出了,shu=IapRead(0x0000)<<8|IapRead(0x0001); 其中IapRead(0x0000)<<8有問題,IapRead(0x0000)是8位的,左移數據會溢出。要強制數據轉換:shu=(uint)IapRead(0x0000)<<8|IapRead(0x0001);
回復

使用道具 舉報

18#
ID:491577 發表于 2023-9-8 23:45 | 只看該作者
單片機很容易發生數據溢出錯誤,我就碰到過,怎么查找都不知道原因,特別是運算中間的溢出更加難查,比如16位數據*100/200,結果一定小于16位,但是這樣寫a=b*100/200;是不對的,這樣才對a=b/200*100;先乘100可能會數據溢出,不小心很容易中招。
回復

使用道具 舉報

19#
ID:1041851 發表于 2023-9-9 09:34 | 只看該作者
Keil處理復雜的計算式時容易出現一些奇怪問題
將"shu=IapRead(0x0000)<<8|IapRead(0x0001); //讀出保存的數據"
這句拆分成兩步試試:
shu = apRead(0x0000) << 8;

shu |= IapRead(0x0001);

也可將每步的結果打印出來看看哪里不對

回復

使用道具 舉報

20#
ID:304306 發表于 2023-9-9 09:48 | 只看該作者
用聯合體(uion)做方便,不用考慮這么多
回復

使用道具 舉報

21#
ID:965189 發表于 2023-9-9 12:33 | 只看該作者
2008_clz 發表于 2023-9-9 09:48
用聯合體(uion)做方便,不用考慮這么多

請教:具體怎么寫。
回復

使用道具 舉報

22#
ID:965189 發表于 2023-9-9 15:09 | 只看該作者
在以上各位大俠的指教下,問題已經解決。多謝各位的熱心幫助。問題出在讀出組合環節。
回復

使用道具 舉報

23#
ID:883242 發表于 2023-9-9 17:25 | 只看該作者
不要去運算這個數,知道地址組合數據即可。
回復

使用道具 舉報

24#
ID:1059013 發表于 2023-9-9 19:40 | 只看該作者
君工創 發表于 2023-9-8 22:41
這個講法有可能,因為某些數會錯,而一些數不會錯。

好像還與不同編譯軟件有關,我遇到PIC編譯軟件是會得到意外結果的
回復

使用道具 舉報

25#
ID:77589 發表于 2023-9-12 15:08 | 只看該作者
hhh402 發表于 2023-9-8 23:29
數據溢出了,shu=IapRead(0x0000)

我認為也是這個問題
回復

使用道具 舉報

26#
ID:77589 發表于 2023-9-12 15:16 | 只看該作者

方法可行,但是后兩句錯了
uint16_t shu;
uint8_t *p;
p = &shu;
IapProgram(0x0000, *p);
p++;
IapProgram(0x0001, *p);
p = &shu;
*p = IapRead(0x0000);
p++;
*p = IapRead(0x0001);
把p++單獨提出來寫,所有人都好理解。而且寫與讀都只需要一次p++。
讀取后的數據自動組合到shu中了。
回復

使用道具 舉報

27#
ID:883242 發表于 2023-9-13 14:32 | 只看該作者
Longan.Wang 發表于 2023-9-12 15:16
方法可行,但是后兩句錯了
uint16_t shu;
uint8_t *p;

我用MinGW_w64 13.0驗證無誤,當然你水平難以理解改成你能理解的方式沒問題,錯了你有何依據?不要憑空想象。
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 天天草草草 | 久久精品视频网站 | 免费国产成人av | 黄色免费av| 97视频精品 | 一区视频 | 国产视频二区在线观看 | 欧美亚洲国产一区二区三区 | 亚洲电影一级片 | 国产精品久久久久久婷婷天堂 | 久久一久久 | 久久男人天堂 | 中文字幕一区在线观看视频 | 中文字幕精品视频 | 特黄色一级毛片 | 欧美一区二区三区视频 | 日韩精品免费一区 | 一区二区在线 | 一级黄色毛片子 | 国产视频2021| 综合亚洲视频 | 黄色大片免费网站 | 91成人午夜性a一级毛片 | 东京久久 | 三级黄色片在线 | 国产日产欧产精品精品推荐蛮挑 | 黄色成人在线观看 | 国产精品永久久久久久久www | 亚洲欧美国产精品久久 | 欧美日韩一区二区视频在线观看 | 最新国产精品 | 国产亚洲精品综合一区 | 久久99精品久久久久久 | 黄色网址在线播放 | 日韩无 | 99看片网| 婷婷不卡 | 午夜爽爽爽男女免费观看 | 麻豆毛片 | 伊伊综合网 | 欧美一级大片免费看 |