单片机教程-51系列单片机读写IIC总线(28)
- 格式:ppt
- 大小:378.00 KB
- 文档页数:20
51单片机的I2C底层驱动程序(IO口模拟)/*Title:I2C for 80C51Author:yuyouliang51单片机(本人使用STC89C52单片机,12T模式)的I2C驱动程序,使用逻辑分析仪对该协议进行分析,发现波形比较美观,SCL 的频率在70KHz左右(11.0592M晶振),低于标准的100K,可以适应大多数的I2C器件。
如果感觉速度过快或过慢,可以自行修改延时。
希望可以给读者一个参考,给读者一些帮助!*//*i2c.h文件 */#ifndef __I2C_H_#define __I2C_H_sbit SCL = P2^1;sbit SDA = P2^0;void start_i2c(); //启动I2C总线:SCL高电平期间,SDA由高变低void stop_i2c(); //停止I2C总线:SCL高电平期间,SDA由低变高void send_i2c(unsigned char c); //主机发送一个字节,先发送最高位unsigned char receive_i2c(); //主机接收一个字节,先接收最高位void master_ack(bit ack); //主机非应答信号(填参数0)或应答信号(填参数1)void slave_ack(); //等待从机应答信号#endif/* i2c.c文件 */#include#include#include#define nop() _nop_()void start_i2c() //启动I2C总线:SCL高电平期间,SDA由高变低{SDA=1;SCL=1;nop();nop();nop();nop();SDA=0;SCL=0;}void stop_i2c() //停止I2C总线,SCL高电平期间,SDA由低变高{SDA=0;SCL=1;nop();nop();nop();nop();SDA=1;}void slave_ack() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
51单片机汇编语言入门教程什么是51单片机
51单片机指的是英特尔公司推出的一种单片机芯片种类,其名字为“AT89S52”。
后来,这种芯片因其使用广泛,被人们简称为“51单片机”。
为什么要研究汇编语言
研究汇编语言能够让我们更好地理解机器是如何执行指令的,
从而更好地优化程序,提高程序运行效率。
汇编语言基础知识
数据类型
- 字节:一个字节是8位二进制数,可以表示0~255之间的数。
- 字:一个字是16位二进制数,可以表示0~之间的数。
- 双字:一个双字是32位二进制数,可以表示0~之间的数。
指令集
51单片机有大约100条汇编指令,这些指令可以完成各种操作,如运算、数据传输、中断处理等。
寄存器
51单片机有4个8位的通用寄存器(寄存器0~3)和2个16
位的通用寄存器(DPTR和PC)。
程序结构
51单片机只有一种程序结构——线性结构。
程序从0地址开始执行,一条一条地执行,直到程序结束。
编写第一个汇编程序
以下是一个简单的汇编程序示例:
ORG 0H ;设置程序起始地址为0H
MOV P1, #55H ;将55H赋值给P1口
END ;程序结束指令
这个程序的作用是将55H赋值给P1口。
总结
通过学习本教程,我们了解了基本的汇编语言知识,包括数据
类型、指令集、寄存器、程序结构以及编写程序的基本步骤。
希望
这份教程可以帮助初学者顺利掌握51单片机汇编语言编程的基础。
51单片机引脚读写函数51单片机是一种常见的微控制器,它有多个引脚用于连接外部设备和执行各种功能。
在使用51单片机时,我们通常需要编写读取和写入引脚的函数来控制外部设备或与其他设备进行通信。
首先,让我们来看看如何编写一个读取引脚状态的函数。
在51单片机的编程中,我们可以使用特定的语言(比如C语言)来编写这样的函数。
一个简单的读取引脚状态的函数可能如下所示:c.int readPin(int pinNumber) {。
return P0 & (1 << pinNumber);}。
在这个函数中,我们使用了P0寄存器来读取引脚的状态。
我们通过将1左移pinNumber位来创建一个掩码,然后使用按位与操作来获取该引脚的状态。
这个函数可以根据具体的引脚编号来读取相应引脚的状态。
接下来,让我们来看看如何编写一个写入引脚状态的函数。
一个简单的写入引脚状态的函数可能如下所示:c.void writePin(int pinNumber, int value) {。
if (value == 1) {。
P0 |= (1 << pinNumber);} else {。
P0 &= ~(1 << pinNumber);}。
}。
在这个函数中,我们同样使用了P0寄存器来写入引脚的状态。
根据传入的value参数,我们使用按位或操作或按位与非操作来设置或清除相应的引脚位。
需要注意的是,以上的示例函数是针对51单片机的特定引脚操作的示例,实际使用时需要根据具体的引脚编号和端口寄存器进行相应的修改。
同时,还需要考虑到引脚的输入输出模式、上下拉电阻等其他因素。
总之,编写51单片机引脚的读写函数需要考虑到具体的引脚编号、端口寄存器的操作以及引脚的输入输出模式等因素,以确保准确可靠地控制引脚的状态。
希望这个回答能够帮助你更好地理解51单片机引脚的读写函数。
51单⽚机内部EEPROM读写#include <reg52.h>#include <intrins.h>//定义类型,⽅便代码移植typedef unsigned char UINT8;typedef unsigned int UINT16;typedef unsigned long UINT32;typedef char INT8;typedef int INT16;typedef long INT32;static UINT8 i=0;/*定义寄存器 ISP*/sfr ISP_DATA= 0xe2; // Flash数据寄存器sfr ISP_ADDRH= 0xe3;// Flash⾼字节地址寄存器sfr ISP_ADDRL= 0xe4;// Flash低字节地址寄存器sfr ISP_CMD= 0xe5;// Flash命令模式寄存器sfr ISP_TRIG= 0xe6;// Flash命令触发寄存器sfr ISP_CONTR= 0xe7;// ISP/IAP 控制寄存器#define NOP() _nop_()#define EEPROM_START_ADDRESS 0X2000#define LED_PORT P2//微秒级延时void DelayNus(UINT16 t){UINT16 d=0;d=t;do{NOP();}while(--d > 0);}//毫秒级延时void DelayNms(UINT16 t){do{DelayNus(1000);}while(--t > 0);}//EEPROM使能void EEPROMEnable(void){ISP_CONTR=0x81;//使能并设置好等待时间}//EEPROM禁⽤void EEPROMDisable(void){ISP_CONTR=0x00;//禁⽌EEPROMISP_CMD = 0X00;//⽆ISP操作ISP_TRIG = 0X00;//清零ISP_ADDRH = 0X00;//清零ISP_ADDRL = 0X00;//清零}//eeprom 设置读写地址(相对地址)void EEPROMSetAddress(UINT16 addr){addr+=EEPROM_START_ADDRESS;//初始化地址ISP_ADDRH=(UINT8)(addr>>8);//设置读写地址⾼字节ISP_ADDRL=(UINT8) addr; //设置读写地址低字节}//EEPROM启动void EEPROMStart(void){ISP_TRIG=0x46;ISP_TRIG=0xB9;}//EEPROM读取单个字节UINT8 EEPROMReadByte(UINT16 addr){ISP_DATA=0X00;ISP_CMD=0X01;EEPROMEnable();EEPROMSetAddress(addr);EEPROMStart();DelayNus(10);//读取⼀个字节需要10usEEPROMDisable();return (ISP_DATA);}//EEPROM写⼊单个字节UINT8 EEPROMWriteByte(UINT16 addr,UINT8 byte) {EEPROMEnable();ISP_CMD=0X02;EEPROMSetAddress(addr);ISP_DATA=byte;EEPROMStart();DelayNus(60);EEPROMDisable();}//EEPROM扇区擦除UINT8 EEPROMSectorErase(UINT16 addr){ISP_CMD=0X03;EEPROMEnable();EEPROMSetAddress(addr);EEPROMStart();DelayNus(10);//EEPROMDisable();}void main(void){EEPROMSectorErase(0);EEPROMWriteByte(0,0x0f);i=EEPROMReadByte(0);LED_PORT = i;while(1);}现象:。
//==========================头文件加载===============================#include <reg52.h> //加载52系列单片机头文件//===========================端口声明================================sbit CLK=P3^6; //74hc574时钟信号线sbit G=P2^4; //74hc574使能sbit IIC_SDA=P2^6; //声明IIC总线的数据线接在单片机的P2。
5端口。
sbit IIC_SCL=P2^5; //声明IIC总线的时钟线接在单片机的P2。
7端口。
unsigned char tabl[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x0BF,0x8C};//0,1,2,3,4,5,6,7,8,9,-,P//===========================函数声明================================ void display(unsigned char aa);void delay(unsigned int t);void delay_IIC(void);void IIC_Init(void);void IIC_start(void);void IIC_stop(void);bit IIC_Tack(void);void IIC_single_byte_write(unsigned char Daddr,unsigned char Waddr,unsigned char Data);unsigned char IIC_single_byte_read(unsigned char Daddr,unsigned char Waddr);void IIC_write_byte(unsigned char Data);unsigned char IIC_read_byte(void);//============================主函数================================= void main() //主函数{unsigned char Data=2,addr=0x01;//—-——-—--—————————-——--————-系统初始化——-—-—--—-—-—————-—---———-IIC_Init();//初始化IIC总线。
STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码STC 51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码原文:(改自周立功软件包)#include <reg51.h>#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned intextern void Delay1us(unsigned char );sbit SDA=P1^6; /*模拟I2C数据传送位*/sbit SCL=P1^7; /*模拟I2C时钟控制位*/bit ack; /*应答标志位*//************************************************************** *****起动总线函数函数原型: void Start_I2c();功能: 启动I2C总线,即发送I2C起始条件.*************************************************************** *****/void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/Delay1us(1);SCL=1;Delay1us(5); /*起始条件建立时间大于4.7us,延时*/SDA=0; /*发送起始信号*/Delay1us(5); /* 起始条件锁定时间大于4μs*/SCL=0; /*钳住I2C总线,准备发送或接收数据 */Delay1us(2);}/************************************************************** *****结束总线函数函数原型: void Stop_I2c();功能: 结束I2C总线,即发送I2C结束条件.*************************************************************** *****/void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/Delay1us(1); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4us*/Delay1us(5);SDA=1; /*发送I2C总线结束信号*/Delay1us(4);}/*******************************************************************字节数据发送函数函数原型: void SendByte(uchar c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
51单片机i2c读写程序的详细讲解下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。
文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!本店铺为大家提供各种类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you! In addition, this shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!《51单片机i2c读写程序的详细讲解》一、概述51单片机是一种常用的单片机,在很多应用中使用的最多的是i2c接口,那么如何在51单片机上进行i2c的读写操作呢?下面将详细讲解i2c读写操作的程序设计过程。
目录1 设计要求 (2)2 设计目的 (2)3 器件EEPROM的介绍 (2)3.1 EEPROM简介 (2)3.2 EEPROM24XX系列功能概述 (3)4 IIC协议的介绍 (3)4.1 IIC协议总线特征 (3)4.2 IIC协议工作原理 (3)4.3 IIC协议总线基本状态 (3)4.4 寻址约定 (5)5 EEPROM读写功能实现 (5)5.1写操作 (5)5.1.1 字节写操作 (6)5.1.2 页写入操作 (6)5.2 确认查询 (7)5.3 读操作 (7)5.3.1 当前地址的读操作 (8)5.3.2 随机读操作 (8)5.3.3 连续读操作 (9)6 具体设计过程 (10)6.1 程序流程设计 (10)6.2执行结果 (13)6.3 系统组成模块结构及功能 (15)6.3.1 函数定义 (15)6.3.2 主函数设计 (17)6.3.3 源程序 (19)7 设计心得体会 (27)8 参考文献 (28)IIC总线式EEPROM存储器应用设计1 设计要求利用51单片机和IIC总线式EEPROM芯片24C02进行存储器设计。
按下KEYWRITE1键,向24C02存储器写入数据1和2;按下KEYWRITE2键,向24C02存储器写入数据3和4;按下KEYREAD键,从24C02存储器读出刚写入的数据数据;写入数据显示在左两位,读出数据显示在右两位。
如图1.1所示。
图1.1 系统仿真运行图2 设计目的通过设计,了解IIC协议的基本原理,并对EEPROM读写功能的实现有个系统的概念,对其实现过程比较清楚。
同时,在设计中,巩固我们所学的理论知识。
3 器件EEPROM的介绍3.1 EEPROM简介EEPROM (Electrically Erasable Programmable Read-Only Memory),电可擦可编程只读存储器--一种掉电后数据不丢失的存储芯片。
EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。
51单片机IIC总线操作及24c02指定地址的读写(单片机用STC89C58RD+)//24c02数据读写操作。
程序实现每一秒钟往24c02的指定地址内写入数据(既每一秒钟保存一次当前值)。
//共计时100秒,计时同步显示到数码管上,同时由8个led灯指示十位数的编码值。
//两个按键:单片机上电后按key6按键读取上次关机时存储到24c02内的数据,接着此数据继续计时显示。
//按key5按键计时停止。
#include <STC89C5xRC.H>#include<intrins.h>#define uchar unsigned char#define sda P20 //24c02数据接到P2.0口#define scl P21 //24c02时钟接到P2.1口//sbit sda=P2^0;//sbit scl=P2^1;sbit key6=P3^7;sbit key5=P3^6;uchar cont=0;uchar write=0; //标志位uchar code table[]={0x28,0xeb,0x32,0xa2,0xe1,0xa4,0x24,0xea,0x20,0xa0};void delay(){_nop_();_nop_();_nop_();}void delay1(uchar x){uchar a,b;for(a=x;a>0;a--)for(b=100;b>0;b--);}/***以下为24c02的IIC总线操作及读写数据的通用程序,IIC总线部分的程序可以用在其他IIC器件中参考郭天祥新概念51c语言***/void start() //开始{sda=1;delay();scl=1;delay();sda=0;delay();}void stop() //停止{sda=0;delay();scl=1;delay();sda=1;delay();}void respons() //应答{uchar i;scl=1;delay();while((sda==1)&&(i<250))i++;scl=0;delay();}void init(){sda=1;delay();scl=1;delay();}void write_byte(uchar date){uchar i,temp;temp=date;for(i=0;i<8;i++){temp=temp<<1;scl=0;delay();sda=CY;delay();scl=1;delay();// scl=0;// delay();}scl=0;delay();sda=1;delay();}uchar read_byte(){uchar i,k;scl=0;delay();sda=1;delay();for(i=0;i<8;i++){scl=1;delay();k=(k<<1)|sda;scl=0;delay();}return k;}void write_add(uchar address,uchar date) //24c02任一地址写入数据{start();write_byte(0xa0);respons();write_byte(address);respons();write_byte(date);respons();stop();}uchar read_add(uchar address) //24c02任一地址读取数据{uchar date;start();write_byte(0xa0);respons();write_byte(address);respons();start();write_byte(0xa1);respons();date=read_byte();stop();return date;}/***以上为24c02的IIC总线操作及读写数据的通用程序,IIC总线部分的程序可以用在其他IIC器件中参考郭天祥新概念51c语言***/void display(uchar shi,uchar ge) //显示子程序,P0口为数码管段{P0=table[shi];P27=0;delay1(5);P27=1;P0=table[ge];P26=0;delay1(5);P26=1;P1=table[shi]; //led指示灯按十位数变化相应亮灭}void main(){uchar keyscan;init();cont=read_add(36);if(cont==100)cont=0;TMOD=0X01; //ding shi qi gong zuo zai fang shi 1.EA=1;ET0=1;TH0=(65536-50000)/256;TL0=(65536-50000)%256;TR0=1; //启动定时器0P3=P3|0xfc; //11111100 置位按键位,p3口除p3.0和p3.1外接有6个按键keyscan=P3;switch(keyscan|0x03){case 0x7f: //如果key6被按下{while(key5!=0){display(cont/10,cont%10); //分解为十位数和个位数if(write==1){write=0;write_add(36,cont); //每1s写入数据cont到36地址处(地址0~255可任选)}}break;}case 0xbf: //如果key5被按下{while(key6!=0){TR0=0; //停止定时器read_add(36); //读取36号地址处数据静态显示display(cont/10,cont%10);}break;}}}void timer0() interrupt 1{uchar temp;TH0=(65536-50000)/256; //50ms中断初值,晶振12MHzTL0=(65536-50000)%256;temp++;if(temp==20) //temp每中断20次为1s(50ms*20=1000ms=1s){temp=0;cont++; //每1s时间到cont加一write=1; //到1s时标志位置一,开始往24c02里写入数据if(cont==100)cont=0; //100s时间到从00重新开始计时}}。
51单片机控制N a n d F l a s h读写的两种方法本文叙述了51单片机控制N a n d F l a s h读写的两种方法:总线方式和I/O模拟方式,并通过逻辑分析仪验证这两种方法均是符合N a n d F l a s h的读写时序的,最后通过逻辑分析仪观察和汇编分析给出了这两种方法读效率的对比。
第一章 单片机与N a n d F l a s h总线连接 1N a n d F l a s h的总线时序分析图1-1N a n d F l a s h总线操作要求将N a n d F l a s h总线操作分为三类:写命令、写地址和数据操作(读数据与写数据仅仅差别在n R和n W引脚,而且这两个引脚无法进行编址,故归为一类)。
根据这三类的时序要求,选出引脚在这三类中变化的进行编址,n E引脚总是要求低电平,不符合要求;A L和C L在这三类操作中有时是低电平有时是高电平,符合要求。
2单片机读写外部数据存储器的时序分析由图2和图3可以知道,51单片机在进行外部数据读写操作时要求A L E信号为低电平,这与N a n d F l a s h总线操作片选信号n E要求相同,因此可以将A L E与n E相连。
为了能够利用N a n d F l a s h的保护功能,将n W P引脚与单片机的一个I/O 口相连。
3N a n d F l a s h与单片机的连接及编址因为对于单片机仅仅M O V X 指令才能访问外部数据存储器,又因为单片机P 0口已经作为数据口与单片机相连,因此只能使用拥有高8位地址的P 2口。
P 2口仅仅在16位地址操作中才有用,因此编址采用16位形式,用不到的补零。
如表2所示,可知N a n d 的命令端口地址为:0×6000h ,地址端口地址为:o x A o o o h ,数据端口地址为:0×2000h 。
在C 程序中声明如下:第二章 单片机与N a n d F l a s h I /O 直接相连1.N a n d 与单片机的连接图1-1描述了N a n d F l a s h 操作的时序要求,根据该要求可以采用单片机的I /O 口与N a n d F l a s h 直接相连,通过I /O 口模拟的方式来控制N a n d F l a s h 的操作。
51单片机I2C通信程序#include#include#define ACK 0#define NOACK 1#define OUTPUT 1#define INPUT 0#define WRITE 0#define READ 1#define TRIALS 100#define ERR_CRC 2#define ERR_BUSY 1#define ERR_OK 0#define uchar unsigned char#define uint unsigned int#define uchar unsigned char#define uint unsigned intuchar EI2C1_SendChar(uchar DevAdr,uchar MemAdr,uchar Chr);uchar EI2C1_RecvChar(uchar DevAdr, uchar *Chr);uchar ReceiveRand(uchar DevAdr, uchar MemAdr, uchar* Chr);uchar PageWrite(uchar DevAdr, uchar MemAdr, uchar* Chr, uchar Siz); uchar SeqRead(uchar DevAdr, uchar MemAdr, uchar* ReceivedChr,uchar Siz);static void Delay(void);static void Write(uchar Data);static uchar Read(void);static bit GetAck(void); static void SetAck(bit Ack); static void start(void); static void stop(void);sbit SDA = P2^5;sbit SCL = P3^6;static void Delay(void){_nop_();_nop_();_nop_();}static void Write(uchar Data) {uchar Shift;uchar I;uchar timeout;Shift = 128;for (I = 8; I != 0; I--) {if (Data & Shift) {SDA = 1;}else {SDA = 0;}Shift >>= 1;SCL = 1;Delay();timeout = 255;while((SCL == 0)&&(timeout!=0)) {timeout--;}SCL = 0;Delay();}}static uchar Read(void){uchar Shift;uchar I;uchar timeout;Shift = 0;SDA = 1;for (I = 8; I != 0; I--) {SCL = 1;Delay();timeout = 255;while((SCL==0)&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}Shift <<= 1;if (SDA) {Shift++;}SCL = 0;Delay();}return Shift;}static bit GetAck(void){uint timeout;SDA = 1; /* SDA HIGH */SCL = 1; /* CLOCK HIGH PULSE */Delay();timeout = 255;while((SCL==0)&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}return(SDA); /* ACKNOWLEDGE V ALUE */}static void SetAck(bit Ack){uint timeout;if (Ack) {SDA = 1; /* MASTER NOACKNOWLEDGE - SDA HIGH */}else {SDA = 0; /* MASTER ACKNOWLEDGE - SDA LOW */ }SCL = 1; /* HIGH CLOCK PULSE */Delay();timeout = 255;while((SCL ==0 )&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}SCL = 0; /* LOW CLOCK PULSE */SDA = 1; /* ACKNOWLEDGE END - SDA HIGH */}static void start(void){SDA = 1; /* SDA HIGH - START SETUP*/SCL = 1; /* CLOCK HIGH PULSE */Delay(); /* CLOCK HIGH PULSE & BUS FREE TIME */ SDA = 0; /* START CONDITION */Delay(); /* START HOLD TIME */SCL = 0; /* CLOCK LOW PULSE */Delay();}static void stop(void){SDA = 0; /* STOP SETUP */SCL = 1; /* CLOCK HIGH PULSE + STOP SETUP TIME */Delay();SDA = 1; /* STOP CONDITION */}uchar EI2C1_SendChar(uchar DevAdr,uchar MemAdr,uchar Chr){uchar Trial;bit Acknowledge;Trial = TRIALS;do {start();Write((uchar)(DevAdr + WRITE));Acknowledge = GetAck();--Trial;} while (Trial && Acknowledge);if (Acknowledge) { /* WRONG ACKNOWLEDGE */SCL = 0; /* CLOCK LOW PULSE */return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}Write(MemAdr);if (GetAck()) { /* WRONG ACKNOWLEDGE */ SCL = 0; /* CLOCK LOW PULSE */stop();return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}Write(Chr);if (GetAck()) { /* WRONG ACKNOWLEDGE */ SCL = 0; /* CLOCK LOW PULSE */stop();return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}stop();return ERR_OK;}uchar EI2C1_RecvChar(uchar DevAdr, uchar *Chr){uchar Trial;bit Acknowledge;Trial = TRIALS;do {start();Write((uchar)(DevAdr + READ)); //写设备地址。
51单片机片内ram读写流程在51单片机中,对内部RAM(Random Access Memory)的读写流程主要包括以下几个步骤:一、读取操作流程:1. 地址定位:首先需要将待读取的内部RAM单元地址送入地址寄存器(通过`MOV`指令将地址值加载到`DPTR`或者`R0/R1`、`R2/R3`等间接寻址寄存器对中,对于低128字节直接寻址区,可以直接使用`ACC`配合`@Ri`或直接用`MOV`指令从指定地址读取)。
2. 读取数据:1)一旦地址被正确加载到地址总线,CPU会自动根据当前的地址去访问相应的RAM单元。
2)使用`MOVX A,@DPTR`指令可以从间接寻址区读取数据到累加器A(对于高128字节特殊功能寄存器区域,通常有特定的指令如`MOV A, direct`来读取)。
3)对于低128字节的数据存储区,可以使用`MOV A, @Ri`直接读取。
3. 数据处理:将读取到的数据进行所需的计算或逻辑操作。
二、写入操作流程:1. 地址定位:同样首先需要确定要写入数据的目标RAM单元地址,并将其送入地址寄存器。
2. 准备数据:确保要写入的数据已经存在于累加器A或其他可立即使用的寄存器中。
3. 执行写入:1)对于间接寻址区,使用`MOVX @DPTR,A`指令将累加器A中的数据写入到指定的RAM单元。
2)对于低128字节的数据存储区,使用`MOV @Ri, A`直接写入。
3)如果是向特殊功能寄存器区域写入,例如P1口寄存器,可以使用类似`MOV P1, A`这样的指令。
以上即为51单片机对片内RAM进行读写的基本流程。
在实际编程过程中,还需要结合具体的程序需求和内存分布情况灵活运用不同的寻址方式和指令集。
在学习单片机的过程中,我常有这样的烦恼:随随便便一个芯片,少则占用三五个IO口,一般的就占用8个,稍微想用多一点芯片吧,老觉得IO口不够用。
学串口的时候觉得串口是个好东西,连两条线就够了,现在学到I2C,觉得这也是一个非常好的东西,也是两条线,还能给每个总线上的设备设立地址,简直就是一个小网络了。
I2C总线使用两条线,一条是时钟线,称为SCL,一条是数据线,称为SDA,各个设备就并在总线上,每一个总线上的设备都有一个自己的地址,主机在操作设备的时候,都会先发送一个地址码,告诉被操作机,接下来的命令由它接收。
接下来说一下I2C总线的数据有效性。
I2C总线进行数据传送时,要求SCL为高电平时,SDA上的数据必需保持稳定,换言之,当SCL为高电平时,SDA的电平不能变换,只有当SCL为低电平时,SDA的电平才能变。
I2C总线通信时,需要遵照一定的协议,以下为一次通信过程:1.由主机发送起始信号,启动I2C总线。
时序为,在SCL为高电平期间,SDA出现一个下降沿。
2.主机发送寻址信号,即告诉特定的设备,接下来的命令是发给它的。
地址分为7位和10位,以7位为例,高7位为设备地址,最低位表示读或写,1表示读,0表示写。
3.应答信号,I2C协议规定,每传送一个字节数据(包括地址及命令)后,都要有一个接收设备返回的应答信号,以确定信号是否被接收设备正确接收到了。
其时序为,在SCL信号为高电平期间,接收设备把SDA电平拉低。
4.数据传输,当主机发送发址并收到应答后,就可以发送数据了,但是发送数据只能每次发送一位,并且每发送一位后都需要收到接收机的应答。
或主机为接收设备时,主机对最后一个字节不应答,表示向发送设备说,数据传送结束。
5.发送停止信号,在全部数据传送完毕后,主机发送停止信号,时序为,在SCL为高电平期间,SDA上产生一个上升沿。
前面讲到,I2C协议要求数据的发送,要求SCL为低电平时,SDA才能变换,看一下上面的时序,可以看到,命令都是SCL为高电平时对SDA的操作,而发送数据则是SCL为低电平时对SDA操作。