⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proccess.c

📁 AVR红外遥控
💻 C
字号:
#include "cc.h"
#include "event.h"
#include "display.h"
#include "checksum.h"
#include "key.h"

#include "proccess.h"

#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>




struct EEPROM {
  u16_t index;        // data address in eeprom
  u8_t sumw[4];       // data in eeprom
  u8_t chksum;        // checksum for mbuf
};
struct EEPROM save;

// 从上电开始的‘功’的总和,要保存在EEPROM的数据。定义它是为方便计算。 
#define SUM_W           (*((u32_t *)(&save.sumw[0])))


struct DISPLAY {
  u32_t u;            // 显示电压
  u32_t i;            // 显示电流
  u32_t p;            // 显示功率
// W = Σ(Pi*T)/3600, T = 1, Pi = sample_v * sample_i
  u32_t w;            // 按秒累计,1小时的功;满1小时除3600后,再累加给:SUM_W

  u16_t cnt_3600;     // 3600秒计数,记录w累加过的时间  
  u8_t  cnt_down;     // 30秒倒计时,用于持续按键功能

};
struct DISPLAY disbuf;



u8_t key_type = 0x00;
#define KEY_TYPE_U    0       // 当前显示电压
#define KEY_TYPE_I    1       // 当前显示电流
#define KEY_TYPE_P    2       // 当前显示功率


u8_t proflag = 0x00;
#define PRO_POWER_OFF         0   // bit0: 掉电进程标志
#define PRO_SAVE              1   // bit1:保存进程标准
#define PRO_DISPLAY           2   // bit2:切换显示进程标志
#define PRO_ONE_KEY           3   // bit3:单次按键进程标志
#define PRO_KEEP_KEY          4   // bit4:持续按键进程标志






// =========================================================================
void proc_init(void) {
  u8_t tmp;
  
  wdt_enable(WDTO_1S);
  
  init_display();
  
  init_interrupt();

  init_key();
  
  
  // read W from eeprom
  cli();
  eeprom_busy_wait();
  save.index = eeprom_read_word ((u16_t *)0);
  
  if (save.index > 511) { // 新的EEPROM读出总是: 0xFF
    // 初始化EEPROM
    save.index = 0x0002;
    SUM_W = 0x00000000;

    save.chksum = 0x00;
    save.chksum = checksum(&save.sumw[0], 5);
  
    eeprom_busy_wait();
    eeprom_write_block(&save.index, (u8_t *)0, 7);

    // 重读 index
    eeprom_busy_wait();
    save.index = eeprom_read_word((u16_t *)0);
  }

  
  // 读数据块,最大读10次
  for (tmp = 0; tmp < 10; tmp++) {
    eeprom_busy_wait();
    eeprom_read_block(&save.sumw[0], (u8_t *)save.index, 5);
    if (checksum(&save.sumw[0], 5) == 0) {
      break;
    }
  }
  
  if (tmp == 10) { // 读失败,无法得出原始数据!给错误信息显示在LED6-13: "FFFFFFFF"
    for (tmp = 5; tmp < 13; tmp++) {
      bcd_buf[tmp] = 0x0f;  // "F"
    }
    sei();
    while (1);              // 永远的停在这里!
  }
  else {  // 正常结束
    eeprom_busy_wait();
    sei();
  }
  
    // 显示进程
  proflag = _BV(PRO_DISPLAY);
  
  key_type = KEY_TYPE_U;      // 默认显示电压
  //key_type = KEY_TYPE_I;    // 默认显示电流
  //key_type = KEY_TYPE_P;    // 默认显示功率
  
  disbuf.w = 0;               // 当前 MW*S
  disbuf.cnt_3600 = 0;        // 小时秒计数
  disbuf.cnt_down = 30;       // 30秒倒计时,用于持续按键功能

  return;
  
}


// =========================================================================
void proc_poweroff(void) {
  
  if ((flag0 & _BV(FLAG0_INT0)) == 0) {
    return;  
  }
  
  // 掉电中....
  display_off();
  proflag |= _BV(PRO_SAVE);
  flag0 &= ~_BV(FLAG0_INT0);
  
  return;
}
  
  
  
  
  
  



