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

📄 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>        //io端口寄存器配置文件,必须包含
#include <util/delay.h>

//端口声明
/*注:
AVR单片机I/O口模拟I2C总线时建议在外部连接上拉电阻 ,这样可通过改变I/O口输入输出方向的方式 
来设置高低电平, 输出口保持不变(0) ,此时如DDRX寄存器为1则变成输出0,若DDRX为0,则I/O口 
呈现高阻状态,但因外部的上拉电阻,总线相当于设置高电平,即通过设置DDRX的方式控制总线的高低
*/

#define SCL_INPUT (DDRC &= ~(1 << PC1))  //SCL设置为输入口
#define SCL_OUTPUT (DDRC |= (1 << PC1))  //SCL设置为输出口
#define SCL_LOW (PORTC &= ~(1 << PC1))   //SCL设置为输出低电平
#define SCL_HIGH (PORTC |= (1 << PC1))   //SCL设置为输出高电平
#define SCL_INDATA (PINC & (1 << PC1))   //读取SCL的端口状态

#define SDA_INPUT (DDRC &= ~(1 << PC0))   //SDA设置为输入口
#define SDA_OUTPUT (DDRC |= (1 << PC0))   //SDA设置为输出口 
#define SDA_LOW (PORTC &= ~(1 << PC0))    //SDA设置为输出低电平
#define SDA_HIGH (PORTC |= (1 << PC0))   //SDA设置为输出高电平
#define SDA_INDATA (PINC & (1 << PC0))   //读取SDA的端口状态

//变量声明
#define EEPROM_BUS_ADDRESS 0xa0         //器件地址

//函数声明
void Delayus(unsigned int lus);         //us延时函数
void Delayms(unsigned int lms);        //ms延时函数
void I2C_Init(void);                    //I2C端口初始化
unsigned char I2C_Start(void);         //发送起始信号
void I2C_Stop(void);                    //发送结束信号
unsigned char I2C_WriteByte(unsigned char dat);  //写一个字节
unsigned char I2C_ReadByte(unsigned char ack);   //读一个字节
unsigned char EEPROM_ReadByte(unsigned int add); //从固定地址读一字节
void EEPROM_WriteByte(unsigned int add,unsigned char data);  //向固定地址写一字节


int main(void)            //GCC中main文件必须为返回整形值的函数,没有参数
{
	unsigned char i;

	PORTB = 0x00;     
	DDRB = 0xFF;       //端口PortB设为输出口,通过相应位LED的变化指示程序运行结果

	I2C_Init();        //I2C端口初始化
	
	EEPROM_WriteByte(0x01aa,0x5a);  //向固定地址写一字节,向第26页的第十个字节写入数据0x5a

	i = EEPROM_ReadByte(0x01aa); //从固定地址读一字节
	
	if(i == 0x5a)
	{
		PORTB |= 0xFE;     //读出的数据正确,则LED0点亮
	}
	else
	{
		PORTB |= 0xFD;       //读出的数据不正确,则LED1点亮
	}
	
	while(1)
	{
		
		
	}
}

//I2C初始化函数
void I2C_Init(void)
{
	SCL_LOW;    //SCL的PORT状态锁定为0,以后不再改变
	SCL_INPUT;   //SCL设置为输入口
	
	SDA_LOW;    //SDA的PORT状态锁定为0,以后不再改变
	SDA_INPUT;    //SDA设置为输入口
	Delayus(10);
}

//I2C起始条件
unsigned char I2C_Start(void)
{
	Delayus(10);
	SDA_INPUT;   //SDA高电平
	Delayus(10);  //延时一段时间,使单片机时钟频率符合I2C时钟
	SCL_INPUT;   //SCL高电平
	Delayus(10);	
	SDA_OUTPUT;	  //SDA变低,产生由高到低的变化
	Delayus(10);	
	SCL_OUTPUT;	  //SCL变低,占用总线
	Delayus(10);
	
	return 1;
}

