找回密码
 立即注册
查看: 94|回复: 11

Ai8051U-32位 深度学习心得

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 5 天前 | 显示全部楼层 |阅读模式
1集 序言:
1. 问题咨询与交流网站:STC技术官网 WWW.STCAI.COMSTC论坛官网 WWW.STCAIMCU.COM,发表与咨询。
2. 学习8051的理由:
2.1. 8051U屏幕显示和视频播放上,优化QSPI的一些flash编程器芯片,适合大容量视频,比普通8051有质的提升。
2.2. IIS录放音功能做全了。
2.3. PWMDMA兼容了。
2.4. 硬件浮点单元可以实现频谱分析仪。
2.5. AI智能化,实现手写计算器。

枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 5 天前 | 显示全部楼层
第2集 硬件及工具介绍:

宣誓:那怕梦想让我们碰得遍体鳞伤,也要坚持勇往直前。
AI8051U实验箱硬件介绍:
一、试验箱介绍
Ai8051U 实验箱 V1.2
包括:
透明盒子×1个(从手柄处打开)      
开发板×1块
跳线帽(短路帽)×1组(千万别丢了,很有用)
USB-TypeA数据线×1条,用于烧录程序
可以从官网下载使用说明书。官网地址:深圳国芯人工智能有限公司-实验箱

PCB(单线路板)
PCBA:‌PCBA(Printed Circuit Board Assembly)指的是印刷电路板组件(元器件焊好后)。

二、关于开发板
官网下载Ai8051U芯片手册。

USB Link1D接口;与官方发行的下载烧录调试工具(建议另入手1个);见说明书:五
USBTypeA、TypeC烧录接口(与官方赠送的USB数据线接口配套的)
USB转双串口,也是TypeC的;STC自己的芯片(AI8H2K12U)波特率最高10Mb/S,在背面(可以替换市面上的CH340)。主流、主推。
89C52RC的UART案例选用的波特率是9600bits/8=1200Bytes/S

现在的PC基本都不再提供串口,因此需要使用一个USB转串口的芯片(CH340N、CH340K)来实现PC与单片机的通讯

TF卡插座,可以用于跑文件系统。
示波器BNC输入;需要表笔连接;右边红色电容用于调节波形(防止波形失真)。
立体声线路输出(上,接音响)、立体声耳机输出(下)
话筒录音
OLED屏接口(如指纹锁屏幕)
8路流水灯(二极管灯,是否点亮作为是否入门标准)
8位数码管(2个4位组成,时钟显示等)
TFT彩屏(彩屏,如猫和老SHU的动画 )
掉电检测电压调节,用于在掉电之前保存用户数据
红外接收头、红外发射。
矩阵键盘,横向用4个引脚、纵向用2个引脚控制8个按键。
板子上的按键都是轻触开关

ADC键盘,1个引脚控制16个按键。
T0、T1按键
INT0、INT1按键
电源按键、复位按键,ISP下载,参见说明书【电源按键】
QSPI / SPI Flash,猫和老鼠的照片存在这上面,MCU读取然后显示到TFT上(画面流畅,章显8051U的flash质的提升)。
LCD插口和对比度调节电位器(可调电阻器,调对比度)
RTC电池,TypeA掉电时为MCU RTC(Real-time Clock)供电
背面
32.768KHz无源晶振
2^15=32768

对比STC89C52RC用的是11.0592MHz 无源晶振,11.0592MHz能够整除UART的多种波特率所需的分母。如:11_059_200/9600=1152
或12MHz。
对于定时器,分频可选两种,分别是12分频和6分频,默认是12分频。系统的时钟频率为11.0592MHz时,按默认分频,计数脉冲的频率是11059200/12 Hz,因此一个计数脉冲的时间是12/11059200 s,大约是1.08us。

如果采用12MHz的晶振,一个计数脉冲的时间是12/12MHz=1us,(定时1ms,计数器加1000次,每次耗时1us)由此可见,对于没有UART等通信波特率需求时,使用12MHz的晶振对于计时更加精确。

24C02 EEPROM
可以用于防止MCU烧掉时,数据被毁。

EEPROM(Electrically Erasable Programmable Read-Only Memory,电可擦写可编程只读存储器)是一种非易失性存储器(断电后仍能保留数据),可以多次写入和擦除数据。EEPROM广泛应用于需要永久存储数据的电子设备中, 常用于存储设备工作模式、用户偏好设置、关键参数等信息。

STC89C52RC 时用的即是AT24C02CN,存储容量为2Kb = 256Bytes(2048位,256字节),采用I2C协议进行读写。

DS18B20 温度传感器
STC89C52用的是同款。

低成本、高精度。

无源蜂鸣器
SP3485,485通信
AI8H2K12U,USB转双串口。板子上用的像是第三款16脚的这种。立创商城¥2.3。
三、软件环境
1 安装keil
Keil官网下载C51\C251\MDK 5.43a;

Ai8051U视频教程第二集-硬件及工具介绍配套程序\02.硬件及工具介绍\网友推荐的Keil-C51C251环境搭建,其中C251和官网最新版是一样的;

有版权问题,需要破解。

已安装过keil C51(V9.61)C251(V560)、MDK(5.43a),同一文件夹里。
安装后快捷方式标注版本,以免混淆。

2 ISP
官网(https://stcai.com/)下载。ISP始终使用最新版即可!

下载最新版****AIapp-ISP-V6.95A 版
视频制作时的版本是6.94Y,bilibili视频更新时间2024-11-21 00:26:11,当前学习时间是2024/12/08 17:18
版本从旧到新依次是:94H、94X、94Y、95A

3 添加头文件


4 代码包
官网(https://stcai.com/)下载 试验箱代码包包含:

手册
原理图
Keil 中断拓展插件,文件 拓展Keil的C代码中断号.zip,解压,exe需要安装。
keil C51/C251 编译器只支持31以内中断号,超过31编译报错。热心网友提供的简单拓展工具,可将中断号拓展到254
四、ISP USB方式烧录程序
1、 使用 USB 线将实验箱与电脑进行连接

2、 打开 AIapp-ISP-v6.95A 下载软件

3、 选择单片机型号为“AI8051U-34K64”,打开需要下载的用户程序

4、 实验箱使用硬件 USB 接口下载。进入 USB 下载模式需要

先==按住==实验箱上的 P3.2/INT0 按键 / 接地
然后按一下 ON/OFF 电源按键 / 断电,接着松开 ON/OFF 电源按键/上电,
最后可松开 P3.2/ INT0 按键。
正常情况下就能识别出“STC USB Writer (HID1)”设备

5、 【打开程序文件】

6、选择的芯片型号、串口、CPU指令模式(默认为32-Bit的C语言)、IRC频率,点击 STC-ISP 下载软件中的【下载 / 编程】按钮。
主频main Fosc 选择与main.c里的定义的相同(24MHz)
谢谢老师
枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 5 天前 | 显示全部楼层
第3集 点亮第一颗LED
新建工程
1)新建空工程(参考手册2.21.6章节)
2)添加头文件(利用ISP软件,结合手册2.21.6章节)
3)输入如下代码并编译(单箭头表示单个文件编译,双箭头与所有文件编译):
   编译下面代码:
