正文

DIY旋转时钟2011-12-02 23:36:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/enc999/53041.html

分享到:

/--------------------------------------------------------
// 项目:梦幻旋转时钟
// 模块:主程序
// 说明:
// 设计:程序匠人(版权所有,引用者请保留原作者姓名)
//--------------------------------------------------------
/*
版本说明:
v01 2008-1-6 0:26
 第一个程序
 
v02 2008-1-6 0:26
 1.LED驱动改为负极控制
 2.缺省时间改为1:15分
 3.修改显示部分
 
v03 2008-1-6 1:59
 1.时针定位原先的算法有误,修改之
 2.该进显示内容,3.6.9.12直接显示数字

v04 2008-1-8 23:05
 1.优化部分程序的写法
 2.扩展部分程序

v05 2008-1-9 21:25
 1.TMR0中断赋初值部分程序有误,导致计时误差(1分钟慢10秒左右).修改之
  原来:  TMR0 = 256-(250-2) ;    //TMR0赋初值
  改为:  TMR0 = TMR0 + (256-(250-2)) ;   //TMR0赋初值

v06 2008-1-14 23:37
 1.显示程序,增加一种数字表盘模式
 2.其它改进

v07 2008-1-16 22:07
 1.数字表盘模式,增加钟摆效果
 2.加大"调整单列显示时间设置值(模糊控制)"的速度

v08 2008-1-17 22:09
 1.收缩钟摆的摆动幅度
 2.中断查询中,先判触发标志,后判使能标志.(可以提高响应速度)
 3.添加串行接收功能(波特率=2400)(通讯已经测试成功!)
  A.初始化部分
  B.中断部分
  C.串行通讯后台处理部分
 4.实现角度校准功能

v09 2008-1-23 22:42
 1.完成全部显示控制程序
 2.波特率改为1200,增强通讯可靠性

v10 2008-1-26 15:17
 1.增加ADC程序模块
 2.增加温度检测及显示程序
 3.增加滤波程序(中位值递推平均滤波)

v11 2008-2-10 16:46
 1.将单文件系统改为多文件系统.原来只有一个 "clock.c"文件,现在拆分为以下若干个程序文件和头文件模块:

  main.c  //主程序 程序文件
  display.c //显示处理 程序文件
  filter.c  //滤波处理 程序文件
  temperature.c  //温度处理 程序文件
  Serial.c //串行通讯 程序文件
  Interruption.c //中断服务 程序文件

  common.h //公共 头文件

  main.h  //主程序 头文件
  display.h //显示处理 头文件
  filter.h  //滤波处理 头文件
  temperature.h  //温度处理 头文件
  Serial.h //串行通讯 头文件
  Interruption.h //中断服务 头文件

v12 2008-2-10 23:01
 1.增加内部eeprom与FLASH操作模块(将角度校正值和闹钟参数保存在内部EEPROM中)
 2.增加一个无按键计数器,当一定时间内未接收到新的命令时,退出设置状态,并把参数保存到内部EEPROM中
 3.改进秒闪功能.在按键2秒内,被设置参数不闪烁.
 4.修改配置位内容
 5.闹钟模式增加进度条
 6.细节改动
 
*/
//--------------------------------------------------------
//--------------------------------------------------------
//插入文件包
//--------------------------------------------------------
#define root
#include "common.h"
//--------------------------------------------------------

 

//--------------------------------------------------------
//定义芯片工作时的配置位
//--------------------------------------------------------
__CONFIG(HS & WDTDIS & PWRTDIS & BOREN & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);

//__CONFIG(HS & WDTDIS  & LVPDIS );


//--------------------------------------------------------
//主函数
//--------------------------------------------------------
void main(void)
{
 init();      //====初始化

 //====循环主体
 while (1)
 {
  asm ("clrwdt");     //喂狗
  //asm ("nop");
 
 
  //
  if ( T_10MS_FLAG ) time_cnt() ;    //如果10毫秒定时溢出标志=1,则调用计时处理程序
  if ( NEW_DISP_EN_FLAG ) new_display() ;   //如果显示刷新使能标志=1,则刷新显示缓冲区
 
  if ( ADGO == 0 ) adc_cnt() ;    //如果ADC结束,则调用ADC处理程序
  if ( TEMP_SCAN_EN_FLAG ) temp_cnt() ;     //如果温度检测使能标志=1,则调用温度处理程序
  
  comm_cnt();      //串行通讯后台处理
  
  if ( (EEPROM_NEW_FLAGS!=0) && (WR==0) && (NO_KEY_JSQ>5) ) new_eeprom() ; //如果EEPROM数据更新标志<>0,且写操作结束,且无按键计数器>5,则更新eeprom内容

 }
}

 

