找回密码
 立即注册
楼主: yzhkpli

stc32g 9.4实验箱-冲哥教学视频学习笔记兼对比8051U实验箱学习

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-05-29 10:43:45

34

主题

199

回帖

637

积分

高级会员

积分
637
发表于 2026-5-12 18:20:12 | 显示全部楼层
yzhk*** 发表于 2026-5-12 18:03
这是一个修改版(基本来自硬件家园的程序)以下程序成功的在普中A2实验板上实现了
按下K3按钮(走线为P32--- ...

最后是main.c
  1. #include <STC89C5xRC.H>
  2. #include "KEY.h"
  3. #include "types.h"
  4. #define  Byte_LED                P2
  5. //全局变量 isr_10ms表示10ms中断标志位
  6. bit isr_10ms=0;
  7. //按键状态
  8. uint8_t key_state=0;
  9. sbit key1=P3^1;
  10. void Timer0_Init(void)                //1毫秒@11.0592MHz
  11. {
  12.         AUXR &= 0x7F;                        //定时器时钟12T模式
  13.         TMOD &= 0xF0;                        //设置定时器模式
  14.         TMOD |= 0x01; // 设置定时器0为模式1(16位定时器)
  15.         TL0 = 0x66;                                //设置定时初始值
  16.         TH0 = 0xFC;                                //设置定时初始值
  17.         TF0 = 0;                                //清除TF0标志
  18.         ET0=1;
  19.         EA=1;
  20.         TR0 = 1;                                //定时器0开始计时
  21. }
  22. void timer0_isr() interrupt 1 //timer0为定时1ms
  23. {
  24.         static uint8_t cnt_10ms=0;
  25.         TL0 = 0x66;                                //设置定时初始值
  26.         TH0 = 0xFC;                                //设置定时初始值
  27.         cnt_10ms++;
  28.         if(cnt_10ms>=10){
  29.                 //isr_10ms=1;//10ms中断标志位置1
  30.                 cnt_10ms=0;
  31.         }
  32.         //P2=key_state;
  33.        
  34.         KEY_Scan_Timer++;//按键扫描定时器
  35. }
  36. void main(void){
  37.         Timer0_Init();
  38.         while(1){
  39.                 //按键1检测函数
  40.                 KEY1_Detect();
  41.                
  42.                 //按键1单击执行
  43.                 if(KEY1_Click_Flag == 1)
  44.                 {
  45.                         KEY1_Click_Flag = 0;
  46.                         Byte_LED = ~Byte_LED;
  47.                 }
  48.         }
  49. }
复制代码
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-05-29 10:43:45

34

主题

199

回帖

637

积分

高级会员

积分
637
发表于 2026-5-14 12:29:52 | 显示全部楼层
今天第一次使用 aicube 生成stc8H的程序,打算仅仅先做一个led闪烁,从点灯开始。

发现一个问题:timer0的时间周期没法改,始终是32,改成200回车也变回去。输入200后,不回车,直接点保存也自动改回去!!!


先看一下main.c,主程序部分
  1. void main(void)
  2. {
  3.     //<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
  4.     // 在此添加用户主函数初始化代码  
  5.     //<<AICUBE_USER_MAIN_INITIAL_END>>
  6.     SYS_Init();
  7.     //<<AICUBE_USER_MAIN_CODE_BEGIN>>
  8.     // 在此添加主函数中运行一次的用户代码  
  9.     //<<AICUBE_USER_MAIN_CODE_END>>
  10.     while (1)
  11.     {
  12.         //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
  13.         // 在此添加主函数中用户主循环代码  
  14.         //<<AICUBE_USER_MAIN_LOOP_END>>
  15.     }
  16. }
复制代码
其中这个 SYS_Init()函数
  1. void SYS_Init(void)
  2. {
  3.     EnableAccessXFR();                  //使能访问扩展XFR
  4.     IAP_SetTimeBase();                  //设置IAP等待参数,产生1us时基
  5.     //<<AICUBE_USER_PREINITIAL_CODE_BEGIN>>
  6.     // 在此添加用户预初始化代码  
  7.     //<<AICUBE_USER_PREINITIAL_CODE_END>>
  8.     PORT2_Init();                       //P2口初始化
  9.     TIMER0_Init();                      //定时器0初始化
  10.     //<<AICUBE_USER_INITIAL_CODE_BEGIN>>
  11.     // 在此添加用户初始化代码  
  12.        
  13.     //<<AICUBE_USER_INITIAL_CODE_END>>
  14. }
复制代码
首先是第一个EnableAccessXFR函数

EnableAccessXFR()函数定义在 stc8h_def.h文件中
        <code>#define EnableAccessXFR()               SET_REG_BIT(P_SW2, EAXFR_MSK)</code>

以下是GLM的解释

这是一个在 STC8H 系列单片机编程中非常核心且常用的宏定义。它的作用是开启对扩展特殊功能寄存器(XFR)的访问权限。
下面为您详细解析这个宏定义的背景、作用以及使用时的注意事项:
1. 宏定义拆解
#define EnableAccessXFR()  SET_REG_BIT(P_SW2, EAXFR_MSK)
SET_REG_BIT(reg, bit): 这是一个底层宏,作用是将某个寄存器的某一位置 1(通常实现为 reg |= bit)。
P_SW2: 这是 STC8H 单片机内的外设功能切换寄存器 2。
EAXFR_MSK: 这是 EAXFR 位的掩码(通常是 0x80,即最高位)。EAXFR 的全称是 Enable Access XFR(允许访问扩展 RAM 区的特殊功能寄存器)。
结论:这个宏的执行效果就是将 P_SW2 寄存器的最高位(EAXFR 位)置 1。
2. 为什么需要这个宏?(背景知识)
传统的 8051 单片机特殊功能寄存器(SFR)只分布在 0x80~0xFF 的地址空间内,数量非常有限。STC8H 系列单片机增加了大量高级外设(如高级 PWM、比较器、增强型串口、USB 等),传统的 SFR 空间已经装不下了。
因此,STC 扩展了一块位于扩展 RAM 区域的寄存器,称为 XFR(eXtended Function Register),地址通常分布在 0xFE00~0xFEFF。
为了防止普通 RAM 读写操作意外修改这些扩展寄存器,STC 设计了一个安全锁,即 P_SW2 寄存器的 EAXFR 位:
当 EAXFR = 0 时,单片机无法修改 XFR 区的寄存器(写操作无效)。
当 EAXFR = 1 时,单片机解锁 XFR 区,可以正常读写。
3. 如何在代码中使用?(重要规范)
在配置 STC8H 的高级外设时,必须先调用 EnableAccessXFR()。为了安全,配置完成后通常建议将其关闭(恢复为 0)。
对应的,头文件中通常也会有关闭的宏:
// 通常在 stc8h_def.h 中也会有这个定义
#define DisableAccessXFR()  CLR_REG_BIT(P_SW2, EAXFR_MSK)
标准使用范例(以配置 GPIO 模式为例):
void GPIO_Init(void)
{
    // 1. 开启 XFR 访问权限
    EnableAccessXFR();
    // 2. 配置扩展寄存器(P0M0, P0M1 在 STC8H 中被映射到了 XFR 区)
    P0M0 = 0x00;
    P0M1 = 0x00; // 准双向口模式
    // 3. 关闭 XFR 访问权限(良好编程习惯,防止后续误操作)
    DisableAccessXFR();
}
4. 注意事项
中断安全:如果你的主程序和中断服务函数(ISR)都需要操作 XFR 区的寄存器,需要注意竞争条件。如果在主程序中开启了 EAXFR,中断发生时可能会干扰当前状态。建议在 ISR 中也独立使用 EnableAccessXFR() 和 DisableAccessXFR(),或者在整个程序运行期间保持 EAXFR=1(如果对安全性要求不高)。
忘记开启的后果:如果忘记调用 EnableAccessXFR() 就去配置扩展寄存器(如 PWM 相关寄存器),代码不会报错,但寄存器的值根本写不进去,导致外设无法正常工作。这是 STC8H 开发中最常见的“坑”之一。
发现aicube给出的程序中没有 DisableAccessXFR();这句。



IAP_SetTimeBase();                  //设置IAP等待参数,产生1us时基
其实就是stc8h_def.h中的一个宏
                        #define IAP_SetTimeBase()               IAP_TPS = ((SYSCLK) / 1000000UL)


IAP_TPS — IAP 等待时间控制寄存器
简单理解为       
IAP_TPS = “当前 CPU 主频(MHz)”的数值,硬件用它来算出擦除/写 EEPROM 需要等多久。




回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-05-29 10:43:45

34

主题

199

回帖

637

积分

高级会员

积分
637
发表于 2026-5-14 13:50:07 | 显示全部楼层
终于用aicube生成的程序框架+打狗棒stc8h+普中A2实现了一个简单的点灯程序


那个timer0周期,是我搞错了。其实是基准周期。也就是在那个设定值基础上用计数值实现更长周期的

  1. //<<AICUBE_USER_HEADER_REMARK_BEGIN>>
  2. ////////////////////////////////////////
  3. // 在此添加用户文件头说明信息  
  4. // 文件名称: main.c
  5. // 文件描述:
  6. // 文件版本: V1.0
  7. // 修改记录:
  8. //   1. (2026-05-14) 创建文件
  9. ////////////////////////////////////////
  10. //<<AICUBE_USER_HEADER_REMARK_END>>
  11. #include "config.h"                     //默认已包含stdio.h、intrins.h等头文件
  12. //<<AICUBE_USER_INCLUDE_BEGIN>>
  13. // 在此添加用户头文件包含  
  14. //<<AICUBE_USER_INCLUDE_END>>
  15. //<<AICUBE_USER_GLOBAL_DEFINE_BEGIN>>
  16. // 在此添加用户全局变量定义、用户宏定义以及函数声明  
  17. volatile uint8_t flag1;
  18. uint16_t time_count = 0; // 新增计数变量
  19. //<<AICUBE_USER_GLOBAL_DEFINE_END>>
  20. ////////////////////////////////////////
  21. // 项目主函数
  22. // 入口参数: 无
  23. // 函数返回: 无
  24. ////////////////////////////////////////
  25. void main(void)
  26. {
  27.     //<<AICUBE_USER_MAIN_INITIAL_BEGIN>>
  28.     // 在此添加用户主函数初始化代码  
  29.     //<<AICUBE_USER_MAIN_INITIAL_END>>
  30.     SYS_Init();
  31.     //<<AICUBE_USER_MAIN_CODE_BEGIN>>
  32.     // 在此添加主函数中运行一次的用户代码  
  33.         P2=0xF0;
  34.     //<<AICUBE_USER_MAIN_CODE_END>>
  35.     while (1)
  36.     {
  37.         //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
  38.         // 在此添加主函数中用户主循环代码
  39.                                 if(flag1){
  40.                                         P2=~P2;
  41.                                         flag1=0;
  42.                                 }
  43.         //<<AICUBE_USER_MAIN_LOOP_END>>
  44.     }
  45. }
  46. ////////////////////////////////////////
  47. // 系统初始化函数
  48. // 入口参数: 无
  49. // 函数返回: 无
  50. ////////////////////////////////////////
  51. void SYS_Init(void)
  52. {
  53.     EnableAccessXFR();                  //使能访问扩展XFR
  54.     IAP_SetTimeBase();                  //设置IAP等待参数,产生1us时基
  55.     //<<AICUBE_USER_PREINITIAL_CODE_BEGIN>>
  56.     // 在此添加用户预初始化代码  
  57.     //<<AICUBE_USER_PREINITIAL_CODE_END>>
  58.     PORT2_Init();                       //P2口初始化
  59.     CLK_Init();                         //时钟模块初始化
  60.     TIMER0_Init();                      //定时器0初始化
  61.     //<<AICUBE_USER_INITIAL_CODE_BEGIN>>
  62.     // 在此添加用户初始化代码  
  63.        
  64.     //<<AICUBE_USER_INITIAL_CODE_END>>
  65.     EnableGlobalInt();                  //使能全局中断
  66. }
  67. ////////////////////////////////////////
  68. // 微秒延时函数
  69. // 入口参数: us (设置延时的微秒值)
  70. // 函数返回: 无
  71. ////////////////////////////////////////
  72. void delay_us(uint16_t us)
  73. {
  74.     do
  75.     {
  76.         NOP(14);                        //(MAIN_Fosc + 500000) / 1000000 - 10
  77.     } while (--us);
  78. }
  79. ////////////////////////////////////////
  80. // 毫秒延时函数
  81. // 入口参数: ms (设置延时的毫秒值)
  82. // 函数返回: 无
  83. ////////////////////////////////////////
  84. void delay_ms(uint16_t ms)
  85. {
  86.     uint16_t i;
  87.     do
  88.     {
  89.         i = MAIN_Fosc / 10000;
  90.         while (--i);
  91.     } while (--ms);
  92. }
  93. ////////////////////////////////////////
  94. // P2口初始化函数
  95. // 入口参数: 无
  96. // 函数返回: 无
  97. ////////////////////////////////////////
  98. void PORT2_Init(void)
  99. {
  100.     SetP2nInitLevelHigh(PIN_ALL);       //设置P2初始化电平
  101.     SetP2nQuasiMode(PIN_ALL);           //设置P2为准双向口模式
  102.     DisableP2nPullUp(PIN_ALL);          //关闭P2内部上拉电阻
  103.     EnableP2nSchmitt(PIN_ALL);          //使能P2施密特触发
  104.     SetP2nSlewRateNormal(PIN_ALL);      //设置P2一般翻转速度
  105.     SetP2nDrivingNormal(PIN_ALL);       //设置P2一般驱动能力
  106.     SetP2nDigitalInput(PIN_ALL);        //使能P2数字信号输入功能
  107.     //<<AICUBE_USER_PORT2_INITIAL_BEGIN>>
  108.     // 在此添加用户初始化代码  
  109.         //P2M0 = 0x00; P2M1 = 0x00;
  110.     //<<AICUBE_USER_PORT2_INITIAL_END>>
  111. }
  112. ////////////////////////////////////////
  113. // 时钟初始化函数
  114. // 入口参数: 无
  115. // 函数返回: 无
  116. ////////////////////////////////////////
  117. void CLK_Init(void)
  118. {
  119.     CLK_SYSCLK_Divider(10);             //切换主时钟前先将系统时钟降频
  120.     HIRC_24M();                         //选择内部预置的频率
  121.     CLK_MCLK_HIRC();                    //选择内部高精度HIRC作为主时钟
  122.     CLK_MCLK2_BYPASS();                 //旁路MCLK2,直接使用MCLK选择
  123.     CLK_SYSCLK_Divider(1);              //设置系统时钟分频系数
  124.     //<<AICUBE_USER_CLOCK_INITIAL_BEGIN>>
  125.     // 在此添加用户初始化代码  
  126.     //<<AICUBE_USER_CLOCK_INITIAL_END>>
  127. }
  128. ////////////////////////////////////////
  129. // 定时器0初始化函数
  130. // 入口参数: 无
  131. // 函数返回: 无
  132. ////////////////////////////////////////
  133. void TIMER0_Init(void)
  134. {
  135. #define T0_RELOAD               (65536 - (float)SYSCLK / 12 * 1 / 1000) //定时周期1毫秒
  136.     TIMER0_TimerMode();                 //设置定时器0为定时模式
  137.     TIMER0_12TMode();                   //设置定时器0为12T模式
  138.     TIMER0_Mode0();                     //设置定时器0为模式0 (16位自动重载模式)
  139.     TIMER0_DisableGateINT0();           //禁止定时器0门控
  140.     TIMER0_SetIntPriority(0);           //设置中断为最低优先级
  141.     TIMER0_EnableInt();                 //使能定时器0中断
  142.     TIMER0_SetReload16(T0_RELOAD);      //设置定时器0的16位重载值
  143.     TIMER0_Run();                       //定时器0开始运行
  144.     //<<AICUBE_USER_TIMER0_INITIAL_BEGIN>>
  145.     // 在此添加用户初始化代码  
  146.     //<<AICUBE_USER_TIMER0_INITIAL_END>>
  147. }
  148. ////////////////////////////////////////
  149. // 定时器0中断服务程序
  150. // 入口参数: 无
  151. // 函数返回: 无
  152. ////////////////////////////////////////
  153. void TIMER0_ISR(void) interrupt TMR0_VECTOR
  154. {
  155.     //<<AICUBE_USER_TIMER0_ISR_CODE1_BEGIN>>
  156.     // 在此添加中断函数用户代码  
  157.         //flag1=~flag1;
  158.         time_count++;
  159.         if(time_count>=500){
  160.                 time_count=0;
  161.                 flag1=1;
  162.         }
  163.     //<<AICUBE_USER_TIMER0_ISR_CODE1_END>>
  164. }
  165. //<<AICUBE_USER_FUNCTION_IMPLEMENT_BEGIN>>
  166. // 在此添加用户函数实现代码  
  167. //<<AICUBE_USER_FUNCTION_IMPLEMENT_END>>
复制代码


回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-05-29 10:43:45

34

主题

199

回帖

637

积分

高级会员

积分
637
发表于 2026-5-16 18:32:51 | 显示全部楼层
用1500个币兑换了一个ai8051U v1.2实验箱。现在开始用这个试验箱学习

第四讲 usb不断电下载
虽然已经有了一箭双雕双串口线和link1D这种工具,但还是要学一下这一讲

keilc251中新建一个download1的project。
将 stc_usb_cdc_32g.LIB和 main.c中提到的两个.h文件拷贝到项目根目录下

main.c内容
  1. #include <AI8051U.H>
  2. #include "stc32_stc8_usb.h"
  3. #include "ai_usb.h"
  4. //新版库函数中教程中这三句已经不需要了
  5. //char *USER_DEVICEDESC = NULL;
  6. //char *USER_PRODUCTDESC = NULL;
  7. //char *USER_STCISPCMD = "@STCISP#";
  8. void main(void){
  9.     P_SW2 |= 0x80;//使能访问XFR
  10.    
  11.     P0M1 = 0x00;   P0M0 = 0x00;
  12.     P1M1 = 0x00;   P1M0 = 0x00;
  13.     P2M1 = 0x00;   P2M0 = 0x00;
  14.     P3M1 = 0x00;   P3M0 = 0x00;
  15.     P4M1 = 0x00;   P4M0 = 0x00;
  16.     P5M1 = 0x00;   P5M0 = 0x00;
  17.     P6M1 = 0x00;   P6M0 = 0x00;
  18.     P7M1 = 0x00;   P7M0 = 0x00;
  19.    
  20.     usb_init();                                     //USB CDC 接口配置
  21.     //set_usb_ispcmd(0);  //禁用不停电下载功能会提升传输速度
  22.                 IE2 |= 0x80;                 //使能USB中断
  23.     EA = 1;
  24.                 while (DeviceState != DEVSTATE_CONFIGURED);     //等待USB完成配置
  25.                 P40=0;
  26.                 while(1){
  27.                        
  28.                         if (bUsbOutReady)
  29.                         {
  30.                                 //printf("OutNumber=%bd\r\n",OutNumber);
  31.                                 //printf_usb("Hello World !\r\n");
  32.                                 USB_SendData(UsbOutBuffer,OutNumber);//);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
  33.                                
  34.                                 usb_OUT_done();
  35.                         }
  36.                         //以下是自定义的代码
  37.                         /*
  38.                         收到用户命令后复位到isp监控程序区
  39.                         选择usb-cdc串口模式
  40.                         下面三个复选框全选中
  41.                         */
  42.                         P00=0;
  43.                         P01=0;
  44.                         P02=0;
  45.                 }
  46. }
复制代码


注意:isp下载软件必须也要设置。设置完成后,哪怕扫描串口没有选中hid那一项,也可以靠程序切到hid,从而可以实现不断电烧录。
截图202605161831317734.jpg
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-5-30 04:44 , Processed in 0.114950 second(s), 57 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表