xyxvlbkm 发表于 2025-6-5 14:59:40

0.初识8051U

第0章 8051U介绍单价:RMB2.3Ai8051U,USB 型 1T 8051,支持32位和8位指令集管脚兼容天王级别的:89C52RC,12C5A60S2要兼容 8位8051指令集,可以用 Keil C51/IAR/SDCC 编译器相当于更强大的 8H8K64U要兼容 32位8051指令集,可以用 Keil C251 编译器,双核兼容设计相当于更强大的 32G12K128, 32G8K64参数:34K SRAM(2K edata, 32K xdata), 64K FlashTFPU@120MHz, 硬件浮点/硬件三角函数 运算器DMA支持PWM, DMA支持外设直接到外设, P2P120MHz-PWM支持硬件移相,16位PWM; 真12位ADCUSB, 4组串口,12位ADC, 轨到轨比较器QSPI, SPI, I2S, I2C,TFT-i8080/M6800 接口PDIP40,LQFP44,LQFP48对比STC32G优势:1. 屏幕显示和视频播放(flash编程器)2. IIS录放音3. PWM_DMA4. 频谱分析仪(上位机)5. 手写计算器6. QSPI、PWM移相、硬件乘除、单精度浮点

xyxvlbkm 发表于 2025-6-6 09:08:23

1.初识AI8051U

第一章硬件及软件工具介绍
一、 实验箱电路资源

二、 软件环境
1.KeilC251 编译器

2. ISP软件

3. 添加型号与头文件

4. 下载插件

5. 下载代码包和手册


xyxvlbkm 发表于 2025-6-6 09:11:09

2.点灯实验


第二章 点灯实验一、 工程文件1. 创建空工程(参考手册2.6.2章节)2. 添加头文件(利用ISP软件,结合手册2.4章节)3. 输入如下代码,并编译#include “ai8051u.h”void main (void){While(1){;}}注:头文件< >与” ”使用存在区别:尖括号< > 编译器会在系统路径下查找头文件;双引号 “ ” ,编译器首先在当前目录下查找头文件,如果没有找到,再到系统路径下查找头文件。二、 点亮LEDhttps://www.stcaimcu.com/data/attachment/forum/202506/05/165524eaw31qmqevqx5z3w.jpgP4.0 低电平 P0.0 低电平 LED0 亮起#include “ai8051u.h”void main (void){P0M1 = 0x00 ; P0M0 = 0x00 ;P4M1 = 0x00 ; P4M0 = 0x00 ;P40 = 0 ;While(1){P00 = 0 ;}}配置I/O口工作模式准双向口(传统8051端口模式,弱上拉)灌电流可达20mA,拉电流为270~150uA ( 存在制造误差 )

xyxvlbkm 发表于 2025-6-9 14:55:28

3. USB不停电下载-串口一键下载功能

第三章 USB不停电下载-串口一键下载功能1.实验对比演示,修改完成后可以编译程序完成后自动下载,便于开发验证新功能,简化烧录功能。2.下载所需文件(STC官网-软件工具-库函数-USB库文件)3.移植关键部分到工程:3.1 添加头文件3.2 USB初始化函数(lib+.h库实现)3.3 命令参数3.4 打开P_SW2寄存器和IE2寄存器(只打开一个位!)#include "ai8051u.h"   // 调用头文件#include "stc32_stc8_usb.h"// 调用头文件char *USER_DEVICEDESC = NULL;char *USER_PRODUCTDESC = NULL;char *USER_STCISPCMD = "@STCISP#";// 烧录软件启动帧void main(void){    P_SW2 |= 0x80;// B7位写1,使能访问XFR    P0M1 = 0x00;   P0M0 = 0x00;    P1M1 = 0x00;   P1M0 = 0x00;    P2M1 = 0x00;   P2M0 = 0x00;    P3M1 = 0x00;   P3M0 = 0x00;    P4M1 = 0x00;   P4M0 = 0x00;    P5M1 = 0x00;   P5M0 = 0x00;    P6M1 = 0x00;   P6M0 = 0x00;    P7M1 = 0x00;   P7M0 = 0x00;    usb_init();       // USB CDC 接口配置    IE2 |= 0x80;   // 使能USB中断    EA = 1;   // IE |= 0X80; while (DeviceState != DEVSTATE_CONFIGURED);   // 等待USB完成配置 while(1) {      if (bUsbOutReady)      {            USB_SendData(UsbOutBuffer,OutNumber);   // 发送数据缓冲区,长度(接收数据原样返回,用于测试)            usb_OUT_done();      }P40 = 0; // P40端口输出0VP00 = 0; // P00端口输出0VP02 = 0; // P02端口输出0V//P01 = 0;// P01端口输出0V }}// 表示按位或P_SW2 |= 0x80; // B7位写1,使能访问XFR可以只对需要的数据位写1。

