yimingamei 发表于 2025-9-20 00:33:39

擎天柱学习纪实:《32位8051单片机Ai8051U深度入门》

<h1>一、前言</h1>
<h2>首先非常感谢STC官方活动赠送的核心版</h2>
<h6>前段时间在www.stcai.com找资料时,无意中看到了官方赠送AI8051U转89C52核心板活动。抱着试一试的心态申请</h6>
<h6>了下,没想到真的通过了,非常的开心。</h6>
<h6>Ai8051U转89C52核心功能实验板收到也有几天了,因为比较忙,一直还没有使用。今天展示下收到的Ai8051U核心板,</h6>
<h6>也简单的聊聊我和STC故事。</h6>
<h6>本人是电子类产品从业者,也是一个电子爱好者。经常会和嵌入式方案公司打交道,非常羡慕他们做出的各种各样的功能。</h6>
<h6>也是因为对电子的爱好,萌生了学习的想法。在网上搜索相关资料,了解单片机、嵌入式,查找学习教程。在这个过程中</h6>
<h6>了解到了开发板,拥有了我自己的8051开发板。促成了我和STC的初次邂逅,也开启了我和STC的相遇到相知之路。废话</h6>
<h6>不多说,晒一晒我的Ai8051U核心板。</h6>
<h3>★AI8051U相较与传统8051有了更快的速度,更多的功能:</h3>
<p>* 超高速32位8051内核,速度比传统8051约快70倍以上</p>
<p>* 支持在线仿真</p>
<p>* 无需USB转TTL,可通过内置硬件USB直接下载</p>
<p>* 1.9-5.5V宽工作电压</p>
<p>* 内部高精准时钟(42MHz以下可调)</p>
<p>* 内置专业级复位电路,省外部复位</p>
<p>* 内置4组串口</p>
<p>* 内置DMA</p>
<p>* 120MHz高速16位PWM(支持硬件移相)</p>
<p>* 15路高速 ADC</p>
<p>* 32位乘除运算(MDU32)</p>
<p>* 单精度浮点运算+三角/反三角函数(TFPU)</p>
<p>* 一路比较器</p>
<p>* 内置 I2C、ICE、I2S、QSPI、LCD驱动模块等</p>
<h4>AI8051U核心板正面:</h4>
<p><img src="data/attachment/forum/202509/20/003737gpxvxnvu8b53u856.jpg" alt="AI8051_Top_A.jpg" title="AI8051_Top_A.jpg" /></p>
<h4>AI8051U核心板背面:</h4>
<p><img src="data/attachment/forum/202509/20/003825i40ejj238h0c5ecm.jpg" alt="AI8051U_Bottom_A.jpg" title="AI8051U_Bottom_A.jpg" /></p>
<h3>★AI8051U核心板和89C52-DIP40封装的基本GPIO引脚定义做到了完全对应,部分特殊引脚做了变动:</h3>
<p>1、原89C52对应的晶振XTAL1、XTAL2引脚位置改为接XTALO(P56)、XTALI(P57),由于AI8051U有内部高精准时钟, 一般情况下不需要外部晶振</p>
<p>2、原89C52对应的RxD(P3.0)、TxD(P3.1)引脚位置改为接RxD3_2(P50)、TxD3_2(P51)</p>
<p>3、AI8051U无需外部复位,原89C52对应的RST位置改为NC</p>
<p>4、AI8051U核心板在Type-C接口相对的另一头,将89C52-DIP40封装没有的其它GPIO预留了出来</p>
<h3>才疏学浅,望君莫笑</h3>
<h3>再来张咱Ai8051U核心板上机图</h3>
<p><img src="data/attachment/forum/202509/20/083937j7lav0whdiwaeah0.png" alt="image.png" title="image.png" /></p>
<h3>完美契合,绝世佳配!!!!!</h3>
<h1>再次感谢STC官方的这次活动,让我们有机会接触到更先进的32位8051</h1>
<h1>祝愿STC 乘风破浪、辉煌永续</h1>

西西研究员 发表于 2025-9-20 10:55:08

推荐优先看的 printf_usb("Hello World !\r\n")及usb不停电下载, 演示视频链接
https://v.stcai.com/sv/1c5eec2-197fcd9b766/1c5eec2-197fcd9b766.mp4
https://v.stcai.com/sv/1fce8086-197cf2b9dd4/1fce8086-197cf2b9dd4.mp4

