其实是有报错的:
就是没有查出来是什么原因:
wuzhengmin 发表于 2026-1-8 08:49
其实,我没有退休的时候,也讲过大专层次的单片机原理,也上过微机原理及应用
当时没有经验,重理论轻实 ...
老师在B站是不是有账号?我好像刷到过您。
cyranohsl 发表于 2026-1-8 17:32
老师在B站是不是有账号?我好像刷到过您。
很久之前,搞过STC的89C52RC...................
我们换台PC机:
结果还是:
我估计是C251编译器的问题
STC可以把部分程序存储器FLASH拿出来当EEPROM使用
把我们要保存的变量值,在关机断电前保存起来
下次开机再读出来,恢复现场
以前都是用2401,或者9346的,现在可以直接写在STC芯片的程序存储空间里
这个IAP功能还是很好用的
STC手册有介绍:
地址是从后往前的:
运行后:
从软件Debug 看是对的
但试验箱的P0口,亮灯是 1100 1000 (0是亮,1是灭)
好像锁存相位是反了,高低顺序也是反的。
硬件仿真画面是:
P0口数据也是0x13是对的,读和写以及擦除都是OK的
第二天反应过来的补充说明: LED的显示1100 1000,的确是表示13,是低位在前,高位在后的:
顺序是这样的:后4位1000变成 0001,前4位1100变成0011 组合起来就是0001 0011 这个主要是
试验箱的硬件电路决定,不用和它较劲.............
我又把深圳大学LED流水灯的实验重新做了一次,硬件Deubg也是这样,但人家是可以在
观察窗口正常显示变量的值,所以Keil uVision这里还是有选项没有选择对,我把编译优化级别选0也没反应
先搁置...........
我是用Ai8051U试验箱做这个实验
先把程序上传:
/*
【例5-2】单片机Flash作为EEPROM使用的基本操作。实现对0x0400单元的擦除和读写操作。
测试工作频率为 11.0592MHz
*/
#include "ai8051u.h" //调用头文件
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void Delay500ms(void); //@11.0592MHz
void SYS_int(void); //系统初始化
//void IapIdLe(void);
void IapIdle();
char IapRead(unsigned long addr);
void IapProgram(unsigned long addr,char dat);
void IapErase(unsigned long addr);
void main(void)
{
unsigned char dataread=0,datawrite=0;
SYS_int(); //系统初始化
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
if (bUsbOutReady)
{
USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done();
}
P40 = 0 ;
IapErase(0x0400);
dataread = IapRead(0x0400);//dataread = 0xff
P0 = IapRead(0x0400); //P0=0xff
IapProgram(0x0400,0x13);
datawrite = IapRead(0x0400);//这里高位在后,低位在前
P0 =IapRead(0x0400); //P1=0x130001 0011
//亮灯是 0011 1000 对不上啊
while (1);
}
void Delay500ms(void) //@11.0592MHz
{
unsigned long edata i;
/*edata是代表扩展数据存储区(Extended DATA)。
作用:用于声明变量存储在单片机片内 RAM 的高 128 字节(地址范围 0x80-0xFF)。
特点:
访问速度:比外部扩展 RAM(xdata)快,但比低 128 字节的直接寻址区(data)稍慢,因为它只能通过间接寻址访问。
使用场景:当 data 区空间不足,但又需要比 xdata 更快的访问速度时使用。
注意,这里用XDATA和DATA,延时时间的不同的!
*/
_nop_();
_nop_();
i = 1382398UL;
while (i) i--;
}
void SYS_int(void) //系统初始化
{
P_SW2 |= 0x80; //B7位写1,使能访问XFR
EAXFR = 1; //允许访问扩展的特殊寄存器·XFR
//(32 位模式请使用这句·注释下一句)
P_SW2 |= 0x80; //允许访问扩展的特殊寄存器·XFR
//8 位模式请使用这句·注释上一句)
WTST=0; //设置取程序代码等待时间.
//赋值为 0 表示不等待,程序以最快速度运行
CKCON=0; //设置访问片内的xdata速度.
//赋值为0 表示用最快速度访问,不增加额外的等待时间
P0M1 = 0x00; P0M0 = 0x00; //端口配置直接用STC的ISP,很方便的
P1M1 = 0x00; P1M0 = 0x00; //端口配置直接用STC的ISP,很方便的
P2M1 = 0x00; P2M0 = 0x00; //端口配置直接用STC的ISP,很方便的
P3M1 = 0x00; P3M0 = 0x00; //端口配置直接用STC的ISP,很方便的
P4M1 = 0x00; P4M0 = 0x00; //端口配置直接用STC的ISP,很方便的
P5M1 = 0x00; P5M0 = 0x00; //端口配置直接用STC的ISP,很方便的
P6M1 = 0x00; P6M0 = 0x00; //端口配置直接用STC的ISP,很方便的
P7M1 = 0x00; P7M0 = 0x00; //端口配置直接用STC的ISP,很方便的
usb_init();
IE2 |= 0x80; //使能USB中断
EA = 1;
}
//void IapIdLe(void)
//{
// IAP_CONTR = 0;//关闭IAP功能
// IAP_CMD =0; //清除命令寄存器
// IAP_TRIG =0; //清除触发寄存器
// IAP_ADDRH = 0x80;//将地址设置到非IAP区域
// IAP_ADDRL = 0;
//}
void IapIdle()
{
IAP_CONTR= 0; //关闭IAP 功能
IAP_CMD = 0;//清除命令寄存器
IAP_TRIG=0; //清除触发寄存器
IAP_ADDRE = 0x00;
IAP_ADDRH=0x12; //将地址设置到非IAP区域
IAP_ADDRL=0x34;
}
char IapRead(unsigned long addr)
{
char dat;
bit flag;
flag = EA;//保存EA 状态
EA=0; //关闭中断
IAP_CONTR=0x80; //使能 IAP
IAP_TPS = 11; //设置等待参数 11MH
IAP_CMD = 1; //设置LAP 读命令
IAP_ADDRL=addr; //设置LAP 低地址
IAP_ADDRH = addr>>8;//设置IAP 高地址
IAP_ADDRE = addr>>16; //设置 LAP 最高地址
IAP_TRIG= 0x5a; //写触发命令(0x5a)
IAP_TRIG=0xa5; //写触发命令(0xa5)
_nop_();
_nop_();
_nop_();
_nop_();
dat=IAP_DATA; //读 IAP 数据
IapIdle(); //关闭LAP 功能
EA=flag; //恢复EA 状态
return dat;
}
void IapProgram(unsigned long addr,char dat)
{
bit flag;
flag = EA; //保存EA 状态
EA=0; //关闭中断
IAP_CONTR = 0x80;//使能 IAP
IAP_TPS = 11; //设置等待参数 11MHz
IAP_CMD = 2; //设置IAP 写命令
IAP_ADDRL = addr;//设置IAP 低地址
IAP_ADDRH = addr>>8;//设置IAP 高地址
IAP_ADDRE =addr>>16;//设置IAP 最高地址
IAP_DATA=dat; //写IAP 数据
IAP_TRIG=0x5a; //写触发命令(0x5a)
IAP_TRIG =0xa5; //写触发命令(0xa5)
_nop_();
_nop_();
_nop_();
_nop_();
IapIdle(); //关闭IAP 功能
EA=flag; //恢复 EA 状态
}
void IapErase(unsigned long addr)
{
bit flag;
flag = EA; //保存EA 状态
EA=0; //关闭中断
IAP_CONTR=0x80; //使能 LAP
IAP_TPS = 11; //设置等待参数 11MH
IAP_CMD=3; //设置LAP 擦除命令
IAP_ADDRL= addr; //设置LAP 低地址
IAP_ADDRH = addr>> 8; //设置 LAP 高地址
IAP_ADDRE=addr>> 16; //设置IAP 最高地址
IAP_TRIG=0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
_nop_();
_nop_();
_nop_();
IapIdle(); //关闭LAP 功能
EA=flag; //恢复 EA 状态
}
结果基本是成功的,读取,擦除,写入都对
就是P0口是输出,好像有点问题,软件仿真也对,P0 现在的现象是
//亮灯是 0011 1000 ,正确应该的 1110 1100 对不上啊
慢慢思考吧,今天的第十二集就到此结束!
20260109专门硬件仿真LED灯(Ai8051U试验箱):
0是LED亮,1是LED灭
当P0=0000 0001时 LED灯:1000 0000 对应0x01
当P0=0000 0010时 LED灯:0100 0000 对应0x02
当P0=0000 0100时 LED灯:0010 0000 对应0x04
当P0=0000 1000时 LED灯:0001 0000 对应0x08
当P0=0001 0000时 LED灯:0000 1000 对应0x10
当P0=0010 0000时 LED灯:0000 0100 对应0x20
当P0=0100 0000时 LED灯:0000 0010 对应0x40
当P0=1000 0000时 LED灯:0000 0001 对应0x80
上面13亮灯是 0011 1000,就对应上了!
下节课我们学习中断:
今天开始学习第十三集:
第十三集 中断原理及工作机制一