//--------------------------------------------------------
//初始化程序
//--------------------------------------------------------
void init(void)
{
 //====IO口设置
 PORTA = 0B00111100 ;  //设置PORTA口电平
 TRISA = 0B00000001 ;  //设置PORTA口输入/输出态

 PORTB = 0B11111110 ;  //设置PORTB口电平
 TRISB = 0B00000001 ;  //设置PORTB口输入/输出态

 PORTC = 0B00001011 ;  //设置PORTC口电平
 TRISC = 0B10000000 ;  //设置PORTC口输入/输出态  (串行接收口RX(RC7)设置为输入态)

 //====寄存器初始化

 //====参数初始化
 DISP_TIME_SET = (65536-1000) ; //单列显示时间设置值

 DISP_LINE = DISP_LINE_ADJ ; //显示列计数器(0~179)=校正值
 TIMR1_JSQ = 0 ;   //TIMR1溢出计数器 = 0

 MOTOR_ST_FLAG = 1 ;  //电机状态标志=1(0=关闭,1=开启)
 SET_EN_FLAG = 0 ;  //设置使能标志=0(0=禁止,1=使能)

 DISP_MODE = 0 ;   //显示状态(0~7)
 SET_MODE = 0 ;    //设置状态(0~7)

 TIME_H = 12 ;                  //时钟"时"(0~23)
 TIME_M  = 0 ;                  //时钟"分"(0~59)
 TIME_S  = 0 ;                   //时钟"秒"(0~59)
 TIME_MS = 0 ;                   //时钟"毫秒"(0~99) (每过10ms,+1)
 TIME_US = 0 ;                   //时钟"微秒"(0~179) (每过(250*0.222us)=55.556us,+1)
 T_10MS_FLAG = 0 ;  //10毫秒定时溢出标志(0=未溢出,1=溢出)

 NEW_DISP_EN_FLAG = 1 ;  //显示刷新使能标志=1(0=禁止,1=使能)

 COMM_PUT_PTR = 0 ;       //接收数据存放指针=0
 COMM_GET_PTR = 0 ;  //接收数据读取指针=0

 SP_RUN = 0 ;   //闹铃时间运行值(0~99分)

 NO_KEY_JSQ = 0 ;   //无按键计数器=0(每1S+1)

 //温度历史纪录队列
 TEMP_LS_QUEUE[0]=25 ;
 TEMP_LS_QUEUE[1]=25 ;
 TEMP_LS_QUEUE[2]=25 ;
 TEMP_LS_QUEUE[3]=25 ;
 TEMP_LS_QUEUE[4]=25 ;
 TEMP_LS_QUEUE[5]=25 ;
 TEMP_LS_QUEUE[6]=25 ;
 TEMP_LS_QUEUE[7]=25 ;
 TEMP_LS_QUEUE[8]=25 ;
 TEMP_LS_QUEUE[9]=25 ;
 TEMP_LS_QUEUE[10]=25 ;
 TEMP_LS_QUEUE[11]=25 ;
 TEMP_LS_QUEUE[12]=25 ;
 TEMP_LS_QUEUE[13]=25 ;
 TEMP_LS_QUEUE[14]=25 ;
 TEMP_LS_QUEUE[15]=25 ;
 TEMP_LS_QUEUE[16]=25 ;
 TEMP_LS_QUEUE[17]=25 ;
 TEMP_LS_QUEUE[18]=25 ;
 TEMP_LS_QUEUE[19]=25 ;
 TEMP_LS_QUEUE[20]=25 ;
 TEMP_LS_QUEUE[21]=25 ;
 TEMP_LS_QUEUE[22]=25 ;
 TEMP_LS_QUEUE[23]=25 ;
 TEMP_LSPJ=25 ;


 //====EEPROM中参数初始化
 eeprom_init() ;
 
 //====INT口,WDT,TIMR0设置
 OPTION = 0B10001111 ;  //预分频器分配给WDT; 预分频=1:128; TMR0时钟源=内部指令周期计数; PORT内部上拉禁止; NT口触发边沿=下降沿;
 TMR0 = 256-250 ;  //TMR0赋初值

 //====TIMR1设置
 T1CON = 0 ;   //TMR1控制寄存器=0
 TMR1HL = DISP_TIME_SET ; //TMR1赋初值

 T1CKPS1 = 0 ;
 T1CKPS0 = 0 ;   //预分频系数=1:1
 T1OSCEN = 0 ;   //关闭内部振荡器电路
 T1SYNC = 0 ;   //同步计数模式
 TMR1CS = 0 ;   //时钟源=内部指令周期计数
 TMR1ON = 1 ;   //计数使能
 
 //====串口设置(说明:只接收,不发送,半工异步通讯,波特率=1200,数据位=8bit,停止位=1bit,无校验位)
 SPBRG = 233 ;   //波特率=fosc/64(SPBRG+1)=18000000/(64*(233+1))=1201.92  

 TXSTA = 0B00000000 ;  //异步低速方式,发送8bit数据
 RCSTA = 0B10010000 ;  //串口工作使能,接收8bit数据,连续接收允许
 
 //====ADC设置
 ADCON1 = 0B00001110 ;  //选择AN0通道为模拟口,其它通道为数字口
 ADCON0 = 0B11000001 ;  //ADC时钟源=自带RC;通道选择AN0;启动AD模块电源
 ADGO = 1 ;   //启动ADC

 //====中断使能
 INTCON = 0 ;   //中断控制寄存器=0
 PIE1 = 0 ;
 PIE2 = 0 ;

 INTE = 1 ;    //使能INT中断
 T0IE = 1 ;   //TMR0中断
 TMR1IE = 1 ;   //TMR1中断

 TXIE = 0 ;   //串口发送中断
 RCIE = 1 ;   //串口接收中断
 
 PEIE = 1 ;   //外设中断
 GIE = 1 ;   //全局中断
 
}

