stc32g 9.4实验箱-冲哥教学视频学习笔记兼对比8051U实验箱学习
打算搞一个8051U实验箱,看了一下冲哥的8051U教学视频,发现因为没有实物没法实验。以前买过stc32g 9.4的实验箱和stc8H的9.6实验箱(差生文具多{:4_167:})
所以打算先学冲哥的stc32g 9.4实验箱视频,试验跑通后再记录8051U教学视频的笔记。
从冲哥的stc32g 9.4实验箱视频第三集开始:开发环境搭建和程序下载
下载stc-isp软件地址: https://stcai.com/gjrj
我下载了 2026年3月最新版 AiCube-ISP-v6.96T
使用win10 lstc2021,已经不需要安装usb驱动。
第四集:建立工程点亮第一颗LED上
摘要
1-LED 点亮原理。
2-新建工程
3-点亮第一个 LED
4-实现自动下载工程
烧写程序使用了官方的示例程序
STC32G-DEMO-CODE-V9.4\01-用P6口做跑马灯\C语言
主程序略。
在程序开头注释
使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
咨询了tongyiqianwen答复是:
根据 Keil C251 编译器的架构特性,您的理解存在偏差。XSmall 模式并不推荐作为通用设置,且其默认变量存储区并非 edata。
在 Keil C251 中,XSmall 模式主要是为了兼容旧版 Keil C251 V2 编译器而保留的,其默认将变量存储在片内 data 区域。
⚙️ Keil C251 内存模型详解
Keil C251 编译器提供了三种内存模型,用于决定未明确指定存储类型的变量的默认存放位置。
内存模型 (Memory Model) 默认存储区 地址范围 特点
XSmall data 片内 RAM 低 128 字节 访问速度最快,但空间极其有限。主要用于兼容旧项目。
Small data 片内 RAM 低 128 字节 最常用且推荐的模式。能生成最高效的代码,适用于绝大多数应用。
Large xdata 外部 RAM (最高64KB) 变量空间巨大,但访问速度相对较慢,因为需要通过数据指针 (DPTR) 间接寻址。
核心要点与建议
1-推荐设置:对于新的 C251 项目,通常推荐使用 Small 模式。它在代码效率和易用性之间取得了最佳平衡。
2-默认存储区:XSmall 和 Small 模式的默认存储区都是 data,而不是 edata。edata 通常指扩展的片内 RAM(如 8052 的 128-255 字节),需要通过 idata 关键字间接寻址访问。
3-灵活管理内存:无论选择哪种模型,您都可以在代码中显式地使用存储类型关键字(如 xdata, idata, pdata 等)来精确控制特定变量的存放位置,以优化程序性能。
高频访问变量:如循环计数器,应放在 data 区。
大型数组/缓冲区:建议用 xdata 关键字显式定义,即使在小模式下,也能将其放至外部 RAM,避免耗尽宝贵的片内 RAM。
直接使用官方的project。rebuild,然后
rebuild输出
Program Size: data=8.0 edata+hdata=257 xdata=0 const=0 code=169
咨询了tongyiqianwen coder 模型,
咨询了coder模型
对于 STC32G 这样的现代增强型 8051 芯片,Keil C251 编译器对 XSmall 模式进行了扩展:
传统 8051:在传统的 8051 架构中,XSmall 模式将未指定存储区的变量放入 data (片内 RAM 低 128 字节)。
现代增强型 8051 (如 STC32G):由于芯片功能强大,内部集成了更多的特殊功能寄存器 (SFR) 和额外的片内 RAM。
编译器会将这部分新增的片内 RAM 视为一个独立的、高效的内存区域,即 edata (Extended Data)。
因此,在 XSmall 模式下,编译器会优先将变量分配到这片 edata 空间中。
hdata:为更大内存而生
hdata 是 Keil C251 编译器为支持更大地址空间的新型 8051 单片机(如 STC32G)而引入的存储类型。
物理位置:扩展的外部 RAM。
地址范围:理论上可寻址高达 16MB 的空间(地址 0x000000 - 0xFFFFFF)。
用途:当您的应用程序数据量巨大,连 64KB 的 xdata 空间都不够用时,就需要使用 hdata 来访问更大的内存区域
为什么会这样?
edata 相对于 xdata 有以下优势:
速度快:访问 edata 的速度远快于访问外部 xdata。
效率高:edata 的寻址方式比 xdata 更高效。
所以,当编译器发现一个变量没有被明确指定存储区时,它会优先选择最快的可用内存空间。
对于 STC32G,这片最快的额外空间就是 edata。这就是为什么您的变量 ledIndex 出现在了 edata 区域。
而data=8.0 到底是什么?
data=8.0 表示的是 程序总共需要的 data 段(片内低 128 字节 RAM)的大小为 8 字节。
这个值不是指某个特定的变量,而是由多个因素共同构成的总和。它主要包括以下几个部分:
系统/运行时开销 (System Overhead):
编译器和链接器需要为程序的正常运行预留一些空间。例如,一些内部的工作寄存器、临时变量或函数调用时的参数传递空间等,可能会被分配到这里。
中断向量表 (Interrupt Vector Table):
虽然中断向量本身在 code 区,但处理中断时所需的现场保护(保存 CPU 寄存器)和恢复操作,通常会在 data 区进行,这会占用少量空间。
堆栈 (Stack):
这是最主要的部分。在 XSmall、Small 等模式下,系统的硬件堆栈指针 (SP) 通常被初始化指向 data 区域。当发生函数调用、中断或使用 push/pop 指令时,数据会被压入和弹出这个位于 data 区的堆栈。链接器会估算一个最小的堆栈空间需求,并将其计入 data 段的总大小。例如,您的 main 函数调用 delay_ms,delay_ms 函数内的局部变量 i 和函数返回地址都会用到堆栈。
被强制分配到 data 区的变量:
如果您的代码中有 data u8 someVar; 这样的声明,那么 someVar 就会占用 data 区的空间。
🧠 在您程序中的具体体现
在您提供的这个简单程序中,data=8.0 基本上可以理解为 系统为您的程序分配的、用于函数调用和中断处理的最小堆栈空间。
ledIndex 变量本身(以及其他未明确指定存储区的变量)并没有进入 data 区,而是被编译器优化到了速度同样很快的 edata 区。
ledNum 数组被 code 关键字修饰,它存储在程序代码区,不占用 data 或 xdata。
delay_ms 函数中的局部变量 i 在函数执行期间需要在堆栈上分配空间,这就构成了对 data 区的需求。
💡 总结
data=8.0 并不是一个具体的变量名,而是链接器计算出的,您的程序在片内低 128 字节 RAM (data 区) 中所必需使用的总空间量。
在您的程序中,这 8 字节很可能是为函数调用堆栈预留的最小空间,加上少量的系统开销。
要 做到 USB不停电下载;
要 尝试 AiCube 图形化自动配置生成程序工具;
推荐优先看的:
printf_usb("Hello World !\r\n")及
USB不停电下载, 演示视频链接:
https://www.stcaimcu.com/thread-19077-1-1.html
下载 最新的 AiCube-ISP-V6.96T 或以上版本软件 !
深圳国芯人工智能有限公司-工具软件
下载 最新的 USB库函数,永远用最新的 USB库函数 !
深圳国芯人工智能有限公司-库函数
下载 最新的 用户手册 !
下载 最新的 上机实践指导书 !
下载 最新的 Ai8051U 用户手册
https://www.stcaimcu.com/data/download/Datasheet/AI8051U.pdf
下载 最新的 Ai8051U 实验指导书,
有 AiCube 图形化自动配置生成程序工具使用说明
https://www.stcaimcu.com/data/do ... %AF%BC%E4%B9%A6.pdf
https://v.stcai.com/sv/1c5eec2-197fcd9b766/1c5eec2-197fcd9b766.mp4
上面是 小李 演示:Ai8051U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成
下载 最新的 STC32G12K128 用户手册
https://www.stcaimcu.com/data/download/Datasheet/STC32G.pdf
下载 最新的 STC32G12K128 实验指导书
有 AiCube 图形化自动配置生成程序工具使用说明
https://www.stcaimcu.com/data/do ... %AF%BC%E4%B9%A6.pdf
https://v.stcai.com/sv/44b59184-197d39b65f2/44b59184-197d39b65f2.mp4
上面是 小李 演示:STC32G12K128, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成
冲哥stc32G第4集:建立工程点亮第一颗LED上
实验箱原理图是首先要P40给与一个低电平,打通Q11 SS8550三极管,
然后P60~P67设置低电平后,则 与之连接的led被点亮。
在原理手册中搜索"I/O 口相关寄存器",查到对应的端口的寄存器
sfr P4 = 0xC0;
sfr P4M1 = 0xB3;
sfr P4M0 = 0xB4;
sfr P6 = 0xE8;
sfr P6M1 = 0xCB;
sfr P6M0 = 0xCC;
sbit P40=P4^0;
sbit P60=P6^0;
sbit P67=P6^7;
void main()
{
P4M0 = 0x00;
P4M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
while (1)
{
P40=0;//三极管控制引脚输出低电平
P67=0;//led引脚输出低电平
}
}
build的时候报告
Build target 'Target 1'
Target has no object modules
Target not created.
Build Time Elapsed:00:00:01
错误信息 "Target has no object modules" 表明 Keil C251 编译器没有找到任何需要编译的源文件,
或者虽然找到了源文件但没有成功将其编译成目标模块(.obj 文件)。
这个问题通常由以下几个原因造成,请按顺序检查:
1. 检查文件是否已添加到项目中
这是最常见的原因。即使你创建了 main.c 文件,也必须将它添加到项目的 "Source Group" 中。
打开你的项目。
在左侧的 "Project" 窗口中,展开 "Target 1"。
检查 "Source Group 1" 下面是否有 main.c 文件。
如果没有:
右键点击 "Source Group 1"。
选择 "Add Files to Group 'Source Group 1'..."。
在弹出的对话框中,找到并选中你的 main.c 文件,点击 "Add"。
点击 "Close"。
这次编译成功,下载后,实验箱的最左边的led点亮。
原理图上显示三极管Q11和P60管脚连接R95+led最相近,但是实际布局中三极管Q11紧靠着P6.7连接的R102电阻+led。
所以P67管脚 设置为低电平时候,靠近Q11的那个,也是最左边的led被点亮。
第四课的时候遇到一个麻烦事,使用最新的AiCube-ISP-v6.96T,写入程序卡住了,右下角显示:
正在等待HID-ISP ...
注意左上角的com6,显示是2CDC
换用老式的 stc-isp-v6.94L
com6的显示就不一样了,显示是2CDC+HID。最后用6.94L烧写成功了。
第四讲不断电下载的程序例子
参考 STC32G-DEMO-CODE-V9.4\76-通过USB HID协议打印数据信息-可用于调试
代码如下,GPIO端口模式无所谓,可以都设置为0x00
#include "./COMM/stc.h"
#include "./COMM/usb.h"
void sys_init();
//USB调试及复位所需定义
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#"; //设置自动复位到ISP区的用户接口命令
BYTE xdata cod;
//// 示例:编写一个回调函数
//void my_usb_in_callback(void) {
// // 在这里处理USB IN传输完成后的逻辑
// // 例如,点亮一个LED,设置一个标志位等
//}
BYTE xdata cod;
void main()
{
//USER_STCISPCMD = "@STCISP#";
sys_init();
usb_init();//该函数声明在stc32_stc8_usb.h中,定义在stc_usb_hid_32g.LIB中
EA=1;
// 注册回调函数(这行代码“调用”了 set_usb_IN_callback)
// set_usb_IN_callback(my_usb_in_callback);
//// 例如,通过函数调用来设置ISP命令
// set_usb_ispcmd("@MY_CUSTOM_ISP_COMMAND#");
while (1)
{
if (bUsbOutReady)
{
// memcpy(UsbInBuffer,UsbOutBuffer,64);//接收数据存放发送缓冲区
// usb_IN();//原样返回接收数据,用于测试
usb_OUT_done(); //接收应答(固定格式)
}
//codes
}
}
void sys_init()
{
WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x30; P0M0 = 0x30; //设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
P1M1 = 0x32; P1M0 = 0x32; //设置P1.1、P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V), P1.1在PWM当DAC电路通过电阻串联到P2.3
P2M1 = 0x3c; P2M0 = 0x3c; //设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V),设置开漏模式需要断开PWM当DAC电路中的R2电阻
P3M1 = 0x50; P3M0 = 0x50; //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
P4M1 = 0x3c; P4M0 = 0x3c; //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
P5M1 = 0x0c; P5M0 = 0x0c; //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
P6M1 = 0xff; P6M0 = 0xff; //设置为漏极开路(实验箱加了上拉电阻到3.3V)
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
//设置USB使用的时钟源
IRC48MCR = 0x80; //使能内部48M高速IRC
while (!(IRC48MCR & 0x01));//等待时钟稳定
}
页:
[1]