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

📄 main.c

📁 这是一个小时计的程序
💻 C
字号:
/*
	工程机械工作小时计示例程序
	文件名:main.c
	MCU   :ATMEGA8
	时 钟 :内部4MHz,外接32768Hz晶振
	
	芯艺 2005-1-13
*/

#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/delay.h>

#define uchar unsigned char
#define uint unsigned int

// CS:PD7  WR:PD6  DT:PD5

#define LCD_CS  PD7
#define LCD_WR  PD6  
#define LCD_DT  PD5
#define LCD_PORT PORTD

uchar eep_bMinute  __attribute__((section(".eeprom")))=30;	//分钟数据EEPROM存储区
uint eep_wHour __attribute__((section(".eeprom")))=33;		//小时数据EEPROM存储区

uchar g_bMinute;											//分钟数据RAM缓冲区
uint g_wHour;												//小时数据RAM缓冲区
uchar g_bDisplayFlag=0;										//全局显示更新标记

//0~9 显示码,每字节格式:A3:D1,D0 A2:D1,D0 A1:D1,D0 A0:D1,D0  ,A3~0 为位对应的存储器相对地址
uchar g_aDisplayBuf[10]={0x6f,0x22,0x79,0x7a,0x36,0x5e,0x5f,0x2a,0x7f,0x7e};


//误差不会太大的延时1ms函数  
void DelayMs(uint ms)
{
	uint i;

	for(i=0;i<ms;i++)
		_delay_loop_2(4 *250);
}

//lcd 用延时函数
void lcd_delaybus(void)
{
	_delay_loop_1(3);
}

//写入时钟发生
void lcd_clk(void)
{
	lcd_delaybus();
	LCD_PORT&=~_BV(LCD_WR);
	lcd_delaybus();
	LCD_PORT|=_BV(LCD_WR);
	lcd_delaybus();
}

//写命令
void lcd_writecmd(uchar dat)
{
	uchar i;
	LCD_PORT&=~_BV(LCD_CS);
	
	//发送 100
	LCD_PORT|=_BV(LCD_DT);
	lcd_clk();
	LCD_PORT&=~_BV(LCD_DT);
	lcd_clk();
	lcd_clk();
	
	//发送C0~C8
	for(i=0;i<9;i++)
	{
		if(dat&0x80)
			LCD_PORT|=_BV(LCD_DT);
		else
			LCD_PORT&=~_BV(LCD_DT);
		dat<<=1;
		lcd_clk();
	}
	
	LCD_PORT|=_BV(LCD_CS);	
}

//按显示码格式连续写16位数据,即4个地址对应数据
void lcd_writedat(uchar addr,uchar dat)
{
	uchar i,j,temp;
	LCD_PORT&=~_BV(LCD_CS);
	
	//发送 101
	LCD_PORT|=_BV(LCD_DT);
	lcd_clk();
	LCD_PORT&=~_BV(LCD_DT);
	lcd_clk();
	LCD_PORT|=_BV(LCD_DT);
	lcd_clk();
	
	// 发送6位地址
	for(i=0;i<6;i++)
	{
		if(addr&0x20)
			LCD_PORT|=_BV(LCD_DT);
		else
			LCD_PORT&=~_BV(LCD_DT);
		addr<<=1;
		lcd_clk();
	}
	
	//将dat视为上述格式的显示码
	//根据显示码发送16位数据
	for(i=0;i<4;i++)
	{
		temp=dat&0x03;
		for(j=0;j<4;j++)
		{
			if(temp&0x01)
				LCD_PORT|=_BV(LCD_DT);
			else
				LCD_PORT&=~_BV(LCD_DT);
			temp>>=1;
			lcd_clk();
		}
		dat>>=2;
	}
	
	LCD_PORT|=_BV(LCD_CS);		
}