yimingamei 发表于 2025-9-23 15:18:05

<h1>● 预学习_AiCube辅助开发,自动生成程序(printf_usb三个实验)</h1>
<h3>一、学习实验</h3>
<h5>实验一:printf_usb输出“Hello World!”</h5>
<iframe src="https://player.bilibili.com/player.html?isOutside=true&amp;aid=115252360451168&amp;bvid=BV1VnJyzjEo7&amp;cid=32573558066&amp;p=1&amp;danmaku=0&amp;autoplay=0" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width="85%" height="auto" style="aspect-ratio: 16/9;"></iframe>
<h5>实验二:查询方式,printf_usb打印接收到的数据(查询到电脑命令后,输出查询到的对应字符串)</h5>
<iframe src="https://player.bilibili.com/player.html?isOutside=true&amp;aid=115252360451288&amp;bvid=BV1VnJyzjE9T&amp;cid=32573622992&amp;p=1&amp;danmaku=0&amp;autoplay=0" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width="85%" height="auto" style="aspect-ratio: 16/9;"></iframe>
<h5>实验三:中断方式,中断接收服务函数收到命名后,printf_usb输出接收到的字符串</h5>
<iframe src="https://player.bilibili.com/player.html?isOutside=true&amp;aid=115252360452818&amp;bvid=BV1VnJyzjEyW&amp;cid=32573686840&amp;p=1&amp;danmaku=0&amp;autoplay=0" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width="85%" height="auto" style="aspect-ratio: 16/9;"></iframe>
<h3>二、学习心得</h3>
<ul>
<li>利用AiCube配置项目程序,可以免去一条一条命令的配置基础功能。如GPIO端口、定时器、中断、UART等的基础配置。</li>
<li>AiCube-ISP内设置USB不停电下载后。代码更改,只需要点击Keil的“编译”,AiCube-ISP自动下载最新代码到单片机。就算拔掉核心板,再重新插上,也不需再将P3.2接地再进行上电。接上核心板,即可进行升级。</li>
<li>初步了解USB的查询方式接收数据的实现,且通过实验加深了印象。</li>
<li>初步了解USB的中断方式接收数据的实现,且通过实验加深了印象。</li>
</ul>

yimingamei 发表于 2025-9-24 23:25:47

<h1>第01集、序言</h1>
<h5>开篇看到的是一句充满青春气息、拼搏精神的句子:</h5>
<h3>“哪怕梦想让我们拼的遍体鳞伤,这一次我们也要勇往直前”</h3>
<h4>为什么出了STC32,还要出Ai8051U呢? Ai8051U到底强在哪里?</h4>
<p><strong>1、屏幕显示</strong></p>
<ul>
<li>实验箱使用了一个8080的8位并口TFT彩屏,传输速度更快,适合高分辨率和实时图像处理场景</li>
<li>可以实现各种界面的刷新,且能保持不错的帧率</li>
<li>实现汉字显示、图片显示、界面的旋转,适合做图形菜单等</li>
<li>实现触屏的手写输入</li>
</ul>
<p><strong>2、IIS录放音</strong></p>
<ul>
<li>可以实现声音的录制、播放、音量调节等</li>
<li>使用Ai8051U即可实现录放音的功能</li>
</ul>
<p><strong>3、PWM_DMA</strong></p>
<ul>
<li>可以实现1000多颗的WS2812灯的显示,且不会有任何干扰</li>
</ul>
<p><strong>4、频谱分析仪(上位机)</strong></p>
<ul>
<li>通过Ai8051U的IIS实现</li>
<li>可以显示声音的频率及中心频点</li>
<li>足够的运算速度,快速的FFT刷新。能实现快速的分析声音频率</li>
</ul>
<p><strong>5、手写计算器</strong></p>
<ul>
<li>通过在屏幕上手写数字的加、减、乘、除,计算出运算结果</li>
</ul>
<p><strong>6、视频播放(Flash编程器)</strong></p>
<ul>
<li>通过串口Flash编译器可以加载动态图片,实现动态视频的播放</li>
</ul>
<p><strong>7、管脚兼容89C52RC、12C5A60S2等单片机,可以做到Pin对Pin的平替</strong></p>
<p><strong>8、支持8位/32位 8051指令集,可与原有8位/32位芯片无缝衔接</strong></p>
<h4>Ai8051U 功能简介:</h4>
<p><img src="data/attachment/forum/202509/24/232509ei755r3yjj38ym8d.jpg" alt="第01集_序言.mp4_20250924_225725927_看图王.jpg" title="第01集_序言.mp4_20250924_225725927_看图王.jpg" /></p>