#include”ai8051u.h”
Void main(void)
{
         While(1)
   {
}
}
详细步骤:
1.新建空工程:
1.1.打开软件Keil_v5,一般软件打开时,显示的是上次编译的软件,取消,新建工程。
1.1.1.官网www.stcaimcu.com/gjrj,软件工具的AiCube-ISP-v6.96(保持最新版本)
1.1.2.打开软件最新版Aicube-ISP-v6.96,在ISP下载软件菜单栏中打开芯片手册,找到型号Ai8051U的手册,并下载放在E:\Ai8051u projects文件夹中,打开手册,并把手册放在左边,打开书签(再次打开就隐藏),找到第2.21章节,新建工程,参照手册教程,选择“2”->选择“2.21.6.c”,需要编辑keil_v5软件时,就把书签隐藏起来。可以看到6.5.1章节,新建项目:new μVision         project->设置项目路径和项目名称(项目名称:led.1)。选择路径:E:\keil_v5\projects\led1
1.2.Keil_v5软件设置:选择单片机型号:STC MCU Database\Ai8051U-32Bit series\Ai32G12K128 Series,至此新建项目完成。
1.3.添加原代码到项目(参考章节2.21.6.d):
1.3.1.在Keil_v5软件菜单栏,右击图标:择“project:led1\Target 1\group sourse 1,从下拉菜单中选择:add existing files to group ‘ sourse group 1’……,选择刚刚编辑好的keil v5主程序文件:main.c,双击即可添加进:group sourse 1 项目中,显示:“group sourse 1”下有一个“main.c”文件。至此添加源代码完成。
1.4.软件设置(参照手册2.24章节):
1.4.1.在软件设置界面,找到一个类似魔术棒的工具或打开窗口:Options for Target ‘Target 1’,先打开‘Target’选1项卡,在‘cpu mode’ 一栏里,选择“sourse (251 native)”,勾选“4 Byte Interrupt Frame Size”即压栈、出栈都选择4字节。
1.4.2.设置项目2(Target):Memory Model勾选:Xsmall near vars far const ptr-4(Xsmall 模式,默认将变量定义在2K的edata,单时钟存取,运行速度快;而small模式edata只有128字节容量,当容量超出会报错;而选择large模式,虽然变量可以有16M寻址空间,但由于是在扩展Xdata上,存取时间2-3分钟,速度太慢了)
1.4.3.设置项目3(Target):code Rom Size选择:’Large:64K Size program’(HUGE:超过64K,同时扩展设置:EXteral Rom:Start:FE0000,Size)
1.4.4.设置项目4(Target):如果超过64K,Extemal memory 要设置(不超过,可先不用设置)
1.4.5.设置项目5(options for Target:’Tarfet 1’窗口中”output“选项页):勾选”create HEX files”选项,程序空间超过64K,则HEX fomat:必须选择:’HEX-386’,如果程序不超过64K,就选择’HEX-80’,至此新建工程完成。
2.单片机程序中的头文件使用方法:
2.1.参照手册2.23章节:
2.1.1.系统目录下的头文件,用“#include<文件名.h>,编译器会在系统路径下查找(首先在当前目录下查找,如果查找不到,再去系统路径下查找)。
2.1.2.当前目录下的头文件,用“#include”文件名.h”,编译器会在当前路径下查找。
2.2.打开软件Ai8051U-ISP-v6.96,找到“头文件”选项卡,点击“keil格式头文件(c)”,点击保存文件到当前目录下:E:\keil_v5projects\ai8051u projects,至此,’ai8051.u’头文件,保存到了该目录下。
3.输入如下代码并编译(单箭头表示单个文件编译,双箭头与所有文件编译):
3.1.在main.c主程序文件中编写代码如下:

#include”ai8051u.h”        //调用头文件
Void main(void)            //主函数
{
                             //只执行一次
While(1)
                   {
//一直执行
}
}
3.2.注意:程序编写规范,如缩进设置:
3.2.1.软件keil_v5界面,点选菜单栏右侧,“扳手”工具:configuration,C/c++ files:Tab Size一栏填写:4空格,这样我们缩进时按下一次Tab键,自动缩进4格。
3.2.2.General editorsetting\encoding,选择:GB2312 (simpified)语言格式
3.2.3.编译0 warning -0 error 初步完成。
3.3.编辑第一个代码:点亮led

#include "ai8051u.h"                //调用头文件
void main(void)
{
        P0M0 = 0x00;                //P0端口(P00-P07)为准双向口
        P0M1 = 0x00;
       
        P4M0 = 0x00;                //P4端口为准双向口
        P4M1 = 0x00;       
       
        while(1)
        {
                P00 = 0;        //P0.0端口输出0V
P01 = 0;        //P0.1端口输出0V
P40 = 0;  //P4.0端口输出0V
}
}

编译无警告无错误。
3.4.结合电路图,了解程序为什么能点亮led灯原理。二极管,有正负极,电压~3.3V,三极管象开关,基极P4.0=0、GPIO接口P0.0=0V,PNP型三极管开关打开(接在电源端基极0V开通;如果NPN三极管接在接地端基极3.3V开通),led二极管正极3V,负极0V,led被点亮。
3.5.单片机IO口配置:
3.5.1.PnM0=PnM1=0x00(或者直接写:’0’也可以,下同),表示Pn的(0~7)端口为准双向口
3.5.2.PnM0=0x00,PnM1=0xff表示Pn的(0~7)端口为高阻输出
3.5.3.PnM0=0xff,PnM1=0x00,表示Pn的(0~7)端口为推挽输出
3.5.4.PnM0=0xff,PnM1=0xff,表示Pn的(0~7)端口为开漏输出
3.5.5.利用计算器(程序模式),二进制、八进制、十进制、十六进制之间相互转换。
3.6.打开ISP下载软件进行设置并连线:
3.6.1.芯片型号选择:AI8051U-34K64
3.6.2.按下按键,断电再上电,观察扫描串口,出现USB-writer,说明PC与单片机已通信连接,松开按键P3.2
3.6.3.在ISP下载软件打开程序可执行代码:E:\keil_v5 projects\Ai8051U projects\objectS\
3.7.LED点亮,可以从最简单原始电路开始观察了解,以帮助我们对微电路的理解。
3.8.IO端口的配置除了在程序中自已编写代码配置。
3.9.也可以在ISP下载软件中直接配置并自动生成代码后,复制到我们的main.c中。操作ISP软件界面中的IO配置工具。

枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 5 天前 | 显示全部楼层
第4集 USB不停电下载

1.实验对比演示
2.下载所需文件(STC官网-软件工具-库函数-USB库文件)
3.移植关键部分到工程:
3.1.添加头文件(利用ISP软件,结合手册2.23章节)
3.2.USB初始化函数(lib+.h库实现)
3.3.命令参数
3.4.打开P_SW2寄存器和IE2寄存器(只打开一个位!)

