【单片机】51单片机使用总结

  • 2023劳动节更新:
      劳动节贵在劳动,因为“劳动”无意间发现一个很有意思的东西——stc-isp之前一直只当作下载器使用,但今天发现它竟然内部还有代码生成的功能,包括令人头痛的串口和定时器,可以说完全可以节约一半的时间!

前言

  目前很多电子类及信息类的专业都会开设单片机相关的课程及课程设计,但一般来说都会有51单片机的身影,因为51单片机确实非常适合入门,可以让初学者意识到寄存器的概念,从而加深对单片机工作原理的认识,属于修炼内功心法的过程。而且按照一般的课程设定,开设的课程都是以INTEL的MCS51系列单片机80C51型号为基础来进行讲述;而单片机课设往往用的是国内最常见的宏晶公司的STC89Cxx系列单片机,但好在后者基本兼容前者,而且功能更加强大,因此想以课程中所学的80C51知识为主,兼以STC的手册来总结51单片机的使用。

注意:下面所有的程序都是以STC89C52型号的单片机作为编程对象,数据手册链接

一、外设及引脚定义

  学习一款单片机,首要的就是查看数据手册,而看数据手册,首要就是看单片机的片上外设及引脚定义,这可以说是电路连接与编程的基础。下面对80C51及STC89C52两个型号分别讲述。

80C51

  • 1、外设分布:

在这里插入图片描述
在这里插入图片描述

  • 2、引脚定义:

在这里插入图片描述
  总结来说,上述引脚可以概括为3类

  • (1)电源和晶振
    在这里插入图片描述
  • (2)I/O口
    在这里插入图片描述
  • (3)控制线
    在这里插入图片描述

STC89C52

  相比于“年代久远”的80C51单片机,比较新的STC89C52单片机多了一些功能:

  • RAM和ROM(FLASH)容量增加:FLASH容量为8K,SRAM容量为512B;
  • 定时器数量增加为3个
  • 增加了看门狗定时器
  • 90C版本(看芯片上的文字最后是否有90C字样)无EA,PSEN引脚,而变成P4.4,P4.6引脚,其中ALE也可以在下载编程时在ISP中设置为P4.5,其引脚图如下所示。
    在这里插入图片描述

二、存储器及特殊功能寄存器

  单片机的存储区域有ROM和RAM两种,即程序存储器和数据存储器,由于51单片机是哈佛结构,因此其程序存储器和数据存储器是独立编址的。且两种存储器都可以选择使用片内的还是片外的存储器,因此在物理上有4个存储空间,但逻辑上只有3个存储空间,因为程序存储器片内和片外是统一编址的。这3个存储空间在汇编语言中访问的指令都不一样。
在这里插入图片描述

程序存储器

  对于程序存储器来说,因为单片机有16位地址总线(P0和P2),因此最后总的扩展区域为64KB。但片内只有4KB(STC89C52是8KB)ROM,决定单片机是访问片内的ROM还是片外的ROM取决于引脚EA的输入电平。
  当EA输入为高电平时,如果寻址范围为0000H~0FFFH时,访问片内存储器,当寻址范围超过这个时,单片机会自动访问片外存储器且从1000H开始;当EA输入为低电平时,单片机会自动访问片外存储器且从0000H开始。

数据存储器

  相比于ROM,51单片机的RAM(数据存储器)要复杂得多。首先来看传统的51单片机的RAM分布,如下图所示。
在这里插入图片描述
  从图中我们看出,传统的51单片机的RAM有256B,其中低128字节分为三个区域:寄存器工作组,位寻址区,普通的RAM;高128字节为特殊功能寄存器区(SFR),可进行位寻址。其中的寄存器位分布及其地址如下图所示:
在这里插入图片描述
在这里插入图片描述
  STC单片机:
在这里插入图片描述

注解:蓝色字体为STC单片机扩展的寄存器,方格内的8位为复位后的值。

我认为这两张图还是很重要的,编程的时候是一个重要参考。

  说完了传统的51单片机,我们再来看看STC单片机,关于这一点,我表示看不懂它的数据手册,前面选型列表中明确说明STC89C52型号的RAM大小为512B,但后面又不知道怎么变成1280B了。。。
  如果按照512B来说,那这512B是如何分布的呢?我根据手册上的前后验证,最终推断出一个相对合理的结论:STC单片机中的RAM区域分为两种:内部RAM内部扩展RAM,其中,内部RAM和传统单片机一样,都是256B,但是它根据用户需要额外多了256B的内部扩展RAM。那么问题来了,这些内部扩展的RAM怎么使用呢?
根据手册,我总结出了四点:

  • 先设置寄存器AUXR(地址为0x8e)中的EXTRAM位为0(这个寄存器复位时会自动清零)在这里插入图片描述
    其中,若EXTRAM为0,则访问内部扩展RAM,若EXTRAM为1,则访问外部扩展RAM。
  • 变量类型使用要在类型前面或后面加上xdata
  • 烧入程序时要勾选内部扩展RAM可用
    在这里插入图片描述
  • 记得不要用超了(256B)
  • 下面是一个例程:
sfr AUXR = 0x8e;    //如果不需要设置AUXR就不用声明
AUXR = 0x00;  //将AUXR寄存器中的EXTRAM位清零
unsigned char xdata var = 1; //定义一个变量在内部扩展RAM中
var = var + 2; //变量可读可写

C语言中的sfr和sbit代码如何使用?

  相信一开始看C51代码的同学都会对两条指令不太理解。就是往往在程序前面的sfr和sbit指令
  对此,我的理解是,在电路板中,已经做好了固定的电路,包括寄存器的连接方式,但是此时这些寄存器只能通过地址去访问,而sfr指令的作用就是将这些寄存器进行命名,使得用户不用去记各个寄存器的地址,使用起来更加方便。
  同理,指令sbit就是对可以按位操作的位进行命名,比如部分可以按位访问的寄存器中的各位名称。
  下面看一个例程

sbit KEY_LEFT = P3^3;
sbit KEY_DOWN = P3^6;
sbit KEY_RIGHT = P3^7;
sbit KEY_TURN = P3^2;

  另外,值得一提的是,一个项目程序中经常会包含的头文件:

#include "reg52.h"

其实内部的代码就是大多常用的寄存器的命名,所以它里面的代码都是sfr和sbit指令。(如何查看:点开main.c左侧的加号,然后就可以看到包含的头文件reg52.h)
在这里插入图片描述

三、基本I/O

  我觉得51单片机的一个很不好的地方在于它端口是双向的,而且在输入输出时不需要类似于Arduino一样先设置端口是输入还是输出。
  先来学习了解一下51单片机的几个端口:51单片机的输入输出口有两种类型:一种是开漏输出,如果作为地址线可以直接使用,但如果作为一般的输入输出线需要外接上拉(10-4.7K),以P0为代表;另一种是双向/弱上拉输入输出,可以输出高低电平,且可以作为输入端口,以P1/P2/P3/P4为代表
  下面总结一些51单片机IO口使用过程中容易忽略的问题:

  • 51单片机的IO口输出高电平时,驱动能力很弱,电流较小,但输出低电平时驱动能力很强,能接受的电流较大【STC89C52系列5V单片机P0口最大灌电流为12mA,P1/P2/P3/P4最大灌电流为6mA】因此,一般驱动LED是接到LED负端。
  • 读入引脚电平时,需要先输出1,再读入引脚电平,准确度较高。【可以理解为输出1是设置端口为输入模式】单片机上电复位时输出高电平。
  • STC89C52系列的90C系列单片机具有P4端口中的P4.4和P4.6,ALE端口也可以当作P4.5使用,只需要在下载程序时在STC-ISP中勾选ALE脚用作P4.5口。在这里插入图片描述
  • 再来看一些编程实例
sfr P4 = 0x8e;
sbit P4_4 = P4^4;
sbit P4_6 = P4^6;

void main()
{
	unsigned char temp;
	P4 = 0xff;   //先输出1
	temp = P4;  //再读取电平值
	P1 = temp;
	while(1);
}

四、定时/计数器

CPU时序

  在开始学习定时/计数器前,一定要先了解CPU内部的时序。在51单片机中,时序有多种定时单位:时钟周期、节拍与状态、机器周期、指令周期

  • 时钟周期:即震荡周期。与外界晶振频率有关。
  • 节拍与状态:一个节拍等于一个时钟周期;一个状态等于两个节拍(2个时钟周期)
  • 机器周期:规定一个机器周期的宽度为6个状态,12个时钟周期。当晶振频率为12MHz时,一个机器周期为1us。
  • 指令周期:执行一条指令所需要的时间称为指令周期。是最大的时序定时单位。51单片机中可包含一、二、三、四个机器周期。
    在这里插入图片描述