yimingamei 发表于 2025-9-25 22:04:00

<h1>第02集、硬件及工具介绍</h1>
<h3>本集主要介绍了实验箱的功能模块和软件的安装:</h3>
<ol>
<li>Ai8051U实验箱的主要功能模块,实验箱包含了学习Ai8051U的主要模块和一些STC的特色功能(如下图)</li>
</ol>
<p><img src="data/attachment/forum/202509/25/220128p777horinwwwq7hx.png" alt="52845692440571.png" title="52845692440571.png" /></p>
<ol start="2">
<li>
<p>Keil软件的下载、安装</p>
</li>
<li>
<p>AiCube-ISP工具下载、ISP功能介绍和添加STC头文件到Keil</p>
</li>
<li>
<p>STC的Keil中断拓展插件的下载、安装</p>
</li>
<li>
<p>Ai8051U代码包、手册、原理图的下载</p>
</li>
<li>
<p>第一个Ai8051U实验箱程序,LED跑马灯讲解:</p>
<p>* Ai8051U实验箱进入下载模式的操作方法</p>
<p>* Ai8051U同时支持8位/32位CPU指令集,下载时需注意选对需要烧录的程序文件</p>
<p>* 在哪里可以找到实验箱代码合适的时钟频率</p>
<p>* LED跑马灯效果展示</p>
</li>
</ol>

yimingamei 发表于 2025-9-30 02:11:49

<h1>第03集、点亮第一颗LED</h1>
<ol>
<li>
<h6>新建工程项目及初步对工程项目进行设置</h6>
<p>* 最新版数据手册和视频有所不同,新建工程项目在2.7章节</p>
<p>* Ai8051U作为32位8051,“Target”选项与8位89C52RC有所不同</p>
<p><img src="data/attachment/forum/202509/30/014939b83poj47ptl3pjtz.png" alt="494594057056959.png" title="494594057056959.png" /></p>
<p><em>上网查了下资料,了解到“Cpu Mode”选项的“binary (8051 compatible)”为8051兼容模式。生成的指令以传统8051指令集为基础,同时通过转义前缀(0A5H)扩展C251新增的指令,生成兼容传统8051的二进制代码。但由于转义前缀的存在,生成的代码并非完全兼容纯8051芯片(纯8051会将转义前缀0A5H识别为无效指令),仅兼容支持C251扩展指令集的芯片。且由于转义前缀的存在,相同功能的代码体积通常比原生模式(每条扩展指令前多1字节前缀),执行效就低且会增加指令解码时间,通过牺牲部分性能换取的兼容性。Ai8051U不支持此模式。</em></p>
<p><em>Memory Model选“Xsmall”:Ai8051U的程序逻辑地址为:FF:0000H~FF:FFFFH,需要使用24位地址线才能正确访问。默认的常量类型(程序存储器类型)必须使用“far”类型,默认指针变量必须为 4 字节。XSmall默认将未指定存储类型的变量定义在内部RAM(edata区)。单时钟存取,访问速度快</em></p>
<p><img src="data/attachment/forum/202509/30/015009da8fra8l3a4h2aam.png" alt="296363945230468.png" title="296363945230468.png" /></p>
<p>* L251 Misc选项“Misc controls”输入框大写输入“REMOVEUNUSED”(视频内没提到,但最新的数据手册即然提到,应该是有用意。)</p>
<p>* Debug选项卡点选“Use”,下拉框选择“STC Monitor-251 Driver”(可以直接通讯仿真,妈妈再也不用担心我的学习了^v^)</p>
</li>
<li>
<h6>Ai8051U的GPIO工作模式介绍</h6>
<p><img src="data/attachment/forum/202509/30/015038a8k7z131885c5k38.png" alt="350022425865759.png" title="350022425865759.png" /></p>
<p><em>Ai8051U的GPIO工作模式相对于传统8051功能更丰富,传统8051仅支持“开漏模式”和“准双向(弱上拉)”。Ai8051U增加了“推挽输出”和“高阻输入”,</em></p>
<p><em>且Ai8051U每个GPIO都可通过对PxM1和PxM0两个寄存器实现:开漏/准双向/推挽输出/高阻输入 四种模式的配置(传统8051仅支持固定单一模式)</em></p>
</li>
<li>
<h6>Ai8051U核心板(擎天柱)点亮LED</h6>
<pre><code>/*代码一:整个P2端口设置为准双向模式*/
    #include &quot;Ai8051U.h&quot;

    void main(void)
    {
          P2M1 = 0x00; P2M0 = 0x00;//P2端口设置为准双向模式

          while(1)
          {
                  P20 = 0;//点亮P20对应的LED
          }
    }

    /*代码二:仅将P2.0管脚设置为准双向模式*/
    #include &quot;Ai8051U.h&quot;

    void main(void)
    {
          P2M1 = 0xFE; P2M0 = 0xFE;//P2.0管脚设置为准双向模式

          while(1)
          {
                  P20 = 0;//点亮P20对应的LED
          }
    }

    /*代码三:P2端口P20、P21管脚对应LED灯点亮*/
    #include &quot;Ai8051U.h&quot;

    void main(void)
    {
          P2M1 = 0x00; P2M0 = 0x00;//P2端口设置为准双向模式

          while(1)
          {
                  P2 = 0xFC;//P2端口P20、P21对应LED灯点亮
          }
    }

    /*代码四:P2端口对应的所有LED灯点亮*/
    #include &quot;Ai8051U.h&quot;

    void main(void)
    {
          P2M1 = 0xFE; P2M0 = 0xFE;//P2.0管脚设置为准双向模式

          while(1)
          {
                  P2 = 0x00;//点亮P2端口对应的所有LED
          }
    }