xyxvlbkm 发表于 2025-6-9 16:16:21

4. C语言基础

第4章 C语言基础1. C语言 USB-CDC串口之printf函数的实现打开USB库中的PRINTF_HID宏定义(去掉//)PRINTF的函数原型的定义#define printfprintf_hidint printf_hid (const char *fmt, ...);参数fmt -- 是格式控制字符串,包含了两种类型的对象:普通字符和转换说明 。普通字符:在输出时,普通字符将原样不动地复制到标准输出。示例:printf("8051U深度入门到32位51大型实战视频\r\n");转换说明:不直接输出,用于控制 printf 中参数的转换和打印。每个转换说明都由一个百分号字符(%)开始,以转换说明符结束,从而说明输出数据的类型、宽度、精度等。示例:               printf("8051U深度入门到32位51大型实战视频,%s\r\n","加油");转换说明简介:1.类型:根据不同的 fmt 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 fmt 参数中指定的每个 % 标签。关于附加参数,既可以是变量,也可以是常量。2.位置:printf()函数的普通字符和转换说明放在" "双引号内,附加参数放在双引号外,每个附加参数之间用逗号隔开。3.数量:printf() 的附加参数与转换说明符是⼀⼀对应关系,如果有 n 个转换说明符, printf() 的参数就应该有 n + 1 个。如果参数个数少于对应的转换说明符,printf() 可能会输出内存中的任意值。 2. 数的进制:2进制、10进制、16进制各进制与十进制的换算公式二进制 1011=1*2^0+1*2^1+0*2^2+1*2^3=1+2+0+8=11八进制 0123=3*8^0+2*8^1+1*8^2=3+16+64=83十六进制0x34A=10*16^0+4*16^1+3*16^2=10+64+768=8423. 3.数据的基本类型想要使用64位变量,需要在程序文件里面添加申明:#pragma float64 4. C语言常用运算符

xyxvlbkm 发表于 2025-6-9 17:29:36

5.按键检测实验第五章 GPIO输入输出GPIO 简介GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。高电平就是指接近于电源正极电压的电平;也叫逻辑“1”;单片机输出高电平就是输出VCC电压,输出低电平就是输出GND的电压。按键输入检测代码实现原理:程序直接读取按键的IO的电平即可,一般使用”==”即可案例1 : 按下P32按钮灯亮,松开P32按钮灯灭;P40 = 0;if( P32 == 0 )//判断P32按钮是否按下 {P00 = 0; } else {P00 = 1; }案例2 : 按下P32按钮灯灭,松开P32按钮灯亮;P40 = 0;if( P32 == 1 )//判断P32按钮是否按下 {P00 = 0; } else {P00 = 1; }案例3 : 按一下灯亮,按一下灯灭;u8 state = 0;//初始状态void Delay20ms(void) //@24.000MHzDelay20ms();{ unsigned long edata i;
_nop_(); _nop_(); i = 119998UL; while (i) i--;}P40 = 0;if( P32 == 0 )//判断P32按钮是否按下{   Delay20ms(); //延时20ms消抖   if( P32 == 0 )   {    state = !state; //变量取反 0 1 0 1 0 1    P00 = state;    printf("state:%d\r\n",(int)state);    while( P32 == 0 ); //松键检测   }} 机械按键按下或者松开有抖动,一般在20ms内。WTST = 0;//设置程序指令延时参数,EAXFR = 1; //扩展寄存器(XFR)访问使能CKCON = 0; //提高访问XRAM速度案例4 : 按一下P32按钮灯亮,按一下P33按钮灯灭;u8 state = 0;//初始状态void Delay20ms(void) //@24.000MHzDelay20ms();{ unsigned long edata i;
_nop_(); _nop_(); i = 119998UL; while (i) i--;}P40 = 0;if( P32 == 0 )//判断P32按钮是否按下{   Delay20ms(); //延时20ms消抖   if( P32 == 0 )   {    P00 = 0; //灯亮    while( P32 == 0 ); //松键检测   }}if( P33 == 0 )//判断P33按钮是否按下{   Delay20ms(); //延时20ms消抖   if( P33 == 0 )   {    P00 =1; //灯灭    while( P33 == 0 ); //松键检测   }}
案例5 : 按一下亮一颗灯,在按一下亮两颗灯,直到全亮(变量+加法和乘法)u8 state = 0;//初始状态void Delay20ms(void) //@24.000MHzDelay20ms();{ unsigned long edata i;
_nop_(); _nop_(); i = 119998UL; while (i) i--;}P40 = 0;if( P32 == 0 )//判断P32按钮是否按下{   Delay20ms(); //延时20ms消抖   if( P32 == 0 )   {    state ++; //变量取反 灯亮数量自加    Switch( state){case 1 : P00 = 0; break//1灯亮 case 2 : P01 = 0; break//2灯亮case 3 : P02 = 0; break//3灯亮case 4 : P03 = 0; break//4灯亮case 5 : P04 = 0; break//5灯亮case 6 : P05 = 0; break//6灯亮case 7 : P06 = 0; break//7灯亮case 8 : P07 = 0; state =0;break//8灯亮default : P00 = 1;P01 = 1;P02 = 1;P03 = 1;P04 = 1;P05 = 1;P06 = 1;P07 = 1;break//8灯灭}    printf("state:%d\r\n",(int)state);    while( P32 == 0 ); //松键检测   }}

