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

📄 hjmcu.c

📁 很实用的单片机例程
💻 C
字号:
/**************************************************************************************************
*** 慧净电子1天入门、10天学会、1年精通单片机与C语言视频教程配套程序源码                         ***
*** 实验目的:HJ-1G 开发板   AVR配套实验程序                                                    ***
*** MCU: ATmega16          部分C源码可以直接用于项目开发、欢迎复制共享、功德无量、没有版权      ***
*** 作者:慧净免费助学会员  
*** 部分源码网上收集整理、如有伤害到你的利益、请来信,hjmcu@163.com 我们的免费助学会员会定期帮你删除掉         ***
*** 编译器:GCC                                                                                ***
*** 百度交流空间:http://hi.baidu.com/HJMCU      WWW.HJMCU.COM                                  ***
*** 论坛交流:http://bbs.hjmcu.com   欢迎来论坛一分钱不要下载配套的仿真电路                     ***
*** 配套的硬件学习板网址:http://shop37031453.taobao.com/                                       ***
*** 日期:2008.8.8                                                                              ***
*** 目标:用C语言写程序就这么简单、慧争祝你1天入门、10天学会、1年精通单片机与C语言、找个好工作  ***
***************************************************************************************************/

//慧净电子大学生课程设计专用实验板《HJ-1G》、直接支持AT89S52 STC89C52单片机
//加转接板后支持AVR ATmega16 32 系列单片机、是你学习单片机的得力助手 一板二用,学完51再学AVR

//HJ-1G 学习板加AVR转接板后,装上ATMETAM16 单片机实验
//HJ-1G 学习板AVR单片机实验,FM报警实验
//注意要把JTAGEN 仿真熔丝位设置成1 才能完成本实验,设置成1时不能用仿真口,只能用ISP下载接口下载程序
//本实验要用到电脑串口,可以用串口线接到电脑串口上,也可以用USB转串口线接到电脑USB接口上。
//请用配套的串口调试软件。
//本实验跟据网上的AVR学习笔记有我们的免费助学会员修改成。
#include <avr/io.h>        
#include <util/delay.h>
#include <avr/interrupt.h>   //中断函数头文件

//常量声明
#define BAUD 9600
#define TURE 1
#define FALSE 0
//时钟/日历寄存器
#define RD	  	0x01         //读
#define WR	  	0x00         //写
#define SECOND		0x80	//秒
#define MINUTE		0x82	//分
#define HOUR		0x84	//时
#define DAY 		0x86	//日
#define MONTH		0x88	//月
#define WEEK		0x8A	//星期 DATE
#define YEAR		0x8C	//年
#define WR_PROTECT	0x8E	//控制(写保护)
#define CHARGE	    0x90	//涓流充电
#define BURST		0xBE	//时钟多字节
//配置位
#define CLK_HALT		0x80	//停止时钟控制位    SECOND	bit7
#define CLK_START		0x00	//启动时钟
#define M12_24			0x80	//12/24小时值选择位 HOUR		bit7 
#define PROTECT			0x80	//写保护控制位      CONTROL	bit7 
#define UPROTECT		0x00	//写保护控制位      CONTROL	bit7 
//涓流充电控制常量
#define TC_D1R2			0xA5	//充电时选择一个二极管和2K电阻  
#define TC_D2R8			0xAB	//充电时选择二个二极管和8K电阻   
#define TC_DISABLED		0x00	//禁止充电功能
//RAM 命令
#define RAMBASE		0xC0	//RAM起始位为0XCO,RAM范围0-31

//全局变量声明
unsigned char Get_Time[7] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};


//函数声明
void Delayus(unsigned int lus);         //us延时函数
void Delayms(unsigned int lms);        //ms延时函数
void Port_Init(void);   //端口初始化配置
void Usart_Init(void);  //USART寄存器设置
void Usart_PutChar(unsigned char cTXData);  //字节发送函数
void Usart_PutString(unsigned char *pcString); //字符串发送函数
unsigned char DS1302_ReadByte(void);         //从DS1302读一个字节数据
void DS1302_WriteByte(unsigned char dat);    //向DS1302写一个字节数据
unsigned char DS1302_ReadData(unsigned addr); //从DS1302的指定地址读一个字节数据
void DS1302_WriteData(unsigned char addr,unsigned data);  
                                                 //向DS1302的指定地址写一个字节数据