详细步骤:
1.实验对比演示
1.1.USB不停电下载,第一次仍然断电上电,以后下载就不需要停电上电操作了
1.2.USB不停电下载,需要main.C程序相关修改配置。
2.下载所需文件(STC官网-软件工具-库函数-USB库文件)
2.1.打开官网www.stcai.Com,软件工具->usb库文件->文件下载:STC_USB_LIBRARY。Zip,解压缩,选择例程文件:stc32g_cdc_query_demo,另存一份放入“04.USB不停电下载”示例文件夹里
2.2.同时打开ISP下载软件,串口模式选择“USB-CDC”。
2.3.注意:USB库文件包含了8位、32位的库文件,供我们选择,这里选择32位头件。
2.4.打开main.C程序,按照Ai8051U手册的6.5章节修改完善代码编写。
3.移植关键部分到工程(参照手册2.13.6~2.14.6章节):
3.1.添加头文件(利用ISP软件,结合手册2.14.5章节)
3.2.直接打开工程:stc32g_cdc_query_demo.uvproj
3.3.右击source group,添加库文件:stc_usb_cdc_32g.lib
3.4.在main.c中包含头文件:stc32_stc8_usb.h
3.5.新建空工程(参考手册2.13章节)



#include "ai8051u.h"              //调用头文件
#include "stc32_stc8_usb.h"         //调用Ai8051U-32位USB函数的头文件


Char *USER_DEVICEDESC = NULL;     //USB专讲
Char *USER_DEVICEDESC = NULL;     //USB专讲
Char *USER_STCISPCMD = “STCISP#”;  //设置命令字

//#include "math.h"
//#include "stdio.h"

void main(void)
{
    P_SW2 |= 0x80;               //B7位写1,使能访问XFR寄存器
   
    P0M1 = 0x00;   P0M0 = 0x00;         //P0端口(P0.0-P0.7)为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;         //P1端口(P1.0-P1.7)为准双向口
    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中断(B7位=1)

    EA = 1;           //使能总中断(查看Ai8051U手册断的系统结构图)
        while(DeviceState != DEVSTATE_CONFIGURED);  //等待USB完成配置
    while (1)
    {
        if (bUsbOutReady)
        {
//            USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
            printf_usb("1. Read Num:%d\n", OutNumber);
            printf_usb("2. Read Num:%d\n", OutNumber);
            printf_usb("3. Read Num:%d\n", OutNumber);
            printf_usb("4. Read Num:%d\n", OutNumber);
            
            usb_OUT_done();               //usb不停电下载

        }
               
                P40 = 0;        //P40端口输出0V
                P00 = 0;        //P00端口输出0V
                P01 = 0;        //P01端口输出0V
       
    }
}

以上是实现USB不停电下载的最小工程代码。
去官网下载USB库文件,其中包含:stc32_stc8_usb.h头文件,及库文件stc_usb_cdc_32g.lib
编译程序,出现“0 error,40个Warning L57”。
3.6.首先我们定义一下L57,具体步骤:
3.6.1.看内容:uncalled function ignored for overlay process;说明程序未调用以下函数:
3.6.1.1.name:usb_bulk_intr_out/usb
3.6.1.2.Lcd12864_Displayclear/util
3.6.1.3.……
3.6.1.4.
在主程序中,找到:#include”stc32_stc8_usb.h”,选择其中的:stc32_stc8_usb,双击,下拉菜单中选择:open document”stc32_stc8_usb.h”右击即可打开头文件:stc32_stc8_usb.h ,其中可看到如下函数:
void LED40_SendDate(BYTE *date,BYTE size);
void LED64_SendDate(BYTE *date,BYTE size);