//--------------------------------------------------------
//EEPROM中参数初始化程序
//--------------------------------------------------------
void eeprom_init(void)
{
 EEADR = EEPROM_EN_ADR ;   
 read_eeprom() ;    //读取 EEPROM格式化标志
 
 if ( EEDATA == 0XA5 )
 {
  EEADR = DISP_LINE_ADJ_ADR ;   
  read_eeprom() ;   //读取 显示列计数器 角度校正值(0~179) (用于校正盘面角度)
  DISP_LINE_ADJ = EEDATA ;
  
  EEADR = TIMER_H_ADR ;   
  read_eeprom() ;   //读取 闹钟"时"(0~23)
  TIMER_H = EEDATA ;

  EEADR = TIMER_M_ADR ;   
  read_eeprom() ;   //读取 闹钟"分"(0~59)
  TIMER_M = EEDATA ;

  EEADR = SP_M_ADR ;   
  read_eeprom() ;   //读取 闹铃时间设置值(0~99分)(说明:0=关闭闹钟)
  SP_M = EEDATA ;
 }
 else
 {
  DISP_LINE_ADJ = 0 ;  //显示列计数器 角度校正值(0~179) (用于校正盘面角度)
 
  //闹钟系统
  TIMER_H = 7 ;   //闹钟"时"(0~23)
  TIMER_M = 15 ;   //闹钟"分"(0~59)
  SP_M = 1 ;   //闹铃时间设置值(0~99分)(说明:0=关闭闹钟)

  //EEPROM数据更新标志=1
  DISP_LINE_ADJ_FLAG = 1 ; //显示列计数器 角度校正值(0~179) (用于校正盘面角度)       
  TIMER_H_FLAG = 1 ;  //闹钟"时"(0~23)                                          
  TIMER_M_FLAG = 1 ;  //闹钟"分"(0~59)                                          
  SP_M_FLAG = 1 ;   //闹铃时间设置值(0~99分)(说明:0=关闭闹钟)                 
  EEPROM_EN_FLAG = 1 ;  //EEPROM格式化标志(0XA5=已经格式化,否则=未格式化)         


 }
}


//--------------------------------------------------------
//计时处理程序
//功能: 1.计时
// 2.电机停转判断
//--------------------------------------------------------
void time_cnt(void)
{
 tU08 i,j ;

 T_10MS_FLAG = 0 ;    //10毫秒定时溢出标志=0

 NEW_DISP_EN_FLAG = 1 ;    //显示刷新使能标志=1(0=禁止,1=使能)
 TEMP_SCAN_EN_FLAG = 1 ;    //温度检测使能标志=1(0=禁止,1=使能)

 //====计时
 if ( ++TIME_MS > 99 )     //"毫秒"+1,结果>最大值?
 {
  TIME_MS = 0 ;    //"毫秒"=0

  if ( ++TIME_S > 59 )    //"秒"+1,结果>最大值?
  {
   TIME_S = 0 ;    //"秒"=0

   if ( ++TIME_M > 59 )    //"分"+1,结果>最大值?
   {
    TIME_M = 0 ;    //"分"=0
    if ( ++TIME_H > 23 ) TIME_H = 0 ; //"时"+1,结果>最大值时,=0
    TEMP_LS_NEW_FLAG = 1 ;          //温度历史纪录队列更新使能标志=1(0=禁止,1=使能)
   }
  }
  


  //====电机停转判断
  if ( ++MOTOR_STOP_JSQ > 3 )             //电机停转计时器+1,>3?
  {
   MOTOR_ST_FLAG = 0 ;  //电机状态标志=0(0=关闭,1=开启)
   SET_EN_FLAG = 0 ;  //设置使能标志=0(0=禁止,1=使能)
  }

  //====无按键计数器+1
  if ( ++NO_KEY_JSQ > 250 ) NO_KEY_JSQ = 250 ;   //无按键计数器+1,>250时,=250
  if ( NO_KEY_JSQ > 15 ) SET_EN_FLAG = 0 ;  //如果无按键计数器>15,则设置使能标志=0(0=禁止,1=使能)
 }
 
 //====设置秒闪标志(1HZ)
 if ( TIME_MS > 49 ) MS_1HZ_FLAG = 1;
 else MS_1HZ_FLAG = 0 ;
}


//--------------------------------------------------------
//ADC处理
//出口: ADR_NEW=最新AD结果
//--------------------------------------------------------
void adc_cnt(void)
{
 ADR_NEW = ADRESH ;     //保存最新AD结果
 ADGO = 1 ;      //重新启动ADC
}


//--------------------------------------------------------
//
// THE END
//
// 版权所有:程序匠人(引用者请保留原作者姓名)
//
//--------------------------------------------------------


阅读(1817) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册