2019-05-27 15:27:31 qq_41889059 阅读数 144
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏

Atmega16单片机串口通信

本篇文章参考自叶大鹏老师于2008年4月5日完成的UART通信PPT制作而成。

串口通信需要使用到的内部寄存器

在进行程序编写前需要对16单片机中的寄存器的作用和使用方法有所了解,下面为16单片机串口通信使用到的几个寄存器:

  1. USART I/O 数据寄存器 - UDR (UDR寄存器用于数据在传输中的存储):
    UDR寄存器用于数据在通信中的存储
  2. USART控制和状态寄存器A - UCSRA
    UCSRA寄存器
    寄存器中位的定义
    寄存器中位的定义
void uart_sendB(uchar data)        /*发送函数*/
{
    while(!(UCSRA&(BIT(UDRE))));   //等待发送缓冲器为空
    UDR=data;                      //将数据存入UDR寄存器
}
  1. USART控制和状态寄存器B - UCSRB
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
void uart_rx(void)              /*串口接收函数*/
{
    UCSRB&=~BIT(RXCIE);         //校验数据是否传输完成,关闭接收中断
    rdata=UDR;                  //将接收到的数据存入rdata
    flag=1;                     //标志位至1
    UCSRB|=BIT(RXCIE);          //接收完毕,开启中断
}
  1. USART控制和状态寄存器C - UCSRC
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. USART波特率寄存器 - UBRRL和UBRRH
    在这里插入图片描述
    在这里插入图片描述
#define mclk 8000000

    baud=mclk/16/baud-1;    //程序片段
    UBRRL=baud;             //设置波特率,先写低位再写高位
    UBRRH=baud>>8;          //设置波特率,先写低位再写高位

程序代码

本段程序编译环境为ICCAVR7 for AVR。
#include<iom16v.h>
#include<macros.h>
#define uchar unsigned char
#define uint unsigned int
#define mclk 8000000
#pragma interrupt_handler uart_rx:12
uchar rdata,flag=0;
void uart_init(uint baud)        //串口初始化
{
    UCSRB=0x00;
    UCSRA=0x00;
    UCSRC=(1<<URSEL)|(0<<UPM0)|(3<<UCSZ0);
    
    baud=mclk/16/baud-1;
    UBRRL=baud;
    UBRRH=baud>>8;
    UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE);
    
    SREG=BIT(7);                    //开中断
    DDRD|=0x02;                     //设计发送口(TX)为输出,这很重要
}
void uart_rx(void)                  //串口接收函数
{
    UCSRB&=~BIT(RXCIE);         //校验数据是否传输完成,关闭接收中断
    rdata=UDR;                  //将接收到的数据存入rdata
    flag=1;                     //标志位至1
    UCSRB|=BIT(RXCIE);          //接收完毕,开启接收中断
}


void uart_sendB(uchar data)   //发送函数
{
    while(!(UCSRA&(BIT(UDRE)))); //等待发送缓冲器为空
    UDR=data;                    //将数据存入UDR
    while(!(UCSRA&(BIT(TXC))));
    UCSRA|=BIT(TXC);          
}

void main(void)
{
    uchar i=4;
    uart_init(19200);
    while(1)
    {
        if(flag)
        {
            uart_sendB(i);
            flag=0;
        }
    }
}
2016-07-04 12:01:58 qq_29918347 阅读数 4708
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏

前段时间一直在加班,单身狗的周末也搭进去了…只是为了解决一个莫名其妙的bug,不过最终bug还是拜倒在了朕的强大气场下,哈哈哈,现在就在这里好好吐槽下软件遇上硬件的坑;

先简单说说情景:软件需要给硬件设备的单片机发送一串byte数组,用于打开软件与硬件设备之间的通讯通道,软件命令发送完,接着就打开一个线程用于接收从硬件设备回传的数据,然后开始做其他的一些操作。但是现在出现的问题是命令发送了,会出现偶尔接收不到数据,刚开始还以为是硬件部门的问题,请硬件部门的人过来协助,结果发现软件发送的指令单片机也是接收到了的,那么是我写的程序有问题?NO~

中间的各种脑残调试,这里就不细说了,说说最终得到的分析结果:从软件发送指令到单片机接收到指令,其实是需要时间的,至于这个时间大概在两百毫秒以内,而软件在发送了这段指令之后,就直接执行后面的接收操作,但是这个时候单片机有可能还没有接收到软件发送的指令,通道没有打开,而我的程序已经在开始读取数据了(读个鬼啊,什么都没有),这样就造成了我的操作界面一直处于等待的状态…那为什么有时候又可以读取到数据了?因为从发送数据到单片机接收数据,这个时间不可控的,为什么不可控,这里我猜测跟系统资源及单片机内的程序有关,这种情况就好像当电脑内存紧张时,软件运行速度会降低一样(当然这种情况要毕竟很少),而单片机程序部分如果接收到指令后还做了其他耗时操作这个也是有可能的…知道了原因,那么在程序发送命令后,就简单粗暴的强制线程睡眠一秒Thread.sleep(200),其实这种方法,依然存在问题,正确的最好的办法是让单片机在接收到我发出的命令后返回一个响应(但是要跟硬件部门沟通了~~~)

2020-01-04 13:18:56 weixin_44212493 阅读数 7
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏

单片机IIC基础通信

1 接口定义
2 程序实例

阅读提示:本章主要讲解过去电路使用较多的24C02- 24C512存储器,对于现在 主流的STC15W系列单片机,通常都具有内部比较器与DataFlash存储器,可 直接代换代换本章各个例程功能(详见第7章)
1 接口定义

I2C总线是两线式串行总线(连同GND为3线),仅需要时钟和数据两根线就可 以进行数据传输,仅需要占用单片机的2个IO引脚,使用时十分方便,I2C总线可 以在同一总线上并接多个器件,每个器件都有自己的器件地址(作为对比:SPI 总线没有器件地址,通过CPU提供片选线确定是否选中芯片),读写操作时需要 先发送器件地址,与该地址相符的器件得到确认后便执行相应的操作,而在同一 总线上的其它器件不做响应,称之为器件寻址。

单片机外围使用I2C接口的器件比较多,最常见的是EEPROM存储器(如:
24C02)与ADC转换芯片(如:MCP3421) 。
24C02与单片机的连接电路如下图所示。
在这里插入图片描述
2 程序实例
24C系列芯片既然作为存储器使用,我们最关心的就是如何将数据写入芯片及 写入成功的数据如何读取出来。

例6.2 使用IAP15W4K58S4单片机的硬件仿真功能仿真观察24C02芯片读写结果
(也可用24C01/04/08/16) 。本例无页面限制,快速,适合连续读写多个字 节,本程序先向芯片写入一组数据,然后读出,若读出的数据与写入的数据相同 则表明实验结果是正确的。

为了简化,我们直接移植成熟的程序代码(配套例程中提供)。
① 除主程序MAIN.C外,其余*.C与*.H文件全部复制到你自己的文件夹并将*.C文 件加入工程,如图所示。
在这里插入图片描述
② 根据实际硬件连接修改引脚定义。在IIC.H中有如下语句,可设置为任意IO口,注
意上拉。

sbit SCL=P3^7; // 串行时钟(代码包必须)

sbit SDA=P4^1; // 串行数据(代码包必须)

③ 根据硬件修改从机地址。在24C01_02.H中有:#define SlaveADDR 0xA0 // 从机 地址格式为:1010 ***0。其中的***对应器件引脚 A2A1A0,,用于设置器件地 址,当硬件上A2A1A0接GND时, ***=000。
④ 在要求严格的情况下,根据R/C时钟频率修改延时函数参数。myfun.c中的延时函 数delay1ms()和delay10ms()延时参数由第1章介绍的软件计算得出。

⑤ 根据R/C时钟频率修改宏定义。IIC.H中的语句 “#define tt 26”的常数26对应
myfun.c中的延时函数void delay (unsigned char t)中的参数t,此常数值确定
5uS延时时间,延时可以更长,不能短,时钟频率为22.1184MHz时t=26。
⑥ 这里的例子使用的是24C02芯片,若换用24C04/08/16,为了提高多字节数据跨页 写入速度,则需要对24C01_02.C中函数WrToRomPageB内部常数0x07改为0x0f。

主程序代码如下(注意是硬件仿真观察实验结果):

#include “STC15W4K.H” // 注意宏定义后面没分号
#include “24C01_02.H”
#include “myfun.h” void main()
{
u8 i;
u8 test_data[20]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,
0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x81,0x91,0xa1};
port_mode(); // 所有IO口设为准双向弱上拉方式。 WrToRomB(SlaveADDR, 5,test_data,20);
// 器件地址、存储单元地址、数据指针、写入字节数
for(i=0;i<20;i++)
{
test_data[ i ]=0;
}
RdFromROM(SlaveADDR, 5,test_data,20); // 连续读取20个字节数据
while(1);
}
例6.5利用24C02记录单片机上电次数(使用工作组方式)

头文件代码如下:

#define E2P_RECORD_ADDR 0x00 // 存储单元地址

#define POWER_UP_MARK 0xAB // 第一次使用标记

struct POWER_UP

{
u32 times;

u8 flag;

};
// 主程序代码如下:

#include “PowerUP.H”

#include “24C01_02.H”

#include “myfun.h”

struct POWER_UP Power_up;
void main()
{

RdFromROM(SlaveADDR,E2P_RECORD_ADDR,(u8*)&Power_up,sizeof(struct POWER_UP));

// 芯片硬件地址、存储单元地址、数据组、写入字节数

if (Power_up.flag != POWER_UP_MARK) // 存储器第一次使用
{

}
else
{

}

Power_up.flag = POWER_UP_MARK; Power_up.times = 1;

Power_up.times++;
WrToRomB(SlaveADDR, E2P_RECORD_ADDR,(u8 *)&Power_up,sizeof(struct POWER_UP));

// 芯片硬件地址、存储单元地址、数据组、写入字节数 UART_init(); UART_Send_StrNum(“上电次数:”,Power_up.times);
// 串口输出上电次数,波特率:9600 /22.1184MHZ
while(1);
}
结果如图所示。
在这里插入图片描述

例6.6 利用24C02断电瞬间存储数据。断电存储就是在系统断电瞬间保存RAM中的重要数据 到EEPROM,在下次系统上电时再读出EEPROM中的数据并运行,断电检测电路原理如图所 示。
在这里插入图片描述
利用单片机外中断检测交流电源的有无,交流供电正常时INT2每10mS进入一次中断,在中断
程序中重装定时器T1初值让定时器一直不产生溢出中断,交流断电时,定时器计数值不断增 加直到溢出,溢出中断程序中单片机立即保存数据到EEPROM 。定时器定时时间要求大于
10mS即可,比如取12或15mS,另外特别注意单片机外中断引脚必须外接上拉电阻。
对于现在主流的STC15W系列单片机,通常都具有内部比较器与DataFlash存储器,可直接 代换24C系列存储器使用,断电检测电路更加简单,如上图单片机VCC与GND间接2只电阻即可。

2018-06-28 14:12:57 qq_29562209 阅读数 7260
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏
一、STC15F2K60S2单片机简介

    中国深圳宏晶STC系列单片机是2005年推出中国本土的第一款具有全球竞争力的,且与MCS-51兼容的STC系列单片机。它完全兼容51单片机,是新一代增强型单片机,速度快、抗干扰性强、加密性强,带ADC/PWM,超低功耗,可以远程升级,内部有MAX810专用复位电路,价格低廉。深圳宏晶科技有限公司根据市场需求,在STC89C51、STC89C52的基础上,先后推出STC10、STC11、STC12、STC15系列单片机。

    其中,STC15F2K60S2单片机是一种增强型的8051单片机,是新型的FLASH单片机,与传统的8051系列单片机兼容,在片内资源、操作性能和运行速度上做了很大的的改进。IAP15F2K60S2是可以把单片机芯片硬件配置为具有仿真功能的单片机,与Keil C51编译器配合使用,进行仿真实验。

二、STC15F2K60S2单片机串口通信的相关知识

    STC15F2K60S2单片机内部有两个可编程的全双工串行通信接口。每个串行口由一个数据缓存器、一个移位寄存器、一个串行控制器和一个波特率发生器组成。每个串行口的数据缓冲器在物理上分为两个独立的发送、接收缓冲器,可以同时发送和接收数据。发送缓存器只可以写入数据,接收缓存器只能读出数据,两个缓冲器共用一个地址。串口1的数据缓冲器为SBUF,地址为99H,串口2的数据缓冲器为S2BUF,地址为9BH。与串行口相关的特殊寄存器见下表。

与串行口相关的特殊寄存器

寄存器 功能 地址 位地址 复位值
PCON 电源控制寄存器 87H SMOD SMOD0 LVDF POF GF1 GF0 PD IDL 00110000
AUXR 辅助寄存器 8EH T0x12 T1x2 UART_M0x6 T2R T2C/T T2x12 EXTRAM S1ST2 00000001
CLK-DIV 时钟分频寄存器 97H MCKO-S1 MCKO-S0 ADRJ Tx-Rx Tx2-Rx2 CLKS2 CLKS1 CLKS0 00000000
SCON 串口控制寄存器 98H SM0 SM1 SM2 REN TB8 RB8 TI RI 00000000
SBUF 串口数据寄存器 99H 00000000
S2CON 串口2控制寄存器 9AH S2M0 - S2M2 S2REN S2TB8 S2RB8 S2TI S2RI 00000000
S2BUF 串口2数据缓冲区 9BH 00000000
AUXR1 辅助寄存器 A2H S1_S1 S1_S0 CCP_S1 CCP_S0 SPI_S1 SPI_S0 0 DPS 01000000
IE 中断控制寄存器 A8H EA ELVD EADC ES ET1 EX1 ET0 EX0 00000000
IE2 中断控制寄存器2 AFH - - - - - ET2 ESPI ES2 xxxxx000
IP2 中断优先级控制寄存器2 B5H - - - - - - PSPI PS2 xxxxxx00
IP 中断优先级控制寄存器 B8H PPCA PLVF PADC PS PT1 PX1 PT0 PX0 00000000
P_SW2 外围功能切换寄存器 BBH - - - - - S4_S S3_S S2_S xxxxx000

(1)寄存PCON中的SMOD位为波特率倍增系数选择位,SMOD为1时,波特率加倍。

(2)辅助寄存器AUXR中的UART_M0x6用于设置串口1在方式0时数据传输的波特率,置1时波特率为fsys/2,置0时波特率为fsys/12。辅助寄存器AUXR中的S1ST2位用于选择串口1在方式1、3时的波特率发生器,置1时选择T2为波特率发生器,置0时选择T1为波特率发生器。

(3)串口控制寄存器SCON的功能和用法与一般的8051单片机类似,不同的是其中的SM0/FE位可以用作帧错误检测。

(4)数据寄存器SBUF和S2BUF分别用于串口1和串口2的数据缓冲器。

(5)寄存器S2CON用于设置串口2的工作方式,其余用法与SCON相同。

(6)寄存器IE、IE2中的PS、PS2位分别用于控制串口1和串口2的中断允许与禁止。置1为允许,置0为禁止。

(7)寄存器IP、IP2中的PS、PS2分别用于控制串口1和串口2的中断优先级,置1为高优先级,置0为低优先级。

(8)时钟分频寄存器CLK_DIV中的Tx_Rx用于设置串口1的中继广播方式,置1为中继广播方式,置0为正常工作方式。

(9)辅助寄存器AUXR1的S1_S1、S1_S0位用于串口1的硬件引脚切换,具体情况如下表。

串口1的硬件引脚切换

S1_S1 S1_S0 TXD RXD
0 0 P3^1 P3^0
0 1 P3^7 P3^6
1 0 P1^7 P1^6
1 1 无效

(10)寄存器P2_SW2的S2_S位用于串口2的硬件引脚切换,具体情况如下表。

串口2的硬件引脚切换

S2_S TXD2 RXD2
0 P1^1 P1^0
1 P4^7 P4^6

    另外,对于波特率,还有一个很重要的寄存器,即电源控制寄存器(PCON),电源管理寄存器(PCON)也在特殊功能寄存器中,字节地址为87H,不可位寻址,复位值0x00。

    PD:掉电模式设定位。PD=0时,单片机处于正常工作状态;PD=1时,单片机进入掉电(Power Down)模式,可由外部中断低电平触发或由下降沿触发或者硬件复位模式唤醒,进入掉电模式后,外部晶振停振,CPU、定时器、串行口全部停止工作,只有外部中断继续工作。

    IDL:空闲模式设定位。IDL=0时,单片机处于正常工作模式;IDL=1时,单片机进入空闲(IDLE)模式,除CPU不工作外,其余的部件继续工作,在空闲模式下可由任何一个中断或硬件复位唤醒。

三、串口通信程序

注:以下程序在一定程度上已调试成功,但是因为有很多功能没有实现完,所以后期可能需要修改,后期会进行更新。

1. UART头文件

#ifndef _UART_H_
#define _UART_H_

#include <STC15F2K60S2.H>

#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
	
extern bit pageflag;	//返回页面ID标志
extern uchar pageID;	//页面ID号	
extern uchar pagenum;	//页面结束数据检测,满3代表结束


void write_COM(uchar COM);
void write_txt(char *s);	 
void write_END(void);
void UART_Init();

#endif

2. UART程序

#include "UART.h"

/*********串口送数据**********/
void write_COM(uchar COM)
{
 	SBUF=COM;			
  while(!TI);
  TI=0;
}
/*********发送文本串**********/
void write_txt(char *s)	  
{
	int i=0;
	while(s[i]!=0)
	{
		write_COM(s[i]);
		i++;
 	}
}
/*********发送结束符**********/
void write_END(void)   
{
	 write_COM(0xFF);
	 write_COM(0xFF);
	 write_COM(0xFF);
}
/*********串口初始化**********/
void UART_Init()
{		
		//串口1	初始化
    SCON = 0x50;   
    AUXR &= 0xBE;  
    AUXR |= 0x00;    
    TMOD &= 0x0F;	
    TMOD |= 0x20;           
    TH1 = 0xfd;                 
    TL1 = 0xfd;                 
    TR1 = 1;                         //定时器1启动
    ES = 1;                         //开放串口中断
    EA = 1;	

//		//串口2	初始化
//    S2CON = 0x10;  
//    T2L = 0xE8;        
//    T2H = 0xFF;      
//    AUXR &= 0xE3;  
//    AUXR |= 0x10;   
//    IE2 &= 0xFE;        
//    IE2 |= 0x01;          	
	                         
}

/************UART1 中断服务程序*******************/
void Uart1(void) interrupt 4 
{
	uchar dataflag=0;//返回的十六进制数据的第一位

  if(RI)                           //如果是接收中断
  {
    RI=0;
    dataflag = SBUF;    //将接收缓冲区的数据保存到num1变量中
    /***********页面接收**********/			
    if(dataflag==0x66) pageflag = 1;
    if(pageflag==1)
    {
	pageID = dataflag;//接收页面ID号
	if(dataflag==0xff)	//开始接收结束符
	{
	    pagenum++;
	    if(pagenum==3) pageflag = 0;//接收3个结束符,数据接收完成				
	}
    }	
		
   }			
    else                           //如果是发送中断,将TI清0
        TI = 0;
}
                                
2013-07-04 17:07:39 a123421514 阅读数 1083
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏

单片机运行时的数据都存在于RAM(随机存储器)中,在掉电后RAM 中的数据是无
法保留的,那么怎样使数据在掉电后不丢失呢?这就需要使用EEPROM FLASHROM 等存储器来实现。在传统的单片机系统中,一般是在片外扩展存储器,单片机与存储器之间通过IIC SPI 等接口来进行数据通信。这样不光会增加开发成本,同时在程序开发上也要花更多的心思。在STC 单片机中内置了EEPROM(其实是采用IAP 技术读写内部FLASH 来实现EEPROM),这样就节省了片外资源,使用起来也更加方便。下面就详细介绍STC 单片机内置EEPROM 及其使用方法。STC 各型号单片机内置的EEPROM 的容量各有不同,见下表:
(内部EEPROM 可以擦写100000 次以上)
上面提到了IAP,它的意思是在应用编程,即在程序运行时程序存储器可由程序自
身进行擦写。正是是因为有了IAP,从而可以使单片机可以将数据写入到程序存储器中,使
得数据如同烧入的程序一样,掉电不丢失。当然写入数据的区域与程序存储区要分开来,以使程序不会遭到破坏。要使用IAP 功能,与以下几个特殊功能寄存器相关:
ISP_DATA ISP/IAP 操作时的数据寄存器。
ISP/IAP
Flash 读出的数据放在此处,向Flash 写的数据也需放在此处
ISP_ADDRH
ISP/IAP 操作时的地址寄存器高八位。
ISP_ADDRL
ISP/IAP 操作时的地址寄存器低八位。
ISP_CMD
ISP/IAP 操作时的命令模式寄存器,须命令触发寄存器触发方可生效。
ISP_TRIG
ISP/IAP 操作时的命令触发寄存器。
ISPENISP_CONTR.7=1 时,对ISP_TRIG 先写入0x46,再写入0xb9ISP/IAP
命令才会生效。
单片机芯片型号起始地址内置EEPROM 容量(每扇区512 字节)
STC89C51RCSTC89LE51RC 0x2000 共八个扇区
STC89C52RCSTC89LE52RC 0x2000 共八个扇区
STC89C54RD+STC89LE54RD+ 0x8000 共五十八个扇区
STC89C55RD+STC89LE55RD+ 0x8000 共五十八个扇区
STC89C58RD+STC89LE58RD+ 0x8000 共五十八个扇区
寄存器标识地址名称7 6 5 4 3 2 1 0 初始值
ISP_DATA 0xE2 ISP/IAP闪存数据寄存器11111111
ISP_ADDRH 0xE3 ISP/IAP
闪存地址高位00000000
ISP_ADDRL 0xE4 ISP/IAP
闪存地址低位00000000
ISP_CMD 0xE5 ISP/IAP
闪存命令寄存器MS2
MS1 MS0 xxxxx000
ISP_TRIG 0xE6 ISP
IAP 闪存命令触发xxxxxxxx
ISP_CONTR 0xE7 ISP/IAP
控制寄存器ISPEN SWBS SWRST WT2
WT1 WT0 00xx000
B7 B6 B5 B4 B3 B2 B1 B0
命令/操作模式选择
保留命令选择
----- 0 0 0 待机模式,无ISP/IAP 操作
----- 0 0 1 对用户的应用程序Flash 区及数据Flash 区字节读
----- 0 1 0 对用户的应用程序Flash 区及数据Flash 区字节编程
----- 0 1 1 对用户的应用程序Flash 区及数据Flash 区扇区擦除
ISP_CONTRISP/IAP 控制寄存器。
ISPENISP/IAP 功能允许位。0:禁止ISP/IAP 编程改变Flash1:允许编程改变Flash
SWBS
:软件选择从用户主程序区启动(0),还是从ISP 程序区启动(1)。
SWRST0:不操作,1:产生软件系统复位,硬件自动清零。
ISP_CONTR 中的SWBS SWRST 这两个功能位,可以实现单片机的软件启动,并启动到ISP 区或用户程序区,这在“STC 单片机自动下载”一节,亦有所应用。
如:
ISP_CONTR=0x60? 则可以实现从用户应用程序区软件复位到ISP 程序区开始运行
程序。
ISP_CONTR=0x20? 则可以实现从ISP 程序区软件复位到用户应用程序区开始运行
程序。
用IAP 向Flash 中读写数据,是需要一定的读写时间的,读写数据命令发出后,要等待
一段时间才可以读写成功。这个等待时间就是由WT2、WT1、WT0 与晶体振荡器频率决定
的。
(以上的建议时钟是(WT2、WT1、WT0)取不同的值时的标称时钟,用户系统中的时钟
不要过高,否则可能使操作不稳定。)