void DS1302_SetTime(unsigned char *time);  //对DS1302设置时间
void DS1302_GetTime(void);   //从DS1302读取时间
unsigned char DS1302_Check(void);           //DS1302是否工作检测
void DS1302_Init(void);                      //DS1302初始化

int main(void)            
{
	unsigned char Set_Time[7] = {0x59,0x59,0x15,0x05,0x12,0x05,0x08};
	                                       //设置秒,分,时,日,月,星期,年
	unsigned char i;
	
	Port_Init();
	Usart_Init();
	
	Usart_PutString("DS1302实时时钟试验");
	Usart_PutString("设置当前时间为:");
	Usart_PutChar(0x0D);
	Usart_PutChar(0x0A);  //发送回车换行
	Usart_PutChar('2');
	Usart_PutChar('0');
	Usart_PutChar(Set_Time[6] / 16 + 0x30);
	Usart_PutChar(Set_Time[6] % 16 + 0x30);
	Usart_PutString("年");
	Usart_PutChar(' ');
	Usart_PutChar(Set_Time[4] / 16 + 0x30);
	Usart_PutChar(Set_Time[4] % 16 + 0x30);
	Usart_PutString("月");
	Usart_PutChar(' ');
	Usart_PutChar(Set_Time[3] / 16 + 0x30);
	Usart_PutChar(Set_Time[3] % 16 + 0x30);
	Usart_PutString("日");
	Usart_PutChar(' ');
	Usart_PutChar(Set_Time[2] / 16 + 0x30);
	Usart_PutChar(Set_Time[2] % 16 + 0x30);
	Usart_PutString("时");
	Usart_PutChar(' ');
	Usart_PutChar(Set_Time[1] / 16 + 0x30);
	Usart_PutChar(Set_Time[1] % 16 + 0x30);
	Usart_PutString("分");
	Usart_PutChar(' ');
	Usart_PutChar(Set_Time[0] / 16 + 0x30);
	Usart_PutChar(Set_Time[0] % 16 + 0x30);
	Usart_PutString("秒");
	Usart_PutChar(' ');
	Usart_PutString("星期");
	Usart_PutChar(' ');
	//Usart_PutChar(Set_Time[5] / 16 + 0x30);
	Usart_PutChar(Set_Time[5] % 16 + 0x30);
	Usart_PutChar(0x0D);
	Usart_PutChar(0x0A);  //发送回车换行	
	
	DS1302_SetTime(Set_Time);
	
	
	sei();          //使能全局中断  
	
	while(1)
	{
		DS1302_GetTime();
		
		Usart_PutString("现在时间");
		Usart_PutChar(0x0D);
		Usart_PutChar(0x0A);  //发送回车换行
		Usart_PutChar('2');
		Usart_PutChar('0');
		Usart_PutChar(Get_Time[6] / 16 + 0x30);
		Usart_PutChar(Get_Time[6] % 16 + 0x30);
		Usart_PutString("年");
		Usart_PutChar(' ');
		Usart_PutChar(Get_Time[4] / 16 + 0x30);
		Usart_PutChar(Get_Time[4] % 16 + 0x30);
		Usart_PutString("月");
		Usart_PutChar(' ');
		Usart_PutChar(Get_Time[3] / 16 + 0x30);
		Usart_PutChar(Get_Time[3] % 16 + 0x30);
		Usart_PutString("日");
		Usart_PutChar(' ');
		Usart_PutChar(Get_Time[2] / 16 + 0x30);
		Usart_PutChar(Get_Time[2] % 16 + 0x30);
		Usart_PutString("时");
		Usart_PutChar(' ');
		Usart_PutChar(Get_Time[1] / 16 + 0x30);
		Usart_PutChar(Get_Time[1] % 16 + 0x30);
		Usart_PutString("分");
		Usart_PutChar(' ');
		Usart_PutChar(Get_Time[0] / 16 + 0x30);
		Usart_PutChar(Get_Time[0] % 16 + 0x30);
		Usart_PutString("秒");
		Usart_PutChar(' ');
		Usart_PutString("星期");
		Usart_PutChar(' ');
		
		//Usart_PutChar(Set_Time[5] / 16 + 0x30);
		Usart_PutChar(Get_Time[5] % 16 + 0x30);
		Usart_PutChar(0x0D);
		Usart_PutChar(0x0A);  //发送回车换行
	
	for(i = 0;i < 4;i++)
	{
		Delayms(1000);
	}
	
	}
}

