📄 hzmmisub18.c
字号:
#include "hzmmi18.h"
//#define T_RELOAD (8000-1-16) //0.9980ms @8MHz,毫秒定时器用
//#define BPS_SET (208-1) //bps=2400,@osc=8Mhz,8000/2.4/16=208
//#define T_RELOAD (4000-1-8) //0.9980ms @4MHz,毫秒定时器用
//#define BPS_SET (104-1) //bps=2400,@osc=4Mhz,4000/2.4/16=104
#define T_RELOAD (5000-1-10) //0.9980ms @5MHz,毫秒定时器用
#define BPS_SET (130-1) //bps=2400,@osc=5Mhz,5000/2.4/16=130
word last_cursor;
byte time_str[10];
extern word work_mode;
extern byte poll_seq;
extern byte menu_in;
extern byte cpu_set_flag;
extern byte time_setting;
extern byte CYCLE_FLAG;
extern byte GPS_en;
void ms_cont_routine(void);
void s_cont_routine(void);
void time_wr_en(void);
void comm_with_lon(void);
int csprintf(char *buf, const char *fmt,...);
int EEPROMwrite(int location, unsigned char byte);
unsigned char EEPROMread(int location);
void str_hz(byte row,byte col,byte *str);
void GPS_ds(void);
void time_str_rd(byte *);
void time_str_wr(byte *);
byte time_sec_rd(void);
void time_sec_wr(byte);
void key_int(void);
void rcv_int(void);
word ms_val;
#pragma interrupt_handler int_timer0:13
void int_timer0(void)//定时器延时器中断,1ms中断一次
{
asm("cli"); //关中断
ms_count++;
if(mstimer2)
{
mstimer2--;//秒定时器用
if(GPS_en)
GPS_ds();
}
else
{
byte i,j;
j=time_sec_rd();//55us
for(i=((T_RELOAD+50)/100);i>0;i--)
{//用50*55us=2.75ms的时间使定时器的秒与实时日历钟的秒同步
if(j!=time_sec_rd())
break;
if(GPS_en)
GPS_ds();
if(mstimer2!=0)
break;
}
if(mstimer2==0)
{
if(i==0)
time_str_wr(time_str);//280us
TCNT1H=0;//清计数器内的值
TCNT1L=0;
TIFR|=0x10;//清可能存在的时间中断
time_str_rd(time_str);//280us
mstimer2=1000-1;
}
soft_dog&=15;
if(soft_dog)soft_dog--;
}
if(mstimer2==(1000-2))
s_cont_routine();
ms_cont_routine();
key_int();
if(mstimer1)mstimer1--; //dlyms用
if(mstimer3)mstimer3--; //串口通讯用
if(poll_com==1)
rcv_int();
if(soft_dog)
{
asm("wdr"); //软看门狗复位
PORTB^=WDG; //硬看门狗复位
}
asm("sei"); //中断允许
}
//中断内读键值
void key_int(void)
{
byte key;
static byte old_key,tmp_key;
static word shake_time;
key=(~PINF)&0xbf;
if(key==0)
{
if(tmp_key!=0)
{
tmp_key=0;
old_key=0;
if(has_key==KEY_RST24)
has_key=0x80;
else
if(has_key==(0x80|KEY_RST24))
has_key=0;
}
return;
}
if(tmp_key!=key)
{
tmp_key=key;
shake_time=ms_count;
return;
}
if((ms_count-shake_time)<30)
return;
if((has_key==0x80)||(has_key==(0x80|KEY_RST24)))
{
old_key=0;
shake_time=ms_count;
return;
}
if(old_key!=tmp_key)
{
for(old_key=0;key!=0;old_key++)
{
key>>=1;
key&=0x7f;
}
if(has_key==KEY_RST24)
{
if(old_key!=KEY_RST24)
has_key=0x80;
old_key=0;
shake_time=ms_count;
return;
}
else
{
has_key=0x80|old_key;
if(old_key==KEY_RST24)
old_key=0;
else
old_key=tmp_key;
}
}
else
{
if((ms_count-shake_time)>500)
{
shake_time=ms_count-(500-200);
has_key|=0x80;
}
}
}
/*
GPS对时的步骤:
判断开入变位点;
GPS脉冲前脉宽应小于505ms,而且后脉宽应大于505ms,
由此找出脉冲前沿(前沿的精准度高于后沿),此数值可用于500ms宽的分脉冲;
分析前沿的间隔时间是否合理,误差应小于0.5%;
表走得快直接写时间;
表走得慢则加一后写时间。
*/
void GPS_ds(void)
{
static byte last_st;
static word GPS_ms;
if(GPS_ms==ms_count)
GPS_en&=0x0f;
if(last_st==(PIND&DN2))//判断变位点
return;
last_st=PIND&DN2;
if((ms_count-GPS_ms)<505)
return;//前脉宽应小于505ms,而且后脉宽应大于505ms
for(;;)
{
GPS_ms=ms_count-GPS_ms;
ms_val=GPS_ms;
//得到大于505ms以上的沿间脉宽,此算法对于整秒整分变位的脉宽也适用
if((GPS_ms>998)&&(GPS_ms<1002))
{//秒误差小于0.2%
if(mstimer2<500)
{//实时日历钟走的慢
if(time_str[0]==0x59)
break;
else
{//在时钟秒不产生进位时对时
time_str[0]++;
if((time_str[0]&0x0f)==0x0a)
time_str[0]+=0x06;
}
}
GPS_en|=0x10;//置GPS秒对时成功标志
}
else
if((GPS_ms>59980)&&(GPS_ms<60020))
{//分误差小于0.2%
if(time_str[0]>=0x30)
{//实时日历钟走的慢
if(time_str[1]==0x59)
break;
else
{//在时钟的时不产生进位时对时
time_str[0]=0;
time_str[1]++;
if((time_str[1]&0x0f)==0x0a)
time_str[1]+=0x06;
}
}
else
time_str[0]=0;
GPS_en|=0x20;//置GPS分对时成功标志
}
else
{
GPS_en&=0x0f;
break;
}
TCNT1H=0;//清计数器内的值
TCNT1L=0;
TIFR|=0x10;//清可能存在的时间中断
time_str_wr(time_str);
mstimer2=1000-1;
break;
}
GPS_ms=ms_count;//记下变位点
}
//时间定时器初始化
void time_init(void)
{
TCCR1A=0;
TCCR1B=0x09; // ctc1=1,ck/1
TIMSK=0x10; // TIME1B COMPEAR INT OK
OCR1AH=(byte)(T_RELOAD/256);
OCR1AL=(byte)T_RELOAD;
soft_dog=5;
ms_count=8888;
mstimer1=0;
mstimer2=1000-1;
mstimer3=0;
// return;
{
word i;
byte j;
time_str_rd(time_str);
j=time_str[0];
for(i=0;i<T_RELOAD;i++)
{//用4000*400us=1.6s的时间使定时器的秒与实时日历钟的秒同步
time_str_rd(time_str);
if(j!=time_str[0])
break;
watchdog();
}
mstimer2=1000-1;
}
}
void spi_init(void)
{
// SPCR=0x75; //不用中断,以最快速度输出,sck平时为低
// SPSR=0x00;
}
//串口波特率初始化
void uart_init(void)
{
UCR=0x18;
USR=0x00;
UBRR=BPS_SET;
}
//端口定义初始化
void init(void)
{
DDRE=0xff;//设置成输出状态
PORTE=LIB_CE | LCD_ID;
// MCUSR=0x80;//ATmega128,JTAG disable
// MCUSR=0x80;
DDRA=0x0;//方向口
PORTA=0x0;
DDRB=RST_TM|SPI_SCK|SPI_MO|SPI_MI|TXD1|WDG|NCPU_BUSY;//设置成输出状态
PORTB=0x60; //ss置低
DDRD=RUN_LAMP | RST_SIGN | ALARM2;//设置成输出状态
PORTD=RUN_LAMP | RST_SIGN | ALARM2;
ctl_data=LCD_LED | LCD_RST | NCPU1_CE | NCPU_RST | COM_SEL;
PORTC=ctl_data;
PORTE|=ALE2;
PORTE&=~ALE2;
time_init();
spi_init();
uart_init();
asm("sei"); //中断允许
time_wr_en();
WDTCR=0x18;//使cpu内部看门狗有效
}
//毫秒级延时函数
void dlyms(word ms)
{
mstimer1=ms;
while(mstimer1)
comm_with_lon();
}
//液晶忙等待
void wait_disp(void)
{
PORTA=0xff;
DDRA=0;
PORTE|=RD_WR;
PORTE|=LCD_ID;
for(;;)
{
PORTE|=LCD_CE;
PORTE|=LCD_CE;
if(!(PINA&LCD_BUSY))
{
PORTE&=~LCD_CE;
PORTE|=LCD_ID;
PORTE&=~RD_WR;
return;
}
PORTE&=~LCD_CE;
}
}
//向液晶发送命令及数据
void disp_order_data(byte order,byte data)
{
wait_disp();
PORTA=order;
DDRA=0xff;
PORTE|=LCD_ID;
PORTE|=LCD_CE;
PORTE&=~LCD_CE;
wait_disp();
PORTA=data;
DDRA=0xff;
PORTE&=~LCD_ID;
PORTE|=LCD_CE;
PORTE&=~LCD_CE;
}
//对液晶发送命令码
void disp_order(byte order)//对液晶发送命令码
{
wait_disp();
PORTA=order;
DDRA=0xff;
PORTE|=LCD_ID;
PORTE|=LCD_CE;
PORTE&=~LCD_CE;
}
//向LCD送数据码
void disp_data(byte data)
{
wait_disp();
PORTA=data;
DDRA=0xff;
PORTE&=~LCD_ID;
PORTE|=LCD_CE;
PORTE&=~LCD_CE;
}
//对液晶初始化,不清屏
void init_disp_nocls(void)//对液晶初始化
{
word i;
for(i=0;i<((T_RELOAD+50)/1000);i++)
{
PORTC=ctl_data&=~LCD_RST;
PORTE|=ALE2;
PORTE&=~ALE2;
}
for(i=0;i<((T_RELOAD+50)/1000);i++)
{
PORTC=ctl_data|=LCD_RST;
PORTE|=ALE2;
PORTE&=~ALE2;
}
disp_order_data(0,0x32);//工作方式:图形方式,光标禁止
disp_order_data(1,0x77);//字符点阵大小为7x7
disp_order_data(2,0x13);//每行(0x13+1)=20个字节
disp_order_data(3,0x4f);//共有(0x4f+1)=80行
disp_order_data(8,0x00);//显示缓冲区从0开始
disp_order_data(9,0x00);//显示缓冲区从0开始
}
//清屏
void cls(void)
{
int i;
if((menu_in==TRUE)||(cpu_set_flag==TRUE)||(CYCLE_FLAG==TRUE))
{//彻底清屏
disp_order_data(0x0a,0);
disp_order_data(0x0b,0);
disp_order(0x0c);
for(i=0;i<20*80;i++)
disp_data(0);
last_cursor=0;
}
else
{//第一行不清屏
disp_order_data(0x0a,(20*16)%256);
disp_order_data(0x0b,(20*16)/256);
disp_order(0x0c);
for(i=0;i<20*80-20*16;i++)
disp_data(0);
last_cursor=0;
}
}
//对液晶初始化,清屏
void init_disp(void)
{
init_disp_nocls();
cls();
}
//输出汉字库地址
void lib_addr_out(void)
{
ctl_data=(ctl_data&0xfc)|(lib_addr.bytes.a2&0x03);
PORTC=ctl_data;//最高的两位A17A16由ALE2锁存
PORTE|=ALE2;
PORTE&=~ALE2;
PORTC=lib_addr.bytes.a1;
PORTE|=ALE1;//第二字节A15-A8由ALE1锁存
PORTE&=~ALE1;
PORTC=lib_addr.bytes.a0;//最低字节直接输出
}
//汉字库数据输出到显示器
void lib_data(void)
{
wait_disp();
PORTE&=~LIB_CE;//汉字库数据输出使能
PORTE&=~LIB_CE;
PORTE&=~LIB_CE;
PORTE&=~LCD_ID;
PORTE|=LCD_CE;//显示器锁存
PORTE&=~LCD_CE;
PORTE|=LIB_CE;//汉字库数据输出关闭
}
//显示GPS光标
void disp_GPS(void)
{
byte j;
word lram;
lram=19;//右上角
for(j=0;j<9;j++)
{
disp_order_data(0x0a,(byte)lram); //起始行位置
disp_order_data(0x0b,(byte)(lram/256)); //起始列位置
disp_order_data(0x0c,GPScursor[j]);
lram+=20;
}
}
//显示汉字串及大ASCII串
void str_hz(byte row,byte col,byte *str)
{
byte q,w,j;
word lram;
lram=row*20+col;
for(;*str;)
{
if(lram>=72*20)
return;
if(*str<160) //如果是ASC码字符
{
q=(*str++);
if(q==13) //处理回车符
{
lram+=20*16;
lram/=20;
lram*=20;
continue;
}
lib_addr.l=q*16l+0x100l+0x800l;
lib_addr_out();
for(j=0;j<16;j++)
{
disp_order_data(0x0a,(byte)lram); //起始行位置
disp_order_data(0x0b,(byte)(lram/256)); //起始列位置
disp_order(0x0c);
lib_data();
PORTC++;
lram+=20;
}
lram-=20*16-1;
if((lram%20)==0)
lram+=20*15;
continue;
}
//如果是汉字
if((lram%20)==19)
{//如果本行只剩下半个字的位置,则将这个位置填空格
for(j=0;j<16;j++)
{
disp_order_data(0x0a,(byte)lram); //起始行位置
disp_order_data(0x0b,(byte)(lram/256)); //起始列位置
disp_order_data(0x0c,0);
lram+=20;
}
lram-=19;
}
q=(*str++)-160;
if(*str==0) break;
w=(*str++)-161;
if(q<=3)
q--;
else
if(q==6)
q-=3;
else
q-=12;
lib_addr.l=(q*94l+w)*32l+0x100l+0x800l+0x1000l;
lib_addr_out();
for(j=0;j<16;j++)
{
disp_order_data(0x0a,(byte)lram); //起始行位置
disp_order_data(0x0b,(byte)(lram/256)); //起始列位置
disp_order(0x0c);
lib_data();
PORTC++;
lib_data();
PORTC++;
lram+=20;
}
lram-=20*16-2;
if((lram%20)==0)
lram+=20*15;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -