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