// =========================================================================
void proc_calculate(void) {
  u32_t tmp1, tmp2, tmp3;
  
  if ((flag0 & _BV(FLAG0_T1)) == 0) {
    return; // 没到1秒,等待采样
  }
  else {
    flag0 &= ~_BV(FLAG0_T1);  // 清标志
  }
  

  // 警告:类型不匹配的计算将导致意外的结果!


  // 计算采样显示电压(伏)
  tmp1 = (u32_t)sample_i;
  tmp1 *= C_DIS_U;
  tmp1 /= C_SMP_U;

   if (tmp1-C_DIS_U*0.1 >= 0){
 		  tmp1 -= C_DIS_U*0.1;
 		}
    else  {
  		tmp1 = 0 ;
 	}
      

  disbuf.u = tmp1;
  // 测试计算结果
  //htobcd5(&bcd_buf[0], disbuf.u);

  // 计算采样显示电流(千安)
  tmp2 = (u32_t)sample_v;
  tmp2 *= C_DIS_I;
  tmp2 /= C_SMP_I;
  disbuf.i = tmp2;
  // 测试计算结果
  //htobcd5(&bcd_buf[0], disbuf.i);


  // 计算显示功率(兆瓦)
  tmp3 = tmp1;
//  tmp3 *= tmp2;
//  tmp3 /= 1000;
  disbuf.p = tmp3;
  // 测试计算结果
  //htobcd8(&bcd_buf[5], disbuf.p);


  // 计算累加1小时内的功 (按秒计算)
  disbuf.w += tmp3;
  // 测试计算结果
  // htobcd8(&bcd_buf[5], disbuf.w);

  
  // 累计1小时的功
  if (++disbuf.cnt_3600 > 3600) { // 1小时到,计算 MW*H 总和

    disbuf.cnt_3600 = 0;          // 计数复位
    
    proflag |= _BV(PRO_SAVE);     // 启动保存进程
    
  }

  // 累计持续按键时间
  if ((proflag & _BV(PRO_KEEP_KEY)) != 0) {
    if (--disbuf.cnt_down == 0) {
      disbuf.cnt_down = 30;
      disbuf.w = 0;
      SUM_W = 0;
      proflag |= _BV(PRO_SAVE);
    }
  }
  
  proflag |= _BV(PRO_DISPLAY);  // 启动显示进程
  
  return;
  
}


// ===========================================================================
void proc_save(void) {
  struct EEPROM readsave;
  u32_t tmp32;
  u16_t tmp16;
  u8_t tmp8;
  
  if ((proflag & _BV(PRO_SAVE)) == 0) {
    return;
  }  
  
  cli();
  
  tmp32 = disbuf.w + 1800;   // 四舍五入;保证不至于永远丢“功”显示不出来的0.01~0.09
  tmp32 /= 3600;             // 由于显示电流小数点1位,电压小数点1位,功小数点1位,所以要再除10
  SUM_W += tmp32;             // 累加给总计
  
  if (SUM_W > 99999999) {     // “功”累计超过8位BCD码,就循环....
    SUM_W -= 100000000;
  }
    
  disbuf.w = 0;               // 清除1小时的记录(因为已经累加给总记录了)
  disbuf.cnt_3600 = 0;        // 计数复位

  
  save.chksum = 0;
  save.chksum = checksum(&save.sumw[0], 5); // 计算校验码
  
  for (tmp16 = save.index; tmp16 < 511; tmp16 += 5) { // ATMEGA8 的 EEPROM = 512
    // 3次读写失败就换块
    for (tmp8 = 0; tmp8 < 3; tmp8++) {
      eeprom_busy_wait();
      eeprom_write_block(&save.sumw[0], (u8_t *)save.index, 5);     // 写块数据
      eeprom_busy_wait();
      eeprom_read_block(&readsave.sumw[0], (u8_t *)save.index, 5);  // 读刚写的块
      if (checksum(&readsave.sumw[0], 5) == 0) {  // 校验成功,写入正确
        goto fin_save;
      }
    }
  
    if (tmp8 == 3) {    // 已经进行过3次操作并失败,换块!
      save.index += 5;  // 偏移 5 byte
      eeprom_busy_wait();
      eeprom_write_word((u16_t *)0, save.index);  // 更新 index

    }
  
  }
  
  // 所有块都写坏,报废!显示 "EEEEEEEE"
  for (tmp8 = 5; tmp8 < 13; tmp8++) {
    bcd_buf[tmp8] = 0x0e; // "E"
  }
  sei();
  while (1);    // 永远的停在这里!


fin_save: // 保存完成
  
  eeprom_busy_wait();
  sei();
  proflag &= ~_BV(PRO_SAVE);  // 清除该进程标志
  
  
  return;
}