Void LCD12864_Displayoff();
Void LCD12864_Displayon();
Void LCD12864_Cursoroff();
Void LCD12864_Cursoron();
……
有这些函数未调用,所以打开魔术棒(或打开F5调试模式),即可打开界面:
Options for Target’Target 1’,点击“L251 Misc”在其中level 2选项,disable warning Number(不能警告的数即屏蔽):填写:57,再编译,就不会出现警告了。
3.7.下载测试:
3.7.1.USB 连线,ISP下载软件,配置:
3.7.1.1.芯片型号:Ai8051U-34k64
3.7.1.2.扫描串口:CDC1-UART1,2CDC+HID
3.7.1.3.波特率范围:2400~115200
3.7.1.4.位数:32-Bit
3.7.1.5.收到用户命令后复位到ISP用户程序区,选择:USB-CDC/串口模式
3.7.1.6.勾选“使用默认的内部自定义命令‘@STCISP#’”
3.7.1.7.勾选“下次使用HID接口进行ISP下载”
3.7.1.8.勾选“每次下载前都先发送自定义命令”
3.7.1.9.勾选“当目标文件变化时自动装载并发送下载命令”
3.7.1.10.USB边线,第一次下载,需要按下P3.2,断电再上电,顺利下载。
3.7.1.11.修改程序:
3.7.1.11.1.原来点亮2个灯,现在屏蔽掉1个,再编译下载,不需要重复按键操作,点击中下载,只有一个Led灯被点亮,证明USB不停电下载成功。
3.7.1.11.2.再次修改:原来P00、P01两led,现在改为P00、P02两个led,程序修改后编译下载,成功点亮P00、P02,证明USB不停电下载成功。
3.8.USB不停电下载的实现,可以帮助我们快速开发、验证程序。
3.9.总结:
3.9.1.USB库文件,不单是AI8051U可以用,STC32、STC8都可以用
3.9.2.移植代码:一步一步移植,从示例代码中一点一点移植过来。
3.9.3.移植过程中,有不董的寄存器,可以同步对照Ai8051U手册中的相关章节内容,即便暂时不完全理解,只要先照搬过来可以了,一边复制一边运行,一般不会错的。后续就不需要移植相关工作,只要把该示例代码保存好,以后使用直接复制粘贴到第5课、第6课,做增减操作就可以使用了。
枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 5 天前 | 显示全部楼层
5C语言基础
摘要
1) C语言USB-CDC串口之printf函数的实现
2) 数的进制:二进制、10进制、十六进制
3) 数据的基本类型
4) C语言常用运算符
详细步骤:
1. C语言USB-CDC串口printf函数的实现
1.1. 打开USB(stc_sub_)中的PRINTF_HID宏定义(去掉//
1.1.1. 先打开一个程序代码,实际操作一下,打开上一个工程,复制代码,打开stc32_stc8_usb.h头文件,其中的// #define PRINTF_HID ,删除反斜杠“//”恢复USB HID定义功能。
1.1.2. 有同学反应:上一节课的USB不停电下载不成功。原因有2个:
1.1.2.1. Keill_v5 软件options for TargetTarget 1’工具栏选项中的配置:
1.1.2.2. 其中Memory model选择:Xsmdll:near vars,for const,ptr-4
1.1.2.3. St_usb_cdc_32.lib 库文件未添加进来。
1.2. 理解PRINTF函数原型的定义:
  #define printf printf_hid  //所有printf_hid出现的地都可以用printf替代
  Int printf_hid(const char *fmt,…);
1.2.1. 参数fmt--是格式控制字符串,包含了两种类型的对象:普通字符和转换说明。
1.2.1.1. 普通字符:在输出时,普通字符原样不动地复制到标准输出
1.2.1.2. 转换说明:
1.2.1.2.1. 类型:根据不同fmt字符串,函数可能需要一系列附加参数,每个参数包含了一个要被插入的值,替换了fmt参数中指定的每个%标签。关于附加参数,既可以是变量,也可以是常量。
1.2.1.2.2. 位置:printf()函数的普通字符和转换说明,放在“”双引号内,附加参数放在双引号外,每个附加参数之间用逗号隔开。
1.2.1.2.3. 数量:printf()的附加参数与转换说明符是一一对应关系,如果有n个转换说明符,printf()的参数就应该有n+1个。如果参数个数少于对应的转换说明符,printf()可能会输出内存中的任意值。(参考转义字符与格式字符)
1.2.1.2.4. 上述过程可通过程序下载测试验证。
1.3. 格式字符:
1.3.1. %d……十进制整型
1.3.2. %ld……十进制长整型
1.3.3. %f……单精度浮点型
1.3.4. %lf……双精度浮点型
1.3.5. %o……八进制整型
1.3.6. %x……十六进制整型
1.3.7. %u……十进制无符号整型
1.3.8. %i……十进制整型(与%d无异)
1.3.9. %c……输出单个字符
1.3.10. %s……输出字符串
1.3.11. %e……输出指数形式
1.3.12. %g……自适应输出(数据够大或够小,则以指数形式输出,否则以小数形式输出)
1.3.13. %p……输出地址
1.3.14. Print f今天是%d%d%d\r\n,24,11,16),打印输出:今天是241116
1.3.15.
1.4. 转义字符:
1.4.1. \?……书写连续多个问号时使用,防止被解析成三字字词
1.4.2. \……用于表示字符常量;即表示1个单引号(‘),通常用于单引号内嵌套单引号时使用。
1.4.3. \”……用于表示一个双引号(”,通常用于双引号内嵌套双引号时使用;如”他说:”你好””,在计算机中,要修改为:”他说:\你好\””,防止计算机误读为:”他说:”+你好+””,导致最后2个双引号为错误语法。
1.4.4. \\……用于表示一个反斜杠(\);由于(\)本身已被定义为转义字符,但如果实际需要反斜杠表示路径时,需要用双反斜杠表示,以防止被解释为一个转义序列符;如要表示:C:\Users\Documents,C语言程序中不能直接写,而应写成C:\\Users\\Documents
1.4.5. \a……警告、蜂鸣
1.4.6. \b……退格符
1.4.7. \f……换页符
1.4.8. \n……换行符(单片机程序中用“\r\n”表示)
1.4.9. \r……回车
1.4.10. \t……水平制表符(TAB键,8个空格)
1.4.11. \v……垂直制表
1.4.12. \ddd……ddd表示1~3个八进制数
1.4.13. \xdd……dd表示2个十六进制数
1.5. 标志
1.5.1. n.m……n几行整,m几行小数;示例:%2.3f
1.5.2. -……左对齐;示例:%-d
1.5.3. 空格……输出值正时空格,负时负号;%#d
1.5.4. #……输出带前导数据:八进制o~~~,十六进制x~~~,其中~表示数字,如%#d;示例:%#d
1.6. ASCII码:定义字符串与十六进制数据之间的转换关系,在单片机程序中经常使用,帮助我们加深理解C语言程序及单片机软件硬件之间的逻辑关系;在ISP软件中程序发送、接收缓冲区,设置显示方式,有文本显示(即字符串),也可同时设置HEX显示(十六进数据),我们对照ASCII码,可以计算它们之间转换关系,或者在程序式计算器中直接换算,在调试某些数值变量时就特别有用。
1.6.1.
2. 数的进制:二进制、10进制、十六进制
2.1. 二进制:逢21,所以只有10两个数,英文写法:Binary,简写Bin
2.2. 八进制:逢81,所以只有0123456789,共10位数,英文写法:Octal,简写Oct
2.3. 十进制:逢101,所以有0123456789,共10位数,英文写法:Decimal,简写Dec
2.4. 十六进制:逢161,所以有0123456789ABCDEF ,16位数,英文写法:Hexadecimal,简写Hex。在内存地址中表示:0x
2.5. 数的进制之间转换,可以统一转换为十进制作为中间换算,也可直接计算器(程序式)中直接换算。
3. 数据的基本类型
3.1. AI8051U-32BIT是基于32位数据变量,但有些浮点式运算,占至64位变量:double64位),那么在C语言程序中,我们必须添加如下申明:
3.1.1. #pragma float64
3.2. Data Type
3.2.1. bit: 1Bits 0Bytes  0 or 1 value range;
3.2.2. Signed char: 8Bits 1Bytes  -128~+127 value range;
3.2.3. unSigned char: 8Bits 1Bytes  0~+255 value range;
3.2.4. Enum:  16Bits  2Bytes  -32768~+32767 value range;
3.2.5. Signed short int: 16Bits  2Bytes  -32768~+32767 value range;
3.2.6. unSigned short int: 16Bits  2Bytes  0~+65535 value range;
3.2.7. Signed  int: 16Bits  2Bytes  -32768~+32767 value range;
3.2.8. unSigned  int: 16Bits  2Bytes  0~+65535 value range;
3.2.9. Signed long int: 32Bits  4Bytes  2147483648~+2147483647 value range;
3.2.10. unSigned long int: 32Bits  4Bytes  0~+4294967295 value range;
3.2.11. Float: 32Bits 4Bytes ±1.17549435e-38~±3.4028235e+38 value range;
3.2.12. Double: 64Bits 8Bytes ±2.2250738585072014e-308~±1.7976931348623158e+308 value range;
3.2.13. Idata*,data*,pdata*(pointers):  8Bits 1Bytes  0~0xFF value range;
3.2.14. near*,xdata*,code*(pointers):  16Bits 2Bytes  0~0xFFFF value range;
3.2.15. far*,huge*(pointers):  32Bits 4Bytes  0~0xFFFFFF value range;
3.2.16. Sbit:  1Bits 0Bytes  0 or 1 value range;
3.2.17. Sfr:   8Bits 1Bytes  0~+255 value range;
3.2.18. Sfr16:  16Bits 2Bytes  0~+65535  value range;
3.2.19. Note:These data types are not provided in ANSI C.They are unique to the C251 compiler.(这些数据类型不提供ANSI C码,它们是独特的C251编译器)
3.2.20. Without using the FLOAT64 compiler Directive,the sixze and range of double is the same as float.(如不使用FLOAT64编译指令,doublefloat数据大小与范围相同)
3.3.  所以,为了使用64位变量double,在程序开头,必须加上:#pragma float64申明。
3.4. 变量类型,可以在程序中重新定义,示例:unsigned char可以用u8替代;那么,我们可以这样定义:
3.5. #define u8 unsigned char: 其中u8……替代变量,unsigned char……被替代变量。
在程序中的表示:
#define u8 unsigned char //8位无符号变量(0~+255),u8替代 unsigned char
#define u16 unsigned char //16位无符号变量0-+65535
U8 X=20;
U8 Y=10;
……
Void main(void)
{
……
While(DeviceState!=DEVSTATE_CONFIGURED);
While(1)
{
  If(bUsbOutReady)
{
Printf(X/Y=%u\r\n,(u16)(X/Y));
Printf(“X%%Y=%u\r\n”,(u16)(X%Y)); //%%1%是转义符,后1%才是取余运算符;
Usb_OUT_done();
}
}
}
备注:上述程序通过编译ISP下载、缓冲区显示,验证结果正确。
3.6. 实际上在单片机里,可能还需要加上地址修饰符,如:xdataedata等,后面详细讲解。
4. C语言常用运算符(0为假,非0为真)
4.1. 算术运算符:
4.1.1. +(加)、-(减)、*(乘)、/()%(取模运算,整除后余数)++(自加运算,整数数值加1)、 --(自减运算,整数数值减1
4.1.2. 假设X=20,Y=10:则X+Y=30,X-Y=10,X*Y=200,X/Y=2,X%Y=0,X++=21,X--=19
4.2. 关系运算符(假设X=20,Y=10)
4.2.1. ==: 检查2个操作数是否相等,相等则为真,(X==Y)为假。
4.2.2. =:检查2个操作数是否相等,不相等则为真,(X=Y)为真。
4.2.3. > : 检查左操作数是否大于右操作数,是则为真,(X> Y)为真。
4.2.4. > : 检查左操作数是否大于右操作数,是则为真,(X> Y)为真。
4.2.5. < : 检查左操作数是否小于右操作数,是则为真,(X< Y)为假。
4.2.6. > =:检查左操作数是否大于等于右操作数,是则为真,(X> =Y)为真。
4.2.7. < =:检查左操作数是否小于等于右操作数,是则为真,(X<= Y)为假。
4.2.8. 注意:0为假,非0为真,用if等判断语句,需要用到真和假的概念,真则执行,否则(假)不执行。
4.2.9. 上述运算符,在判断语句经常使用如:ifX>Y{条件为真}else{条件为假}
4.3. 逻辑运算符{假设A=50000 0101,B=100000 1010),用二进制计算}
4.3.1. &&:逻辑与。皆真为真,有假为假。(A&&B)为真。
4.3.2. ||:逻辑异或运算符。皆假为假,有真为真;(A||B)为真。
4.3.3. !:逻辑非运符。用来逆转操作的状态,使真为假,假为真。(!A)为假。
4.4. 赋值运算符:
4.4.1. =:赋值运算符运算符;右侧操作数赋值给左侧操作数;C=A+B,A+B的值赋值给C
4.4.2. +=:加且赋值运算符;左边操作数加右边操作数的结果赋值给左边操作数;C+=AC=C+A
4.4.3. -=:减且赋值运算符;左边操作数减右边操作数的结果赋值给左边操作数;C-=AC=C-A
4.4.4. *=:乘且赋值运算符;左边操作数乘右边操作数的结果赋值给左边操作数;C*=AC=C*A
4.4.5. /=:除且赋值运算符左边操作数右边操作数的结果赋值给左边操作数;C/=AC=C/A
4.4.6. %=:求模且赋值运算符;左边操作数右边操作数的余数赋值给左边操作数;C%=AC=C%AC/A的余数)
4.4.7. <<=:左移且赋值运算符;     C<<=2 C=C<<2
4.4.8. >>=右移且赋值运算符;       C>>=2 C=C>>2
4.4.9. &=:按位与且赋值运算符;    C&=2 C=C&2
4.4.10. ^=:按位异或且赋值运算符;  C^=2 C=C^2
4.4.11. |=:按位或且赋值运算符;    C|=2 C=C|2
4.5. 位运算符:
4.5.1. &:与运算符;同一为一,其它为零;
4.5.2. |:或运算符;有一为一,皆零为零;
4.5.3. ^:异或运算符;相同为零,不同为一;
4.5.4. ~:取反运算符;零变一,一变零;
4.5.5. <<:二进制左移运算符;左操作数值向左(高位)移动,右操作数指定位数(低位补零)
4.5.6. >>:二进制右移运算符;左操作数值向右(低位)移动,右操作数指定位数(高位补零)
4.6. 其它运算符:
4.6.1. Condition ? x:y 如果condition 为真,则值为X,否则值为Y
4.6.2. .点和->(箭头):成员运算符,用于引用类、结构体、共用体成员;结
4.6.3. &: 取地址运算符;返回变量的存储地址;
4.6.4. *:指针运算符,指向一个变量;如*a,指向变量a
4.6.5. ,:逗号运算符;会顺序执行一系列运算;整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。
枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 5 天前 | 显示全部楼层
第6集 IO输入输出
摘要
1)什么是GPIO
2)按键输入检测
3)课后小练
详细步骤:
1.什么是GPIO:
1.1.GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚状态-高电平或低电平。
1.2.工作电压:VCC=1.9V~5.5V(当温度在-40℃以下最低电压3.0V)。
1.3.通常VDD对地电压(压差):+5.5V(最小-0.3V)、+3.3V(最小-0.3V)两种。
1.4.高电平:输出端口电压接近电源正极的电压,通常以“1”表示;如果电源电压是5.5V,输出端口的最大电压不能超过+5.5(or +3.3)+0.3=+5.8(+3.6)V,否则会损坏内部元件。
1.5.低电平:输出端口电压是GND的电压,通常以“0”表示。
1.6.PnM0与PnM1的组合方式:
1.6.1.PnM0=PnM1=0x00:准双向口模式,弱上拉(传统8051端口模式),灌电流达20mA,
拉电流为270~150μA(存在制造误差)。
1.6.2.PnM0=0x00,PnM1=0xFF:推挽输出(强上拉输出,可达20mA,要加限流电阻)。
1.6.3.PnM0=0xFF,PnM1=0x00:高阻输入(电流既不流入,也不输出。
1.6.4.PnM0=PnM1=0xFF:开漏模式(open-drain),内部上拉电阻断开,开漏模式既可读外部状态也可对外输出(高电平低电平)。如要正确读外部状态或需要对外输出高电平需要外加上拉电阻,否则读不到外部状态,也对外输不出高电平。
1.6.4.1.===【开漏工作模式】,对外设置输出为1,等同于【高阻输入】
1.6.4.2.===【开漏工作模式】,【打开内部上拉电阻或外部加上拉电阻】简单等同于【准双向口】。
1.7.附录电气特性里面附有2张表格,分别是VDD=3.3V、VDD=5.0V:
1.7.1.串口VIH1输入高电平(普通I/O)电压范围1.09V,测度环境关闭施密特触发器。
1.7.2.串口VIL1输入低电平电压范围0.99V,测度环境打开施密特触发器。
1.7.3.可在手册中查找:端口施密特触发控制寄存器(PXNCS,其中x-代表端口号,每个端口号8Bit,1Byte)。
1.7.4.端口施密特触发控制寄存器地址,可查询手册,默认值均为:PXNCS=0x00。
2.按键输入检测:
2.1.硬件准备:默认P3.2是准双向口,且默认初始为高电平,通过电阻和按钮开关接地。当按下按钮后,接地变为低电平。
2.2.程序代码实现:
2.3.所有任务,都要同时配置P40=0,放在while(1)大括号内的开始位置(注意仅执行一次),且if()语句的外面(否则还要发一条命令才能启动),可以结合AI8051U-34K64实验箱结构原理图查看。
2.4.任务1:按下P32灯亮,松开P32灯灭;代码:if (P32==0)P00=0; else P00=1;
2.5.任务2:按下P32灯灭,松开P32灯亮;代码:if (P32==1)P00=0; else P00=1;
2.6.任务3:按一下P32灯亮,一下P32灯灭;代码实现,先#define u8 unsigned char后面 定义一变量u8 state=0;(初始值赋0,写在大括号前面 or在大括号内的最前面,但不要写在大括号中间,因为它是不支持C99的格式),然后在if (P32==0)state=!State;(变量取反)P00=state; printf(“state:%d\r\n”,(int)state);while(p32==0);//等待P32键松开执行下一步(否则会不停 0-1- 0-1……闪烁),程序下载后,测试结果并不稳定,原因是按键按下,其实存在前沿、后沿抖动,中间才是稳定状态,抖动时间大概20ms内。延时函数代码如下:

#include”ai8051u.h”
#include”stc32_stc8_usb.h”

#define u8 unsigned char
#define u8 unsigned int
U8 state=0;
Char *USER_DEVICE_DESC=NULL;
Char *USER_PRODUCTDESC=NULL;
Char *USER_STCISPCMD=”@STCISP#”;

Void delay20ms(void)  //@24MHZ,Delay20ms();  //延时20ms消抖
             {
Unsigned long edata i;
_nop_();
_nop_();
i=11998UL;
While(i) i--;
}
Void main(void)
{
WTST=0;    //设置程序指令延时参数,赋值为0可将CPU执行指令速度最快
EAXFR=1;   //扩展寄存器XFR设置使能
CKCON=0;   //提高访问XRAM速度


P_SW2 |=0X00;
P0M1=0x00;P0M1=0x00;
P1M1=0x00;P1M1=0x00;
P2M1=0x00;P2M1=0x00;
……
P7M1=0x00;P7M1=0x00;

Usb_init();
IE2 |=0x80;
EA=1;
P40=0;
While(DeviceState !=DEVSTATE_CONGIGURED);
While(1)
{
if(bUsbOutReady)
{
//USB_sENDdata(usbOutBuffer,OutNumber);
Usb_OUT_done();
}
//任务1:按下P32按钮灯亮,松开P32灯灭
if(P32==0)          //判断P32键是否按下
{
P00=0;
}
Else
{
P00=1;
}
//任务2:按下P32按钮灯灭,松开P32灯亮
if(P32==1)            //判断P32键是否按下
{
P00=0;
}
Else
{
P00=1;
}
//任务3:按一下P32按钮灯亮,再按一下P32灯灭
if(P32==0)             //判断P32键是否按下
{
Dekay20ms();        //延时20ms消抖
{
State=! state;
P00=state;
Printf(“state:%d\r\n),(int)state);
While(p32==0);
}
}
}





2.7.抖动消除措施:在ISP下载软件界面,找到软件延时工具,主频设置与实际一致,延时时间20ms保存,复制延时函数代码,粘贴到main主程中。位置放在主函数前面,并且在主函数if()语句里调用该函数:
2.8.
2.9.复制上节课内容,在程序代码中,删除其中不用的代码,通过
2.10.注意:P40=0;启动一次就够了,所以放在while()内执行即可。
3.课后小练习:
3.1.课后任务1:按一下P32按键灯亮,按一下P33灯灭。
3.2.课后任务2:按一下一颗灯亮,再按一下亮2个灯……直到全亮(变量+加法和乘法)。
枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 5 天前 | 显示全部楼层
第7集 定时器中断
前言:
妈妈:宝贝,妈妈要炒菜,你每一分钟塞一根木头进去,不要让火熄灭了。
儿子:一分钟多久?
妈妈:按照你的速度的话,你从100数到0就可以了。
儿子:好的。
妈妈:记信,这中间不要去干别的,不然会烧糊。
儿子:我知道了妈妈。
代码如下:
While(1)
{
//添一根柴
//Delay60s();
}
问题:单核CPU,单次只能执行一个任务,在从100数到0的过程中,如果没有别的特殊情况,不能再去做别的事情,那么这怎么办?
这就是我们今天要讨论和解决的内容:定时器
摘要:
1)定时器的介绍
2)定时器的应用
3)函数的定义、声明、调用
详细步骤:
1.定时器的介绍:
1.1.问题:LED3秒闪烁一下,这3秒按下按键1,但是没有反应了?怎么办?
答:因为MCU单核的,同一时间只能执行一个事情,没有特殊情况不能被打断。所以        这里就要引入一个特殊的情况,定时器中断。
1.2.先看一个程序:在主程序中调用一个延时函数:
//任务1:按下P32按钮灯灭,松开P32灯亮
While(1)
{
If(bUsbOutReady)
{
Usb_OUT_done();
}
Delay3000ms();     //延时3s
State=! state;       //变量取反:0 1 0 1
P00=state;
If(P32==0)
{
Delay20ms();
If(P32==0)
{
While(P32==0)
Printf(“按键按下:%d\r\n”,count++)
}
}
}      
//任务结束
1.2.1.从上述程序案例执行情况看,程序执到语句停滞不前:Delay3000ms();
1.2.2.因为是单核,不能多线程同时并行执行,那么怎么办呢?采用中断处理程序,而中断处理最常用的就是定时器中断功能去解决。
1.3.定时器作用:
1.3.1.用于计时系统。可实现软件计时,或者使程序每隔一固定时间(周期性)完成一项操作。
1.3.2.替代长时间的Delay,提高程序的运行效率和处理速度(可以打断主循环,执行完中断任务后再回去执行原来的任务)。
2.定时器的应用:
2.1.任务1:LED灯3秒取反一次,这期间任意时刻按下按键,串口打印按键次数。
2.2.参考AI8051U手册的第17.1~17.2.3章节内容,了解定时器/计数器0的控制寄存器、模式寄存器的设置
2.2.1.定时器/计数器0控制寄存器TCON:B5位TF0=0允许计数;B4位TR0=1;且TMOD.3=0时定时器0,允许开始计数。
2.2.2.定时器/计数器0的T0_M1=T0_M0=0时,选择定时器/计数器0为模式0,16位自动重载模式(寄存器溢出,数值会重载),且TMOPS=0X5B,不为零,可作为8位预分频,组成16+8=24位定时器/计数器(了解定时器0的TR0=0禁止计数,TR0=1允许计数,2个隐藏寄存器RL_TH0,RL_TL0及TH0、TL0工作模式)。
2.2.3.在ISP下载软件中,找到定时器计算器工具,设置时钟主频24、定时长度3秒、选择定时器型号0、24位自动重载、12T等,生成代码,复制粘贴至主程序中。
2.2.4.了解定时器/计数器0的定时长度(秒)(12T)=12*(TMOPS+1)*(65535-(TH0+TL0))/(SYSCLK)=12*(91+1)*(65535-0X0100-0X3F)/24000=2.9998(注意:16位TH0是16位的高8位=0x01,实际是0x0100)
2.3.定时器计算器生成代码,包含了定时器中断函数和定时器初始化函数。将定时器初始化函数放在main()函数前;定时器中断函数放在main()函数后面。
2.4.中断处理主程序修改如下:

#include”ai8051u.h”        //调用头文件
#include”stc32_stc8_usb.h”  //调用头文件
#include "intrins.h"                         //调用头文件

#define u8 unsigned char      //8位无符号变量(0-255)
#define u16 unsigned int       //16位无符号变量(0-65535)
U8 state=0;                    //初始状态
U8 run_state=0;               //运行状态
Char *USER_DEVICE_DESC=NULL;
Char *USER_PRODUCTDESC=NULL;
Char *USER_STCISPCMD=”@STCISP#”;

Void delay20ms(void)  //@24MHZ,Delay20ms();  //延时20ms消抖
{
Unsigned long edata i;
_nop_();
_nop_();
i=11998UL;
While(i) i--;
}
void Timer0_Init(void);                //3秒@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中断
        Timer0_Init();                                                                        //定时器初始化
        EA = 1;                                                                                       
IE |= 0X80;        
        P40 = 0;        
        while (DeviceState != DEVSTATE_CONFIGURED);     //等待USB完成配置        
        while(1)
        {
               
        if (bUsbOutReady)                                                        //如果接收到了数据
        {
            //USB_SendData(UsbOutBuffer,OutNumber);  
//发送数据缓冲区,长度(接收数据原样返回, 用于测试)
            
            usb_OUT_done();                                
        }
               
//                任务1:
//                if( P32 == 0 )                                                                //判断P32按钮是否按下
//                {
//                        Delay20ms();                                                        //延时20ms消抖
//                        if( P32 == 0 )
//                        {
//                                printf("按键按下次数\xfd:%d 次\r\n",(int)count);
//                                count++;
//                                
//                                while( P32 == 0 );                                        //等待P32松开
//                                
//                        }
//                }
        
//                任务2:灯按一下点亮三秒后熄灭。
//                if( P32 == 0 )                                                                //判断P32按钮是否按下
//                {
//                        Delay20ms();                                                        //延时20ms消抖
//                        if( P32 == 0 )
//                        {
////                                printf("按键按下次数\xfd:%d 次\r\n",(int)count);
////                                count++;
//                                P00 = 0;
//                                Timer0_Init();
//                                while( P32 == 0 );                                        //等待P32松开
//                                
//                        }
//                }


                //任务3:救护车灯控制器,按下报警按钮,红蓝交替闪烁(LED1和LED2              表示红和蓝灯),再按一下报警按钮,红蓝灯停止。
                if( P32 == 0 )                                                                //判断P32按钮是否按下
                {
                        Delay20ms();                                                        //延时20ms消抖
                        if( P32 == 0 )
                        {
                                Run_State = !Run_State;                                //运行状态取反
                                
                                if( Run_State==1 )                                        //运行
                                {
                                        Timer0_Init();                 //函数调用
                                }
                                else
                                {
                                        TR0 = 0;                                                //关闭定时器
                                        P00 = 1;
                                        P01 = 1;
                                }
//                                P00 = 0;
//                                Timer0_Init();
                                while( P32 == 0 );                                        //等待P32松开
                                
                        }
                }
               
        }
}
//void Timer0_Init(void)                //3秒@24.000MHz        函数定义
//{
//        TM0PS = 0x5B;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
//        AUXR &= 0x7F;                        //定时器时钟12T模式
//        TMOD &= 0xF0;                        //设置定时器模式
//        TL0 = 0x3F;                                //设置定时初始值
//        TH0 = 0x01;                                //设置定时初始值
//        TF0 = 0;                                //清除TF0标志
//        TR0 = 1;                                //定时器0开始计时
//        ET0 = 1;                                //使能定时器0中断
//        
//        //TM0PS = 91
//        //12T                 /12
//        // THO-TL0 = 319
//        
//}

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

void Timer0_Isr(void) interrupt 1                //3秒执行一次
{
        state = !state;               
        
        P00 = state;
        P01 = !state;
}
程序结束。
3.函数的定义、声明、调用
3.1.整个main主程序,定时器/计数器Timer0的声明:
3.1.1.函数声明:void Timer0_Init(void);        //3秒@24.000MHz
3.1.2.函数定义:
void Timer0_Init(void)        //500毫秒@24.000MHz  函数定义
{
                TM0PS = 0x0F;                //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存                                                        器,详情请查看数据手册 )
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
                TL0 = 0xDC;                                //设置定时初始值
                TH0 = 0x0B;                                //设置定时初始值
                TF0 = 0;                                //清除TF0标志
                TR0 = 1;                                //定时器0开始计时
                ET0 = 1;                                //使能定时器0中断
}
3.1.3.函数调用:Timer0_Init();
3.1.4.函数声明在主函数前头文件后用分号结束,函数定义在主函数后,函数调用在主函数主循环内。
枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:47
  • 最近打卡:2025-10-21 14:54:18

16

主题

136

回帖

1194

积分

版主

积分
1194
发表于 3 天前 | 显示全部楼层
推荐优先看的 printf_usb("Hello World !\r\n")及usb不停电下载, 演示视频链接

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 昨天 17:03 | 显示全部楼层
西西*** 发表于 2025-10-21 14:54
推荐优先看的 printf_usb("Hello World !\r\n")及usb不停电下载, 演示视频链接

版主您好:实验一、二、三,都已学习并心得
枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-10-23 16:48:09
已绑定手机

7

主题

43

回帖

319

积分

中级会员

积分
319
发表于 昨天 17:05 | 显示全部楼层
实验一:PRINTF_USB 直接输出数据
1. 去官网WWW.STCAI.COM,下载软件工具中的:
1.1. 工具软件:Aicube-isp-v6.96A软件、keil中断拓展插件、工具使用说明、触摸按键套件。
1.2. 库函数:USB库函数(适用于所有带USB模块的芯片,如AI8051U及其他STC 8位、32位芯片)。
1.3. AI8051U系列32位硬件乘除运算MDU32库函数。
1.4. 8系列MDU:16位硬件16位MDU16、32位MDU32C乘除库函数。
1.5. 8G-8H系列通用库函数。
1.6. 8A8K64D3通用库函数。
1.7. 32位MDU库函数。
1.8. 32位TFPU库函数。
1.9. 32G12k128主控库函数。
1.10. 32F系列TFPU库函数。
1.11. AI8051U创新、传统风格库函数。
1.12. AI8051U、32位硬件三角函数和浮点运算的TFPU库函数。
2. 打开USB库函数:
2.1. 范例程序“
2.1.1. STC-CDC查询、STCCDC中断、STC-hid查询、STC-hid中断(今天用到的是STC-CDC)。
2.2. Usb库函数:
2.2.1. stc_usb_cdc_8h_data.lib
2.2.2. stc_usb_cdc_data_8h_b151.lib
2.2.3. stc_usb_cdc_8h_xdata.lib
2.2.4. stc_usb_cdc_xdata_8h_b151.lib
2.2.5. stc_usb_cdc_32g_data.lib(<64kB)
2.2.6. stc_usb_cdc_data_32g_huge.lib(>64KB)
2.2.7. ai_usb.h
2.2.8. keilkill中断拓展
2.2.9. Stc32_stc8_usb.h
2.2.10. 库文件使用说明。
3. AICUBE 项目助手设置界面:
3.1. 项目设置:
3.1.1. 单片机型号:AI8051U-32Bit
3.1.2. 项目名称:test1
3.1.3. 项目路径:E:\AI8051U
3.1.4. 项目类型:单文件类型
3.1.5. 自动打开项目:是
3.1.6. 自动备份keil项目文件:是
3.1.7. 备份深度:2
3.1.8. 编码格:GB2312(新增UTF-8)
3.1.9. Cpu模式:源模式(sourse)
3.1.10. 存储器模式:xsmall模式
3.1.11. 代码等等小模式:large模式
3.1.12. 4字节中断帧:是
3.1.13. 使能REMOVEUNUSED:是
3.1.14. 创建HEX格式:是
3.1.15. HEX格式:HEX-80(代码>64kB,用HEX-386)
3.2. 图形化I/O设置
3.2.1. 如右图:芯片管脚功能:
3.2.2. 左键选择管脚功能,右键配置管脚模式
3.2.3. 可以看到右下输出窗口,显示配置
3.3. 点击左侧窗口“PERIPHERAL,外设”下拉的相应端口必须勾选后,才能生效。
3.4. 图形化时钟配置(一般默认,不需要设置):
3.4.1. 主时钟源:内部PLL输出
3.4.2. 系统时钟分频:3
3.4.3. 主时钟输出:否
3.4.4. 选择内部高速IRC频率:内部预置频率
3.4.5. 内部预置频率:40MHZ
3.4.6. 启动外部高速晶振:否
3.4.7. 启动内部低速IRC:否
3.4.8. 启动内部48MHZ高速IRC:否
3.4.9. PLL时钟源:内部高速IRC
3.4.10. PLL输出时钟分频:4分频
3.4.11. PLL输出:8倍频(96MHZ)
3.4.12. 高速外设时钟预分频:1
3.4.13. I2S时钟分频:1
3.4.14. PWMA时钟分频:1
3.4.15. PWMB时钟分频:1
3.4.16. TFPU时钟分频:1
3.4.17. 设置是否正确,检查有无黄色文本(报错),报错必重新修改设置。黄色报错,蓝色可配置。
3.5. SYS,系统:
3.5.1. GLK 时钟:一定要勾选,保障上一章节“图形化时钟配置”对时钟的所有配置生效。
3.5.2. 除时钟配置外,其他如外部中断、定时器/计数器、TFT、总线等,根据电路要求需要设置。
3.6. USB通用串口总线设置:
3.6.1. USB协议:CDC通信设备协议
3.6.2. 数据处理方式:查询方式
3.6.3. USB不停电下载:是
3.6.4. ISP下载命令:@STCISP#
3.6.5. 等USB主机检测到DEVICE并配置完成:否
3.6.6. 中断优先级:最低优先级。
4. 保存以上所有设置。
5. 实际操作:
5.1. 重新打开AIcube项目
5.2. 首先勾选“USB通用串行总线”:
5.3. USB具体设置:
5.3.1. USB协议:CDC通信设备协议
5.3.2. USB端口:D-(P3.0),D+(P3.1)
5.3.3. 数据处理方式:查询方式
5.3.4. USB不停电下载:是
5.3.5. ISP下载命令:@STCISP#
5.3.6. 等USB主机检测到DEVICE并配置完成:否
5.3.7. 中断优先级:最低优先级。
5.4. 本实操对其他配置暂时不需要用到,不做设置
5.5. 保存上述设置。
5.6. 生成并打开keil项目
5.7. 打开main.c
5.8. 先编译一下,0 error,0 warning
5.9. 添加头文件和主函数
5.10. 必须在对应的begin与end之间添加
5.11. 从keil范例程序中:深圳大学上机试验有编好的PRINTF_USB 直接打印数据程序中的C语言打开,在main函数段,找到并复制”printf_usb(“hello world!\r\n”);粘贴到本实验对应主函数位置。
5.12. 将不需要的有关查询语句注释掉(不要册除,保证原程序的完整性)。
5.13. 在相应头文件位置复制粘贴:
5.13.1. #include”ai8051u.h”
5.13.2. #include”ai_usb.h”
5.13.3. 用TAB键将代码对齐,规范代码风格
5.13.4. 如果遇到程序较大,可以使用4分屏命令:windows->spilot,方便编辑程序,不需要用就退出:windows->close all。
5.13.5. 编译程序显示:0 error,0 warning,表示编译成功。
5.14. 回到AiCube 界面:进行设置:
5.14.1. 单片机型号:AI8051U-32K64
5.14.2. 通信方式:USB-CDC
5.14.3. 最低波特率:2400
5.14.4. 最高波特率:115200
5.14.5. 起始地址:勾选“清除代码缓冲区”、“清除EEPROM缓冲区”
5.14.6. 硬件配置:
5.14.6.1. IRC调节模式:勾选“不调节,使用内部预置频率”
5.14.6.2. IRC 预置频率:40MHZ
5.14.6.3. 勾选:振荡器放大增益>(12MHZ以上建议选择)。
5.14.6.4. 勾选:上电复位使用较长延时
5.14.6.5. 勾选:允许低电压复位(禁止低电压中断)
5.14.7. 打开程序:E:\AI8051U PROJECTS\OBJECT\Printf_usb.hex
5.15. 先用普通USB下载
5.15.1. 参照AI8051U实验箱1.2使用说明,对照实物(本人无实验箱,只能做前半部分)
5.15.2. 硬件连接:用USB线将PC与实验箱连接上
5.15.3. 先按下P3.2(接地)、接着按下电源按键(断电)再松开电源按键上电。
5.15.4. 出现:ISP下载软件上USB-CDC跳转为(HID1)USB-Writer(自动识别、已经通信了)。
5.15.5. 此时,系统与端口3.2 无关了,可松开P3.2按键,进入程序下载模式。
5.15.6. 打开程序:找到objects->printf_usb.hex
5.15.7. 点击”下载/编程“:此时可在软件右下方窗口显示:下载成功!并提示:1秒后自动跳转USB-CDC串口助手
5.15.8. 1秒后,软件右上方USB-CDC串口助手打开,且不停下载显示“hello world!”。
5.15.9. 在右上方窗口左下角处点击“关闭串口”,程序立即停止下载。
5.16. USB不停电下载(注:第1次下载须先普通下载后才能进入不停电下载):
5.17. ISP下载软件里,除了硬件设置外,还要在软件项目进行设置:
5.17.1. 在ISP下载软件中,选择”收到用户命令后复位到ISP监控程序区”
5.17.1.1. 勾选:USB-CDC(串口模式)
5.17.1.2. 勾选:使用默认的内部自定”@STCISP#”
5.17.1.3. 勾选:下次下载使用HID接口进行ISP下载
5.17.1.4. 勾选:每次下载前先发送自定义命令。
5.17.1.5. 勾选:每次下载前都重新装载目标文件
5.17.1.6. 勾选:当目标文件变化时自动装载并发送下载命令。
5.17.2. 软件设置后,USB连线连接PC与硬件实验箱。
5.17.3. 按下P3.2按键(接地)、接着按下电源按键(断电)再松开电源按键给板子上电。
5.17.4. 出现:(HID1)usb-writer(串行接口通信了)
5.17.5. 此时系统与端口P3.2无关了了,可松开P3.2按键,进入程序下载模式
5.17.6. 下面操作与USB普通下载相同。
5.18. 不停电下载与普通下载的区别:
5.18.1. 当源代码发生改变,软件仍然可以等待并下载。
5.18.2. 点击下载/编程:下载模式由USB-CDC转变为(HID1)USB-WRITER。
枯躁的背后,有成功的喜悦。
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-10-24 05:13 , Processed in 0.142029 second(s), 95 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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