//端口状态初始化设置函数
void Port_Init()
{
	PORTD = 0X00;          //USART的发送接收端口分别为PD0和PD1
	DDRD |= (1 << PD1);   //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口
	
	DDRC |= (1 << PC0) | (1 << PC1); //DS1302的SCLK和I/O引脚设为输出
	DDRC |= (1 << PC5);                //DS1302的RST引脚设为输出
}

//USART寄存器配置函数
void Usart_Init()
{
	UCSRA = 0X00;	
	UCSRC |= (1<<URSEL) | (1 << UCSZ1) | (1 << UCSZ0);  //异步,数据格式8,N,1
	     //UCSRC寄存器与UBRRH寄存器共用相同的I/O地址,写 UCSRC 时, URSEL 应设置为 1。
	UBRRL = (F_CPU / BAUD / 16 - 1) % 256;    //波特率设置
	UBRRH = (F_CPU / BAUD / 16 - 1) / 256;		
	UCSRB |= (1 << RXCIE) | (1 << RXEN) | (1 << TXEN);    //发送使能
	
}

//字节发送函数
void Usart_PutChar(unsigned char cTXData)
{
	while( !(UCSRA & (1 << UDRE)) );  //只有数据寄存器为空时才能发送数据
	UDR = cTXData;	                 //发送数据送USART I/O数据寄存器-UDR
}

//接收中断函数
ISR(USART_RXC_vect )
{
	unsigned char Rev;
	Rev = UDR;              //从USART I/O数据寄存器-UDR中读出数据
	Usart_PutChar(Rev);    //将接收到的数据发送
}


void Usart_PutString(unsigned char *pcString)
{
	while (*pcString)
	{
		Usart_PutChar(*pcString++);
	}	
}

//从DS1302读一个字节数据
unsigned char DS1302_ReadByte(void)         
{
	unsigned char i,dat = 0;  //dat存放读出的数据,初始化为0
	PORTC &= ~(1 << PC0);     //DS1302的I/O口上拉不使能,
	DDRC &= ~(1 << PC0);      //DS1302的I/O口设置为输入口,准备读数据
	
	for(i = 0;i < 8;i++)     //读8位,低位在前,右移
	{
		dat >>= 1;           //读出的数据右移一位
		PORTC |= (1 << PC1);  //DS1302的SCLK端口拉高
		Delayus(10);          //
		PORTC &= ~(1 << PC1);  //DS1302的SCLK端口拉低,产生下降沿,
		Delayus(10); 
		if(PINC & (1 << PC0))     //读数据端口状态
		{
			dat |= 0x80;          //如果数据端口位高,相应数据位置1
		}		
	}
	DDRC |= (1 << PC0);		 //最后将数据端口设置为输出
    return dat;				 //返回读出的数据
}

//向DS1302写一个字节数据
void DS1302_WriteByte(unsigned char dat)    
{
	unsigned char i;
	
	for(i = 0;i < 8;i++)      //写8位,低位在前
	{
		PORTC &= ~(1 << PC1);  //DS1302的SCLK置低
		if(dat & 0x01)        //写数据位
		{
			PORTC |= (1 << PC0);   //如果该位为1,则I/O口置高
		}
		else
		{
			PORTC &= ~(1 << PC0);   //如果该位为0,则I/O口置低
		}
		Delayus(10);          //
		PORTC |= (1 << PC1);   //DS1302的SCLK置高,产生上升沿
		dat >>= 1;               //数据右移1位
	}  
}