// ===========================================================================
void proc_key(void) {
  u8_t tmp8;
  
  if (read_key() == 0) { // 无键按下
    proflag &= ~_BV(PRO_ONE_KEY);   // 清除单次按键标志
    proflag &= ~_BV(PRO_KEEP_KEY);  // 清除持续按键标志
    disbuf.cnt_down = 30;           // 复位持续按键倒计数
    return; // 退出
  }

  
  // 检查是否持续按键
  if ((proflag & _BV(PRO_ONE_KEY)) != 0x00) { // 以前按过键,状态为连续按键状态
     proflag |= _BV(PRO_KEEP_KEY);
     return;
      
  }
  

  // 不是持续按键,是单次按键
  // 抖动检测
  tmp8 = cnt_t2;
  while (((cnt_t2 - tmp8) < 3) && (read_key() == 1));    // 150mS去抖动等待
  if (read_key() == 1) { //有效单次按键
     
    proflag |= _BV(PRO_ONE_KEY);         // 设置单次按键标志
      
    // 切换显示类型
    if (++key_type == 3) {
      key_type = 0;
    }
      
    proflag |= _BV(PRO_DISPLAY);    // 启动显示切换进程

  }
  else {
    proflag &= ~_BV(PRO_ONE_KEY);   // 清除单次按键标志
    proflag &= ~_BV(PRO_KEEP_KEY);  // 清除持续按键标志
    disbuf.cnt_down = 30;           // 复位持续按键倒计数
  }
    
  return;
  
}


// ===========================================================================
void proc_display(void) {
  
  u32_t tmp1, tmp2;
  
  // 是否起用本进程?
  if ((proflag & _BV(PRO_DISPLAY)) == 0) {
    return;
  }
  
  // 显示‘功’W
  tmp1 = disbuf.w + 1800;  // 四舍五入;保证不至于永远丢“功”显示不出来的0.01~0.09
  tmp1 /= 3600;            // 由于显示电流小数点1位,电压小数点1位,功小数点1位,所以要再除10
  tmp2 = SUM_W;
  tmp2 += tmp1;
  
  if (tmp2 > 99999999) {    // “功”累计超过8位BCD码,就循环....
    tmp2 -= 100000000;
  }
  
  htobcd8(&bcd_buf[5], tmp2);      // 刷新显示缓冲区
  bcd_buf[10] |= 0x80;             // 小数点位置 
  
  // 倒计时显示
  if ((proflag & _BV(PRO_KEEP_KEY)) != 0) { // 倒计时清除"FFF30".."FFF29"...
    htobcd5(&bcd_buf[0], disbuf.cnt_down);
    bcd_buf[0] = 0x0f; // "F"
    bcd_buf[1] = 0x0f; // "F"
    bcd_buf[2] = 0x0f; // "F"
    
    goto fin_display;
  }
  
  // V/I/P显示
  switch (key_type)
  {
    case KEY_TYPE_U:
      htobcd5(&bcd_buf[0], disbuf.u); // 显示数
      bcd_buf[2] |= 0x80;             // 小数点位置
      LED14_ON;
      LED15_OFF;
      LED16_OFF;
      break;
    case KEY_TYPE_I:
      htobcd5(&bcd_buf[0], disbuf.u); // 显示数
      bcd_buf[2] |= 0x80;             // 小数点位置
      LED14_OFF;
      LED15_ON;
      LED16_OFF;
      break;
    case KEY_TYPE_P:
      htobcd5(&bcd_buf[0], disbuf.u); // 显示数
      bcd_buf[2] |= 0x80;             // 小数点位置
      LED14_OFF;
      LED15_OFF;
      LED16_ON;
      break;
  }

fin_display:      
  proflag &= ~_BV(PRO_DISPLAY);
  
  return;
}




// ===========================================================================
void proc_test_sample(void) {

  if ((flag0 & _BV(FLAG0_T1)) != 0) {

    htobcd5(&bcd_buf[0], (u32_t)sample_i);
    htobcd8(&bcd_buf[5], (u32_t)sample_v);
    
    flag0 &= ~_BV(FLAG0_T1);
  }

  return;
  
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -