蓝桥杯-单片机基础12——基于2023年IIC代码实现开机次数记录(串行EEPROM存储器AT24C02)

news2024/11/28 18:47:35

蓝桥杯单片机组备赛指南请查看这篇文章:戳此跳转蓝桥杯备赛指南文章

本文章针对蓝桥杯-单片机组比赛开发板所写,代码可直接在比赛开发板上使用。

型号:国信天长4T开发板(绿板),芯片:IAP15F2K61S2

(使用国信天长蓝板也可以完美兼容,与绿板几乎无差别)


使用iic通信的外设有两个:PCF8951,AT24C02。另外一个的讲解文章参考该专栏上一篇

1. 代码目的

        通过对AT24C02的正确设置,可以将单片机开机次数记录下来,并显示在数码管上。并设置独立按键S7为重启模拟按键,即按下S7时,开机次数也会加1。

        即,最终实现自增的方式有:拔插电源、按下开关机键、按下松开下载按键S2、按下松开S7

显示格式为:

当开机次数为一位时,显示:-------X

当开机次数为两位时,显示:------XX

当开机次数为三位时,显示:-----XXX

更多位数我们不做考虑,按照前面的逻辑继续即可

2. iic基础知识讲解


         IIC总线全称:Inter-Integrated Circuit,是由飞利浦公司开发出来的一种串行总线协议,它是一种多主机的总线,当发生主机竞争时,有总线仲裁机制

           IIC总线只有2根信号线,一根是数据线SDA,一根是时钟线SCL。SDA和SCL均为双向信号线,通过上拉电阻接正电源。当总线空闲时,两根线都是高电平。连接到总线上的任一器件,输出低电平,都将使总线的信号变低。
      连接总线的器件输出级必须是集电极或漏极开路,以形成线“与”功能。
      每个具有IIC接口的设备都有一个唯一的地址,也叫做设备地址。

3. AT24C02芯片讲解

        该器件简单来说,就是一个掉电不会丢失数据的存储器

        我们将上方的芯片原理图,与开发板硬件原理图进行对比分析。开发板硬件原理图如下:

读写地址:

        蓝桥杯开发板采用的是2Kbit的存储器,因此我们只看第一行        

        对比上方两个原理图,发现A0,A1,A2全部接地,为000,则读与写只由lsb的最后一位决定,当R/W赋值1则读取数据,赋值0则写入数据。结合msb与lsb内容,当我们需要读取数据时,则写入0xA1;需要写入数据时,则写入0xA0

内存地址字节

        24C02的末尾是02,因此是一个2K Bit的串行EEPROM存储器;2KBit为21024Bit,除以8等于256,因此内部含有256个字节;又因为2^{8}=256,因此在24C02里面有8个大小为8字节的页写缓冲器

        因此我们可以对其进行的操作内存地址有:0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07共8页地址可选择,每页8个字节,可存储2^{8}以内的数据大小

若使用指针寻址,会在查询到页尾时自动跳转到页首继续读取

4. iic底层文件处理(添加头文件方式)

        官方提供了底层iic.c文件,我们可以直接采用,对PCF8951进行正确的通信设置。但是,从16年开始为了增加难度,代码会故意出现错误与遗漏,我们以2023年官方提供的底层文件为参考

        下载链接:链接:https://pan.baidu.com/s/1LfixDiinqsOhYbhrAptbMQ      提取码:1111

步骤一:创建头文件iic.h

        在keil5左侧工程导航栏中,在source group处右键点击“add new items”到工程:

        在新建的iic.h文件中,添加以下代码:

#ifndef __IIC_H__
#define __IIC_H__
 
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);

#endif

步骤二:定义iic.c原函数文件

        在keil5左侧工程导航栏中,在source group处右键点击“add existing items”到工程,并选中官方提供的底层文件:

        此时我们的左侧工程栏就会出现一个新的文件,我们双击打开,并查看原理图:

        因此我们需要在iic.c文件中添加如下代码:

步骤三:在主函数中添加我们新建的头文件

        至此,对于头文件的操作结束。最终我们的iic.c代码的全部展示如下:

/*    #   I2C代码片段说明
    1.     本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
    2.     参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
        中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>
 
sbit sda = P2^1;
sbit scl = P2^0;
 
#define DELAY_TIME    5
 
//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();        
    }
    while(n--);          
}
 
//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
    I2C_Delay(DELAY_TIME);
    sda = 0;
    I2C_Delay(DELAY_TIME);
    scl = 0;    
}
 
//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
    I2C_Delay(DELAY_TIME);
    sda = 1;
    I2C_Delay(DELAY_TIME);
}
 
//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
    
    for(i=0; i<8; i++){
        scl = 0;
        I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
        I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
        I2C_Delay(DELAY_TIME);
    }
    
    scl = 0;  
}
 
//
unsigned char I2CReceiveByte(void)
{
    unsigned char da;
    unsigned char i;
    for(i=0;i<8;i++){   
        scl = 1;
        I2C_Delay(DELAY_TIME);
        da <<= 1;
        if(sda) 
            da |= 0x01;
        scl = 0;
        I2C_Delay(DELAY_TIME);
    }
    return da;    
}
 
//
unsigned char I2CWaitAck(void)
{
    unsigned char ackbit;
    
    scl = 1;
    I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
    I2C_Delay(DELAY_TIME);
    
    return ackbit;
}
 
//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
    I2C_Delay(DELAY_TIME);
    scl = 1;
    I2C_Delay(DELAY_TIME);
    scl = 0; 
    sda = 1;
    I2C_Delay(DELAY_TIME);
}

5. 程序时序流程

        不管是写入数据或是读取数据,时序操作的前5步都是相同的。有时,我们把读取数据的前5步称为“伪写操作”。在编程时,我们需要做的其实就是在主函数文件中,按照顺序将上述过程写出来。
        我们只需要记住1~11个步骤,在比赛时利用官方提供的驱动文件,自己写出调用函数即可。

        操作时,时序错误可能发生在一个地方,即第10步产生非应答信号处。不同的底层代码产生非应答信号的实参不同,我们去观察源程序:

        根据iic时序要求,当scl拉低为低电平时,将sda保持到高电平产生非应答信号,保持到低电平时产生应答信号。因此,

        产生非应答信号:ackbit=1

        产生应答信号:ackbit=0

具体比赛时需要根据官方给的源码,选择不同的传入实参

6. 外设代码参考


7. 代码参考

        按下松开S2下载按键、拔插电源、重启开关,开发板自身会产生类似于重启的效果

        按下松开S7独立按键,为程序定义的伪重启按键

#include <reg52.h>
#include <intrins.h>
#include "iic.h"

sbit S7 = P3^0;
unsigned char power_count = 0;
unsigned char code duanma [18]={ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0x88 ,
												0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,0xbf , 0x7f };

void SMGrunning ();
void write_at24c02 ( unsigned char addr , unsigned char value );
unsigned char read_at24c02 ( unsigned char addr );
												
												
void select_HC573 ( unsigned char channal )
{
	switch ( channal )
	{
		case 4:
			P2 = ( P2 & 0x1f ) | 0x80;
		break;
		case 5:
			P2 = ( P2 & 0x1f ) | 0xa0;
		break;
		case 6:
			P2 = ( P2 & 0x1f ) | 0xc0;
		break;
		case 7:
			P2 = ( P2 & 0x1f ) | 0xe0;
		break;
	}
}

void init_sys ()
{
	select_HC573 ( 4 );
	P0 = 0xff;
	select_HC573 ( 5 );
	P0 = 0x00;
}

void state_SMG ( unsigned char pos_SMG , unsigned char value_SMG )
{
	select_HC573 ( 7 );
	P0 = 0xff;
	
	select_HC573 ( 6 );
	P0 = 0x01 << pos_SMG;
	select_HC573 ( 7 );
	P0 = value_SMG;
}

void state_SMG_all ( unsigned char value_SMG_all )
{
	select_HC573 ( 6 );
	P0 = 0xff;
	select_HC573 ( 7 );
	P0 = value_SMG_all;
}

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

void Delay20ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 216;
	j = 37;
	do
	{
		while (--j);
	} while (--i);
}

void keyrunning ()
{
	if ( S7 == 0 )
	{
		Delay20ms();
		if ( S7 == 0 )
		{
			while ( S7 == 0 )
			{
				SMGrunning ();
			}
			
			power_count ++;
			write_at24c02 ( 0x01 , power_count );
		}
	}
}

void write_at24c02 ( unsigned char addr_write , unsigned char value_write )
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr_write);
	I2CWaitAck();
	
	I2CSendByte(value_write);
	I2CWaitAck();
	I2CStop();
}

unsigned char read_at24c02 ( unsigned char addr_read )
{
	unsigned char power_count_temp;
	
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr_read);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	power_count_temp = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return power_count_temp;
}

void SMGrunning ()
{
	state_SMG ( 0 , duanma[16] );
	Delay1ms();
	state_SMG ( 1 , duanma[16] );
	Delay1ms();
	state_SMG ( 2 , duanma[16] );
	Delay1ms();
	state_SMG ( 3 , duanma[16] );
	Delay1ms();
	state_SMG ( 4 , duanma[16] );
	Delay1ms();
	if ( power_count/100 != 0 )
	{		
		state_SMG ( 5 , duanma[power_count/100] );
	}
	else
	{
		state_SMG ( 5 , duanma[16] );
	}
	Delay1ms();
	if ( power_count/10 != 0 )
	{		
		state_SMG ( 6 , duanma[power_count/10] );
	}
	else
	{
		state_SMG ( 6 , duanma[16] );
	}
	Delay1ms();
	state_SMG ( 7 , duanma[power_count%10] );
	Delay1ms();
	
	state_SMG_all ( 0xff );
}

void main ()
{
	init_sys ();
	power_count = read_at24c02 ( 0x01 );
	power_count ++;
	write_at24c02 ( 0x01 , power_count );
	while ( 1 )
	{
		SMGrunning ();
		keyrunning ();
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1562398.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

libusb Qt使用记录

1.libusb 下载 &#xff0c;选择编译好的二进制文件&#xff0c;libusb-1.0.26-binaries.7z libusb Activity 2. 解压 3. 在 Qt Widgets Application 或者 Qt Console Application 工程中导入库&#xff0c;Qt 使用的是 minggw 64编译器&#xff0c;所以选择libusb-MinGW-x64。…

在岸上是永远学不会游泳的

为了让各位技术宅的师傅们了解如何追女孩&#xff0c;花无缺表哥来投稿啦&#xff01;&#xff01;&#xff01; 在岸上是永远也学不会游泳的&#xff0c;就算是最好的教练来教你也没用&#xff0c;因为你没有去实践。实践是快速学习的最佳手段&#xff0c;将这些方法运用到工…

深度学习理论基础(三)封装数据集及手写数字识别

目录 前期准备一、制作数据集1. excel表格数据2. 代码 二、手写数字识别1. 下载数据集2. 搭建模型3. 训练网络4. 测试网络5. 保存训练模型6. 导入已经训练好的模型文件7. 完整代码 前期准备 必须使用 3 个 PyTorch 内置的实用工具&#xff08;utils&#xff09;&#xff1a; ⚫…

java数据结构与算法刷题-----LeetCode695. 岛屿的最大面积

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 深度优先遍历2. 广度优先 1. 深度优先遍历 这不是找最短路径&…

量化交易入门(三十八)CCI指标Python实现和回测

今天我们先单纯用CCI指标来完成策略的编写&#xff0c;后续我们会改进这个策略&#xff0c;将CCI指标和前面讲到的MACD和RSI相结合来优化&#xff0c;看看我们优化后的效果会不会更好。 一、量化策略 CCI指标在量化交易中的策略&#xff1a; 在以下情况下生成买入信号&#…

C# 排序的多种实现方式(经典)

一、 对数组进行排序 最常见的排序是对一个数组排序&#xff0c;比如&#xff1a; int[] aArray new int[8] { 18, 17, 21, 23, 11, 31, 27, 38 }; 1、利用冒泡排序进行排序&#xff1a; &#xff08;即每个值都和它后面的数值比较&#xff0c;每次拿出最小值&#xff09; s…

黄仁勋:我们有望在未来五到十年内见证完全由人工智能生成的游戏

黄仁勋&#xff1a;我们有望在未来五到十年内见证完全由人工智能生成的游戏 近日&#xff0c;英伟达&#xff08;Nvidia&#xff09;GPU技术大会上&#xff0c;英伟达首席执行官黄仁勋&#xff08;Jensen Huang&#xff09;对未来游戏产业的展望引发了业界的广泛关注。在一次与…

centos安装docker,docker安装centos进而安装宝塔

背景 由于工作需要自己有许多的web应用要部署在云服务器上。然而资金有限每年都要去阿里云&#xff0c;腾讯云&#xff0c;华为云买最便宜的服务器&#xff0c;这就意味着每年都要经历一次痛苦的环境安装项目部署的过程&#xff08;nginx、mysql、elasticsearch、redis等等&am…

【Redis】Redis的类型及相关操作

一、常用的key操作命令 keys * 查看当前数据库的键值 ttl key 查看还有多少秒过期&#xff0c;-1表示永不过期&#xff0c;-2表示过期 del / unlink key 同样是删除&#xff0c;unlink是非阻塞删除&#xff0c;del则有可能导致阻塞 select dbindex 切换数据库 flushdb 清空…

CA根证书——https安全保障的基石

HTTPS通信中&#xff0c;服务器端使用数字证书来证明自己的身份。客户端需要验证服务器发送的证书的真实性。这就需要一个可信的第三方机构&#xff0c;即CA&#xff0c;来颁发和管理证书。CA根证书是证书颁发机构层次结构的顶级证书&#xff0c;客户端信任的所有证书都可以追溯…

并发编程之线程池的详细解析

线程池 线程池的优势&#xff1a; 线程池做的工作只要是控制运行的线程数量&#xff0c;处理过程中将任务放入队列&#xff0c;然后线程创建石后启动这些任务&#xff0c;如果线程数量超过了最大数量&#xff0c;超出数量的线程排队等候&#xff0c;等其他线程执行完毕&#xf…

【回眸】Tessy 单元测试软件使用指南(三)怎么打桩和指针赋值和测试

目录 前言 Tessy 如何进行打桩操作 普通桩 高级桩 手写桩 Tessy单元测试之指针相关测试注意事项 有类型的指针&#xff08;非函数指针&#xff09;&#xff1a; 有类型的函数指针&#xff1a; void 类型的指针&#xff1a; 结语 前言 进行单元测试之后&#xff0c;但凡…

css-盒子阴影

1.box-shadow: 10px 20px 10px 10px blue; 参数对应顺序&#xff1a;上下&#xff0c;左右 &#xff0c;模糊程度&#xff0c;颜色 &#xff0c;阴影大小 2.box-shadow: 10px 20px 10px 20px blue,-10px -20px 10px 50px red; 负号就是相反方向 支持多个阴影 在后面加逗号 3…

dockerfile制作-pytoch+深度学习环境版

你好你好&#xff01; 以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 文档内容docker相关术语docker常用命令容器常用命令根据dockerfile创建容器dokerfile文件内容 docker问题&#xff1a;可能的原因和解决方法示例修改修改后的D…

谷粒商城——通过接口幂等性防止重复提交订单

如果用户向后端服务提交多次相同订单的提交服务&#xff0c;那么后端应该只生成一条订单记录。 有一些操作天然是幂等的&#xff0c;如查询操作和删除操作等。 幂等性实现 1.token机制&#xff08;仅这个方法适用于订单的重复提交&#xff09; 后端先生成1个令牌将其记录在R…

MATLAB绘制堆叠填充图--巧用句柄

MATLAB绘制堆叠填充图–巧用句柄 目录 MATLAB绘制堆叠填充图--巧用句柄1. 主要原理讲解1.1 主要函数1.2 句柄原理 2. 绘图示例2.1 准备数据2.2 绘制堆叠填充图-使用句柄控制图形属性2.3 设置填充颜色和样式2.4 添加标题和标签2.5 绘图效果 3. 结语 堆叠填充图是一种常见的数据可…

【2024年5月备考新增】《2024高项论文精华版(3)考试技巧》

3 考试技巧 3.1 考试难度 考试难度上&#xff0c;越是常见的题目、越是被大家预测的题目&#xff0c;阅卷就会更严格。 越是大家猜测不到的&#xff0c;越是小众的题目&#xff0c;阅卷严格程度就会低。 3.2 技巧 1、记住软考论文的目的&#xff0c;不是为了证明你的格式严谨…

中科驭数超低时延网络解决方案入选2023年度金融信创优秀解决方案

近日&#xff0c;由中国人民银行领导、中国金融电子化集团有限公司牵头组建的金融信创生态实验室发布「2023年度第三期金融信创优秀解决方案」&#xff0c;中科驭数超低时延网络解决方案从众多方案中脱颖而出&#xff0c;成功入选&#xff0c;代表了该方案的技术创新和金融实践…

使用plasmo开发浏览器插件在网页指定位置添加自定义UI

使用plasmo开发浏览器插件的时候&#xff0c;有时候需要在指定网站的指定页面添加自定义的UI内容&#xff0c;如果通过content.js内容脚本去通过js创建的话&#xff0c;可就太麻烦了&#xff0c;要写不少的js代码。不过plasmo已经帮我们实现了这个功能&#xff0c;就是Content …

安全防御产品—锐安盾重磅上线,助力更安全、更流畅的业务体验

在互联网时代&#xff0c;互联网技术蓬勃发展&#xff0c;然而&#xff0c;随之而来的网络安全问题也备受关注。诸如DDoS攻击、CC攻击、常见Web攻击等攻击手段突如其来&#xff0c;导致企业业务中断&#xff0c;严重影响企业业务正常运行。对此&#xff0c;锐成云重磅推出安全防…