/-------------------------------------------------------- // 项目:梦幻旋转时钟 // 模块:主程序 // 说明: // 设计:程序匠人(版权所有,引用者请保留原作者姓名) //-------------------------------------------------------- /* 版本说明: 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 // // 版权所有:程序匠人(引用者请保留原作者姓名) // //--------------------------------------------------------

评论