xyxvlbkm 发表于 2025-6-10 10:47:19

6. 定时器

第六章 定时器单核CPU,单次只能执行一个任务。1. 定时器的介绍定时器作用:( 1 ) 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作( 2 ) 替代长时间的Delay;提高程序的运行效率和处理速度(可以打断主循环)2. 定时器的应用案例1:LED灯三秒取反一次,这期间任意时刻按下按钮,串口打印按键次数。void Timer0_Init(void)//3秒@20.000MHz{ TM0PS = 0x4C;//设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 ) AUXR &= 0x7F;//定时器时钟12T模式 TMOD &= 0xF0;//设置定时器模式 TL0 = 0x59; //设置定时初始值 TH0 = 0x02; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时}int count=1; //按键计数变量u8 state = 0; //初始状态//放主循环if( P32 == 0 ) //判断P32按钮是否按下{ Delay20ms(); //延时20ms消抖 if( P32 == 0 ) {printf("按键按下次数\xfd:%d 次\r\n",(int)count);count++;
while( P32 == 0 ); //等待P32松开 }}void Timer0_Isr(void) interrupt 1 //3秒执行一次{ state = !state; P00 = state;}3. 函数的定义、声明、调用定义:包含返回值,函数名和入口参数,并定义了函数具体功能。 返回值类型 函数名(入口参数)    {      // 函数体      // 函数执行的代码      return 返回值;}!void Delay20ms(void) { unsigned long edata i; _nop_(); _nop_(); i = 119998UL; while (i) i--;}函数的名称应当能够描述函数的功能,便于代码的阅读和理解。函数名称应当使用有意义的英文单词或者组合的英文单词,避免使用特殊字符或数字。函数名称不能与C语言的关键字同名。返回值类型 函数名(入口参数);void Delay20ms(void);声明:在头文件或者被调用之前使用,注意末尾要加分号函数名(入口参数);Delay20ms();调用:在需要调用的地方直接使用函数名,加上括号和分号。如果有入口参数的,需要在括号的多个参数之间加逗号隔开。案例2:灯按一下点亮三秒后熄灭案例3:救护车灯控制器,按下报警按钮,红蓝交替闪烁(LED1和LED2表示红灯和蓝灯),再按一下报警按钮,红蓝灯停止。提高案例:电子功德箱:(已实现)1. 按下按钮1,串口显示“双倍功德时间”,再次按下显示“单倍功德时间”2. 按下按键2,双倍功德时间下串口显示“功德+2 当前功德:xxx”;3. 按下按键2,单倍功德时间下串口显示“功德+1 当前功德:xxx”;4. 功德+1时,LED点亮1秒后熄灭表示功德成功点亮;5. 功德+2时,LED点亮2秒后熄灭表示功德成功点亮;
/*
电子功德箱
1. 按下按钮1,串口显示“双倍功德时间”,再次按下显示“单倍功德时间”
2. 按下按键2,双倍功德时间下串口显示“功德+2 当前功德:xxx”;
3. 按下按键2,单倍功德时间下串口显示“功德+1 当前功德:xxx”;
4. 功德+1时,LED点亮1秒后熄灭表示功德成功点亮;
5. 功德+2时,LED点亮2秒后熄灭表示功德成功点亮;
*/
#include "ai8051u.h"                        //调用头文件
#include "stc32_stc8_usb.h"                //调用头文件
#include "intrins.h"                        //d调用头文件

#define u8unsigned char                //8位无符号变量(0-255)
#define u16 unsigned int                //16位无符号变量(0-65535)       
       
u8 state = 0;                                        //初始状态
u8 Run_State = 1;                                //运行状态
// 功德运行 状态 1:功德+1
//                        状态 2:功德+2
u8 Run_Sum = 0;                                //功德值

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

void Delay20ms(void)        //@24.000MHzDelay20ms();
{
        unsigned long edata i;

        _nop_();
        _nop_();
        i = 119998UL;
        while (i) i--;
}
void Timer0_delay1S_Init(void);                //1秒@24.000MHz
void Timer0_delay2S_Init(void);                //2秒@24.000MHz

void main(void)
{
        int count=1;                                                                        //按键计数变量
       
    WTST = 0;                                                                                //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1;                                                                                 //扩展寄存器(XFR)访问使能
    CKCON = 0;                                                                                 //提高访问XRAM速度
       
    P0M1 = 0x00;   P0M0 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;
       
        usb_init();                                     //USB CDC 接口配置

    IE2 |= 0x80;                                    //使能USB中断
       
    EA = 1;                                                                                        //IE |= 0X80;
       
        P40 = 0;
       
        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB完成配置
       
        while(1)
        {
               
      if (bUsbOutReady)                                                        //如果接收到了数据
      {
            //USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
            
            usb_OUT_done();                                                        //
      }
                //任务3:救护车灯控制器,按下报警按钮,红蓝交替闪烁(LED1和LED2              表示红和蓝灯),再按一下报警按钮,红蓝灯停止。
                if( P32 == 0 )                                                                //判断P32按钮是否按下
                {
                        Delay20ms();                                                        //延时20ms消抖
                        if( P32 == 0 )
                        {       
                                if( Run_State==1 )                                        //运行
                                {
                                        Run_State = 2 ;
                                        printf("双倍功德时间\r\n");
                                }
                                else
                                {
                                        Run_State = 1 ;
                                        printf("单倍功德时间\r\n");
                                }
                                while( P32 == 0 );                                        //等待P32松开
                        }
                }
                if( P33 == 0 )                                                                //判断P33按钮是否按下
                {
                        Delay20ms();                                                        //延时20ms消抖
                        if( P33 == 0 )
                        {       
                                if( Run_State==1 )                                        //运行
                                {
                                        Run_Sum += 1 ;
                                        P00 = 0;
                                        Timer0_delay1S_Init();
                                        printf("功德+1 当前功德:%d 次\r\n",(int)Run_Sum);
                                }
                                else
                                {
                                        Run_Sum += 2 ;
                                        P00 = 0;
                                        Timer0_delay2S_Init();
                                        printf("功德+2 当前功德:%d 次\r\n",(int)Run_Sum);
                                }
                                while( P33 == 0 );                                        //等待P33松开
                        }
                }
        }
}

void Timer0_delay1S_Init(void)                //1秒@24.000MHz
{
        TM0PS = 0x1E;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0xFC;                                //设置定时初始值
        TH0 = 0x03;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}

void Timer0_delay2S_Init(void)                //2秒@24.000MHz
{
        TM0PS = 0x3D;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0xFC;                                //设置定时初始值
        TH0 = 0x03;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}

void Timer0_Isr(void) interrupt 1                //3秒执行一次
{
        P00 = 1;
        TR0 = 0;                                //定时器0停止计时
        ET0 = 0;                                //失能定时器0中断
}

xyxvlbkm 发表于 7 天前

7. 定时器周期性调度任务
第七章 定时器
7.1 周期性任务介绍

    任务1:用一个定时器实现这个任务。LED1实现0.3秒取反一次,LED2实现0.6秒取反一次,LED3 0.9秒取反一次

               通过一个变量计数,假设这个变量1ms自加一次,加到300即为300ms,加到600就是600ms;计数到达后重新清0;
               数组使用分为如下两步
               1.定义
                  类型 名称[长度] = { 数值 };
               2.使用
               赋值:名称[索引] = 数值


任务2:数组点亮LED,实现流水灯


注意事项:
LED是0点亮,1熄灭
数组长度需要把握好
流水灯移动的时间


任务3:按键1按一下,LED通过数组移动一下;


注意事项:
按键不能在通过while判断是否按下松开了
可以通过按键按下计数



检测到按键连续按下,按键计数变量+1,只要松开一下,计数清0,计数累积到50ms的时候判定为按下。

7.2 文件的创建(.c 和 .h)

    创建程序文件三步,把硬件需要的初始化弄一个config.c
            新建文件并保存      
            添加到工程
            添加引用路径   


一般一个.c和一个.h文件执行一个外设或者一个任务或功能。这样可以让代码看起来简洁明了


新建xxx.c和xxx.h文件,代表一个功能块。
xxx.h格式:
#ifndef __XXX_H
#define __XXX_H
调用头文件
函数声明...
#endif
xxx.c格式
#include “xxx.h”
函数定义
添加文件一定要记得引用路径和添加到工程里。

7.3 结构体的介绍

    LED1 0.3秒闪一次,LED2 0.6秒闪一次,LED3 0.9秒闪一次


   typedef struct
    {
      u8 Run;               //任务状态:Run/Stop
      u16 TIMCount;         //定时计数器
      u16 TRITime;          //重载计数器
      void (*TaskHook) (void); //任务函数
    } TASK_COMPONENTS;
      static TASK_COMPONENTS Task_Comps[]=
{
//状态计数周期函数
    {0,      1,       1,   执行功能},         
    {0,   10,   10,    执行功能},      
};   


1都有定时器1ms加的变量,
2都有一个设定的计数目标,
3都有需要执行的功能,
4.定时时间到了才能执行

7.4 结构体数组的周期性任务调度

简易舞台灯光控制系统
1.按下按钮1,一键启动或者关闭LED动作,
2.启动后电脑上的LED开始工作
P0口的LED灯循环往下移动一位
P2口的LED灯循环往上移动一位
P4口的LED高四位和低四位交替闪烁
P1口的8个LED全量或者全灭交替(P1.2的位置用P5.2代替




xyxvlbkm 发表于 7 天前

8. 数码管任务
第八章 数码管
8.1 数码管介绍
数码管也叫LED数码管,内部是由多个发光二极管封装在一起组成,理论可以显示任意的字符或者图案。
8.2 数码管显示原理

按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管 AS”代表单色,而“BS”代表双色‌



8.3 数码管静态显示

8.4 数码管动态显示


具体的控制的流程如图所示,N表示有几个数码管!
其中需要注意每个延时不能太短,我们这边程序就以1ms为准,
且需要保证总共一个循环结束的时间不能大于20ms,
因为人眼的视觉不容易分辨出50HZ以上的动态刷新。

    任务2:数码管显示“12345678”


    任务3:数码管显示“00-00-00”分别代表时分秒 ,每过1秒钟秒+1;

8.5 虚拟显示——LED和数码管



简易10秒免单计数器
1.在前四位数码管上显示目标时间,即“ 10. 00 ”表示定时时间10秒钟
2.后四位显示当前的计时00.00,最小单位为10ms,
3.按下开始按钮后,每10ms最末尾的数字+1;直到按下结束按钮后停止计数。


xyxvlbkm 发表于 7 天前

9. 虚拟LED和数码管任务
第九章 虚拟LED和数码管

1.硬件准备


2.软件准备(最新的ISP软件) 菜单栏 -> 仿真调试接口



3.参数设置仿真调试接口 -> 接口设置



4.选择指定的接口和协议匹配

一、 虚拟显示-LED


二、 虚拟数码管



三、 虚拟键盘


任务3:按下数字按键在数码管显示对应的按键数字!
例:按下按键0数码管显示0;


密码锁
1.没有输入时,显示“- - - - - - - -”
2.有输入时,按下一个按键,开始按顺序写入
    例如,第一个按下1,显示“1 - - - - - - -”   
    例如,第二个按下3,显示“1 3 - - - - - -”
3.当按下的密码为“ 1 2 3 4 5 6 7 8”时,数码管显示open的字符,否则,还是显示“- - - - - - - -”


页: [1] 2
查看完整版本: 0.初识8051U