#include "reg52.h"
#include "eeprom.h"

//****************** 关闭 ISPIAP 功能 **************
void ISP_IAP_Disable(void)
{
ISP_CONTR = 0x00;
ISP_CMD = 0X00;
ISP_TRIG = 0x00;
EA = 1; //开中断
}

//*******************字节读***************************

uchar Byte_read(uint byte_addr)
{

ISP_CONTR = En_Wait_TIME; //开启ISP/IAP;并送等待时间
ISP_CMD = Read_COM; //送字节读命令字
ISP_ADDRH = (uchar)(byte_addr >>8); //送地址高字节
ISP_ADDRL = (uchar)(byte_addr &0X00FF); //送地址低字节
EA = 0; //关中断
ISP_TRIG = 0X46; //送触发命令字 0X46、0XB9
ISP_TRIG = 0XB9;
_nop_();
ISP_IAP_Disable(); //关闭ISP/IAP功能
EA = 1; //开中断
return ((unsigned char)ISP_DATA);
}

//********************字节编程***********************

void Byte_program(uint byte_addr uchar isp_iap_data)
{

ISP_CONTR = En_Wait_TIME; //开启ISP/IAP;并送等待时间
ISP_CMD = Prog_COM; //送字节编程命令字
ISP_ADDRH = (uchar)(byte_addr >>8); //送地址高字节
ISP_ADDRL = (uchar)(byte_addr &0X00FF); //送地址低字节
ISP_DATA = isp_iap_data; //送数据进ISP_DATA
EA = 0; //关中断
ISP_TRIG = 0X46; //送触发命令字 0X46、0XB9
ISP_TRIG = 0XB9;
_nop_();
ISP_IAP_Disable(); //关闭ISP/IAP功能
EA = 1; //开中断
}

//********************* 扇区擦除*********************
void Sector_erase(uint sector_addr)
{

ISP_CONTR = En_Wait_TIME; //开启ISP/IAP;并送等待时间
// ISP_CONTR=0xc1;
ISP_CMD = Dele_COM; //送扇区擦除命令字
ISP_ADDRH = (uchar)(sector_addr >>8); //送地址高字节
ISP_ADDRL = (uchar)(sector_addr &0X00FF); //送地址低字节
EA = 0; //关中断
ISP_TRIG = 0X46; //送触发命令字 0X46、0XB9
ISP_TRIG = 0XB9;
_nop_();
ISP_IAP_Disable(); //关闭ISP/IAP功能
EA = 1;
}


#ifndef _eeprom_h
#define _eeprom_H

//*********************EEPROM定义命令字节******************
#define Read_COM 0X01 //字节读数据存储区
#define Prog_COM 0X02 //字节编程数据存储区
#define Dele_COM 0X03 //扇区擦除数据存储区
#define En_Wait_TIME 0X81 //设置等待时间 并使能ISP/IAP

//从用户区启动程序
//0X00==40MHZ以下0X01==20MHZ以下
//0X02==10MHZ以下0X03==5MHZ以下现在设置了20MHZ以下的
//
#define Start_ADDRH 0X20 //扇区地址高位STC89C/LE52RC
#define Start_ADDRL 0X00 //扇区地址低位

#endif

注意了,要写数据时,一定要对该扇区先擦除后写数据的,所以要写的数据尽量不要多,也可以对不同功能的数据存在不同的扇区里。如:

Sector_erase(0X2e00); //扇区擦除第八个扇区
Byte_program(0X2e00Eeprom_ReadCode);//写EEPROM保存可读命令

要读数据时,就直接读就可以了。

ReadData=Byte_read(0X2002);//读取该地址的数据

读一个字节、编程一个字节、擦除一个扇区分别用时10us、60us、10ms

 

没有更多推荐了,返回首页