wuzhengmin 发表于 2026-1-8 12:13:26

其实是有报错的:

就是没有查出来是什么原因:

cyranohsl 发表于 2026-1-8 17:32:29

wuzhengmin 发表于 2026-1-8 08:49
其实,我没有退休的时候,也讲过大专层次的单片机原理,也上过微机原理及应用

当时没有经验,重理论轻实 ...

老师在B站是不是有账号?我好像刷到过您。

wuzhengmin 发表于 2026-1-8 18:10:48

cyranohsl 发表于 2026-1-8 17:32
老师在B站是不是有账号?我好像刷到过您。

很久之前,搞过STC的89C52RC...................

wuzhengmin 发表于 2026-1-8 18:12:44

我们换台PC机:

结果还是:

我估计是C251编译器的问题

wuzhengmin 发表于 2026-1-8 19:39:52

STC可以把部分程序存储器FLASH拿出来当EEPROM使用

把我们要保存的变量值,在关机断电前保存起来

下次开机再读出来,恢复现场

以前都是用2401,或者9346的,现在可以直接写在STC芯片的程序存储空间里

这个IAP功能还是很好用的

STC手册有介绍:

wuzhengmin 发表于 2026-1-8 19:59:29

地址是从后往前的:

wuzhengmin 发表于 2026-1-8 21:58:02

运行后:

从软件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也没反应


先搁置...........

wuzhengmin 发表于 2026-1-8 22:25:59

我是用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,就对应上了!








wuzhengmin 发表于 2026-1-8 22:33:19

下节课我们学习中断:

wuzhengmin 发表于 2026-1-9 10:26:14

今天开始学习第十三集:

第十三集 中断原理及工作机制一

页: 48 49 50 51 52 53 54 55 56 57 [58] 59 60 61 62 63 64 65 66 67
查看完整版本: 有关DMA,山东大学陈桂友教授