</code></pre>
</li>
<li>
<h6>AiCube-ISP的I/O配置工具使用</h6>
<p><img src="data/attachment/forum/202509/30/234442m60kdfmwzhzl6ykk.jpg" alt="317374326269603.jpg" title="317374326269603.jpg" /></p>
<p><em>AiCube-ISP不仅是一个烧录软件,同时还包含了很多的辅助工具,I/O配置工具就是其中之一。如感觉自己手动配置,计算太麻烦,可使用I/O配置工具</em><br />
<em>进行I/O口的模式配置,选择好每个IO管脚需要的工具模式,即可自动生成对应的IO配置代码</em>。</p>
</li>
<li>
<h6>实验学习视频展示:</h6>
</li>
</ol>
<iframe src="https://player.bilibili.com/player.html?isOutside=true&amp;aid=115288918005761&amp;bvid=BV1jfnrz2EMQ&amp;cid=32729466411&amp;p=1&amp;danmaku=0&amp;autoplay=0" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width="75%" height="auto" style="aspect-ratio: 16/9;"></iframe>

yimingamei 发表于 2025-10-2 17:12:13

<h1>第04集、USB不停电下载</h1>
<p>本集看似只是讲了USB不停电下载,其实涉及到了挺多硬件知识,看视频时一直边看边查手册,以下为个人学习心得。</p>
<h5>1、USB不停电下载介绍及所需文件(USB库文件下载)</h5>
<ul>
<li>开发过程中经常需要反复修改代码,重新编译生成HEX。反复的停电/上电进行下载模式就成了一件冗余且繁琐的事。有了USB不停电下</li>
</ul>
<p>载这个功能,可以省去这些冗余且繁琐的事。修改代码后,只需重新编译生成HEX文件,AiCube-ISP就可以自动将最新的代码下载进单片机。</p>
<ul>
<li>USB库文件下载方法:进入STC官网(www.stcai.com)首页-&gt;软件工具,找到“库函数-USB库文件”下载</li>
</ul>
<h5>2、USB库函数详解:USB-CDC库函数和USB-HID库函数区别</h5>
<ul>
<li>USB-CDC:即虚拟串口,基于USB通讯设备类协议。USB-CDC虚拟串口忽略传统串口的波特率和起始位、停止位等冗余信息,传输</li>
</ul>
<p>速度的比特率为全速USB的通讯速度12Mpbs(即每秒12M位,约1.5M/S,有效传输速度一般可达800K/S)。丢弃传统串口简单的软件奇</p>
<p>偶校验机制,有USB硬件CRC校验,以及校验出错重传机制,保证数据100%正确。可自动缓存数据,未处理完上位机上一笔数据,如有</p>
<p>新数据下传,可自动将新数据缓存,以保证数据100%不丢失或被覆盖,适用于大数据量的快速传输项目。</p>
<ul>
<li>USB-HID:基于 USB 人机交互接口协议。所有版本Windows系统中都可免装驱动程序,即插即用。但数据传输速度较低,理论数据</li>
</ul>
<p>带宽仅64K/S,仅适用于小数据量的数据传输项目。</p>
<h5>3、USB库函数详解:不同Lib库文件适用范围</h5>
<ul>
<li>STC USB-CDC库文件</li>
</ul>
<table>
<thead>
<tr>
<th>库文件名</th>
<th>功能说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>stc_usb_cdc_8h_data.LIB</td>
<td>Ai8051U-8系列/STC8H系列Small存储模式USB-CDC库函数</td>
</tr>
<tr>
<td>stc_usb_cdc_8h_data_bl51.LIB</td>
<td>Ai8051U-8系列/STC8H系列Small存储模式,超64K代码USB-CDC库函数</td>
</tr>
<tr>
<td>stc_usb_cdc_8h_xdata.LIB</td>
<td>Ai8051U-8系列/STC8H系列Large存储模式USB-CDC库函数</td>
</tr>
<tr>
<td>stc_usb_cdc_8h_xdata_bl51.LIB</td>
<td>Ai8051U-8系列/STC8H系列Large存储模式,超64K代码USB-CDC库函数</td>
</tr>
<tr>
<td>stc_usb_cdc_32g.LIB</td>
<td>Ai8051U-32系列/STC32G系列64K代码模式USB-CDC库函数</td>
</tr>
<tr>
<td>stc_usb_cdc_32g_huge.LIB</td>
<td>Ai8051U-32系列/STC32G系列Huge代码模式USB-CDC库函数</td>
</tr>
</tbody>
</table>
<ul>
<li>STC USB-HID库文件</li>
</ul>
<table>
<thead>
<tr>
<th>库文件名</th>
<th>功能说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>stc_usb_hid_8h_data.LIB</td>
<td>Ai8051U-8系列/STC8H系列Small存储模式USB-HID库函数</td>
</tr>
<tr>
<td>stc_usb_hid_8h_data_bl51.LIB</td>
<td>Ai8051U-8系列/STC8H系列Small存储模式,超64K代码USB-HID库函数</td>
</tr>
<tr>
<td>stc_usb_hid_8h_xdata.LIB</td>
<td>Ai8051U-8系列/STC8H系列Large存储模式USB-HID库函数</td>
</tr>
<tr>
<td>stc_usb_hid_8h_xdata_bl51.LIB</td>
<td>Ai8051U-8系列/STC8H系列Large存储模式,超64K代码USB-HID库函数</td>
</tr>
<tr>
<td>stc_usb_hid_32g.LIB</td>
<td>Ai8051U-32系列/STC32G系列64K代码模式USB-HID库函数</td>
</tr>
<tr>
<td>stc_usb_hid_32g_huge.LIB</td>
<td>Ai8051U-32系列/STC32G系列Huge代码模式USB-HID库函数</td>
</tr>
</tbody>
</table>
<h5>4、USB库函数详解:query(查询方式)和interrupt(中断方式)区别</h5>
<ul>
<li>query(查询方式):固定的执行间隔,只有一个循环执行完,到达执行语句才会响应。适应于非紧急、大数据量的非实时性传输(如传感器数据、</li>
</ul>
<p>网页数据、文件下载)。</p>
<ul>
<li>interrupt(中断方式):不管代码执行到哪一行,当产生了“中断请求”时会立即响应,主机收到后优先处理该数据。适应于紧急、小数据量、</li>
</ul>
<p>低延迟的实时性传输(如设备错误码、状态切换通知)。</p>
<h5>5、USB库函数详解:头文件</h5>
<ul>
<li>STC USB库文件包含两个头文件“ai_usb.h”和“stc32_stc8_usb.h”。官方手册注解“ai_usb.h”为“Ai8051U系列USB库函数头文件”,</li>
</ul>
<p>“stc32_stc8_usb.h”为“STC8H/STC32G系列USB库函数头文件”。实际比较了下,代码是一致的。</p>
<h5>6、移植USB不停电下载关键部分到工程</h5>
<ul>
<li>添加头文件和lib库文件</li>
</ul>
<p><img src="data/attachment/forum/202510/02/161724njji6jtpt71jr76e.png" alt="129554789299612.png" title="129554789299612.png" /></p>
<p><em>(复制工程需要的头文件和lib库文件到工程项目文件夹内,并调用头文件和将lib文件添加到项目)</em></p>
<p><img src="data/attachment/forum/202510/02/161806gzxfifpi3s3t6sng.jpg" alt="180483652520739.jpg" title="180483652520739.jpg" /></p>
<p><em>((冲哥视频的项目文件下是没有“ai8051u.h”,但为何编译时也不会报错?是因为之前使用AiCube添加过型号和头文件到Keil安装目录下。双引号调用的头</em></p>
<p><em>文件会先在工程目录下查找头文件是否存在,如果工程目录下没有对应的头文件,会继续到Keil的安装目录下查找。如未提前添加过STC的头文件到Keil</em></p>
<p><em>目录下,才会报错。)</em></p>
<ul>
<li>USB函数初始化(lib+.h实现)</li>
</ul>
<pre><code class="language-C">usb_init();//USB-CDC接口配置(USB初始化)
</code></pre>
<ul>
<li>命令参数代码移植</li>
</ul>
<pre><code class="language-C">   char *USER_DEVICEDESC = NULL;
   char *USER_PRODUCTDESC = NULL;
   char *USER_STCISPCMD = &quot;@STCISP#&quot;;
</code></pre>
<p><em>(最新的USB库函数内已包含了用户程序中不需要再对USER_DEVICEDESC,USER_PRODUCTDESC,USER_STCISPCMD进行定义。因此使用新USB库<br />
函数时,用户程序中无需再进行定义。如定义了,需要删除掉。)</em></p>
<ul>
<li>P_SW2寄存器和IE2寄存器使能</li>
</ul>
<pre><code class="language-C">P_SW2 |= 0x80;//使能访问XFR
IE2 |= 0x80;//使能USB中断
EA = 1;//使能中断总开关
</code></pre>
<p><em>a. P_SW2功能脚切换控制寄存器的B7(EAXFR)为“扩展 RAM 区特殊功能寄存器(XFR)访问控制寄存器”,而USB的一些寄存器都在&quot;EAXFR&quot;的列表里(可查看<br />
Ai8051U手册的第13.4章节(扩展特殊功能寄存器列表))。因此需要使能B7位(EAXFR),才可正常访问USB的这些寄存器。为何不直接赋值要使用“|= 0x80”(或=)<br />
呢?如果直接赋值,会改变P_SW2寄存器的其它位状态,因此使用“|= 0x80”只会改变B7的状态(P_SW2支持位寻址,也可以写为 EAXFR = 1)</em></p>
<p><img src="data/attachment/forum/202510/02/163657dmq7s9obpackad9o.jpg" alt="154256815360069.jpg" title="154256815360069.jpg" /></p>
<p><em>b. IE2中断使能寄存器的B7(EUSB)为&quot;USB中断允许位&quot;,因此需要对IE2的B7位进行赋值使能。同样为了不影响IE2的其它位,使用“|= 0x80”对IE2的B7位(EUSB)进<br />
行赋值(IE2也支持位寻址,同样可以写为 EUSB = 1)</em></p>
<p><img src="data/attachment/forum/202510/02/163716x898re8l847mm8m8.jpg" alt="501095345441146.jpg" title="501095345441146.jpg" /></p>
<p><em>c. EA为总中断允许控制位,也就是所有中断的总开关(可查看Ai8051U手册第15.2章节了解)。如果EA未使能,就算中断允许位使能了,也同样无法实现功能。</em></p>
<p><img src="data/attachment/forum/202510/02/163731ae7o1o46kq314844.jpg" alt="442124805024031.jpg" title="442124805024031.jpg" /></p>
<ul>
<li>USB不停电下载代码添加</li>
</ul>
<pre><code class="language-C">if (bUsbOutReady)
{
   USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
   
   usb_OUT_done();
}
</code></pre>
<p><em>(最新USB库函数,不需要等待USB配置完成,在printf_usb和USB_SendData函数中对配置状态和忙标志进行了检测。因些无需添加<br />
&quot;while (DeviceState = DEVSTATE_CONFIGURED);&quot;这段代码。</em></p>
<h5>7、完整工程代码(Ai8051U 擎天柱核心板_版本)</h5>
<pre><code class="language-C">#include &quot;Ai8051U.h&quot;
#include &quot;ai_usb.h&quot;

void main(void)
{
P_SW2 |= 0x80;//使能访问XFR

P2M1 = 0x00; P2M0 = 0x00;//P2端口设置为准双向模式

usb_init();//USB-CDC接口配置(USB初始化)

IE2 |= 0x80;//使能USB中断
EA = 1;//使能中断总开关
while(1)
{
    if (bUsbOutReady)
    {
      USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)

      usb_OUT_done();
    }
    P20 = 0;//点亮P20对应的LED
    //P22 = 0;//点亮P22对应的LED
}
}
</code></pre>
<h5>8、学习USB不停电下载_实验视频</h5>
<iframe src="https://player.bilibili.com/player.html?isOutside=true&amp;aid=115303530896954&amp;bvid=BV1EDHwzkEbu&amp;cid=32790022106&amp;p=1&amp;danmaku=0&amp;autoplay=0" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width="75%" height="auto" style="aspect-ratio: 16/9;"></iframe>
<h5>9、补充内容:&quot;WARNING L57&quot;警告问题</h5>
<ul>
<li>
<p>代码在进行编译时,Build Output窗口会提示&quot;WARNING L57&quot;的警告,是因为USB库函数内有许多函数在项目内未使用到。有两种方法可解决:<br />
a. 如冲哥视频在&quot;Options for Target...&quot;-&gt;&quot;L251 Misc&quot;选项卡,“disable Warning Numbers”输入框内输入“57”</p>
<p><img src="data/attachment/forum/202510/04/182919rx0mmumx4muur0zm.png" alt="205862527331536.png" title="205862527331536.png" /></p>
</li>
<li>
<p>在&quot;Options for Target...&quot;-&gt;&quot;L251 Misc&quot;选项卡,“Misc controls”输入框大写输入“REMOVEUNUSED”</p>
<p><img src="data/attachment/forum/202510/04/182939ndqcmtqtcxsjvx4d.png" alt="82555998348612.png" title="82555998348612.png" /></p>
</li>
</ul>

yimingamei 发表于 前天 15:51

<h1>第05集、C语言基础</h1>
<h4>1、C语言 USB-CDC 串口之printf函数的实现</h4>
<ul>
<li>
<p>冲哥讲解中直接复制的上一次项目,这样省去了很多配置的时间。但个人觉得作为一个新手或初次使用32位8051的学习者,自己新建配置工程,配置项目<br />
能更好的熟悉流程。达到一定熟练度和理解了,再化繁为简。以免因为对流程的不熟悉,项目未配置好或需要的库文件未完整添加,导致出现各种各样的编<br />
译问题(纯个人观点,不喜勿喷!)。</p>
</li>
<li>
<p>启用USB库文件中的 <code>PRINTF_HID</code>宏定义,打开 <code>PRINTF_HID</code>的功能(去掉前面的“//”)。</p>
<p><img src="data/attachment/forum/202510/14/154620a47w01cjz4indp0z.jpg" alt="577863018972135.jpg" title="577863018972135.jpg" /></p>
</li>
<li>
<p>理解PRINTF函数原型定义,<code>#define</code>的作用<br />
<em>a. 最新USB库函数和冲哥视频讲解有所区别,<code>printf</code>指向的非 <code>pintf_hid</code>,而是 <code>printf_usb</code>。即 <code>int printf_usb (const char *fmt, ...);</code>函数。</em><br />
<em>b. <code>printf</code>是替换名,在整个项目中“printf”实现的是 <code>printf</code>函数的功能。</em><br />
<em>c. <code>#define</code>是一个宏定义命令,它用来将一个标识符定义为一个字符串。在这里 <code>#define printf printf_usb</code> 中 <code>printf</code>是“替换名”,<code>printf_usb</code><br />
是“被替换名”。项目中出现 <code>Printf</code>的地方都会调用 <code>printf_usb</code>函数。</em></p>
</li>
<li>
<p>printf_usb函数的参数讲解<br />
<em>a. 参数fmr:格式控制字符串,包含了两种类型的对象,分别是“普通字符”和“转换说明”。</em><br />
<em>b. 普通字符:在输出时,普通字符会原封不动的复制到标准输出(即打的是什么,输出的就是什么)。如:<code>printf(&quot;Hello STC!/r/n&quot;);</code>输出就是“Hello STC!”</em><br />
<em>c. 转换说明:不直接输出字符,用于控制printf中参数的转换和打印。第个转换说明都由一个百分号(%)开始,以转换字符结束。用以说明输出数据的类型、宽<br />
度、精度等。如 <code>printf(&quot;Hello STC,%s !\r\n&quot;,&quot;YYDS&quot;);</code>输出就是“Hello STC,YYDS! ”</em></p>
</li>
<li>
<p>USB-CDC串口的优势:普通串口需要特定的波特率才可通讯,而USB-CDC串口任意的波特率都可以工作,它本质上是USB在通信。</p>
</li>
<li>
<p>fmr的“转换说明”详解<br />
<em>a. 类型:函数可能需要一系列的附加参数,每个参数包含一个要被插入的值,附加参数即可是变量,也可以是常量。fmt的转换说明根据不同的格式字符,插入<br />
不同类型的值。如上面提到的 <code>%s</code>代表“以字符串输出”,如换成 <code>%d</code>代表“以十进制整形输出”。(常用的格式字符如下图)</em></p>
<p><img src="data/attachment/forum/202510/14/154830lntg7rdlng7iy4tx.jpg" alt="180518213791598.jpg" title="180518213791598.jpg" /><br />
<em>b. 位置:普通字符和转换说明都必须放在双引号(&quot;&quot;)内。附加参数放在双引号外,且用逗号( , )隔开。如附加参数是字符串,需要使用在双引号(“”)内。</em><br />
<em>c. 数量: 附加参数和转换说明符是一 一对应,如是n个转换说明符,应该是n+1个参数(1为普通字符,也是一个参数)。如参数缺少一个对应转换说明符,printf函<br />
数可能会输出内存中的任意值。</em></p>
</li>
<li>
<p>USB-CDC串口之printf函数实验代码(注意:<code>USB_SendData(UsbOutBuffer,OutNumber);</code>为原路返回,用于测试,无需此函数,用“//”注释掉)</p>
</li>
</ul>
<pre><code>/*实验代码一:输出“Hello STC!”*/
#include &quot;Ai8051U.h&quot;
#include &quot;ai_usb.h&quot;

void main(void)
{
P_SW2 |= 0x80;//使能访问XFR

P2M1 = 0x00; P2M0 = 0x00;//P2端口设置为准双向模式

usb_init();//USB-CDC接口配置(USB初始化)

IE2 |= 0x80;//使能USB中断
EA = 1;//使能中断总开关
while(1)
{
        if (bUsbOutReady)
        {
                        //USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
                        printf(&quot;Hello STC!\r\n&quot;);
                        usb_OUT_done();
        }
}
}

/*实验代码二:输出“Hello STC,YYDS !”*/
#include &quot;Ai8051U.h&quot;
#include &quot;ai_usb.h&quot;

void main(void)
{
P_SW2 |= 0x80;//使能访问XFR

P2M1 = 0x00; P2M0 = 0x00;//P2端口设置为准双向模式

usb_init();//USB-CDC接口配置(USB初始化)

IE2 |= 0x80;//使能USB中断
EA = 1;//使能中断总开关
while(1)
{
        if (bUsbOutReady)
        {
                        //USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
                        printf(&quot;Hello STC,%s !\r\n&quot;,&quot;YYDS&quot;);
                        usb_OUT_done();
        }
}
}
</code></pre>
<h4>2、进位计数制:2进制、10进制、16进制,已有基础,跟着重新复习了下。</h4>
<p><img src="data/attachment/forum/202510/14/154918ltqsp92a2qycaalt.jpg" alt="517618943613193.jpg" title="517618943613193.jpg" /></p>
<h4>3、数据的基本类型</h4>
<p><img src="data/attachment/forum/202510/14/154941ntf2gkgargg1g1rg.jpg" alt="179864324930610.jpg" title="179864324930610.jpg" /><br />
<em>(注:如要使用64位数据类型“double”,程序文件中需要添加 <code>#pragma float64</code>)</em></p>
<h4>4、C语言常用运算符,学习过,温习下。</h4>
<p><img src="data/attachment/forum/202510/14/154957y414raweafccez9f.jpg" alt="562927151702072.jpg" title="562927151702072.jpg" /></p>
<p><img src="data/attachment/forum/202510/14/155010th50hdkb44xn3kbh.jpg" alt="77817004381517.jpg" title="77817004381517.jpg" /></p>
页: [1]
查看完整版本: 擎天柱学习纪实:《32位8051单片机Ai8051U深度入门》