数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 300|回复: 4

[C51] 库仑计代码遇到存储问题请教

[复制链接]
发表于 2026-7-15 22:46:54 来自手机浏览器 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
代码基本完成了,在调试中遇到把校准值改后,能储存,就是再开机又恢复到之前值了,不知道什么原因
把代码贴出来,请大哥帮忙看看什么原因,都是AI写的,用ai改还是老问题
链接:https://pan.baidu.com/s/1rl3O5jmmQwThJziH4ZE25g 提取码:10vf


  1. /****************************************************************************
  2. *  STC8H3K64S2-TSSOP20 库仑计主程序 (大字体版)  
  3. *  
  4. *  修改版本 V2.1-board2:
  5. *  适配新板子引脚定义:
  6. *    - KEYS  (菜单/切换键)  → P3.0
  7. *    - KEYA  (加一键)       → P3.1
  8. *    - KEYD  (减一键)       → P3.2
  9. *    - LCD_DAT (SDA)        → P3.7
  10. *    - LCD_CLK (SCL)        → P3.6
  11. *    - LCD_RS  (A0/DC)      → P3.5
  12. *    - LCD_RST              → P3.4
  13. *    - LCD_CS               → P5.5
  14. *    - CURRENT2 (电流采样)  → ADC0 (P1.0)
  15. *    - VOLTAGE2 (电压采样)  → ADC6 (P1.6)
  16. *    - TEMPERATURE          → ADC7 (P1.7)
  17. *  
  18. *  编译环境: Keil C51 V9.60+
  19. *  晶振: 内部IRC 35MHz
  20. ****************************************************************************/

  21. #include <reg51.h>
  22. #include <intrins.h>

  23. // ============================================================================
  24. //  宏定义
  25. // ============================================================================

  26. #define VERSION         "V2.1-board2"

  27. // 时钟配置 (内部IRC 35MHz)
  28. #define TIMER0_RELOAD_H   0xF4
  29. #define TIMER0_RELOAD_L   0xCC

  30. // ADC配置
  31. #define ADC_VREF        3300
  32. #define ADC_RESOLUTION  4096

  33. // 电压检测参数
  34. #define VOLTAGE_DIV_R1  300000UL
  35. #define VOLTAGE_DIV_R2  10000UL
  36. #define VOLTAGE_RATIO   31

  37. // 电流检测参数
  38. #define SHUNT_RESISTOR  2
  39. #define INA199_GAIN     100
  40. #define INA199_VREF     1650

  41. // 容量参数
  42. #define DEFAULT_CAPACITY    10000UL
  43. #define CAPACITY_MIN        100UL
  44. #define CAPACITY_MAX        999900UL

  45. // 滤波参数
  46. #define ADC_FILTER_LEN      8

  47. // 温度检测
  48. #define TEMPERATURE_CHANNEL 7       // ADC7 = P1.7 NTC热敏电阻
  49. #define NTC_B_VALUE         3950    // B值
  50. #define NTC_R25             10000   // 25度时电阻10K
  51. #define NTC_PULLUP          10000   // 上拉电阻10K

  52. // EEPROM地址
  53. #define EEPROM_ADDR_CAPACITY    0x0000
  54. #define EEPROM_ADDR_REMAINING   0x0004

  55. // ============================================================================
  56. //  STC8H3K64S2 扩展SFR定义
  57. // ============================================================================

  58. sfr P1M0 = 0x92;
  59. sfr P1M1 = 0x91;
  60. sfr P3M0 = 0xB2;
  61. sfr P3M1 = 0xB1;
  62. sfr P5     = 0xC8;
  63. sbit P54   = P5^4;
  64. sfr P5M0   = 0xCA;
  65. sfr P5M1   = 0xC9;

  66. sfr AUXR   = 0x8E;
  67. sfr ADC_CONTR   = 0xBC;
  68. sfr ADC_RES     = 0xBD;
  69. sfr ADC_RESL    = 0xBE;
  70. sfr ADCCFG      = 0xDE;

  71. #define ADC_POWER   0x80
  72. #define ADC_START   0x40
  73. #define ADC_FLAG    0x20

  74. sfr IAP_DATA    = 0xC2;
  75. sfr IAP_ADDRH   = 0xC3;
  76. sfr IAP_ADDRL   = 0xC4;
  77. sfr IAP_CMD     = 0xC5;
  78. sfr IAP_TRIG    = 0xC6;
  79. sfr IAP_CONTR   = 0xC7;

  80. #define IAP_EN      0x80

  81. // ============================================================================
  82. //  【修改】LCD引脚定义 - 按新板子
  83. // ============================================================================

  84. sbit LCD_RST = P3^4;    // 改: P3.4 (原P3.0)
  85. sbit LCD_SCL = P3^6;    // 改: P3.6 (原P3.2)
  86. sbit LCD_SDA = P3^7;    // 改: P3.7 (原P3.3)
  87. sbit LCD_CS  = P5^5;    // 改: P5.5 (原P3.4)
  88. sbit LCD_A0  = P3^5;    // 不变: P3.5

  89. // ============================================================================
  90. //  【修改】按键引脚定义 - 换到独立引脚,避免与LCD冲突
  91. // ============================================================================

  92. sbit KEY_MENU = P5^4;   // 菜单/切换键 → P5.4 (独立引脚)
  93. sbit KEY_UP   = P1^1;   // 加一键 → P1.1 (独立引脚)
  94. sbit KEY_DOWN = P1^2;   // 减一键 → P1.2 (独立引脚)

  95. // ============================================================================
  96. //  全局变量 - 全部放xdata
  97. // ============================================================================

  98. unsigned int xdata adc_voltage_buf[ADC_FILTER_LEN];
  99. unsigned int xdata adc_current_buf[ADC_FILTER_LEN];
  100. unsigned int xdata adc_temp_buf[ADC_FILTER_LEN];
  101. unsigned char xdata adc_buf_index = 0;

  102. unsigned long xdata voltage_x100;
  103. long xdata current_x100;
  104. unsigned long xdata power_x10;
  105. unsigned long xdata wh_x100;
  106. unsigned char xdata temperature_x10 = 0;
  107. unsigned int xdata adc_temp_raw = 0;       // 温度ADC原始值

  108. unsigned long xdata total_capacity;
  109. long xdata remaining_capacity;
  110. unsigned char xdata percentage = 0;

  111. long xdata coulomb_accumulator = 0;

  112. unsigned char xdata sys_running = 0;
  113. unsigned char xdata display_mode = 0;

  114. unsigned int xdata timer1ms_cnt = 0;
  115. unsigned int xdata timer10ms_cnt = 0;
  116. unsigned int xdata timer100ms_cnt = 0;
  117. unsigned int xdata timer500ms_cnt = 0;
  118. unsigned long xdata run_seconds = 0;

  119. bit bdata flag_adc_sample = 0;
  120. bit bdata flag_coulomb_int = 0;
  121. bit bdata flag_display_refresh = 0;
  122. bit bdata flag_key_scan = 0;

  123. unsigned char xdata key_state = 0;
  124. unsigned char xdata key_press = 0;
  125. unsigned int xdata key_hold_cnt = 0;

  126. unsigned char xdata lcd_buffer[1024];
  127. unsigned long xdata temp_capacity = 0;       // 设置模式临时容量

  128. // ============================================================================
  129. //  校准参数
  130. // ============================================================================

  131. unsigned int xdata cal_voltage_beiShu = 2082;   // 电压倍率校准 2.082 * 1000
  132. unsigned char xdata cal_voltage_lingDian = 3;    // 电压零点校准
  133. unsigned int xdata cal_current_beiShu = 1273;   // 电流倍率校准 1.273 * 1000
  134. unsigned char xdata cal_current_lingDian = 5;    // 电流零点校准

  135. unsigned char xdata cal_menu = 0;        // 校准菜单项 0-3
  136. unsigned char xdata cal_mode = 0;        // 0=正常显示 1=校准模式
  137. bit bdata flag_cal_save = 0;           // 保存校准标志

  138. // ============================================================================
  139. //  6x8 ASCII字库 - code区
  140. // ============================================================================

  141. unsigned char code font_6x8[][6] = {
  142.     {0x00,0x00,0x00,0x00,0x00,0x00}, // 0x20 space
  143.     {0x00,0x00,0x5F,0x00,0x00,0x00}, // !
  144.     {0x00,0x07,0x00,0x07,0x00,0x00}, // "
  145.     {0x14,0x7F,0x14,0x7F,0x14,0x00}, // #
  146.     {0x24,0x2A,0x7F,0x2A,0x12,0x00}, // $
  147.     {0x23,0x13,0x08,0x64,0x62,0x00}, // %
  148.     {0x36,0x49,0x55,0x22,0x50,0x00}, // &
  149.     {0x00,0x05,0x03,0x00,0x00,0x00}, // \'
  150.     {0x00,0x1C,0x22,0x41,0x00,0x00}, // (
  151.     {0x00,0x41,0x22,0x1C,0x00,0x00}, // )
  152.     {0x08,0x2A,0x1C,0x2A,0x08,0x00}, // *
  153.     {0x08,0x08,0x3E,0x08,0x08,0x00}, // +
  154.     {0x00,0x50,0x30,0x00,0x00,0x00}, // ,
  155.     {0x08,0x08,0x08,0x08,0x08,0x00}, // -
  156.     {0x00,0x60,0x60,0x00,0x00,0x00}, // .
  157.     {0x20,0x10,0x08,0x04,0x02,0x00}, // /
  158.     {0x3E,0x51,0x49,0x45,0x3E,0x00}, // 0
  159.     {0x00,0x42,0x7F,0x40,0x00,0x00}, // 1
  160.     {0x42,0x61,0x51,0x49,0x46,0x00}, // 2
  161.     {0x21,0x41,0x45,0x4B,0x31,0x00}, // 3
  162.     {0x18,0x14,0x12,0x7F,0x10,0x00}, // 4
  163.     {0x27,0x45,0x45,0x45,0x39,0x00}, // 5
  164.     {0x3C,0x4A,0x49,0x49,0x30,0x00}, // 6
  165.     {0x01,0x71,0x09,0x05,0x03,0x00}, // 7
  166.     {0x36,0x49,0x49,0x49,0x36,0x00}, // 8
  167.     {0x06,0x49,0x49,0x29,0x1E,0x00}, // 9
  168.     {0x00,0x36,0x36,0x00,0x00,0x00}, // :
  169.     {0x00,0x56,0x36,0x00,0x00,0x00}, // ;
  170.     {0x00,0x08,0x14,0x22,0x41,0x00}, // <
  171.     {0x14,0x14,0x14,0x14,0x14,0x00}, // =
  172.     {0x41,0x22,0x14,0x08,0x00,0x00}, // >
  173.     {0x02,0x01,0x51,0x09,0x06,0x00}, // ?
  174.     {0x32,0x49,0x79,0x41,0x3E,0x00}, // @
  175.     {0x7E,0x11,0x11,0x11,0x7E,0x00}, // A
  176.     {0x7F,0x49,0x49,0x49,0x36,0x00}, // B
  177.     {0x3E,0x41,0x41,0x41,0x22,0x00}, // C
  178.     {0x7F,0x41,0x41,0x22,0x1C,0x00}, // D
  179.     {0x7F,0x49,0x49,0x49,0x41,0x00}, // E
  180.     {0x7F,0x09,0x09,0x01,0x01,0x00}, // F
  181.     {0x3E,0x41,0x41,0x51,0x32,0x00}, // G
  182.     {0x7F,0x08,0x08,0x08,0x7F,0x00}, // H
  183.     {0x00,0x41,0x7F,0x41,0x00,0x00}, // I
  184.     {0x20,0x40,0x41,0x3F,0x01,0x00}, // J
  185.     {0x7F,0x08,0x14,0x22,0x41,0x00}, // K
  186.     {0x7F,0x40,0x40,0x40,0x40,0x00}, // L
  187.     {0x7F,0x02,0x04,0x02,0x7F,0x00}, // M
  188.     {0x7F,0x04,0x08,0x10,0x7F,0x00}, // N
  189.     {0x3E,0x41,0x41,0x41,0x3E,0x00}, // O
  190.     {0x7F,0x09,0x09,0x09,0x06,0x00}, // P
  191.     {0x3E,0x41,0x51,0x21,0x5E,0x00}, // Q
  192.     {0x7F,0x09,0x19,0x29,0x46,0x00}, // R
  193.     {0x46,0x49,0x49,0x49,0x31,0x00}, // S
  194.     {0x01,0x01,0x7F,0x01,0x01,0x00}, // T
  195.     {0x3F,0x40,0x40,0x40,0x3F,0x00}, // U
  196.     {0x1F,0x20,0x40,0x20,0x1F,0x00}, // V
  197.     {0x7F,0x20,0x18,0x20,0x7F,0x00}, // W
  198.     {0x63,0x14,0x08,0x14,0x63,0x00}, // X
  199.     {0x03,0x04,0x78,0x04,0x03,0x00}, // Y
  200.     {0x61,0x51,0x49,0x45,0x43,0x00}, // Z
  201.     {0x00,0x00,0x00,0x00,0x00,0x00},
  202.     {0x00,0x00,0x00,0x00,0x00,0x00},
  203.     {0x00,0x00,0x00,0x00,0x00,0x00},
  204.     {0x00,0x00,0x00,0x00,0x00,0x00},
  205.     {0x00,0x00,0x00,0x00,0x00,0x00},
  206.     {0x00,0x00,0x00,0x00,0x00,0x00},
  207.     {0x20,0x54,0x54,0x54,0x78,0x00}, // a
  208.     {0x7F,0x48,0x44,0x44,0x38,0x00}, // b
  209.     {0x38,0x44,0x44,0x44,0x20,0x00}, // c
  210.     {0x38,0x44,0x44,0x48,0x7F,0x00}, // d
  211.     {0x38,0x54,0x54,0x54,0x18,0x00}, // e
  212.     {0x08,0x7E,0x09,0x01,0x02,0x00}, // f
  213.     {0x08,0x14,0x54,0x54,0x3C,0x00}, // g
  214.     {0x7F,0x08,0x04,0x04,0x78,0x00}, // h
  215.     {0x00,0x44,0x7D,0x40,0x00,0x00}, // i
  216.     {0x20,0x40,0x44,0x3D,0x00,0x00}, // j
  217.     {0x00,0x7F,0x10,0x28,0x44,0x00}, // k
  218.     {0x00,0x41,0x7F,0x40,0x00,0x00}, // l
  219.     {0x7C,0x04,0x18,0x04,0x78,0x00}, // m
  220.     {0x7C,0x08,0x04,0x04,0x78,0x00}, // n
  221.     {0x38,0x44,0x44,0x44,0x38,0x00}, // o
  222.     {0x7C,0x14,0x14,0x14,0x08,0x00}, // p
  223.     {0x08,0x14,0x14,0x18,0x7C,0x00}, // q
  224.     {0x7C,0x08,0x04,0x04,0x08,0x00}, // r
  225.     {0x48,0x54,0x54,0x54,0x20,0x00}, // s
  226.     {0x04,0x3F,0x44,0x40,0x20,0x00}, // t
  227.     {0x3C,0x40,0x40,0x20,0x7C,0x00}, // u
  228.     {0x1C,0x20,0x40,0x20,0x1C,0x00}, // v
  229.     {0x3C,0x40,0x30,0x40,0x3C,0x00}, // w
  230.     {0x44,0x28,0x10,0x28,0x44,0x00}, // x
  231.     {0x0C,0x50,0x50,0x50,0x3C,0x00}, // y
  232.     {0x44,0x64,0x54,0x4C,0x44,0x00}, // z
  233. };

  234. // ============================================================================
  235. //  大字体字模 (10x24像素,纵向取模,字节倒序)
  236. // ============================================================================

  237. unsigned char code num0[] = {
  238.     0xFC,0xFE,0xFF,0x0F,0x07,0x07,0x0F,0xFF,0xFE,0xFC,
  239.     0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,
  240.     0x0F,0x1F,0x3F,0x3C,0x38,0x38,0x3C,0x3F,0x1F,0x0F
  241. };

  242. unsigned char code num1[] = {
  243.     0x00,0x18,0x18,0x1C,0xFE,0xFF,0xFF,0x00,0x00,0x00,
  244.     0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,
  245.     0x00,0x00,0x38,0x38,0x3F,0x3F,0x3F,0x38,0x38,0x00
  246. };

  247. unsigned char code num2[] = {
  248.     0x3C,0x3E,0x3F,0x0F,0x07,0x07,0x8F,0xFF,0xFE,0xFC,
  249.     0x00,0x00,0x80,0xE0,0xF8,0x7E,0x1F,0x07,0x01,0x00,
  250.     0x38,0x3E,0x3F,0x3F,0x39,0x38,0x38,0x38,0x38,0x38
  251. };

  252. unsigned char code num3[] = {
  253.     0x3C,0x3E,0x3F,0x0F,0x07,0x07,0x0F,0xFF,0xFE,0xFC,
  254.     0x00,0x00,0x00,0x00,0x0E,0x0E,0x1F,0xFF,0xFB,0xF1,
  255.     0x0E,0x1E,0x3E,0x3C,0x38,0x38,0x3C,0x3F,0x1F,0x0F
  256. };

  257. unsigned char code num4[] = {
  258.     0x00,0x00,0x00,0xC0,0xF8,0xFF,0xFF,0xFF,0x00,0x00,
  259.     0x80,0xF0,0xFE,0x3F,0x07,0xFF,0xFF,0xFF,0x00,0x00,
  260.     0x07,0x07,0x07,0x07,0x07,0x3F,0x3F,0x3F,0x07,0x07
  261. };

  262. unsigned char code num5[] = {
  263.     0xFF,0xFF,0xFF,0x87,0x87,0x87,0x87,0x87,0x07,0x07,
  264.     0x0F,0x0F,0x0F,0x07,0x03,0x03,0x07,0xFF,0xFF,0xFE,
  265.     0x0E,0x1E,0x3E,0x3C,0x38,0x38,0x3C,0x3F,0x1F,0x0F
  266. };

  267. unsigned char code num6[] = {
  268.     0xFC,0xFE,0xFF,0x0F,0x07,0x07,0x0F,0x3F,0x3E,0x3C,
  269.     0xFF,0xFF,0xFF,0x0F,0x07,0x07,0x0F,0xFF,0xFE,0xFC,
  270.     0x0F,0x1F,0x3F,0x3C,0x38,0x38,0x3C,0x3F,0x1F,0x0F
  271. };

  272. unsigned char code num7[] = {
  273.     0x07,0x07,0x07,0x07,0x07,0x07,0xE7,0xFF,0xFF,0x3F,
  274.     0x00,0x00,0x00,0xC0,0xF8,0xFF,0x1F,0x03,0x00,0x00,
  275.     0x00,0x00,0x00,0x3F,0x3F,0x3F,0x00,0x00,0x00,0x00
  276. };

  277. unsigned char code num8[] = {
  278.     0xFC,0xFE,0xFF,0x0F,0x07,0x07,0x0F,0xFF,0xFE,0xFC,
  279.     0xFB,0xFF,0xFF,0x1F,0x0E,0x0E,0x1F,0xFF,0xFF,0xFB,
  280.     0x0F,0x1F,0x3F,0x3C,0x38,0x38,0x3C,0x3F,0x1F,0x0F
  281. };

  282. unsigned char code num9[] = {
  283.     0xFC,0xFE,0xFF,0x0F,0x07,0x07,0x0F,0xFF,0xFE,0xFC,
  284.     0x0F,0x1F,0x3F,0x3C,0x38,0x38,0x3C,0xFF,0xFF,0xFF,
  285.     0x0F,0x1F,0x3F,0x3C,0x38,0x38,0x3C,0x3F,0x1F,0x0F
  286. };

  287. unsigned char code *big_num[] = {num0, num1, num2, num3, num4, num5, num6, num7, num8, num9};

  288. unsigned char code strV[] = {
  289.     0x30,0xF0,0x80,0x00,0x80,0xF0,0x30,0x00,
  290.     0x00,0x01,0x0F,0x3C,0x0F,0x01,0x00,0x00
  291. };

  292. unsigned char code strA[] = {
  293.     0x00,0x00,0xC0,0xF0,0xC0,0x00,0x00,0x00,
  294.     0x30,0x3E,0x07,0x04,0x07,0x3E,0x30,0x00
  295. };

  296. unsigned char code strW[] = {
  297.     0xF0,0xF0,0x00,0x00,0x00,0xF0,0xF0,0x00,
  298.     0x0F,0x3F,0x38,0x0E,0x38,0x3F,0x0F,0x00
  299. };

  300. // 温度符号 8x2(大尺寸,和大字体单位配套)
  301. unsigned char code strDegreeC[] = {
  302.     0x06,0x09,0x06,0x00,0x00,0x00,0x00,0x00,
  303.     0x00,0x00,0x00,0x38,0x44,0x44,0x38,0x00
  304. };

  305. unsigned char code strPoint[] = {
  306.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  307.     0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00
  308. };

  309. // ============================================================================
  310. //  NTC温度查找表 (MF52E 10K B=3950, ADC 12bit, 上拉10K)
  311. //  ADC值对应温度(-40~120度), 索引=温度+40, 值=ADC读数
  312. // ============================================================================

  313. unsigned int code temp_table[] = {
  314.     140,149,159,168,178,188,199,210,222,233,
  315.     246,259,272,286,301,317,333,349,367,385,
  316.     403,423,443,464,486,509,533,558,583,610,
  317.     638,667,696,727,758,791,824,858,893,929,
  318.     965,1003,1041,1080,1119,1160,1201,1243,1285,1328,
  319.     1371,1414,1459,1503,1548,1593,1638,1684,1730,1775,
  320.     1821,1867,1912,1958,2003,2048,2093,2137,2182,2225,
  321.     2269,2312,2354,2397,2438,2479,2519,2559,2598,2637,
  322.     2675,2712,2748,2784,2819,2853,2887,2920,2952,2984,
  323.     3014,3044,3073,3102,3130,3157,3183,3209,3234,3259,
  324.     3283,3306,3328,3351,3372,3393,3413,3432,3452,3470,
  325.     3488,3506,3523,3539,3555,3571,3586,3601,3615,3628,
  326.     3642,3655,3667,3679,3691,3702,3714,3724,3735,3745,
  327.     3754,3764,3773,3782,3791,3799,3807,3815,3822,3830,
  328.     3837,3844,3850,3857,3863,3869,3875,3881,3887,3892,
  329.     3897,3902,3907,3912,3917,3921,3926,3930,3934,3938,3942
  330. };

  331. // ============================================================================
  332. //  函数声明
  333. // ============================================================================

  334. void System_Init(void);
  335. void Clock_Init(void);
  336. void GPIO_Init(void);
  337. void Timer0_Init(void);
  338. void ADC_Init(void);
  339. void UART1_Init(void);
  340. void UART1_SendByte(unsigned char dat);
  341. void UART1_SendString(unsigned char *str);
  342. void UART1_SendNumber(unsigned long num);
  343. void UART1_SendHex(unsigned char hex);
  344. void UART1_SendCRLF(void);

  345. void LCD_Init(void);
  346. void LCD_WriteCmd(unsigned char cmd);
  347. void LCD_WriteData(unsigned char dat);
  348. void LCD_Clear(void);
  349. void LCD_SetPos(unsigned char page, unsigned char col);
  350. void LCD_Refresh(void);

  351. void LCD_ShowChar(unsigned char page, unsigned char col, unsigned char ch);
  352. void LCD_ShowString(unsigned char page, unsigned char col, unsigned char *str);
  353. void LCD_ShowNumber(unsigned char page, unsigned char col, unsigned long num, unsigned char len);
  354. void LCD_ShowSignedFloat(unsigned char page, unsigned char col, long num_x100, unsigned char int_len, unsigned char dec_len);
  355. void LCD_ShowFloat(unsigned char page, unsigned char col, unsigned long num_x100, unsigned char int_len, unsigned char dec_len);

  356. void LCD_ShowBigPic(unsigned char page, unsigned char col, unsigned char width, unsigned char height, unsigned char code *pic);
  357. void LCD_ShowBigNum(unsigned char page, unsigned char col, unsigned char num);
  358. void LCD_ShowBigSignedFloat(unsigned char page, unsigned char col, long num_x100, unsigned char int_digits, unsigned char dec_digits);
  359. void LCD_ShowBigFloat(unsigned char page, unsigned char col, unsigned long num_x100, unsigned char int_digits, unsigned char dec_digits);

  360. void LCD_Update_Normal(void);
  361. void LCD_Update_Setting(void);
  362. void LCD_Update_Calibration(void);

  363. unsigned int ADC_Read(unsigned char channel);
  364. unsigned int ADC_GetAverage(unsigned int *buf);
  365. void ADC_Sample(void);

  366. void Calculate_Voltage(void);
  367. void Calculate_Current(void);
  368. void Calculate_Power(void);
  369. void Coulomb_Integrate(void);
  370. void Calculate_Percentage(void);
  371. void Calculate_Temperature(void);
  372. unsigned int get_temperature_adc(unsigned int adc);

  373. void Key_Scan(void);
  374. void Key_Process(void);

  375. void EEPROM_Read(unsigned int addr, unsigned char *buf, unsigned char len);
  376. void EEPROM_Write(unsigned int addr, unsigned char *buf, unsigned char len);
  377. void Load_Parameters(void);
  378. void Save_Parameters(void);

  379. void Delay_ms(unsigned int ms);

  380. // ============================================================================
  381. //  主函数
  382. // ============================================================================

  383. void main(void)
  384. {
  385.     System_Init();

  386.     UART1_SendString("BOOT ");
  387.     UART1_SendString((unsigned char *)VERSION);
  388.     UART1_SendCRLF();

  389.     Load_Parameters();

  390.     UART1_SendString("CAP=");
  391.     UART1_SendNumber(total_capacity);
  392.     UART1_SendString(" CAL=");
  393.     UART1_SendNumber((unsigned long)cal_voltage_beiShu);
  394.     UART1_SendString(",");
  395.     UART1_SendNumber((unsigned long)cal_current_beiShu);
  396.     UART1_SendCRLF();

  397.     LCD_Init();
  398.     LCD_Clear();

  399.     LCD_ShowString(3, 20, "Coulometer");
  400.     LCD_ShowString(5, 40, VERSION);
  401.     LCD_Refresh();
  402.     Delay_ms(1500);

  403.     LCD_Clear();
  404.     LCD_Refresh();

  405.     sys_running = 1;

  406.     while(1)
  407.     {
  408.         if(flag_adc_sample)
  409.         {
  410.             flag_adc_sample = 0;
  411.             ADC_Sample();
  412.         }

  413.         if(flag_coulomb_int)
  414.         {
  415.             flag_coulomb_int = 0;
  416.             Calculate_Voltage();
  417.             Calculate_Current();
  418.             Calculate_Power();
  419.             Calculate_Temperature();
  420.             Coulomb_Integrate();
  421.             Calculate_Percentage();
  422.         }

  423.         if(flag_key_scan)
  424.         {
  425.             flag_key_scan = 0;
  426.             Key_Scan();
  427.             Key_Process();
  428.         }

  429.         if(flag_display_refresh)
  430.         {
  431.             flag_display_refresh = 0;
  432.             if(cal_mode == 1)
  433.                 LCD_Update_Calibration();
  434.             else if(display_mode == 0)
  435.                 LCD_Update_Normal();
  436.             else
  437.                 LCD_Update_Setting();
  438.         }

  439.         _nop_();
  440.     }
  441. }

  442. // ============================================================================
  443. //  系统初始化
  444. // ============================================================================

  445. void System_Init(void)
  446. {
  447.     Clock_Init();
  448.     GPIO_Init();
  449.     Timer0_Init();
  450.     ADC_Init();
  451.     UART1_Init();
  452.     EA = 1;
  453. }

  454. void Clock_Init(void)
  455. {
  456. }

  457. // ============================================================================
  458. //  【修改】GPIO初始化 - 按键换到独立引脚
  459. // ============================================================================
  460. void GPIO_Init(void)
  461. {
  462.     // P1口: P1.0=电流ADC0, P1.1=KEY_UP, P1.2=KEY_DOWN, P1.6=电压ADC6, P1.7=温度ADC7
  463.     // 0xC7 = 1100 0111b → P1.0, P1.1, P1.2, P1.6, P1.7 高阻输入
  464.     P1M1 = 0xC7;
  465.     P1M0 = 0x00;

  466.     // P3口配置:
  467.     // 全部输出(强推挽): P3.4=LCD_RST, P3.5=LCD_A0, P3.6=LCD_SCL, P3.7=LCD_SDA
  468.     // P3.0-P3.3 未使用,设为输出避免悬空
  469.     // P3M1 = 0x00
  470.     // P3M0 = 0xFF = 1111 1111b → P3全部强推挽输出
  471.     P3M1 = 0x00;
  472.     P3M0 = 0xFF;

  473.     // P5口: P5.4=KEY_MENU(输入), P5.5=LCD_CS(输出)
  474.     // P5M1 = 0x10 = 0001 0000b → P5.4 高阻输入
  475.     // P5M0 = 0x20 = 0010 0000b → P5.5 强推挽输出
  476.     P5M1 = 0x10;
  477.     P5M0 = 0x20;

  478.     LCD_CS = 1;
  479.     LCD_A0 = 0;
  480.     LCD_SCL = 0;
  481.     LCD_SDA = 0;
  482.     LCD_RST = 1;

  483.     KEY_MENU = 1;
  484.     KEY_UP = 1;
  485.     KEY_DOWN = 1;
  486. }

  487. void Timer0_Init(void)
  488. {
  489.     AUXR &= 0x7F;
  490.     TMOD &= 0xF0;
  491.     TMOD |= 0x00;

  492.     TL0 = TIMER0_RELOAD_L;
  493.     TH0 = TIMER0_RELOAD_H;

  494.     TF0 = 0;
  495.     TR0 = 1;
  496.     ET0 = 1;
  497. }

  498. void ADC_Init(void)
  499. {
  500.     ADCCFG = 0x00;
  501.     ADC_CONTR = 0x00;
  502.     Delay_ms(1);
  503.     ADC_CONTR = ADC_POWER;
  504.     Delay_ms(1);
  505. }

  506. // ============================================================================
  507. //  【修复】串口初始化 - 修正波特率9600@35MHz
  508. // ============================================================================
  509. // 35MHz, T1x12=1, SMOD=0, 定时器1模式2(8位自动重装)
  510. // Baud = (1/32) * 35000000 / (256-TH1) = 9600
  511. // TH1 = 256 - 35000000/32/9600 = 256 - 114 = 142 = 0x8E
  512. // ============================================================================
  513. void UART1_Init(void)
  514. {
  515.     SCON = 0x50;        // 模式1, 允许接收
  516.     AUXR |= 0x40;       // T1x12=1, 定时器1时钟=Fosc/1
  517.     AUXR &= 0xFE;       // S1ST2=0, 串口1选定时器1

  518.     TMOD &= 0x0F;       // 清定时器1模式位
  519.     TMOD |= 0x20;       // 定时器1模式2(8位自动重装)

  520.     TH1 = 0x8E;         // 9600bps [url=home.php?mod=space&uid=3057940]@[/url] 35MHz
  521.     TL1 = 0x8E;

  522.     TR1 = 1;
  523.     ES = 1;
  524. }

  525. // ============================================================================
  526. //  【新增】串口调试函数
  527. // ============================================================================

  528. void UART1_SendByte(unsigned char dat)
  529. {
  530.     SBUF = dat;
  531.     while(!TI);
  532.     TI = 0;
  533. }

  534. void UART1_SendString(unsigned char *str)
  535. {
  536.     while(*str != '\0')
  537.     {
  538.         UART1_SendByte(*str);
  539.         str++;
  540.     }
  541. }

  542. void UART1_SendNumber(unsigned long num)
  543. {
  544.     unsigned char buf[12];
  545.     unsigned char i = 0;

  546.     if(num == 0)
  547.     {
  548.         UART1_SendByte('0');
  549.         return;
  550.     }

  551.     while(num > 0)
  552.     {
  553.         buf[i++] = num % 10 + '0';
  554.         num /= 10;
  555.     }

  556.     while(i > 0)
  557.     {
  558.         UART1_SendByte(buf[--i]);
  559.     }
  560. }

  561. void UART1_SendHex(unsigned char hex)
  562. {
  563.     unsigned char h = hex >> 4;
  564.     unsigned char l = hex & 0x0F;

  565.     UART1_SendByte(h < 10 ? h + '0' : h - 10 + 'A');
  566.     UART1_SendByte(l < 10 ? l + '0' : l - 10 + 'A');
  567. }

  568. void UART1_SendCRLF(void)
  569. {
  570.     UART1_SendByte('\r');
  571.     UART1_SendByte('\n');
  572. }

  573. // ============================================================================
  574. //  定时器0中断 (1ms)
  575. // ============================================================================

  576. void Timer0_ISR(void) interrupt 1
  577. {
  578.     static unsigned int sec_cnt = 0;

  579.     timer1ms_cnt++;
  580.     timer10ms_cnt++;
  581.     timer100ms_cnt++;
  582.     timer500ms_cnt++;
  583.     sec_cnt++;

  584.     if(sec_cnt >= 1000)
  585.     {
  586.         sec_cnt = 0;
  587.         run_seconds++;
  588.     }

  589.     if(timer10ms_cnt >= 10)
  590.     {
  591.         timer10ms_cnt = 0;
  592.         flag_adc_sample = 1;
  593.     }

  594.     if(timer1ms_cnt % 20 == 0)
  595.     {
  596.         flag_key_scan = 1;
  597.     }

  598.     if(timer100ms_cnt >= 100)
  599.     {
  600.         timer100ms_cnt = 0;
  601.         flag_coulomb_int = 1;
  602.     }

  603.     if(timer500ms_cnt >= 500)
  604.     {
  605.         timer500ms_cnt = 0;
  606.         flag_display_refresh = 1;
  607.     }
  608. }

  609. // ============================================================================
  610. //  ADC操作
  611. // ============================================================================

  612. unsigned int ADC_Read(unsigned char channel)
  613. {
  614.     unsigned int adc_value;

  615.     ADC_CONTR = ADC_POWER | ADC_START | (channel & 0x0F);

  616.     _nop_();
  617.     _nop_();
  618.     _nop_();
  619.     _nop_();

  620.     while(!(ADC_CONTR & ADC_FLAG));

  621.     ADC_CONTR &= ~ADC_FLAG;

  622.     adc_value = (ADC_RES & 0x0F) << 8;
  623.     adc_value |= ADC_RESL;

  624.     return adc_value;
  625. }

  626. unsigned int ADC_GetAverage(unsigned int *buf)
  627. {
  628.     unsigned long sum = 0;
  629.     unsigned char i;

  630.     for(i = 0; i < ADC_FILTER_LEN; i++)
  631.     {
  632.         sum += buf[i];
  633.     }

  634.     return (unsigned int)(sum >> 3);
  635. }

  636. // ============================================================================
  637. //  【修改】ADC采样 - 电流ADC0(P1.0), 电压ADC6(P1.6), 温度ADC7(P1.7)
  638. // ============================================================================
  639. void ADC_Sample(void)
  640. {
  641.     // 【修改】电流→ADC0(P1.0), 电压→ADC6(P1.6) 互换
  642.     adc_current_buf[adc_buf_index] = ADC_Read(0);     // 电流采样 → ADC0
  643.     adc_voltage_buf[adc_buf_index] = ADC_Read(6);     // 电压采样 → ADC6
  644.     adc_temp_buf[adc_buf_index] = ADC_Read(TEMPERATURE_CHANNEL);  // 温度 → ADC7

  645.     adc_buf_index++;
  646.     if(adc_buf_index >= ADC_FILTER_LEN)
  647.     {
  648.         adc_buf_index = 0;
  649.     }
  650. }

  651. // ============================================================================
  652. //  测量计算
  653. // ============================================================================

  654. void Calculate_Voltage(void)
  655. {
  656.     unsigned int adc_avg;
  657.     long voltage_mv;
  658.     long temp;

  659.     adc_avg = ADC_GetAverage(adc_voltage_buf);

  660.     // 应用零点校准
  661.     if(adc_avg >= cal_voltage_lingDian)
  662.         adc_avg -= cal_voltage_lingDian;
  663.     else
  664.         adc_avg = 0;

  665.     // 计算电压值 (mV)
  666.     voltage_mv = (long)adc_avg * ADC_VREF / ADC_RESOLUTION;

  667.     // 应用分压比和倍率校准
  668.     temp = voltage_mv * VOLTAGE_RATIO;
  669.     temp = temp * (long)cal_voltage_beiShu / 1000L;

  670.     voltage_x100 = (unsigned long)(temp / 10);

  671.     if(voltage_x100 > 9900) voltage_x100 = 9900;
  672. }

  673. void Calculate_Current(void)
  674. {
  675.     unsigned int adc_avg;
  676.     unsigned long voltage_mv;
  677.     long current_ma;

  678.     adc_avg = ADC_GetAverage(adc_current_buf);

  679.     voltage_mv = (unsigned long)adc_avg * ADC_VREF / ADC_RESOLUTION;

  680.     if(voltage_mv >= INA199_VREF)
  681.     {
  682.         current_ma = (long)(voltage_mv - INA199_VREF) * 5;
  683.     }
  684.     else
  685.     {
  686.         current_ma = -(long)(INA199_VREF - voltage_mv) * 5;
  687.     }

  688.     current_x100 = current_ma / 10;

  689.     if(current_x100 > 1500) current_x100 = 1500;
  690.     if(current_x100 < -1500) current_x100 = -1500;
  691. }

  692. void Calculate_Power(void)
  693. {
  694.     long power;

  695.     power = (long)voltage_x100 * current_x100 / 1000;

  696.     if(power < 0) power = -power;

  697.     power_x10 = (unsigned long)power;

  698.     wh_x100 = power_x10 * 100 / 36000;
  699.     if(wh_x100 > 999999) wh_x100 = 999999;
  700. }

  701. void Coulomb_Integrate(void)
  702. {
  703.     long dQ_ma_ms;

  704.     dQ_ma_ms = current_x100 * 10 * 100;

  705.     coulomb_accumulator += dQ_ma_ms;

  706.     while(coulomb_accumulator >= 3600000L)
  707.     {
  708.         coulomb_accumulator -= 3600000L;
  709.         remaining_capacity--;
  710.     }

  711.     while(coulomb_accumulator <= -3600000L)
  712.     {
  713.         coulomb_accumulator += 3600000L;
  714.         remaining_capacity++;
  715.     }

  716.     if(remaining_capacity > (long)total_capacity)
  717.         remaining_capacity = (long)total_capacity;
  718.     if(remaining_capacity < 0)
  719.         remaining_capacity = 0;
  720. }

  721. void Calculate_Percentage(void)
  722. {
  723.     if(total_capacity > 0)
  724.     {
  725.         percentage = (unsigned char)(remaining_capacity * 100 / (long)total_capacity);
  726.     }
  727.     else
  728.     {
  729.         percentage = 0;
  730.     }

  731.     if(percentage > 100) percentage = 100;
  732. }

  733. // ============================================================================
  734. //  温度计算
  735. // ============================================================================

  736. unsigned int get_temperature_adc(unsigned int adc)
  737. {
  738.     unsigned char min, max, mid;
  739.     unsigned int result;

  740.     if(adc < temp_table[0]) return 0xFFFE;
  741.     if(adc > temp_table[160]) return 0xFFFF;

  742.     min = 0;
  743.     max = 160;

  744.     while(min < max)
  745.     {
  746.         mid = (min + max) >> 1;
  747.         if(adc <= temp_table[mid])
  748.             max = mid;
  749.         else
  750.             min = mid + 1;
  751.     }

  752.     result = (unsigned int)(min - 40) * 10;
  753.     return result;
  754. }

  755. void Calculate_Temperature(void)
  756. {
  757.     unsigned int adc_avg;
  758.     unsigned int temp_result;

  759.     adc_avg = ADC_GetAverage(adc_temp_buf);
  760.     adc_temp_raw = adc_avg;

  761.     temp_result = get_temperature_adc(adc_avg);

  762.     if(temp_result == 0xFFFE)
  763.         temperature_x10 = 0;
  764.     else if(temp_result == 0xFFFF)
  765.         temperature_x10 = 255;
  766.     else
  767.         temperature_x10 = (unsigned char)(temp_result / 10);
  768. }

  769. // ============================================================================
  770. //  LCD驱动 (ST7567 4线SPI)
  771. // ============================================================================

  772. void SPI_WriteByte(unsigned char dat)
  773. {
  774.     unsigned char i;

  775.     for(i = 0; i < 8; i++)
  776.     {
  777.         LCD_SCL = 0;

  778.         if(dat & 0x80)
  779.             LCD_SDA = 1;
  780.         else
  781.             LCD_SDA = 0;

  782.         LCD_SCL = 1;
  783.         dat <<= 1;
  784.     }

  785.     LCD_SCL = 0;
  786. }

  787. void LCD_WriteCmd(unsigned char cmd)
  788. {
  789.     LCD_CS = 0;
  790.     LCD_A0 = 0;
  791.     SPI_WriteByte(cmd);
  792.     LCD_CS = 1;
  793. }

  794. void LCD_WriteData(unsigned char dat)
  795. {
  796.     LCD_CS = 0;
  797.     LCD_A0 = 1;
  798.     SPI_WriteByte(dat);
  799.     LCD_CS = 1;
  800. }

  801. void LCD_Init(void)
  802. {
  803.     LCD_RST = 0;
  804.     Delay_ms(10);
  805.     LCD_RST = 1;
  806.     Delay_ms(10);

  807.     LCD_WriteCmd(0xE2);
  808.     Delay_ms(10);

  809.     LCD_WriteCmd(0xA2);
  810.     LCD_WriteCmd(0xA0);
  811.     LCD_WriteCmd(0xC8);
  812.     LCD_WriteCmd(0x2F);
  813.     Delay_ms(50);

  814.     LCD_WriteCmd(0x24);
  815.     LCD_WriteCmd(0x81);
  816.     LCD_WriteCmd(0x25);

  817.     LCD_WriteCmd(0x40);
  818.     LCD_WriteCmd(0xAF);

  819.     LCD_Clear();
  820. }

  821. void LCD_Clear(void)
  822. {
  823.     unsigned int i;

  824.     for(i = 0; i < 1024; i++)
  825.     {
  826.         lcd_buffer[i] = 0x00;
  827.     }
  828. }

  829. void LCD_SetPos(unsigned char page, unsigned char col)
  830. {
  831.     LCD_WriteCmd(0xB0 + page);
  832.     LCD_WriteCmd(0x10 + (col >> 4));
  833.     LCD_WriteCmd(0x00 + (col & 0x0F));
  834. }

  835. // ============================================================================
  836. //  LCD显示函数 (6x8)
  837. // ============================================================================

  838. void LCD_ShowChar(unsigned char page, unsigned char col, unsigned char ch)
  839. {
  840.     unsigned char i;
  841.     unsigned char index;

  842.     if(ch < 0x20 || ch > 0x7A)
  843.         ch = 0x20;

  844.     index = ch - 0x20;

  845.     for(i = 0; i < 6; i++)
  846.     {
  847.         if(col + i < 128)
  848.         {
  849.             lcd_buffer[page * 128 + col + i] = font_6x8[index][i];
  850.         }
  851.     }
  852. }

  853. void LCD_ShowString(unsigned char page, unsigned char col, unsigned char *str)
  854. {
  855.     while(*str != '\0')
  856.     {
  857.         LCD_ShowChar(page, col, *str);
  858.         col += 6;
  859.         str++;
  860.     }
  861. }

  862. void LCD_ShowNumber(unsigned char page, unsigned char col, unsigned long num, unsigned char len)
  863. {
  864.     unsigned char buf[10];
  865.     unsigned char i;

  866.     for(i = 0; i < len; i++)
  867.     {
  868.         buf[len - 1 - i] = num % 10 + '0';
  869.         num /= 10;
  870.     }

  871.     for(i = 0; i < len; i++)
  872.     {
  873.         LCD_ShowChar(page, col + i * 6, buf[i]);
  874.     }
  875. }

  876. void LCD_ShowSignedFloat(unsigned char page, unsigned char col, long num_x100, unsigned char int_len, unsigned char dec_len)
  877. {
  878.     unsigned char buf[12];
  879.     unsigned char i = 0;
  880.     unsigned char pos = 0;
  881.     unsigned long abs_val;

  882.     if(num_x100 < 0)
  883.     {
  884.         buf[pos++] = '-';
  885.         abs_val = (unsigned long)(-num_x100);
  886.     }
  887.     else
  888.     {
  889.         buf[pos++] = ' ';
  890.         abs_val = (unsigned long)num_x100;
  891.     }

  892.     {
  893.         unsigned long div = 1;
  894.         unsigned char j;
  895.         unsigned char leading_zero = 1;

  896.         for(j = 1; j < int_len; j++)
  897.             div *= 10;

  898.         for(j = 0; j < int_len; j++)
  899.         {
  900.             unsigned char digit = abs_val / div / 100;
  901.             if(digit > 0 || !leading_zero || j == int_len - 1)
  902.             {
  903.                 buf[pos++] = digit + '0';
  904.                 leading_zero = 0;
  905.             }
  906.             else
  907.             {
  908.                 buf[pos++] = ' ';
  909.             }
  910.             abs_val %= div * 100;
  911.             div /= 10;
  912.         }
  913.     }

  914.     buf[pos++] = '.';

  915.     {
  916.         unsigned long frac = abs_val % 100;
  917.         unsigned char digit1 = frac / 10;
  918.         unsigned char digit2 = frac % 10;

  919.         if(dec_len >= 1) buf[pos++] = digit1 + '0';
  920.         if(dec_len >= 2) buf[pos++] = digit2 + '0';
  921.     }

  922.     for(i = 0; i < pos; i++)
  923.     {
  924.         LCD_ShowChar(page, col + i * 6, buf[i]);
  925.     }
  926. }

  927. void LCD_ShowFloat(unsigned char page, unsigned char col, unsigned long num_x100, unsigned char int_len, unsigned char dec_len)
  928. {
  929.     LCD_ShowSignedFloat(page, col, (long)num_x100, int_len, dec_len);
  930. }

  931. void LCD_Refresh(void)
  932. {
  933.     unsigned char page;
  934.     unsigned char col;

  935.     for(page = 0; page < 8; page++)
  936.     {
  937.         LCD_SetPos(page, 0);

  938.         for(col = 0; col < 128; col++)
  939.         {
  940.             LCD_WriteData(lcd_buffer[page * 128 + col]);
  941.         }
  942.     }
  943. }

  944. // ============================================================================
  945. //  大字体显示函数 (10x24)
  946. // ============================================================================

  947. void LCD_ShowBigPic(unsigned char page, unsigned char col, unsigned char width, unsigned char height, unsigned char code *pic)
  948. {
  949.     unsigned char i, j;
  950.     unsigned char idx = 0;

  951.     for(j = 0; j < height; j++)
  952.     {
  953.         for(i = 0; i < width; i++)
  954.         {
  955.             if(col + i < 128 && page + j < 8)
  956.             {
  957.                 lcd_buffer[(page + j) * 128 + col + i] = pic[idx++];
  958.             }
  959.             else
  960.             {
  961.                 idx++;
  962.             }
  963.         }
  964.     }
  965. }

  966. void LCD_ShowBigNum(unsigned char page, unsigned char col, unsigned char num)
  967. {
  968.     if(num > 9) return;
  969.     LCD_ShowBigPic(page, col, 10, 3, big_num[num]);
  970. }

  971. void LCD_ShowBigSignedFloat(unsigned char page, unsigned char col, long num_x100, unsigned char int_digits, unsigned char dec_digits)
  972. {
  973.     unsigned char pos = 0;
  974.     unsigned char i;
  975.     unsigned long abs_val;
  976.     unsigned char current_col = col;

  977.     if(num_x100 < 0)
  978.     {
  979.         LCD_ShowChar(page + 1, current_col, '-');
  980.         current_col += 6;
  981.         abs_val = (unsigned long)(-num_x100);
  982.     }
  983.     else
  984.     {
  985.         abs_val = (unsigned long)num_x100;
  986.     }

  987.     {
  988.         unsigned long div = 1;
  989.         unsigned char j;
  990.         unsigned char leading_zero = 1;

  991.         for(j = 1; j < int_digits; j++)
  992.             div *= 10;

  993.         for(j = 0; j < int_digits; j++)
  994.         {
  995.             unsigned char digit = abs_val / div / 100;
  996.             if(digit > 0 || !leading_zero || j == int_digits - 1)
  997.             {
  998.                 LCD_ShowBigNum(page, current_col, digit);
  999.                 current_col += 10;
  1000.                 leading_zero = 0;
  1001.             }
  1002.             else
  1003.             {
  1004.                 current_col += 10;
  1005.             }
  1006.             abs_val %= div * 100;
  1007.             div /= 10;
  1008.         }
  1009.     }

  1010.     LCD_ShowBigPic(page + 1, current_col, 8, 2, strPoint);
  1011.     current_col += 8;

  1012.     {
  1013.         unsigned long frac = abs_val % 100;
  1014.         unsigned char digit1 = frac / 10;
  1015.         unsigned char digit2 = frac % 10;

  1016.         if(dec_digits >= 1)
  1017.         {
  1018.             LCD_ShowBigNum(page, current_col, digit1);
  1019.             current_col += 10;
  1020.         }
  1021.         if(dec_digits >= 2)
  1022.         {
  1023.             LCD_ShowBigNum(page, current_col, digit2);
  1024.             current_col += 10;
  1025.         }
  1026.     }
  1027. }

  1028. void LCD_ShowBigFloat(unsigned char page, unsigned char col, unsigned long num_x100, unsigned char int_digits, unsigned char dec_digits)
  1029. {
  1030.     LCD_ShowBigSignedFloat(page, col, (long)num_x100, int_digits, dec_digits);
  1031. }

  1032. // ============================================================================
  1033. //  显示界面更新 - 大字体版
  1034. // ============================================================================

  1035. void LCD_Update_Normal(void)
  1036. {
  1037.     unsigned char col;
  1038.     unsigned long cap_for_display;

  1039.     LCD_Clear();

  1040.     // 第1行: 电压 (Page 0-2, 左)
  1041.     LCD_ShowBigFloat(0, 0, voltage_x100, 2, 2);
  1042.     LCD_ShowBigPic(1, 50, 8, 2, strV);

  1043.     // 第1行: 容量Ah (Page 0-2, 右)
  1044.     cap_for_display = (unsigned long)(remaining_capacity / 10);
  1045.     LCD_ShowBigFloat(0, 66, cap_for_display, 2, 2);
  1046.     LCD_ShowString(2, 116, "Ah");

  1047.     // 第2行: 功率 (Page 3-5, 左)
  1048.     LCD_ShowBigFloat(3, 0, power_x10, 3, 1);
  1049.     LCD_ShowBigPic(4, 50, 8, 2, strW);

  1050.     // 第2行: 电流 (Page 3-5, 右)
  1051.     LCD_ShowBigSignedFloat(3, 66, current_x100, 2, 2);
  1052.     LCD_ShowBigPic(4, 120, 8, 2, strA);

  1053.     // ========== 第3行: 电池百分比 (Page 6, 6x8小字体) ==========
  1054.     {
  1055.         LCD_ShowString(6, 0, "BAT");
  1056.         LCD_ShowNumber(6, 24, percentage, 3);
  1057.         LCD_ShowChar(6, 42, '%');
  1058.     }

  1059.     // ========== 第4行: 时间和温度 (Page 7, 6x8小字体) ==========
  1060.     {
  1061.         unsigned long rs = run_seconds;
  1062.         unsigned char hours = rs / 3600;
  1063.         unsigned char minutes = (rs % 3600) / 60;
  1064.         unsigned char seconds = rs % 60;

  1065.         // 时间显示
  1066.         LCD_ShowNumber(7, 0, hours, 2);
  1067.         LCD_ShowChar(7, 12, ':');
  1068.         LCD_ShowNumber(7, 18, minutes, 2);
  1069.         LCD_ShowChar(7, 30, ':');
  1070.         LCD_ShowNumber(7, 36, seconds, 2);
  1071.         LCD_ShowChar(7, 48, 'T');

  1072.         // 温度显示 - 纯6x8小字体
  1073.         {
  1074.             unsigned char buf[8];
  1075.             unsigned char t = temperature_x10;
  1076.             unsigned char i = 0;

  1077.             if(t >= 100) {
  1078.                 buf[i++] = t / 100 + '0';
  1079.                 t %= 100;
  1080.             }
  1081.             if(t >= 10) {
  1082.                 buf[i++] = t / 10 + '0';
  1083.             } else {
  1084.                 buf[i++] = '0';
  1085.             }
  1086.             buf[i++] = t % 10 + '0';
  1087.             buf[i++] = '.';
  1088.             buf[i++] = '0';
  1089.             buf[i++] = 'C';
  1090.             buf[i] = '\0';

  1091.             LCD_ShowString(7, 72, buf);
  1092.         }
  1093.     }

  1094.     LCD_Refresh();
  1095. }

  1096. void LCD_Update_Setting(void)
  1097. {
  1098.     LCD_Clear();

  1099.     LCD_ShowString(4, 20, "Set Capacity");
  1100.     LCD_ShowString(5, 0, "Capacity:");
  1101.     LCD_ShowFloat(6, 0, (unsigned long)(temp_capacity / 10), 4, 2);
  1102.     LCD_ShowString(6, 54, "Ah");

  1103.     LCD_ShowString(7, 0, "+    OK    -");

  1104.     LCD_Refresh();
  1105. }

  1106. // ============================================================================
  1107. //  校准界面显示 - 大字体
  1108. // ============================================================================

  1109. void LCD_Update_Calibration(void)
  1110. {
  1111.     unsigned long display_val;

  1112.     LCD_Clear();

  1113.     if(cal_menu <= 1)
  1114.     {
  1115.         LCD_ShowString(0, 0, "U CAL");
  1116.         if(cal_menu == 0) LCD_ShowString(0, 40, "ZERO");
  1117.         else LCD_ShowString(0, 40, "RATE");

  1118.         if(cal_menu == 0)
  1119.         {
  1120.             display_val = (unsigned long)cal_voltage_lingDian * 100;
  1121.             LCD_ShowBigFloat(1, 0, display_val, 2, 2);
  1122.         }
  1123.         else
  1124.         {
  1125.             display_val = (unsigned long)cal_voltage_beiShu;
  1126.             LCD_ShowBigFloat(1, 0, display_val, 4, 0);
  1127.         }
  1128.     }
  1129.     else
  1130.     {
  1131.         LCD_ShowString(0, 0, "U NOW");
  1132.         LCD_ShowBigFloat(1, 0, voltage_x100, 2, 2);
  1133.         LCD_ShowBigPic(2, 50, 8, 2, strV);
  1134.     }

  1135.     if(cal_menu >= 2)
  1136.     {
  1137.         LCD_ShowString(4, 0, "I CAL");
  1138.         if(cal_menu == 2) LCD_ShowString(4, 40, "ZERO");
  1139.         else LCD_ShowString(4, 40, "RATE");

  1140.         if(cal_menu == 2)
  1141.         {
  1142.             display_val = (unsigned long)cal_current_lingDian * 100;
  1143.             LCD_ShowBigFloat(5, 0, display_val, 2, 2);
  1144.         }
  1145.         else
  1146.         {
  1147.             display_val = (unsigned long)cal_current_beiShu;
  1148.             LCD_ShowBigFloat(5, 0, display_val, 4, 0);
  1149.         }
  1150.     }
  1151.     else
  1152.     {
  1153.         LCD_ShowString(4, 0, "I NOW");
  1154.         LCD_ShowBigSignedFloat(5, 0, current_x100, 2, 2);
  1155.         LCD_ShowBigPic(6, 116, 8, 2, strA);
  1156.     }

  1157.     LCD_ShowString(7, 0, "+    SAVE   -");

  1158.     if(cal_menu == 0) LCD_ShowString(7, 60, "<U0>");
  1159.     else if(cal_menu == 1) LCD_ShowString(7, 60, "<Ub>");
  1160.     else if(cal_menu == 2) LCD_ShowString(7, 60, "<I0>");
  1161.     else LCD_ShowString(7, 60, "<Ib>");

  1162.     LCD_Refresh();
  1163. }

  1164. // ============================================================================
  1165. //  【修改】按键扫描 - 适配新按键引脚
  1166. // ============================================================================

  1167. void Key_Scan(void)
  1168. {
  1169.     unsigned char key_temp = 0;

  1170.     // 【修改】按键引脚: P1.1=KEY_UP(加一), P5.4=KEY_MENU(菜单), P1.2=KEY_DOWN(减一)
  1171.     if(KEY_UP == 0)    key_temp |= 0x01;   // 加一键 P1.1
  1172.     if(KEY_MENU == 0)  key_temp |= 0x02;   // 菜单/切换键 P5.4
  1173.     if(KEY_DOWN == 0)  key_temp |= 0x04;   // 减一键 P1.2

  1174.     if(key_temp != key_state)
  1175.     {
  1176.         key_state = key_temp;
  1177.         key_hold_cnt = 0;
  1178.     }
  1179.     else
  1180.     {
  1181.         if(key_hold_cnt < 65535)
  1182.             key_hold_cnt++;
  1183.     }

  1184.     // 【修改】长按检测:加一键(KEY_UP/P3.1)长按3秒进入校准模式
  1185.     if(cal_mode == 0 && display_mode == 0 && (key_state & 0x01) && key_hold_cnt >= 150)
  1186.     {
  1187.         cal_mode = 1;
  1188.         cal_menu = 0;
  1189.         key_hold_cnt = 0;
  1190.         key_press = 0;
  1191.         return;
  1192.     }

  1193.     if(key_hold_cnt == 2)
  1194.     {
  1195.         key_press = key_state;
  1196.     }
  1197.     else
  1198.     {
  1199.         key_press = 0;
  1200.     }
  1201. }

  1202. // ============================================================================
  1203. //  【修改】按键处理 - 适配新按键布局
  1204. // ============================================================================
  1205. void Key_Process(void)
  1206. {
  1207.     static unsigned char xdata setting_item = 0;

  1208.     if(key_press == 0) return;

  1209.     // 校准模式按键处理
  1210.     if(cal_mode == 1)
  1211.     {
  1212.         if(key_press & 0x01)  // 加一键(KEY_UP)
  1213.         {
  1214.             switch(cal_menu)
  1215.             {
  1216.                 case 0:
  1217.                     if(cal_voltage_lingDian < 100) cal_voltage_lingDian++;
  1218.                     break;
  1219.                 case 1:
  1220.                     cal_voltage_beiShu += 10;
  1221.                     if(cal_voltage_beiShu > 5000) cal_voltage_beiShu = 5000;
  1222.                     break;
  1223.                 case 2:
  1224.                     if(cal_current_lingDian < 100) cal_current_lingDian++;
  1225.                     break;
  1226.                 case 3:
  1227.                     cal_current_beiShu += 10;
  1228.                     if(cal_current_beiShu > 5000) cal_current_beiShu = 5000;
  1229.                     break;
  1230.             }
  1231.         }
  1232.         else if(key_press & 0x04)  // 减一键(KEY_DOWN)
  1233.         {
  1234.             switch(cal_menu)
  1235.             {
  1236.                 case 0:
  1237.                     if(cal_voltage_lingDian > 0) cal_voltage_lingDian--;
  1238.                     break;
  1239.                 case 1:
  1240.                     if(cal_voltage_beiShu >= 10) cal_voltage_beiShu -= 10;
  1241.                     break;
  1242.                 case 2:
  1243.                     if(cal_current_lingDian > 0) cal_current_lingDian--;
  1244.                     break;
  1245.                 case 3:
  1246.                     if(cal_current_beiShu >= 10) cal_current_beiShu -= 10;
  1247.                     break;
  1248.             }
  1249.         }
  1250.         else if(key_press & 0x02)  // 菜单键(KEY_MENU) - 切换菜单项或保存
  1251.         {
  1252.             if(cal_menu < 3)
  1253.             {
  1254.                 cal_menu++;
  1255.             }
  1256.             else
  1257.             {
  1258.                 cal_menu = 0;
  1259.                 cal_mode = 0;
  1260.                 Save_Parameters();
  1261.             }
  1262.         }
  1263.         return;
  1264.     }

  1265.     // 正常模式按键处理
  1266.     switch(display_mode)
  1267.     {
  1268.         case 0:
  1269.             if(key_press & 0x02)  // 菜单键(KEY_MENU)短按 - 进入容量设置
  1270.             {
  1271.                 display_mode = 1;
  1272.                 setting_item = 0;
  1273.                 temp_capacity = total_capacity;
  1274.             }
  1275.             break;

  1276.         case 1:
  1277.             if(key_press & 0x01)  // 加一键(KEY_UP)
  1278.             {
  1279.                 if(setting_item == 0)
  1280.                 {
  1281.                     temp_capacity += 100;
  1282.                     if(temp_capacity > CAPACITY_MAX)
  1283.                         temp_capacity = CAPACITY_MAX;
  1284.                 }
  1285.             }
  1286.             else if(key_press & 0x04)  // 减一键(KEY_DOWN)
  1287.             {
  1288.                 if(setting_item == 0)
  1289.                 {
  1290.                     if(temp_capacity >= 100)
  1291.                         temp_capacity -= 100;
  1292.                 }
  1293.             }
  1294.             else if(key_press & 0x02)  // 菜单键(KEY_MENU) - 保存并退出
  1295.             {
  1296.                 total_capacity = temp_capacity;
  1297.                 remaining_capacity = total_capacity;
  1298.                 Save_Parameters();
  1299.                 display_mode = 0;
  1300.             }
  1301.             break;

  1302.         default:
  1303.             display_mode = 0;
  1304.             break;
  1305.     }
  1306. }

  1307. // ============================================================================
  1308. //  【终极修复】EEPROM操作 - STC官方标准时序
  1309. // ============================================================================
  1310. // STC8H3K64S2 IAP参数:
  1311. //   - 扇区大小: 512字节
  1312. //   - 35MHz时WT: 4 (IAP_CONTR = 0x84)
  1313. //   - 字节编程: 约30-40us
  1314. //   - 扇区擦除: 约5-10ms
  1315. // ============================================================================

  1316. void IAP_SectorErase(unsigned int addr)
  1317. {
  1318.     unsigned int sector;

  1319.     sector = addr & 0xFE00;     // 512字节扇区对齐

  1320.     EA = 0;

  1321.     IAP_CONTR = 0x84;             // 使能IAP, WT=4 (35MHz)
  1322.     IAP_CMD = 0x02;               // 扇区擦除命令
  1323.     IAP_ADDRH = (unsigned char)(sector >> 8);
  1324.     IAP_ADDRL = (unsigned char)(sector);
  1325.     IAP_TRIG = 0x5A;
  1326.     IAP_TRIG = 0xA5;

  1327.     _nop_();
  1328.     _nop_();
  1329.     _nop_();
  1330.     _nop_();
  1331.     _nop_();

  1332.     IAP_CONTR = 0x00;
  1333.     IAP_CMD = 0x00;

  1334.     EA = 1;
  1335. }

  1336. void IAP_ByteRead(unsigned int addr, unsigned char *buf, unsigned char len)
  1337. {
  1338.     unsigned char i;

  1339.     EA = 0;

  1340.     for(i = 0; i < len; i++)
  1341.     {
  1342.         IAP_CONTR = 0x84;
  1343.         IAP_CMD = 0x01;           // 字节读
  1344.         IAP_ADDRH = (unsigned char)(addr >> 8);
  1345.         IAP_ADDRL = (unsigned char)(addr);
  1346.         IAP_TRIG = 0x5A;
  1347.         IAP_TRIG = 0xA5;
  1348.         _nop_();
  1349.         _nop_();

  1350.         buf[i] = IAP_DATA;
  1351.         addr++;
  1352.     }

  1353.     IAP_CONTR = 0x00;
  1354.     IAP_CMD = 0x00;

  1355.     EA = 1;
  1356. }

  1357. void IAP_ByteWrite(unsigned int addr, unsigned char *buf, unsigned char len)
  1358. {
  1359.     unsigned char i;

  1360.     EA = 0;

  1361.     for(i = 0; i < len; i++)
  1362.     {
  1363.         IAP_CONTR = 0x84;
  1364.         IAP_CMD = 0x03;           // 字节编程
  1365.         IAP_ADDRH = (unsigned char)(addr >> 8);
  1366.         IAP_ADDRL = (unsigned char)(addr);
  1367.         IAP_DATA = buf[i];
  1368.         IAP_TRIG = 0x5A;
  1369.         IAP_TRIG = 0xA5;
  1370.         _nop_();
  1371.         _nop_();

  1372.         addr++;
  1373.     }

  1374.     IAP_CONTR = 0x00;
  1375.     IAP_CMD = 0x00;

  1376.     EA = 1;
  1377. }

  1378. // 兼容原函数名
  1379. #define EEPROM_Read     IAP_ByteRead
  1380. #define EEPROM_Write    IAP_ByteWrite

  1381. // ============================================================================
  1382. //  【修复】参数加载
  1383. // ============================================================================

  1384. void Load_Parameters(void)
  1385. {
  1386.     unsigned char buf[24];
  1387.     unsigned char i;

  1388.     IAP_ByteRead(0x0000, buf, 24);

  1389.     // 调试输出原始数据
  1390.     UART1_SendString("LOAD:");
  1391.     for(i = 0; i < 24; i++)
  1392.     {
  1393.         UART1_SendByte(' ');
  1394.         UART1_SendHex(buf[i]);
  1395.     }
  1396.     UART1_SendCRLF();

  1397.     // 容量
  1398.     total_capacity = ((unsigned long)buf[0] << 24) | ((unsigned long)buf[1] << 16) |
  1399.                      ((unsigned long)buf[2] << 8) | buf[3];

  1400.     if(total_capacity == 0xFFFFFFFF || total_capacity == 0)
  1401.     {
  1402.         total_capacity = DEFAULT_CAPACITY;
  1403.         UART1_SendString("CAP DEFAULT");
  1404.         UART1_SendCRLF();
  1405.     }

  1406.     // 剩余容量
  1407.     remaining_capacity = ((long)buf[4] << 24) | ((long)buf[5] << 16) |
  1408.                          ((long)buf[6] << 8) | buf[7];

  1409.     if(remaining_capacity < 0 || remaining_capacity > (long)total_capacity)
  1410.     {
  1411.         remaining_capacity = total_capacity;
  1412.     }

  1413.     // 校准参数 (buf[16]~buf[23])
  1414.     if(buf[22] == 0xAA && buf[23] == 0x55)
  1415.     {
  1416.         cal_voltage_beiShu = ((unsigned int)buf[16] << 8) | buf[17];
  1417.         cal_voltage_lingDian = buf[18];
  1418.         cal_current_beiShu = ((unsigned int)buf[19] << 8) | buf[20];
  1419.         cal_current_lingDian = buf[21];
  1420.         UART1_SendString("CAL OK");
  1421.         UART1_SendCRLF();
  1422.     }
  1423.     else
  1424.     {
  1425.         UART1_SendString("CAL INVALID");
  1426.         UART1_SendCRLF();
  1427.     }
  1428. }

  1429. // ============================================================================
  1430. //  【修复】参数保存 - 合并写入避免互相覆盖
  1431. // ============================================================================

  1432. void Save_Parameters(void)
  1433. {
  1434.     unsigned char buf[24];
  1435.     unsigned char i;

  1436.     // 组装所有数据 (0x0000-0x0017)
  1437.     buf[0]  = (unsigned char)(total_capacity >> 24);
  1438.     buf[1]  = (unsigned char)(total_capacity >> 16);
  1439.     buf[2]  = (unsigned char)(total_capacity >> 8);
  1440.     buf[3]  = (unsigned char)(total_capacity);

  1441.     buf[4]  = (unsigned char)(remaining_capacity >> 24);
  1442.     buf[5]  = (unsigned char)(remaining_capacity >> 16);
  1443.     buf[6]  = (unsigned char)(remaining_capacity >> 8);
  1444.     buf[7]  = (unsigned char)(remaining_capacity);

  1445.     buf[8]  = 0xFF; buf[9]  = 0xFF;
  1446.     buf[10] = 0xFF; buf[11] = 0xFF;
  1447.     buf[12] = 0xFF; buf[13] = 0xFF;
  1448.     buf[14] = 0xFF; buf[15] = 0xFF;

  1449.     buf[16] = (unsigned char)(cal_voltage_beiShu >> 8);
  1450.     buf[17] = (unsigned char)(cal_voltage_beiShu);
  1451.     buf[18] = cal_voltage_lingDian;
  1452.     buf[19] = (unsigned char)(cal_current_beiShu >> 8);
  1453.     buf[20] = (unsigned char)(cal_current_beiShu);
  1454.     buf[21] = cal_current_lingDian;
  1455.     buf[22] = 0xAA;
  1456.     buf[23] = 0x55;

  1457.     // 调试输出
  1458.     UART1_SendString("SAVE:");
  1459.     for(i = 0; i < 24; i++)
  1460.     {
  1461.         UART1_SendByte(' ');
  1462.         UART1_SendHex(buf[i]);
  1463.     }
  1464.     UART1_SendCRLF();

  1465.     // 先擦除扇区
  1466.     IAP_SectorErase(0x0000);
  1467.     Delay_ms(15);                 // 擦除需要5-10ms,给15ms保险

  1468.     // 写入数据
  1469.     IAP_ByteWrite(0x0000, buf, 24);
  1470.     Delay_ms(5);                  // 24字节编程约需1ms,给5ms保险

  1471.     // 读取验证
  1472.     {
  1473.         unsigned char readbuf[24];
  1474.         unsigned char ok = 1;
  1475.         IAP_ByteRead(0x0000, readbuf, 24);
  1476.         for(i = 0; i < 24; i++)
  1477.         {
  1478.             if(buf[i] != readbuf[i])
  1479.             {
  1480.                 ok = 0;
  1481.                 break;
  1482.             }
  1483.         }
  1484.         UART1_SendString(ok ? "SAVE OK" : "SAVE FAIL");
  1485.         UART1_SendCRLF();
  1486.     }
  1487. }

  1488. // ============================================================================
  1489. //  延时函数
  1490. // ============================================================================

  1491. void Delay_ms(unsigned int ms)
  1492. {
  1493.     unsigned int i, j;

  1494.     for(i = 0; i < ms; i++)
  1495.     {
  1496.         for(j = 0; j < 1200; j++)
  1497.         {
  1498.             _nop_();
  1499.         }
  1500.     }
  1501. }

  1502. // ============================================================================
  1503. //  串口中断
  1504. // ============================================================================

  1505. void UART1_ISR(void) interrupt 4
  1506. {
  1507.     if(RI)
  1508.     {
  1509.         RI = 0;
  1510.     }

  1511.     if(TI)
  1512.     {
  1513.         TI = 0;
  1514.     }
  1515. }
复制代码



发表于 2026-7-16 06:01:28 来自手机浏览器 | 显示全部楼层
游客请登录后查看回复内容
回复 支持 反对

使用道具 举报

发表于 2026-7-16 08:35:24 | 显示全部楼层
游客请登录后查看回复内容

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-7-16 10:19:00 来自手机浏览器 | 显示全部楼层
游客请登录后查看回复内容
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|数码之家-技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2026-7-26 07:20 , Processed in 0.202800 second(s), 10 queries , Gzip On, Redis On.

Powered by Discuz!

© MyDigit.Net Since 2006

快速回复 返回顶部 返回列表