I2C协议在项目开发中使用很常见,很多存储芯片使用I2C接口。由于51单片机没有I2C接口,这里使用IO口模拟I2C通讯协议,来完成I2C芯片驱动。使用的I2C芯片为AT24C02。
原理图如下:
代码如下:
//程序功能:计时器每一秒向AT24C02保持数据,同时数码管显示,重启之后读取出数据接着计时,100S循环
//程序问题:无法写入
#include
#define uint unsigned int
#define uchar unsigned char
//变量定义
uint timer_flag; //用于判断定时器T0方式一是否计满1s
uchar shiwei,gewei; //数码管显示的十位与个位
uint number;
uchar time_date; //当前时间数据
//控制端口声明
sbit duanxuan=P2^6; //数码管段选端
sbit weixuan=P2^7; //数码管位选端
sbit AT24C02_SDA=P2^0; //AT24C02串行数据输入输出端口
sbit AT24C02_SCLK=P2^1; //时钟信号端口
//数码管显示数字段码定义
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
//相关函数声明
void delay_minute(); //延时us级函数声明
void delay_xs(uint); //延时s级函数声明
void timer_init(); //定时器T0方式一初始化函数声明
void AT24C02_init(); //I^2C通讯总线初始化函数声明
void star(); //I^2C通讯启动函数声明
void stop(); //I^2C通讯停止函数声明
void response(); //应答函数声明
void write_in_byte(uchar); //写入一个字节函数声明
uchar read_out_byte(); //读出一个字节函数声明,函数放回到读出的值
//注意写入一个字节与写入数据的区别,前者是后者的一个子过程,读取同
void saveing(uchar,uchar); //向AT24C02保存数据函数声明
uchar load(uchar); //从AT24C02载入掉电之前的数据,函数放回到读出的值
void quwei(uchar); //显示数字取出各位与十位
void display(uchar); //数码管显示函数声明
//主函数
void main()
{
AT24C02_init(); //AT24C02初始化
time_date=load(3); //开机首先载入AT24C02中的数据,这里读取的是第三位址的数据
if(time_date>100) //防止上一次保存的数据是100,这里计时是100循环的
{
time_date=1;
}
timer_init(); //计时器T0方式一初始化
while(1)
{
display(time_date); //显示时间
if(timer_flag==1) //如果计满一秒,就保存时间数据
{
timer_flag=0;
saveing(3,time_date); //保存时间数据
}
}
}
//延时us级函数主体
void delay_minute()
{;;}
//延时s级函数主体
void delay_xs(uint s)
{
uint i,j;
for(i=s;i>0;i--)
{
for(j=110;j>0;j--)
{
}
}
}
//定时器T0方式一初始化函数主体
void timer_init()
{
//方式选择
TMOD=0x01;
//预装初值
TH0=(65536-46080)/256;
TL0=(65536-46080)%6;
//开中断
EA=1;
ET0=1;
//启动定时器
TR0=1;
}
//I^2C通讯总线初始化函数主体
void AT24C02_init() //两线均写1 AT24C02数据有效规则,sclk为高电平且sda数据稳定,当sda发生有效数据变化时,sclk必须要是0
{
AT24C02_SDA=1;
delay_minute();
AT24C02_SCLK=1;
delay_minute();
}
//I^2C通讯启动函数主体
void star() //启动规则:SCLK-1,SDA下降沿
{
AT24C02_SDA=1; //一定要SDA首先为1,再是SCLK为1,否则会出现一个停止信号
delay_minute();
AT24C02_SCLK=1;
delay_minute();
AT24C02_SDA=0;
delay_minute();
}
//I^2C通讯停止函数主体
void stop() //停止规则:SCLK-1,SDA上升沿
{
AT24C02_SDA=0; //一定要SDA首先为0,再是SCLK为1,否则会出现一个启动信号
delay_minute();
AT24C02_SCLK=1;
delay_minute();
AT24C02_SDA=1;
delay_minute();
}
//应答函数主体
void response() //应答规则:SCLK-1,等待从机把SDA拉低
{
uint i;
AT24C02_SCLK=1;
delay_minute();
while(AT24C02_SDA==1&&i<255)//等待从机把SDA拉低,且超过一定时间没有应答,默认已经应答
{
i++;
}
AT24C02_SCLK=0; //应答之后,SCLK-0.防止数据误操作,因为SCLK-1,数据就是有效地
delay_minute();
}
//写入一个字节函数主体
void write_in_byte(uchar date)
{
uint i,buffer; //i用于循环发送每一位,buffer缓冲数据
buffer=date;
for(i=0;i<8;i++)
{
buffer=buffer<<1; //buffer左旋,高位就放入CY
AT24C02_SCLK=0; //有效发送规则:sclk-0变化数据,sclk-1数据稳定后有效
delay_minute();
AT24C02_SDA=CY;
delay_minute();
AT24C02_SCLK=1;
delay_minute();
}
AT24C02_SCLK=0; //不发送,一定是SCLK-0,SDA-1
delay_minute();
AT24C02_SDA=1;
delay_minute();
}
//读出一个字节函数主体
uchar read_out_byte() //读出规则:启动-控制字片选+写(为了写入要读取的地址)-应答-写入存储地址-应答-读取数据-应答-停止
{
uchar i,buffer_writting;
//--------------------------------------------------
//不能少的
AT24C02_SCLK=0; //方便SDA数据发生有效变化
delay_minute();
AT24C02_SDA=1;
delay_minute();
//--------------------------------------------------
for(i=0;i<8;i++)
{
AT24C02_SCLK=1;
delay_minute();
buffer_writting=(buffer_writting<<1)|AT24C02_SDA;//buffer_writting左旋之后与AT24C02_SDA的数据线与
delay_minute();
AT24C02_SCLK=0;
delay_minute();
}
return buffer_writting;
}
//向AT24C02保存数据函数主体
void saveing(uchar address,uchar time_date0) //写入字节规则:启动-控制字片选+写-应答-写入存储地址-应答-写入数据-应答-停止
{
star(); //启动信号
write_in_byte(0xa0);
response();
write_in_byte(address);
response();
write_in_byte(time_date0);
response();
stop();
}
//从AT24C02载入掉电之前的数据函数主体
uchar load(uchar address) //读出规则:启动-控制字片选+写(为了写入要读取的地址)-应答-写入存储地址-应答-读取数据-应答-停止
{
uchar time_date_former;
star();
write_in_byte(0xa0);
response();
write_in_byte(address);
response();
time_date_former=read_out_byte();
stop();
return time_date_former;
}
//显示数字取出各位与十位函数主体
void quwei(uchar quwei_date)
{
shiwei=quwei_date/10;
gewei=quwei_date;
}
//数码管显示函数函数主体
void display(uchar display_date)
{
quwei(display_date);
//显示第一个数码管
duanxuan=1;
P0=table[shiwei];
duanxuan=0;
P0=0xff;
weixuan=1;
P0=0xfe;
weixuan=0;
delay_xs(2);
//显示第二的数码管
duanxuan=1;
P0=table[gewei];
duanxuan=0;
P0=0xff;
weixuan=1;
P0=0xfd;
weixuan=0;
delay_xs(2);
}
//T0定时器方式一中断服务程序
void T0_timer_no1() interrupt 1
{
//预装初值
TH0=(65536-46080)/256;
TL0=(65536-46080)%6;
number++;
if(number==20) //20次计满就是1s
{
number=0;
time_date++; //时间累加
timer_flag=1; //计满一次就保存数据
if(time_date==100) //100s循环计时
{
time_date=0;
}
}
}
以上,结束。
关键字:51单片机 I2C AT24C02
引用地址:
51单片机 I2C AT24C02
推荐阅读最新更新时间:2024-03-16 14:38
51单片机LED流星雨拖尾灯程序
流星雨就是几个亮度不同的灯一起滚动,亮度依次更暗,像流星雨拖着尾巴。 控制全彩(三色)led也可以用同样的概念编程。 用的是51的单片机pwm实现的拖尾效果 程序的解说以及视频演示请打开http://www.51hei.com/bbs/dpj-22524-1.html 里面有详细的说明. 程序源码: #include reg52.h #define uint unsigned int #define uchar unsigned char uchar abit=16; //流到哪位 uchar atimer0_n; uchar code abit8 ={1,2,4,8,16,32,64,128,0}; uchar nn; c
[单片机]
51单片机的延时子程序
延时程序在单片机编程中使用非常广泛,但一些读者在学习中不知道延时程序怎么编程,不知道机器周期和指令周期的区别,不知道延时程序指令的用法, ,本文就此问题从延时程序的基本概念、机器周期和指令周期的区别和联系、相关指令的用法等用图解法的形式详尽的回答读者 我们知道程序设计是单片机开发最重要的工作,而程序在执行过程中常常需要完成延时的功能。例如 在交通灯的控制程序中,需要控制红灯亮的时间持续30秒,就可以通过延时程序来完成。延时程序是如何实现的呢?下面让我们先来了解一些相关的概念。 一、机器周期和指令周期 1.机器周期是指单片机完成一个基本操作所花费的时间,一般使用微秒来计量单片机的运行速度,51 单片机的一个机器周期包
[单片机]
基于51单片机自动售货机设计
一.硬件方案 本设计由STC系列单片机+12864显示+电源模块+按键模块+蜂鸣器报警模块等元件组成。 使用STC89C52(STC89C52数据手册)单片机设计,设有8个按键,3个按键模拟硬币(5元、1元、5角),另外5个按键模拟货物选择,一块12864显示屏;如图: 二.设计功能 (1)开机启动显示货物价格列表,自动切换列表。 (2)可以选择①—⑤种货物(或更多)。 (3)按对应按键可选择该货物。 (4)选择后,提示要投进的金额,并显示投币有效时间30秒(可修改)。 (5)按键模拟投币,有5元、1元、5角。 (6)投币金额等于或大于所选货物的金额则购物成功。 (7)若投币不足,则30秒后自动退回。 三.设计原理图 (1
[单片机]
用定时器做的流水灯
简介:在51单片机开发板上,用定时器做了一个流水灯程序,调整非常灵活,很实用拿出来和朋友们一起分享 #include reg52.h unsigned char sz ={ 0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f, 0xbf,0xdf,0xef,0xf7, 0xfb,0xfd, }; void main() { unsigned char cnt = 0; //声明定时器并赋值 unsigned char sec = 0; //声明计数器并赋值 TMOD = 0x01; //设置定时器模式为1 TH0 = 0xb8; //高位定时器并赋初值 TL0 = 0x00; //低位定时
[单片机]
51单片机实验13:温度传感器模块应用
开发板温度模块电路图如下: 目的:利用开发板温度传感器测量温度,并在数码管显示。 开发板温度传感器模块相关内容:https://blog.csdn.net/cax1165/article/details/86763991 开发板数码管模块的相关内容:https://blog.csdn.net/cax1165/article/details/86557551 主函数: #include reg52.h #include temp.h #define uc unsigned char #define ui unsigned int sbit LSA=P2^2; sbit LSB=P2^3; sbit LSC
[单片机]
51单片机扩充串行口的方法
基本的 51 单片机有四个并行口,其中还包含了一个串行口。 当接口不够用的时候,大家就会想到,使用什么外接芯片来扩充。 但是,各种教材、参考书、网络文章,介绍扩充并行口的花样不少,扩充串行口的方法,几乎无人问津。 偶尔见到一个,也是使用 8250、8251 等“巨型”芯片来扩充的 使用这些芯片,就要占用单片机很多的更为紧缺的并行口,基本上就是得不偿失。更别说还要设置复杂的控制字了。 使用简单的三态门,即可为单片机扩充串行口,仅仅占用单片机的一、二个引脚作为控制引线而已。 实际上是很简单的,就像使用 74LS373、74LS244 扩充并行口一样,为串行口,配上合适三态门就行了。 选用 74LS125(低电平
[单片机]
51单片机的中断基本知识介绍
1、中断的概念 对于单片机中断的概念,我们可以这样理解:单片机处理某一事件A时,发生了另一事件B请求(中断请求);单片机暂时中断当前工作,转去处理事件B(中断响应和中断服务);待单片机将事件B处理完毕,再回到原来事件A被中断的地方继续处理事件A(中断返回),这一过程称为中断。 引起单片机中断的根源或原因: 中断源向单片机提出中断请求。 2、中断优先级 单片机的中断系统一般允许多个中断源,当几个中断源同时向单片机请求中断,要求为它服务的时候,这就存在单片机优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。单片机总是先响应优先级别最高的中断请
[单片机]
51单片机烧写程序的方法
STC89C51是应用广泛的51单片机,很多人都是通过该单片机入门学习的,单片机的学习需要勤动手。单片机需要烧写程序,要用到相关的软件和硬件。下面介绍一下51单片机烧写程序的方法。 1 所用到的硬件工具 51单片机烧写程序需要用到单片机的UART串口,所用到的工具为USB/TTL,具有四个引脚分别为5V、GND、TXD、RXD,需要和单片机的UART口连接,在连接的时候需要注意的是,串口要交叉连接,即USB/TTL的TXD和单片机的RXD连接;USB/TTL的RXD和单片机的TXD连接。 2 所用到的软件以及设置 STC的51单片机需要用到STC-ISP软件,该软件可以在STC的官网上下载到 烧写过程为:1)选择具体的单片机型
[单片机]