//LCD显示器初始化程序
void lcd_init(void)
{
	//初始化控制I/O口
	DDRD=_BV(LCD_CS)|_BV(LCD_WR)|_BV(LCD_DT);
	LCD_PORT=_BV(LCD_CS)|_BV(LCD_WR)|_BV(LCD_DT);
	
	lcd_writecmd(0x20);		//模块初始化选择
	lcd_writecmd(0x18);		//选择震荡器(内部RC)
	lcd_writecmd(0x01);		//震荡器开
	lcd_writecmd(0x03);		//LCD ON
}

//清除
void lcd_clear(void)
{
	uchar i;
	for(i=0;i<24;i+=4)
		lcd_writedat(i,0x00);	
}

//显示十进制一位, bit:显示位 从右0~5位  num:显示数0~9  dot:是否显示小数点
void lcd_displaybit(uchar bit , uchar num ,uchar dot )
{
	uchar temp;
	
	num%=10;
	bit=(5-bit)*4;
	temp=g_aDisplayBuf[num];
	
	if(dot)
		temp|=0x80;
	
	lcd_writedat(bit++,temp);
}


//显示小时,显示在从左4位  范围:0~9999
void lcd_displayhour(uint h)
{
	uint temp;
	uchar flag=0;
	h%=10000;
	
	//显示千位
	temp=h/1000;
	if(temp)
	{
		flag=1;
		lcd_displaybit(5,temp,0);
	}
	h%=1000;
	
	//显示百位
	temp=h/100;
	if(temp || flag)
	{
		flag=1;
		lcd_displaybit(4,temp,0);
	}
	h%=100;
	
	//显示十位
	temp=h/10;
	if(temp || flag)
		lcd_displaybit(3,temp,0);
	h%=10;
	
	//显示个位
	lcd_displaybit(2,h,1);	
}

//显示分钟
void lcd_displayminute(uchar m)
{
	m%=60;
	lcd_displaybit(1,m/10,0);
	lcd_displaybit(0,m%10,0);
}

//掉电检测(外部)中断例程
SIGNAL(SIG_INTERRUPT0)
{
	//保护计时数据
	eeprom_write_word(&eep_wHour,g_wHour);
	eeprom_busy_wait();
	eeprom_write_byte(&eep_bMinute,g_bMinute);
	
	//只有电压上升到正常情况才返回
	while((PIND & _BV(PD2))==0) 
		DelayMs(1);
}

//T/C2  时钟中断例程 8秒中断一次
SIGNAL(SIG_OVERFLOW2)
{
	static uchar sec=0;
	//根据秒信号计时值增加
	sec+=8;
	if(sec>=60)
	{
		if(++g_bMinute>=60)
		{
			g_wHour++;
			g_bMinute=0;
		}
		sec-=60;
		g_bDisplayFlag=1;
	}
}


int main(void)
{
	DelayMs(1000);
	
	//读取工作时间
	g_bMinute=eeprom_read_byte(&eep_bMinute);
	g_wHour=eeprom_read_word(&eep_wHour);
	
	//显示器初始化并显示当前时间
	lcd_init();
	lcd_clear();
	lcd_displayhour(g_wHour);
	lcd_displayminute(g_bMinute);
	
	//等待电压上升到18v
	while((PIND & _BV(PD2))==0) 
		DelayMs(1);	
	
	//掉电检测外部中断使能
	MCUCR=0;			//INT0 低电平触发中断
	GICR=_BV(INT0);		//INT0 中断允许
	
	//计时用T/C2初始化
	TCCR2=0;
	TCNT2=0;
	ASSR=_BV(AS2);							//选择异步时钟(32768Hz)
	TCCR2=_BV(CS21)|_BV(CS20);  	//64分频 , 中断周期为0.5秒
	TIMSK=_BV(TOIE2);						//T/C2 溢出中断允许
	
	sei();						//总中断允许
		
	while(1)
	{	
		if(g_bDisplayFlag)		//时间是否得到更新
		{
			lcd_displayhour(g_wHour);
			lcd_displayminute(g_bMinute);
			g_bDisplayFlag=0;
		}
		else
		{
			DelayMs(1);
		}
	}//while		
}//main

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -