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

📄 hzmmisub18.c

📁 ATMEL的ATMEGA128驱动160×80液晶调试程序
💻 C
📖 第 1 页 / 共 2 页
字号:

#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 + -