//I2C结束条件
void I2C_Stop(void)
{
	Delayus(10);
	SDA_OUTPUT;   //SDA低电平
	Delayus(10);	
	SCL_INPUT;   //SCL高电平	
	Delayus(10);	
	SDA_INPUT;   //SDA变为高电平,产生由低到高的变化
	Delayus(10);		
}

//向I2C写一个字节
unsigned char I2C_WriteByte(unsigned char dat)
{
	unsigned char i,ack; //ack为应答信号
	for(i = 0;i < 8; i++)       //写8位(1个字节)数据
	{
		if(dat & 0x80)        //写入数据,左移,从最高位写入
		{
			SDA_INPUT;       //如果该位为1,SDA拉高电平
		}
		else
		{
			SDA_OUTPUT;		//	如果该位为0,SDA拉低电平
		}
		SCL_INPUT;        //SCL高电平,保持数据
		Delayus(10);
		SCL_OUTPUT;		 //SCL低电平,数据被送入I2C
		dat <<= 1;       //需要写入的数据左移一位,送最高位
		Delayus(10);    //
	}
	Delayus(10);
	SDA_INPUT;             //SDA拉高,同时变为输入口
	Delayus(10);
	SCL_INPUT;	    //SCL拉高,准备读取应答信号
	Delayus(10);
	
	if(SDA_INDATA)
	{
		ack = 0;           //如果此时SDA为高,说明没有应答信号
		PORTB |= 0x04;     //没有应答信号,点亮LED2
	}
	else
	{
		ack = 1;         //如果此时SDA为低,说明有应答信号
		PORTB |= 0x08;       //有应答信号,点亮LED3
	}
	SCL_OUTPUT;	        //SCL拉低
	Delayus(10);
	return ack;       //返回应答信号
}

//从I2C读一个字节
unsigned char I2C_ReadByte(unsigned char ack)
{
	unsigned char i,dat = 0;     //dat为读出的数据
	SDA_INPUT;                  //SDA变为输入口
	for(i = 0;i < 8;i++)       //读出8位(1个字节)数据
	{
		Delayus(10);
		SCL_OUTPUT;		  //SCL低,这时允许从I2C发送数据到SDA上
		Delayus(10);
		SCL_INPUT;    //SCL高,准备读取SDA上的数据
		
		Delayus(10);
		dat <<= 1;       //读取的数据左移一位,从最高位读起
		if(SDA_INDATA)
		{
			dat++;  //如果DSA为高,则读取的数据加1
		}
		
		Delayus(10);
	}
	SCL_OUTPUT;	      //SCL拉低,准备下一个数据变化
	Delayus(10);
	if(!ack)     //
	{
		SDA_INPUT;   //发送NACK
	}
	else
	{
		SDA_OUTPUT;		 //发送ACK
	}
	Delayus(10);
	SCL_INPUT;       //SCL高
	Delayus(10);
	SCL_OUTPUT;       //SCL低
	
	Delayus(10);
	
	return (dat);     //返回读到的数据
}

//从固定地址读一字节
unsigned char EEPROM_ReadByte(unsigned int add)
{
	unsigned char data;
	
	I2C_Start();         //发送起始信号
                    
	I2C_WriteByte(EEPROM_BUS_ADDRESS | ((add >> 8) << 1));  //写器件地址和页地址的高3位	
	
	I2C_WriteByte(add);  //写页地址的低4位和页地址内部偏移量
	
	I2C_Start();         //发送起始信号
	I2C_WriteByte(EEPROM_BUS_ADDRESS | 0x01);  //发送读命令
	data = I2C_ReadByte(0);   //读一个字节    
	I2C_Stop();               //发送结束信号
	
	return data;
} 

//向固定地址写一字节
void EEPROM_WriteByte(unsigned int add,unsigned char data)
{
	I2C_Start();         //发送起始信号
                    
	I2C_WriteByte(EEPROM_BUS_ADDRESS | ((add >> 8) << 1));  //写器件地址和页地址的高3位
	
	I2C_WriteByte(add);  //写页地址的低4位和页地址内部偏移量
	
	I2C_WriteByte(data);  //写一个字节数据
	I2C_Stop();               //发送结束信号
	Delayms(10);
}
  
//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 + -