//从DS1302的指定地址读一个字节数据
unsigned char DS1302_ReadData(unsigned addr) 
{
	unsigned char data;
	
	PORTC &= ~(1 << PC5); //拉低片选端
	PORTC &= ~(1 << PC1);//拉低时钟端
	Delayus(10);
	PORTC |= (1 << PC5);//拉高片选端
	Delayus(10);
	DS1302_WriteByte(addr);//写入操作命令(地址)
	Delayus(10);
	data = DS1302_ReadByte();//读出数据
	Delayus(10);
	PORTC &= ~(1 << PC1);	 //拉低时钟端	
	PORTC &= ~(1 << PC5); //拉低片选端		
	
	return data; 
}

//向DS1302的指定地址写一个字节数据
void DS1302_WriteData(unsigned char addr,unsigned data)  
{
	PORTC &= ~(1 << PC5); //拉低片选端
	PORTC &= ~(1 << PC1);//拉低时钟端
	Delayus(10);
	PORTC |= (1 << PC5);//拉高片选端
	Delayus(10);
	DS1302_WriteByte(addr);//写入操作命令(地址)
	Delayus(10);
	PORTC &= ~(1 << PC1);//拉低时钟端
	Delayus(10);
	DS1302_WriteByte(data);//写入数据
	PORTC &= ~(1 << PC1);	 //拉低时钟端

	Delayus(10);
	PORTC &= ~(1 << PC5); //拉低片选端	
}

//对DS1302设置时间											 
void DS1302_SetTime(unsigned char *time)  
{
	unsigned char i;
	unsigned char addr = 0x80;//写入地址从秒寄存器开始
	
	DS1302_WriteData(WR_PROTECT | WR,UPROTECT);//控制命令,WP位为0,允许写操作
	Delayms(5);
	for(i = 0;i < 7;i++)
	{
		DS1302_WriteData(addr | WR,time[i]);// 秒 分 时 日 月 星期 年   
		addr += 2;
		Delayms(1);
	}
	DS1302_WriteData(WR_PROTECT | WR,PROTECT);//控制命令,WP位为1,不允许写操作    
}

//从DS1302读取时间
void DS1302_GetTime(void)   
{
	unsigned char i;
	/*
	//
	unsigned char addr;
	PORTA &= ~(1 << PA1);
	for(i = 0;i < 7;i++)
	{
		tim[i] = DS1302_ReadData(addr | RD);
		addr += 2;
	}
	*/
	
	////////////////////
	PORTC &= ~(1 << PC5);
	Delayus(10);
	PORTC |= (1 << PC5);
	Delayus(10);
	DS1302_WriteByte(0xbf);
	for(i = 0;i < 8;i++)
	{
		Get_Time[i] = DS1302_ReadByte();
	}
	PORTC &= ~(1 << PC5);
	///////////////////////////////////

	PORTC &= ~(1 << PC1);	
}

//DS1302是否工作检测
unsigned char DS1302_Check(void)           
{
	DS1302_WriteData(WR_PROTECT | WR,UPROTECT);
	DS1302_WriteData(RAMBASE | WR,0x31);
	
	if(DS1302_ReadData(RAMBASE | WR) == 0x31)
	{
		return TURE;
	}
	else
	{
		return FALSE;
	}	
}

//DS1302初始化
void DS1302_Init(void)     
{
	DS1302_WriteData(WR_PROTECT | WR,UPROTECT);   //写入写允许命令
    DS1302_WriteData(SECOND | WR,CLK_START);      //启动振荡器,DS1302开始工作
	DS1302_WriteData( WR_PROTECT | WR,PROTECT);     //控制命令,WP位为1,不允许写操作			 
}


//us级别的延时函数
void Delayus(unsigned int lus)
{
	while(lus--)
	{
		_delay_loop_2(3);      //_delay_loop_2(1)是延时4个时钟周期,参数为3则延时12
		           //个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us
    }
}

//ms级别的延时函数
void Delayms(unsigned int lms)
{
	while(lms--)
	{
		Delayus(1000);        //延时1ms
    }
}

⌨️ 快捷键说明

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