概述

  8051单片机中有两个16位的计数器,T0和T1,但STC89C52系列单片机中多了一个定时器T2。
  先说T0和T1。
  51单片机中的定时器/计数器T0和T1都具有计数方式定时方式两种工作方式。其核心是一个加法计数器,本质是对脉冲进行计数。只是脉冲来源不同:如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟得到一个计数脉冲,计数值加1;如果计数脉冲来自单片机外部引脚(T0为P3.4,T1为P3.5),则为计数方式,每来一个脉冲加1【输入脉冲频率最大为时钟频率的1/24】。
  补充:STC单片机中如果定时器/计数器工作在定时模式时,可在烧入程序时在STC-ISP中设置是除以12还是除以6。
在这里插入图片描述

T0,T1相关寄存器

在这里插入图片描述

  • TCON——定时器/计数器控制寄存器,可位寻址
D7D6D5D4D3D2D1D0
TF1TR1TF0TR0IE1IT1IE0IT0

  • TMOD——定时器/计数器模式寄存器,只能字节寻址
D7D6D5D4D3D2D1D0
GATEC/TM1M0GATEC/TM1M0

  其中,高四位为计数器1,低四位为计数器0,但功能相同。

  1. GATE:当GATE=0时,计数器的启动与停止由TCON寄存器中的TRx位来控制(TRx=1允许计数,TRx=0禁止计数);当GATE=1时,计数器的启动与停止由TRx和INTx共同控制,当INTx为高电平,且TRx置位时,计数器才能启动。

这种特性可以用来测量外部脉冲的宽度。

  1. C/T:当C/T=1时,处于计数器模式;当C/T=0时,处于定时器模式;
  2. M0,M1:控制定时/计数器工作模式,当(M1,M0)=(0,0)时,工作在模式0;当(M1,M0)=(0,1)时,工作在模式1;当(M1,M0)=(1,0)时,工作在模式2;当(M1,M0)=(1,1)时,工作在模式3。
  • THx,TLx——数据寄存器
      为读写寄存器,可读可写。复位后变为0。用来装入计数器初值

T0,T1的四种工作模式

  • 模式0
      模式0下,T0,T1为13位定时器/计数器,由TLx的低5位和THx的8位组成,当TLx的低5位溢出时,会向THx进位,如果THx溢出时,TFx标志位置位,触发中断。在这里插入图片描述

  • 模式1
      模式1与模式0很像,但是计数器是16位,即TLx的8位加上THx的8位。
    在这里插入图片描述

  • 模式2
      将16位计数寄存器分为两个8位寄存器,组成一个可重装入的8位计数寄存器。 当TLx计数溢出时,一方面将TFx置位,另一方面将THx的内容重新装入TLx,继续计数。可重复装入。
    在这里插入图片描述

  • 模式3
      将T0分为两个8位的定时/计数器(TL0和TH0),单独工作。
    在这里插入图片描述
    注意:当T0工作在模式3下,T1只能工作在模式0、1、2下,且不能用中断! 模式3下可以有三个定时/计数器。

  综上,可以得到定时/计数器在不同工作模式下的定时时间如下图所示:
在这里插入图片描述

  另外,需要明确的是,51单片机的定时/计数器是会一直运行的,除非关闭定时/计数器。其中,模式0,1,3都需要溢出时(一般在中断服务程序中)手动重新装入初值,否则下一次计数就会从0开始。但模式2可以自动重复装入初值,因此模式2常用作波特率发生器

T2定时器

  T2定时器是8052的扩展定时器,从Keil中的reg52.h文件中可以看出。
  T2定时器也是一个16位的定时器,可以设置为三种工作模式:16位自动重装定时器,16位捕获,波特率发生器。与其相关的寄存器有6个,如下图所示。
在这里插入图片描述
  其中,最为关键的寄存器就是T2CON——T2定时器控制寄存器,其各位说明如下图所示:
在这里插入图片描述在这里插入图片描述
其工作模式选择命令如下表所示:
在这里插入图片描述
下面分别介绍:

  1. 捕获模式
      进入捕获模式,需要将引脚CP/RL2置1,当EXEN=0时,定时器2作为无自动装入初值的一个16位的定时/计数器,定时器溢出时TF2标志位自动置位,产生中断。如果EXEN=1时,以上特性仍保留(即仍然在计数),但是增加了捕获特性。即即外部输入T2EX由1变零时,将定时器2中TL2和TH2的当前值各自捕获到RCAP2LRCAP2H两个寄存器中。且EXF2会置位,同时产生中断。(中断向量和溢出中断一样,可以通过在中断服务程序中判断EXF2和TF2来判断)
  2. 自动重装定时器模式
    在这里插入图片描述
  • DCEN=0(默认)时,为向上计数。

    • 如果EXEN2=0,定时器2 递增计数到0FFFFH,并在溢出后将TF2置位,然后将RCAP2L和RCAP2H中的16位值作为重新装载值装入定时器2。其中RCAP2L和RCAP2H的值是通过软件预设的。
    • 如果EXEN2=1,16位数据的重新装载不仅可以通过定时器溢出来实现,还可以通过外界输入T2EX产生负跳变来实现。同样,T2EX负跳变会使EXF2置位且产生中断(如果中断允许开了的话)
      在这里插入图片描述
  • DCEN=1时(手动设置),为向下计数。此时EXEN2位不起作用。

    • T2EX=1时,递增计数。计数到0FFFFH时溢出,置位TF2,产生中断,同时,该溢出还会使RCAP2L 和RCAP2H中的16 位值作为重新装载值放入TL2和TH2。
    • T2EX=0时,递减计数。当TL2和TH2计数到等于RCAP2L和RCAP2H时,定时
      器产生中断。
      在这里插入图片描述
  1. 波特率发生器
      参考定时/计数器T0和T1的模式2,可以发现如果要作为波特率发生器,必须要能够自动装入初值,因此当T2作为波特率发生器时,它也具有自动装入初值的功能。当TH2溢出时,TL2和TH2会重新装载寄存器RCAP2L,RCAP2H中的初值。原理如下图所示。
    在这里插入图片描述
    此时得到的波特率计算公式如下:
    Bode_Rate= { 定时器2溢出频率 16 , 采用外部时钟信号 Sysclk n × [ 65536 − ( RCAP2H, RCAP2L ) ] , 采用内部时钟信号 \text{Bode\_Rate=}\left\{ \begin{array}{c} \frac{\text{定时器2溢出频率}}{16}, \text{采用外部时钟信号}\\ \\ \frac{\text{Sysclk}}{\text{n}\times \left[ 65536-\left( \text{RCAP2H, RCAP2L} \right) \right]}, \text{采用内部时钟信号}\\ \end{array} \right. Bode_Rate= 16定时器2溢出频率,采用外部时钟信号n×[65536(RCAP2H, RCAP2L)]Sysclk,采用内部时钟信号
    其中,12T模式下,n=16;6T模式下,n=32。
      另外,值得一提的是,T2与T0,T1的模式2(波特率发生器)有一点不一样,那就是在TH2溢出时,只会重新装入初值,不会触发TF2中断,因此TF2中断不必被禁止。此外,如果EXEN2(T2EX使能位)被置位,那么T2EX产生下降沿时会触发中断,但不会重新装载初值,相当于装载初值和触发中断被分离开来了。因此如果需要的话,可以把T2EX作为外部中断使用

五、串行通讯

  8051系列单片机有一个全双工串行通讯端口,即常说的UART。设有两个独立的发生、接收缓冲器,可以同时发送和接收数据,且两个缓冲器共用一个地址两个缓冲器统称串行通信特殊功能寄存器SBUF。其两个通讯引脚为P3.0/RXD和P3.1/TXD。

注意:与外设相连时,TXD要连RXD,RXD连TXD

串行口控制寄存器SCON和PCON

  51单片机有两个控制寄存器SCON和PCON,控制了串行口的工作方式及其波特率的设置。

SCON(可位寻址,复位为全0)

  SCON寄存器的各位如下表所示:

D7D6D5D4D3D2D1D0
SM0/FESM1SM2RENTB8RB8TIRI
  • SM0/FE:当PCON寄存器中的SMOD0位为1时,该位用于帧错误检测,当检测到一个无效停止位时,该位置1;当PCON寄存器中的SMOD0为0时,该位和SM1一起指定串行口的工作方式。如下图所示:
    在这里插入图片描述
  • SM2:为0时,一般用于单机通信;为1时一般用于多机通信(方式2或者方式3)
  • REN:接收允许控制位,REN=1,允许接收;REN=0,禁止接收。
  • TB8:方式2或者方式3下发送的第9位,可用软件自定义。
  • RB8:方式2或者方式3下接收到的第9位。方式1下为接收到的停止位(SM2=0)
  • TI:发送中断标志位。触发时硬件置位,需用软件复位。
  • RI:接收中断标志位。触发时硬件置位,需用软件复位。

PCON(电源控制寄存器,不可位寻址)

D7D6D5D4D3D2D1D0
SMODSMOD0-POFGF1GF0PDIDL
  其中,只有D7,D6与串口有关,其他各位都与掉电方式有关。
  • SMOD:波特率选择位,要通过软件设置。当SMOD=1时,方式1,2,3的通信波特率加倍。复位时SMOD=0.
  • SMOD0:帧错误检测有效控制位。当SMOD0=1时,帧错误检测有效;当SMOD0=0时,帧错误检测无效。复位时为0.

串行口的四种工作方式

  • 方式0——同步移位寄存器
      发送数据时:RXD引脚逐位输出需要传输的数据(低位在先),TXD输出同步脉冲。8位输出完毕后,中断标志TI置1。其波形如下图所示。
    在这里插入图片描述
      接收数据时:RXD接收串行数据,TXD输出同步脉冲,接收8位后,置位RI标志位,触发中断。
    在这里插入图片描述
      在实际电路中,往往将其与移位寄存器相连,实现并转串的功能。
    在这里插入图片描述
    在这里插入图片描述
  • 方式1——8位UART,波特率可变
      当单片机的串行口工作在方式1时,每一帧数据格式为:1位起始位,8位数据位,1位停止位。如下图所示。
    在这里插入图片描述
    其中,第9位停止位发送时是直接发送一个1,接收时会自动放到SCON寄存器中的RB8位。
  • 方式2——9位UART,波特率固定
      当单片机的串行口工作在方式2时,每一帧数据格式为:1位起始位,9位数据位,1位停止位。共11位数据。其中,第9位数据位为可编程位,发送时由SCON中的TB8位提供;接收时放入RB8位。这一位既可作为多机通信中的地址数据标志位,又可作为数据的奇偶校验位
  • 方式3——9位UART,波特率可变
      方式3下数据帧格式与方式2一样,但波特率可调,由定时器1或者定时器2确定。

总结——常用工作方式及其波特率的设定

在这里插入图片描述

六、中断

  51单片机有3类中断源:外部中断INTx、串口中断,定时器中断Tx。共有4个中断优先级。(8051系列比较老的单片机只有两个优先级)在同一优先级下如果同时触发中断,则按照既定的查询次序来响应。如下表所示。
在这里插入图片描述

注意:STC89C52系列没有INT2和INT3,80C51系列还没有Timer2

其中查询次序号也是中断类型号,例如:

void Int0_Routine(void) interrupt 0
void Timer0_Rountine(void) interrupt 1
void Int1_Routine(void) interrupt 2
void Timer1_Rountine(void) interrupt 3
void UART_Routine(void) interrupt 4
void Timer2_Routine(void) interrupt 5

总结一下各中断的使用:

中断源中断号触发行为允许位标志位
INT00(IT0/TCON.0 = 1):下降沿;  (IT0/TCON.0 = 0): 低电平EX0/IE.0IE0/TCON.1
Timer01定时器0溢出ET0/IE.1TF0/TCON.5
INT12(IT1/TCON.2 = 1):下降沿;   (IT1/TCON.2 = 0): 低电平EX1/IE.2IE1/TCON.3
Timer13定时器1溢出ET1/IE.3TF1/TCON.7
UART4发送或接收完成ES/IE.4TI/SCON.1 & RI/SCON.0
Timer25定时器2溢出ET2/IE.5TF2/T2CON.7 & EXF2/T2CON.6

中断寄存器

  下表列出了与STC89C52系列单片机有关的所有寄存器
在这里插入图片描述
  其中,TCON,SCON,T2CON寄存器都在前面有表述,而IE寄存器中还有一位EA总中断控制位,EA=1总中断打开;EA=0总中断关闭。IE上电复位为0。
  最后的三个寄存器IP,IPH,XICON是用来设置中断优先级的,且STC89C52系列只有六个中断,不必使用XICON寄存器。故只需要设置IP和IPH即可。
IP(可位寻址)

D7D6D5D4D3D2D1D0
--PT2PSPT1PX1PT0PX0
IPH(不可位寻址)
D7D6D5D4D3D2D1D0
-----------------------------------------------
PX3HPX2HPT2HPSHPT1HPX1HPT0HPX0H
   其中两个寄存器的低6位分别用来设置STC单片机的6个中断的优先级,且是按照中断号来排序的,即PX0和PX0H对应外部中断INT0,PT0和PT0H对应Timer0中断。
  设置优先级时,当(IPH,IP)为(0,0)时,优先级最低,为(1,1)时,优先级最高。

七、内部EEPROM的使用

  内部的EEPROM,可以说是STC单片机的一个特色了吧。根据数据手册,我们可以看到STC89C52单片机不仅有8K的Flash,还配备了一个5K的EEPROM供读写使用,这样就可以在不接外设芯片的前提下存储一些掉电不会消失的数据。查阅资料得知,它的本质是通过IAP技术读写Flash来实现EEPROM的效果。

背景知识(重要!)

  在STC单片机中,有三个掉电数据不消失的区域:一个是用户程序区(AP区),是用来存放用户编写的程序的区域;一个是叫ISP监控程序区(ISP区),这个是芯片出厂时就已经固化在单片机内部的一段程序,STC单片机之所以可以进行ISP串行下载程序,就是因为芯片在出厂时已经在内部固化了ISP引导码,程序上电复位时会首先从ISP区开始执行代码。首先单片机会检测是否有上位机下载程序的需要,若经过短暂的时间没有检测到上位机有下载程序的需求,单片机便会从用户程序区(AP区)开始执行代码,这也是为什么51单片机下载时要先下电,然后再上电就是为了使得程序从ISP区开始执行,从而实现用户程序的下载参考链接
  第三个掉电数据不消失的区域就是STC单片机自带的EEPROM了。根据数据手册,可以得知,当程序在ISP区域时,可以对用户程序(AP区)进行编程,还可以对EEPROM(也叫Data Flash区)进行编程;但是程序在AP区时,只能对EEPROM进行编程

EEPROM扇区范围

在这里插入图片描述
  在使用EEPROM时,要注意地址寄存器中的值不能超出这个范围。其中,一个扇区为512字节。

相关寄存器

  首先来了解一下与EEPROM读写有关的寄存器,如下图所示。
在这里插入图片描述

  • ISP_DATA
    ISP/IAP操作时的数据寄存器,ISP/IAP 从Flash读出的数据放在此处,向Flash写的数据也需放在此处
  • ISP_ADDRH、ISP_ADDRL
    ISP/IAP操作时的EEPROM的地址寄存器 的高八位和低八位,复位值都是00H。
  • ISP_CONTR
    在这里插入图片描述
    ISPEN:ISP/IAP功能允许位。为0时禁止ISP/IAP读写EEPROM,为1时允许。
    SWBS:软件复位“原点”选择,当SWBS=0时,选择从AP区重新启动;当SWBS=1时,选择从ISP区重新启动。
    SWRST:0,不操作;1,产生软件复位。
    WT0,WT1,WT2:设置等待时间
    在这里插入图片描述
  • ISP_CMD
    ISP_CMD寄存器的低3位分别为MS0(0)、MS1(1)、MS2(2),它们的取值对应的指令如下表所示。
    在这里插入图片描述
  • ISP_TRIG
    ISP_TRIG是ISP/IAP操作时的命令触发寄存器。在ISPEN(ISP_CONTR.7) = 1 时,对ISP_TRIG先写入46h,再写入B9H,ISP/IAP 命令才会生效。

再来看看例程,和官方给的差不多

#include "reg52.h"
#include "intrins.h"   //含_nop_()函数
/****需要初始化寄存器,reg52头文件中没有****/
sfr ISP_DATA = E2H;
sfr ISP_ADDRH = E3H;
sfr ISP_ADDRL = E4H;
sfr ISP_CMD = E5H;
sfr ISP_TRIG = E6H;
sfr ISP_CONTR = E7H;

#define CMD_IDLE 0              //空闲模式
#define CMD_READ 1              //IAP字节读命令
#define CMD_PROGRAM 2           //IAP字节编程命令
#define CMD_ERASE 3             //IAP扇区擦除命令
//#define ENABLE_IAP 0x80	//如果系统时钟<30MHz选这个
//#define ENABLE_IAP 0x81	//如果系统时钟<24MHz选这个
#define ENABLE_IAP 0x82	        //如果系统时钟<20MHz选这个
//#define ENABLE_IAP 0x83	//如果系统时钟<12MHz选这个
//#define ENABLE_IAP 0x84	//如果系统时钟<6MHz选这个
//#define ENABLE_IAP 0x85	//如果系统时钟<3MHz选这个
//#define ENABLE_IAP 0x86	//如果系统时钟<2MHz选这个
//#define ENABLE_IAP 0x87	//如果系统时钟<1MHz选这个

/**关闭IAP函数(禁止对EEPROM操作)**/
void IapIdle(void)
{
	IAP_CONTR = 0 ;         //关闭IAP功能
	IAP_CMD = 0 ;	        //清除命令寄存器
	IAP_TRIG = 0 ;	        //清除触发寄存器
	IAP_ADDRH = 0x80 ;	    //将地址设置到非IAP地址区域
	IAP_ADDRL = 0 ;
}

/**从ISP/IAP/EEPROM区域读取1字节**/
unsigned char IapReadByte(unsigned int addr)
{
	unsigned char dat;
	IAP_CONTR = ENABLE_IAP;	 //使能IAP
	IAP_CMD = CMD_READ;	     //设置IAP命令为“读”
	IAP_ADDRL = addr ;	     //设置IAP低位地址
	IAP_ADDRH = addr>>8 ;	//设置IAP高位地址
	IAP_TRIG = 0x46;	//写触发命令(0x46)
	IAP_TRIG = 0xB9;	//写触发命令(0xB9)[触发命令必须先送0x46 再送0xB9才能成功触发]
	_nop_();	        //等待ISP/IAP/EEPROM操作完成
	dat = IAP_DATA;	    //读取ISP/IAP/EEPROM数据
	IapIdle();	        //关闭IAP功能
	return dat;
}

/**写1字节数据到从ISP/IAP/EEPROM区域**/
void IapProgramByte(unsigned int addr,unsigned char dat)
{
	IAP_CONTR = ENABLE_IAP;	//使能IAP
	IAP_CMD = CMD_PROGRAM;	//设置IAP命令为“写”
	IAP_ADDRL = addr ;	    //设置IAP低位地址
	IAP_ADDRH = addr>>8 ;	//设置IAP高位地址
	IAP_DATA = dat;	        //写ISP/IAP/EEPROM数据
	IAP_TRIG = 0x46;	//写触发命令(0x46)
	IAP_TRIG = 0xB9;	//写触发命令(0xB9)[触发命令必须先送0x46 再送0xB9才能成功触发]
	_nop_();	        //等待ISP/IAP/EEPROM操作完成
	IapIdle();	        //关闭IAP功能
}

/**扇区擦除**/
void IapEraseSector(unsigned int addr)
{
	IAP_CONTR = ENABLE_IAP;	//使能IAP
	IAP_CMD = CMD_ERASE;	//设置IAP命令为“擦除”
	IAP_ADDRL = addr ;	    //设置IAP低位地址
	IAP_ADDRH = addr>>8 ;	//设置IAP高位地址
	IAP_TRIG = 0x46;	//写触发命令(0x46)
	IAP_TRIG = 0xB9;	//写触发命令(0xB9)[触发命令必须先送0x46 再送0xB9才能成功触发]
	_nop_();	        //等待ISP/IAP/EEPROM操作完成
	IapIdle();	        //关闭IAP功能
}

参考链接

使用注意事项

  • 重复写入数据前必须先对原地址进行擦除操作,只有先擦除才能再次写入。
  • 擦除操作只能擦除一个扇区,而不能只擦除一个字节。
  • 如果要对某个扇区进行擦除,但原先一部分数据需要保留,可以先读出到单片机的RAM中,然后在擦除之后重新写入。因此每个扇区用的字节数越少越好,操作起来越灵活越快。
  • 扇区中任意一个字节的地址都是扇区的地址,不用求首地址。
  • 建议:同一次修改的数据放在同一扇区中,不是同一次修改的数据放在另外的扇区,就不需读出保护。
  • 每写入一个字节,地址寄存器不会自动加1。
  • 每一次操作EEPROM都需要给ISP_TRIG寄存器送46H和B9H。
  • 19
    点赞
  • 197
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记录无知岁月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值