MagicBude 发表于 2025-1-25 20:01:55

8051U学习打卡+笔记

<h1>一、序言——8051U 强在哪里</h1>
<h2>(一)功能优势</h2>
<ol>
<li><strong>屏幕显示和视频播放(flash 编程器)</strong>:具备强大的屏幕显示与视频播放功能,依托于 flash 编程器实现高效稳定的运行。</li>
<li><strong>IlS 录放音</strong>:支持 IlS 录放音功能,满足多种音频处理需求。</li>
<li><strong>PWM DMA</strong>:PWM 与 DMA 协同工作,优化系统性能。</li>
<li><strong>频谱分析仪(上位机)</strong>:配备频谱分析仪,通过上位机实现对信号的精准分析。</li>
<li><strong>手写计算器</strong>:具备手写计算器功能,方便快捷进行数据运算。</li>
<li><strong>QSPI,PWM 移相,硬件乘除,单精度浮点</strong>:支持 QSPI 接口,具备 PWM 移相功能,拥有硬件乘除及单精度浮点运算能力,提升数据处理速度和精度。</li>
</ol>
<h2>(二)产品简介</h2>
<p><strong>Ai8051U 属于 USB 型 1T 8051,支持 32 位和 8 位指令集,价格仅为 RMB2.3。其管脚兼容天王级别的 89C52RC 和 12C5A60S2。</strong></p>
<ul>
<li><strong>8 位 8051 指令集兼容</strong>:如需兼容 8 位 8051 指令集,可使用 Keil C51/IAR/SDCC 编译器,性能相当于更强大的 8H8K64U。</li>
<li><strong>32 位 8051 指令集兼容</strong>:若要兼容 32 位 8051 指令集,可采用 Keil C251 编译器,采用双核兼容设计,性能相当于更强大的 32G12K128 和 32G8K64。</li>
</ul>
<p><strong>Ai8051U 还拥有以下硬件配置:</strong></p>
<ul>
<li><strong>存储资源</strong>:34K SRAM(2K edata,32K xdata),64K Flash。</li>
<li><strong>运算单元</strong>:TFPU@120MHz,配备硬件浮点 / 硬件三角函数运算器。</li>
<li><strong>DMA 功能</strong>:DMA 支持 PWM,且支持外设直接到外设(P2P)的数据传输。</li>
<li><strong>PWM 与 ADC</strong>:120MHz - PWM 支持硬件移相,为 16 位 PWM,配备真 12 位 ADC。</li>
<li><strong>接口资源</strong>:具备 USB、4 组串口、12 位 ADC、轨到轨比较器,以及 QSPI、SPI、I2S、I2C、TFT - i8080/M6800 接口。</li>
<li><strong>封装形式</strong>:提供 PDIP40、LQFP44、LQFP48 多种封装形式。</li>
</ul>

MagicBude 发表于 2025-1-25 20:59:24

<h1>二、硬件及工具介绍</h1>
<h2>(一)硬件介绍</h2>
<p><img src="data/attachment/forum/202501/25/210422tr0u515jm8m8g5ru.png" alt="image-20250125201613443" /></p>
<p><img src="data/attachment/forum/202501/25/210422uhzpz5j5z3l3vjlm.png" alt="image-20250125201627349" /></p>
<h2>(二)软件和工具</h2>
<ol>
<li><strong>安装 KEIL 编程软件</strong></li>
</ol>
<p><img src="data/attachment/forum/202501/25/210420wkggxgrd35gng3nh.png" alt="image-20250125202958393" /></p>
<ol start="2">
<li><strong>下载 ISP 软件</strong></li>
</ol>
<p><img src="data/attachment/forum/202501/25/210420eagfea9eova9iez1.png" alt="image-20250125203036829" /></p>
<ol start="3">
<li><strong>添加头文件</strong></li>
</ol>
<p><img src="data/attachment/forum/202501/25/210420b47o7snxqfwowgj4.png" alt="image-20250125203949494" /></p>
<ol start="4">
<li><strong>下载插件</strong></li>
</ol>
<p><img src="data/attachment/forum/202501/25/210420zmtqeodpdfoo6cce.png" alt="image-20250125203112285" /></p>
<ol start="5">
<li><strong>下载代码包和手册</strong></li>
</ol>
<p><img src="data/attachment/forum/202501/25/210424gkjbjiijixk3248k.png" alt="image-20250125203020028" /></p>
<h2>(三)下载第一个程序</h2>
<ol>
<li><strong>单片机型号选择 “AI8051U-34K64”。</strong></li>
<li><strong>实验箱使用硬件 USB 接口下载。具体操作步骤如下:</strong></li>
</ol>
<ul>
<li><strong>先按住实验箱上的 P3.2/INTO 按键(P32 接地)。</strong></li>
<li><strong>然后按一下 ON/OFF 电源按键进行断电操作。</strong></li>
<li><strong>接着松开 ON/OFF 电源按键完成上电操作。</strong></li>
<li><strong>最后松开 P3.2/INT0 按键。正常情况下就能识别出 “(HID1) USB Writer” 设备。</strong></li>
<li><strong>点击界面中的 “打开程序文件” 按钮,在出现的打开程序代码文件的对话框中选择需要下载的文件。</strong></li>
</ul>
<p><strong>注意事项</strong>:下载的时候一定要记得选对 IRC 时钟频率,可在代码中查看。</p>

MagicBude 发表于 2025-1-25 22:38:17

<h1>三、点亮第一颗 LED</h1>
<h2>(一)新建工程</h2>
<ol>
<li><strong>创建空工程</strong>:参考手册 6.5 章节进行操作。</li>
<li><strong>添加头文件</strong>:利用 ISP 软件,结合手册 6.4 章节完成添加。</li>
<li><strong>输入代码并编译</strong></li>
</ol>
<pre><code class="language-c">#include &quot;AI8051U.h&quot;            //调用头文件
void main(void)
{
    while(1)
    {
   
    }
}
</code></pre>
<h3>拓展知识:C 语言中 include 用法</h3>
<p>#include 命令是预处理命令的一种,其作用是将别的源代码内容插入到所指定的位置。有两种指定插入头文件的方式:</p>
<ul>
<li><code>#include&lt;文件名.h&gt;</code>:编译器会到系统路径下查找头文件。</li>
<li><code>#include&quot;文件名.h&quot;</code>:编译器首先在当前目录下查找头文件,如果没有找到,再到系统路径下查找。</li>
</ul>
<p><strong>推荐使用</strong> <code>#include&quot;文件名.h&quot;</code>的方式,并把所有用到的文件放到自己的文件夹里,这样将工程发给别人时不容易出现问题。</p>
<h2>(二)点亮第一个 LED</h2>
<ol>
<li><strong>实验箱代码及操作</strong></li>
</ol>
<p>输入以下代码,下载到板子上查看效果。</p>
<pre><code class="language-c">#include &quot;AI8051U.h&quot;            //调用头文件
void main(void)
{
    P0M1 = 0x00;   P0M0 = 0x00; //P0端口(P00-P07为准双向口)
    P4M1 = 0x00;   P4M0 = 0x00; //P4端口(P40-P47为准双向口)

    while(1)
    {
      P40 = 0;                //P40端口输出0V
      P00 = 0;                //P40端口输出0V
    }
}
</code></pre>
<ol start="2">
<li><strong>核心板代码</strong></li>
</ol>
<p>如果是核心板,使用以下代码。</p>
<pre><code class="language-c">#include &quot;AI8051U.h&quot;            //调用头文件
void main(void)
{
    P2M1 = 0x00;   P2M0 = 0x00;//P2端口(P20-P27为准双向口)

    while(1)
    {
      P20 = 0;                //P20端口输出0V
    }
}
</code></pre>
<h2>(三)硬件介绍</h2>
<p><img src="data/attachment/forum/202501/25/223247r6gyrqyibqlly7lq.png" alt="image-20250125222429973" /></p>
<p><img src="data/attachment/forum/202501/25/223246yyiggnqceq7zciyi.png" alt="image-20250125222512370" /></p>
<h2>(四)为什么能点亮 LED</h2>
<p><img src="data/attachment/forum/202501/25/223246drvr3vikt1yrytf8.png" alt="image-20250125222753868" /></p>
<p><img src="data/attachment/forum/202501/25/223246dl59docq9kuvvbkc.png" alt="image-20250125222913503" /></p>
<p><img src="data/attachment/forum/202501/25/223246smib5pb11bzmfdmb.png" alt="image-20250125223047190" /></p>

MagicBude 发表于 2025-1-26 00:30:56

<h1>四、USB 不停电下载</h1>
<h2>1. 下载所需文件</h2>
<p><strong>从 STC 官网(</strong><a href="https://stcai.com/">stcai.com</a> - 软件工具 - 库函数 - USB 库文件)获取所需文件。</p>
<p><strong>图片展示:</strong></p>
<p><img src="data/attachment/forum/202501/26/003014pqezyy4pvavyz1z1.png" alt="image" /></p>
<p><img src="data/attachment/forum/202501/26/003013r362226n2z26g22j.png" alt="image" /></p>
<h3>知识拓展</h3>
<ul>
<li><strong>查询模式(轮询方式)</strong>:CPU 通过不断地查询设备的状态寄存器或相关标志位,来判断设备是否准备好进行数据传输或操作。</li>
<li><strong>中断模式</strong>:当设备完成特定操作或发生特定事件时,会主动向 CPU 发送一个中断请求信号。CPU 在接收到中断请求后,会暂停当前正在执行的程序,转去执行相应的中断服务程序来处理该事件,处理完成后再返回原来的程序继续执行。为了让代码最稳定高效地运行,一般选择<strong>查询模式</strong>。</li>
<li><strong>CDC 模式(通信设备类模式)</strong>:即 Communication Device Class 模式,是 USB 协议中用于通信设备的一类标准模式。主要用于模拟串口通信等数据传输方式,让 USB 设备能够像传统串口设备一样与主机进行数据交互。</li>
<li><strong>HID 模式(人机接口设备模式)</strong>:即 Human Interface Device 模式,是用于人机交互设备的一种 USB 设备模式,定义了一套人机接口协议,用于规范设备与主机之间的交互方式。在两者之中,推荐使用<strong>CDC 模式</strong>。</li>
</ul>
<p><strong>图片展示:</strong></p>
<p><img src="data/attachment/forum/202501/26/003013rqq9qr1yzdbjcbjq.png" alt="image" /></p>
<h3>操作步骤</h3>
<p><strong>将</strong> <code>stc_usb_adc_32.LIB</code>和 <code>stc_stc8_usb.h</code>两个文件复制到自己的工程目录下。</p>
<p><strong>图片展示:</strong></p>
<p><img src="data/attachment/forum/202501/26/003014ms8heh16854h6llz.png" alt="image" /></p>
<p><img src="data/attachment/forum/202501/26/003012dldrorjopxesxqni.png" alt="image" /></p>
<h3>LIB 文件说明</h3>
<p><strong>LIB 文件是一种库文件,库的开发者可以将代码的具体实现隐藏在 LIB 文件中,只向外部提供函数接口等,防止代码被篡改。将常用的代码封装在 LIB 文件中,多个项目可以共享这些代码,提高了开发效率,避免了重复开发。</strong></p>
<h2>2. 移植关键部分到工程</h2>
<h3>2.1 添加头文件</h3>
<pre><code class="language-c">#include &quot;stc32_stc8_usb.h&quot;
</code></pre>
<h3>2.2 USB 初始化函数(tib+.h 库实现)</h3>
<pre><code class="language-c">usb_init();
</code></pre>
<h3>2.3 命令参数</h3>
<p><img src="data/attachment/forum/202501/26/003013c76cucjezu6jdijz.png" alt="image" /></p>
<p><img src="data/attachment/forum/202501/26/003019jss1fl8rwunnnsnz.png" alt="image" /></p>
<p><img src="data/attachment/forum/202501/26/003019oppom9jnxgixossi.png" alt="image" /></p>
<h3>2.4 打开 P_SW2 寄存器和 IE2 寄存器(只打开一个位)</h3>
<pre><code class="language-c">P_SW2 |= 0x80;      //B7位写1,使能访问XFR
IE2 |= 0x80;           //使能USB中断
</code></pre>
<h3>整体代码</h3>
<pre><code class="language-c">#include &quot;AI8051U.h&quot;            //调用头文件
#include &quot;stc32_stc8_usb.h&quot;

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;

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();
     }
 }
}
</code></pre>

神农鼎 发表于 2025-1-26 10:07:19

认真学习的

MagicBude 发表于 2025-1-26 12:55:11

<h1>五、C 语言基础</h1>
<h2>1. C 语言 USB - CDC 串口之 printf 函数的实现</h2>
<h3>1.1 打开 USB 库中的 PRINTF.HID 宏定义 (去掉 <code>//</code>)</h3>
<pre><code>#define PRINTF_HID            //printf输出直接重定向到USB口(早期命名方式)
</code></pre>
<h3>1.2 理解 PRINTF 的函数原型的定义</h3>
<pre><code>#define printf printf_hid
int printf_hid (const char *fmt, ...);
</code></pre>
<h3>1.3 参数 <code>fmt</code>说明</h3>
<p><strong>参数</strong> <code>fmt</code>是格式控制字符串,包含了两种类型的对象:普通字符和转换说明。</p>
<ul>
<li><strong>普通字符</strong>:在输出时,普通字符将原样不动地复制到标准输出。<br />
<strong>示例:</strong>
<pre><code>printf(&quot;8051U深度入门到32位51大型实战视频\r\n&quot;);
</code></pre>
</li>
<li><strong>转换说明</strong>:不直接输出,用于控制 <code>printf</code>中参数的转换和打印。每个转换说明都由一个百分号字符(<code>%</code>)开始,以转换说明符结束,从而说明输出数据的类型、宽度、精度等。<br />
<strong>示例:</strong>
<pre><code>printf(&quot;8051U深度入门到32位51大型实战视频,%s\r\n&quot;, &quot;加油&quot;);
</code></pre>
</li>
</ul>
<h3>1.4 转换说明简介</h3>
<ol>
<li><strong>类型</strong>:根据不同的 <code>fmt</code>字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 <code>fmt</code>参数中指定的每个 <code>%</code>标签。关于附加参数,既可以是变量,也可以是常量。</li>
<li><strong>位置</strong>:<code>printf()</code>函数的普通字符和转换说明放在 <code>&quot;&quot;</code>双引号内,附加参数放在双引号外,每个附加参数之间用逗号隔开。</li>
<li><strong>数量</strong>:<code>printf()</code>的附加参数与转换说明符是一一对应关系,如果有 <code>n</code>个转换说明符,<code>printf()</code>的参数就应该有 <code>n + 1</code>个。如果参数个数少于对应的转换说明符,<code>printf()</code>可能会输出内存中的任意值。</li>
</ol>
<h3>1.5 标志</h3>
<table>
<thead>
<tr>
<th><strong>标志</strong></th>
<th><strong>含义</strong></th>
<th><strong>实例</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>n,m</strong></td>
<td><strong>n 表示整数占几行,m 表示小数占几行</strong></td>
<td><strong>%2.3f</strong></td>
</tr>
<tr>
<td><strong>-</strong></td>
<td><strong>输出的结果左对齐</strong></td>
<td><strong>%-d</strong></td>
</tr>
<tr>
<td><strong>空格</strong></td>
<td><strong>输出值为正时冠以空格,为负时冠以负号</strong></td>
<td></td>
</tr>
<tr>
<td><strong>#</strong></td>
<td><strong>输出带有前导的数据(八进制为 0---,十六进制为 X---,- 代表数字)</strong></td>
<td><strong>%#d</strong></td>
</tr>
</tbody>
</table>
<h3>1.6 格式字符</h3>
<table>
<thead>
<tr>
<th><strong>格式字符</strong></th>
<th><strong>含义</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>%d</strong></td>
<td><strong>以十进制整数形式输出</strong></td>
</tr>
<tr>
<td><strong>%ld</strong></td>
<td><strong>以十进制长整形输出</strong></td>
</tr>
<tr>
<td><strong>%f</strong></td>
<td><strong>以单精度浮点型输出</strong></td>
</tr>
<tr>
<td><strong>%lf</strong></td>
<td><strong>以双精度浮点型输出</strong></td>
</tr>
<tr>
<td><strong>%o</strong></td>
<td><strong>以八进制整型输出整数</strong></td>
</tr>
<tr>
<td><strong>% x 或 % X</strong></td>
<td><strong>以十六进制形式输出整数</strong></td>
</tr>
<tr>
<td><strong>%u</strong></td>
<td><strong>以十进制无符号整形输出</strong></td>
</tr>
<tr>
<td><strong>%i</strong></td>
<td><strong>以十进制整形输出(与 % d 无异)</strong></td>
</tr>
<tr>
<td><strong>%c</strong></td>
<td><strong>输出单个字符</strong></td>
</tr>
<tr>
<td><strong>%s</strong></td>
<td><strong>输出字符串</strong></td>
</tr>
<tr>
<td><strong>% e 或 % E</strong></td>
<td><strong>以指数形式输出</strong></td>
</tr>
<tr>
<td><strong>% g 或 % G</strong></td>
<td><strong>自适应数据输出(数据够大或够小则以指数形式输出,否则以小数形式输出)</strong></td>
</tr>
<tr>
<td><strong>%p</strong></td>
<td><strong>输出地址</strong></td>
</tr>
</tbody>
</table>
<h3>1.7 转义字符</h3>
<table>
<thead>
<tr>
<th><strong>转义字符</strong></th>
<th><strong>释义</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>?</strong></td>
<td><strong>在书写连续多个问号时使用,防止它们被解析成三字字词</strong></td>
</tr>
<tr>
<td><strong>'</strong></td>
<td><strong>用于表示字符常量</strong></td>
</tr>
<tr>
<td><strong>&quot;</strong></td>
<td><strong>用于表示一个字符串内部的双引号</strong></td>
</tr>
<tr>
<td><strong>\</strong></td>
<td><strong>用于表示一个反斜杠,防止它被解释为一个转义序列符</strong></td>
</tr>
<tr>
<td><strong>\a</strong></td>
<td><strong>警告字符,蜂鸣</strong></td>
</tr>
<tr>
<td><strong>\b</strong></td>
<td><strong>退格符</strong></td>
</tr>
<tr>
<td><strong>\f</strong></td>
<td><strong>换页符</strong></td>
</tr>
<tr>
<td><strong>\n</strong></td>
<td><strong>换行符</strong></td>
</tr>
<tr>
<td><strong>\r</strong></td>
<td><strong>回车</strong></td>
</tr>
<tr>
<td><strong>\t</strong></td>
<td><strong>水平制表符 (8 个空格)</strong></td>
</tr>
<tr>
<td><strong>\v</strong></td>
<td><strong>垂直制表符</strong></td>
</tr>
<tr>
<td><strong>\ddd</strong></td>
<td><strong>ddd 表示 1 - 3 个八进制的数字。如:\120</strong></td>
</tr>
<tr>
<td><strong>\xdd</strong></td>
<td><strong>dd 表示 2 个十六进制数字,如:\x30</strong></td>
</tr>
</tbody>
</table>
<h3>1.8. ASCII 可显示字符(共 95 个)</h3>
<table>
<thead>
<tr>
<th><strong>二进制</strong></th>
<th><strong>十进制</strong></th>
<th><strong>十六进制</strong></th>
<th><strong>图形</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>0010 0000</strong></td>
<td><strong>32</strong></td>
<td><strong>20</strong></td>
<td><strong>(space)</strong></td>
</tr>
<tr>
<td><strong>0010 0001</strong></td>
<td><strong>33</strong></td>
<td><strong>21</strong></td>
<td><strong>!</strong></td>
</tr>
<tr>
<td><strong>0010 0010</strong></td>
<td><strong>34</strong></td>
<td><strong>22</strong></td>
<td><strong>&quot;</strong></td>
</tr>
<tr>
<td><strong>0010 0011</strong></td>
<td><strong>35</strong></td>
<td><strong>23</strong></td>
<td><strong>#</strong></td>
</tr>
<tr>
<td><strong>0010 0100</strong></td>
<td><strong>36</strong></td>
<td><strong>24</strong></td>
<td><strong>$</strong></td>
</tr>
<tr>
<td><strong>0010 0101</strong></td>
<td><strong>37</strong></td>
<td><strong>25</strong></td>
<td><strong>%</strong></td>
</tr>
<tr>
<td><strong>0010 0110</strong></td>
<td><strong>38</strong></td>
<td><strong>26</strong></td>
<td><strong>&amp;</strong></td>
</tr>
<tr>
<td><strong>0010 0111</strong></td>
<td><strong>39</strong></td>
<td><strong>27</strong></td>
<td><strong>'</strong></td>
</tr>
<tr>
<td><strong>0010 1000</strong></td>
<td><strong>40</strong></td>
<td><strong>28</strong></td>
<td><strong>(</strong></td>
</tr>
<tr>
<td><strong>0010 1001</strong></td>
<td><strong>41</strong></td>
<td><strong>29</strong></td>
<td><strong>)</strong></td>
</tr>
<tr>
<td><strong>0010 1010</strong></td>
<td><strong>42</strong></td>
<td><strong>2A</strong></td>
<td><strong>*</strong></td>
</tr>
<tr>
<td><strong>0010 1011</strong></td>
<td><strong>43</strong></td>
<td><strong>2B</strong></td>
<td><strong>+</strong></td>
</tr>
<tr>
<td><strong>0010 1100</strong></td>
<td><strong>44</strong></td>
<td><strong>2C</strong></td>
<td><strong>,</strong></td>
</tr>
<tr>
<td><strong>0010 1101</strong></td>
<td><strong>45</strong></td>
<td><strong>2D</strong></td>
<td><strong>-</strong></td>
</tr>
<tr>
<td><strong>0010 1110</strong></td>
<td><strong>46</strong></td>
<td><strong>2E</strong></td>
<td><strong>.</strong></td>
</tr>
<tr>
<td><strong>0010 1111</strong></td>
<td><strong>47</strong></td>
<td><strong>2F</strong></td>
<td><strong>/</strong></td>
</tr>
<tr>
<td><strong>0011 0000</strong></td>
<td><strong>48</strong></td>
<td><strong>30</strong></td>
<td><strong>0</strong></td>
</tr>
<tr>
<td><strong>0011 0001</strong></td>
<td><strong>49</strong></td>
<td><strong>31</strong></td>
<td><strong>1</strong></td>
</tr>
<tr>
<td><strong>0011 0010</strong></td>
<td><strong>50</strong></td>
<td><strong>32</strong></td>
<td><strong>2</strong></td>
</tr>
<tr>
<td><strong>0011 0011</strong></td>
<td><strong>51</strong></td>
<td><strong>33</strong></td>
<td><strong>3</strong></td>
</tr>
<tr>
<td><strong>0011 0100</strong></td>
<td><strong>52</strong></td>
<td><strong>34</strong></td>
<td><strong>4</strong></td>
</tr>
<tr>
<td><strong>0011 0101</strong></td>
<td><strong>53</strong></td>
<td><strong>35</strong></td>
<td><strong>5</strong></td>
</tr>
<tr>
<td><strong>0011 0110</strong></td>
<td><strong>54</strong></td>
<td><strong>36</strong></td>
<td><strong>6</strong></td>
</tr>
<tr>
<td><strong>0011 0111</strong></td>
<td><strong>55</strong></td>
<td><strong>37</strong></td>
<td><strong>7</strong></td>
</tr>
<tr>
<td><strong>0011 1000</strong></td>
<td><strong>56</strong></td>
<td><strong>38</strong></td>
<td><strong>8</strong></td>
</tr>
<tr>
<td><strong>0011 1001</strong></td>
<td><strong>57</strong></td>
<td><strong>39</strong></td>
<td><strong>9</strong></td>
</tr>
<tr>
<td><strong>0011 1010</strong></td>
<td><strong>58</strong></td>
<td><strong>3A</strong></td>
<td><strong>:</strong></td>
</tr>
<tr>
<td><strong>0011 1011</strong></td>
<td><strong>59</strong></td>
<td><strong>3B</strong></td>
<td><strong>;</strong></td>
</tr>
<tr>
<td><strong>0011 1100</strong></td>
<td><strong>60</strong></td>
<td><strong>3C</strong></td>
<td><strong>&lt;</strong></td>
</tr>
<tr>
<td><strong>0011 1101</strong></td>
<td><strong>61</strong></td>
<td><strong>3D</strong></td>
<td><strong>=</strong></td>
</tr>
<tr>
<td><strong>0011 1110</strong></td>
<td><strong>62</strong></td>
<td><strong>3E</strong></td>
<td><strong>&gt;</strong></td>
</tr>
<tr>
<td><strong>0011 1111</strong></td>
<td><strong>63</strong></td>
<td><strong>3F</strong></td>
<td><strong>?</strong></td>
</tr>
<tr>
<td><strong>0100 0000</strong></td>
<td><strong>64</strong></td>
<td><strong>40</strong></td>
<td><strong>@</strong></td>
</tr>
<tr>
<td><strong>0100 0001</strong></td>
<td><strong>65</strong></td>
<td><strong>41</strong></td>
<td><strong>A</strong></td>
</tr>
<tr>
<td><strong>0100 0010</strong></td>
<td><strong>66</strong></td>
<td><strong>42</strong></td>
<td><strong>B</strong></td>
</tr>
<tr>
<td><strong>0100 0011</strong></td>
<td><strong>67</strong></td>
<td><strong>43</strong></td>
<td><strong>C</strong></td>
</tr>
<tr>
<td><strong>0100 0100</strong></td>
<td><strong>68</strong></td>
<td><strong>44</strong></td>
<td><strong>D</strong></td>
</tr>
<tr>
<td><strong>0100 0101</strong></td>
<td><strong>69</strong></td>
<td><strong>45</strong></td>
<td><strong>E</strong></td>
</tr>
<tr>
<td><strong>0100 0110</strong></td>
<td><strong>70</strong></td>
<td><strong>46</strong></td>
<td><strong>F</strong></td>
</tr>
<tr>
<td><strong>0100 0111</strong></td>
<td><strong>71</strong></td>
<td><strong>47</strong></td>
<td><strong>G</strong></td>
</tr>
<tr>
<td><strong>0100 1000</strong></td>
<td><strong>72</strong></td>
<td><strong>48</strong></td>
<td><strong>H</strong></td>
</tr>
<tr>
<td><strong>0100 1001</strong></td>
<td><strong>73</strong></td>
<td><strong>49</strong></td>
<td><strong>I</strong></td>
</tr>
<tr>
<td><strong>0100 1010</strong></td>
<td><strong>74</strong></td>
<td><strong>4A</strong></td>
<td><strong>J</strong></td>
</tr>
<tr>
<td><strong>0100 1011</strong></td>
<td><strong>75</strong></td>
<td><strong>4B</strong></td>
<td><strong>K</strong></td>
</tr>
<tr>
<td><strong>0100 1100</strong></td>
<td><strong>76</strong></td>
<td><strong>4C</strong></td>
<td><strong>L</strong></td>
</tr>
<tr>
<td><strong>0100 1101</strong></td>
<td><strong>77</strong></td>
<td><strong>4D</strong></td>
<td><strong>M</strong></td>
</tr>
<tr>
<td><strong>0100 1110</strong></td>
<td><strong>78</strong></td>
<td><strong>4E</strong></td>
<td><strong>N</strong></td>
</tr>
<tr>
<td><strong>0100 1111</strong></td>
<td><strong>79</strong></td>
<td><strong>4F</strong></td>
<td><strong>O</strong></td>
</tr>
<tr>
<td><strong>0101 0000</strong></td>
<td><strong>80</strong></td>
<td><strong>50</strong></td>
<td><strong>P</strong></td>
</tr>
<tr>
<td><strong>0101 0001</strong></td>
<td><strong>81</strong></td>
<td><strong>51</strong></td>
<td><strong>Q</strong></td>
</tr>
<tr>
<td><strong>0101 0010</strong></td>
<td><strong>82</strong></td>
<td><strong>52</strong></td>
<td><strong>R</strong></td>
</tr>
<tr>
<td><strong>0101 0011</strong></td>
<td><strong>83</strong></td>
<td><strong>53</strong></td>
<td><strong>S</strong></td>
</tr>
<tr>
<td><strong>0101 0100</strong></td>
<td><strong>84</strong></td>
<td><strong>54</strong></td>
<td><strong>T</strong></td>
</tr>
<tr>
<td><strong>0101 0101</strong></td>
<td><strong>85</strong></td>
<td><strong>55</strong></td>
<td><strong>U</strong></td>
</tr>
<tr>
<td><strong>0101 0110</strong></td>
<td><strong>86</strong></td>
<td><strong>56</strong></td>
<td><strong>V</strong></td>
</tr>
<tr>
<td><strong>0101 0111</strong></td>
<td><strong>87</strong></td>
<td><strong>57</strong></td>
<td><strong>W</strong></td>
</tr>
<tr>
<td><strong>0101 1000</strong></td>
<td><strong>88</strong></td>
<td><strong>58</strong></td>
<td><strong>X</strong></td>
</tr>
<tr>
<td><strong>0101 1001</strong></td>
<td><strong>89</strong></td>
<td><strong>59</strong></td>
<td><strong>Y</strong></td>
</tr>
<tr>
<td><strong>0101 1010</strong></td>
<td><strong>90</strong></td>
<td><strong>5A</strong></td>
<td><strong>Z</strong></td>
</tr>
<tr>
<td><strong>0101 1011</strong></td>
<td><strong>91</strong></td>
<td><strong>5B</strong></td>
<td><strong>[</strong></td>
</tr>
<tr>
<td><strong>0101 1100</strong></td>
<td><strong>92</strong></td>
<td><strong>5C</strong></td>
<td><strong>\</strong></td>
</tr>
<tr>
<td><strong>0101 1101</strong></td>
<td><strong>93</strong></td>
<td><strong>5D</strong></td>
<td><strong>]</strong></td>
</tr>
<tr>
<td><strong>0101 1110</strong></td>
<td><strong>94</strong></td>
<td><strong>5E</strong></td>
<td><strong>^</strong></td>
</tr>
<tr>
<td><strong>0101 1111</strong></td>
<td><strong>95</strong></td>
<td><strong>5F</strong></td>
<td><strong>_</strong></td>
</tr>
<tr>
<td><strong>0110 0000</strong></td>
<td><strong>96</strong></td>
<td><strong>60</strong></td>
<td><strong>`</strong></td>
</tr>
<tr>
<td><strong>0110 0001</strong></td>
<td><strong>97</strong></td>
<td><strong>61</strong></td>
<td><strong>a</strong></td>
</tr>
<tr>
<td><strong>0110 0010</strong></td>
<td><strong>98</strong></td>
<td><strong>62</strong></td>
<td><strong>b</strong></td>
</tr>
<tr>
<td><strong>0110 0011</strong></td>
<td><strong>99</strong></td>
<td><strong>63</strong></td>
<td><strong>c</strong></td>
</tr>
<tr>
<td><strong>0110 0100</strong></td>
<td><strong>100</strong></td>
<td><strong>64</strong></td>
<td><strong>d</strong></td>
</tr>
<tr>
<td><strong>0110 0101</strong></td>
<td><strong>101</strong></td>
<td><strong>65</strong></td>
<td><strong>e</strong></td>
</tr>
<tr>
<td><strong>0110 0110</strong></td>
<td><strong>102</strong></td>
<td><strong>66</strong></td>
<td><strong>f</strong></td>
</tr>
<tr>
<td><strong>0110 0111</strong></td>
<td><strong>103</strong></td>
<td><strong>67</strong></td>
<td><strong>g</strong></td>
</tr>
<tr>
<td><strong>0110 1000</strong></td>
<td><strong>104</strong></td>
<td><strong>68</strong></td>
<td><strong>h</strong></td>
</tr>
<tr>
<td><strong>0110 1001</strong></td>
<td><strong>105</strong></td>
<td><strong>69</strong></td>
<td><strong>i</strong></td>
</tr>
<tr>
<td><strong>0110 1010</strong></td>
<td><strong>106</strong></td>
<td><strong>6A</strong></td>
<td><strong>j</strong></td>
</tr>
</tbody>
</table>
<h2>2. 数的进制:2进制、10进制、16进制</h2>
<table>
<thead>
<tr>
<th><strong>十进制</strong></th>
<th><strong>二进制</strong></th>
<th><strong>八进制</strong></th>
<th><strong>十六进制</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>1</strong></td>
<td><strong>1</strong></td>
<td><strong>1</strong></td>
<td><strong>0x1</strong></td>
</tr>
<tr>
<td><strong>2</strong></td>
<td><strong>10</strong></td>
<td><strong>2</strong></td>
<td><strong>0x2</strong></td>
</tr>
<tr>
<td><strong>3</strong></td>
<td><strong>11</strong></td>
<td><strong>3</strong></td>
<td><strong>0x3</strong></td>
</tr>
<tr>
<td><strong>4</strong></td>
<td><strong>100</strong></td>
<td><strong>4</strong></td>
<td><strong>0x4</strong></td>
</tr>
<tr>
<td><strong>5</strong></td>
<td><strong>101</strong></td>
<td><strong>5</strong></td>
<td><strong>0x5</strong></td>
</tr>
<tr>
<td><strong>6</strong></td>
<td><strong>110</strong></td>
<td><strong>6</strong></td>
<td><strong>0x6</strong></td>
</tr>
<tr>
<td><strong>7</strong></td>
<td><strong>111</strong></td>
<td><strong>7</strong></td>
<td><strong>0x7</strong></td>
</tr>
<tr>
<td><strong>8</strong></td>
<td><strong>1000</strong></td>
<td><strong>10</strong></td>
<td><strong>0x8</strong></td>
</tr>
<tr>
<td><strong>9</strong></td>
<td><strong>1001</strong></td>
<td><strong>11</strong></td>
<td><strong>0x9</strong></td>
</tr>
<tr>
<td><strong>10</strong></td>
<td><strong>1010</strong></td>
<td><strong>12</strong></td>
<td><strong>0xA</strong></td>
</tr>
<tr>
<td><strong>11</strong></td>
<td><strong>1011</strong></td>
<td><strong>13</strong></td>
<td><strong>0xB</strong></td>
</tr>
<tr>
<td><strong>12</strong></td>
<td><strong>1100</strong></td>
<td><strong>14</strong></td>
<td><strong>0xC</strong></td>
</tr>
<tr>
<td><strong>13</strong></td>
<td><strong>1101</strong></td>
<td><strong>15</strong></td>
<td><strong>0xD</strong></td>
</tr>
<tr>
<td><strong>14</strong></td>
<td><strong>1110</strong></td>
<td><strong>16</strong></td>
<td><strong>0xE</strong></td>
</tr>
<tr>
<td><strong>15</strong></td>
<td><strong>1111</strong></td>
<td><strong>17</strong></td>
<td><strong>0xF</strong></td>
</tr>
<tr>
<td><strong>16</strong></td>
<td><strong>10000</strong></td>
<td><strong>20</strong></td>
<td><strong>0x10</strong></td>
</tr>
<tr>
<td><strong>17</strong></td>
<td><strong>10001</strong></td>
<td><strong>21</strong></td>
<td><strong>0x11</strong></td>
</tr>
<tr>
<td><strong>18</strong></td>
<td><strong>10010</strong></td>
<td><strong>22</strong></td>
<td><strong>0x12</strong></td>
</tr>
</tbody>
</table>
<h3>各进制之间互相转换的方法:</h3>
<h4>(1) 十进制转二进制</h4>
<p><strong>采用 “除 2 取余,逆序排列” 法。将十进制数除以 2,得到商和余数,再将商继续除以 2,直到商为 0。将每次得到的余数从右到左排列,即为对应的二进制数。例如,将十进制数 10 转换为二进制:</strong> <strong>10 ÷ 2 = 5 余 0</strong> <strong>5 ÷ 2 = 2 余 1</strong> <strong>2 ÷ 2 = 1 余 0</strong> <strong>1 ÷ 2 = 0 余 1</strong> <strong>从下往上取余数得到 1010,即十进制 10 对应的二进制是 1010。</strong></p>
<h4>(2) 十进制转八进制</h4>
<p><strong>“除 8 取余,逆序排列” 法。将十进制数除以 8,得到商和余数,再将商继续除以 8,直到商为 0。将每次得到的余数从右到左排列,就是对应的八进制数。比如,把十进制数 20 转换为八进制:</strong> <strong>20 ÷ 8 = 2 余 4</strong> <strong>2 ÷ 8 = 0 余 2</strong> <strong>从下往上取余数得到 24,即十进制 20 对应的八进制是 24。</strong></p>
<h4>(3) 十进制转十六进制</h4>
<p><strong>“除 16 取余,逆序排列” 法。十进制数除以 16,得到商和余数,商再除以 16,直至商为 0。将余数从右到左排列得到十六进制数。十六进制中 10 - 15 分别用 A - F 表示。例如,十进制数 26 转换为十六进制:</strong> <strong>26 ÷ 16 = 1 余 10(用 A 表示)</strong> <strong>1 ÷ 16 = 0 余 1</strong> <strong>从下往上取余数得到 1A,即十进制 26 对应的十六进制是 1A。</strong></p>
<h4>(4) 二进制转十进制</h4>
<p><strong>按位加权求和法。从右至左,将二进制数的每一位乘以 2 的相应位数次幂(幂次从 0 开始),然后将所有结果相加。例如,二进制数 1011 转换为十进制:</strong></p>
<h4>(5) 八进制转十进制</h4>
<p><strong>同样是按位加权求和法。从右至左,八进制数的每一位乘以 8 的相应位数次幂(幂次从 0 开始),再把结果相加。比如,八进制数 35 转换为十进制:</strong></p>
<h4>(6) 十六进制转十进制</h4>
<p><strong>按位加权求和。从右至左,十六进制数的每一位乘以 16 的相应位数次幂(幂次从 0 开始),相加得到十进制数。十六进制中 A - F 分别对应 10 - 15 。例如,十六进制数 2A 转换为十进制:</strong></p>
<h4>(7) 二进制转八进制</h4>
<p><strong>从右向左,每 3 位一组,不足 3 位的在左边补 0,然后将每组二进制数转换为对应的八进制数。例如,二进制数 11010 转换为八进制:</strong> <strong>先分组为 011 010,011 对应八进制 3,010 对应八进制 2,所以结果是 32。</strong></p>
<h4>(8) 二进制转十六进制</h4>
<p><strong>从右向左,每 4 位一组,不足 4 位的在左边补 0,将每组二进制数转换为对应的十六进制数。比如,二进制数 111011 转换为十六进制:</strong> <strong>分组为 0011 1011,0011 对应十六进制 3,1011 对应十六进制 B,结果就是 3B。</strong></p>
<h4>(9) 八进制转二进制</h4>
<p><strong>将八进制数的每一位转换为对应的 3 位二进制数。例如,八进制数 57 转换为二进制:</strong> <strong>5 对应二进制 101,7 对应二进制 111,结果是 101111。</strong></p>
<h4>(10) 十六进制转二进制</h4>
<p><strong>把十六进制数的每一位转换为对应的 4 位二进制数。例如,十六进制数 A3 转换为二进制:</strong> <strong>A(10)对应二进制 1010,3 对应二进制 0011,结果是 10100011。</strong></p>
<h4>(11) 八进制转十六进制</h4>
<p><strong>可以先将八进制转换为二进制,再将二进制转换为十六进制。</strong></p>
<h4>(12) 十六进制转八进制</h4>
<p><strong>先把十六进制转换为二进制,再将二进制转换为八进制 。</strong></p>
<h2>3.数据的基本类型</h2>
<p><strong>想要使用64位变量,需要在程序文件里面添加申明:</strong><code>#pragma float64</code></p>
<p><img src="data/attachment/forum/202501/26/125149krqi70qooixxnhx7.png" alt="image-20250126123309805" /></p>
<h2>4.C语言常用运算符</h2>
<h3>算术运算符</h3>
<p><strong>下表显示了 C 语言支持的所有算术运算符。假设变量 A 的值为 18,变量 B 的值为 5,则:</strong></p>
<table>
<thead>
<tr>
<th><strong>运算符</strong></th>
<th><strong>描述</strong></th>
<th><strong>实例</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>+</strong></td>
<td><strong>两个数相加</strong></td>
<td><strong>A+B 将得到 23</strong></td>
</tr>
<tr>
<td><strong>-</strong></td>
<td><strong>一个数减另一个数</strong></td>
<td><strong>A-B 将得到 13</strong></td>
</tr>
<tr>
<td><strong>*</strong></td>
<td><strong>两个数相乘</strong></td>
<td><strong>A*B 将得到 90</strong></td>
</tr>
<tr>
<td><strong>/</strong></td>
<td><strong>分子除以分母</strong></td>
<td><strong>A/B 将得到 3.6</strong></td>
</tr>
<tr>
<td><strong>%</strong></td>
<td><strong>余数运算符,整除后的余数</strong></td>
<td><strong>B%A 将得到 3</strong></td>
</tr>
<tr>
<td><strong>++</strong></td>
<td><strong>自增运算符,整数值增加 1</strong></td>
<td><strong>A++ 将得到 19</strong></td>
</tr>
<tr>
<td><strong>--</strong></td>
<td><strong>自减运算符,整数值减少 1</strong></td>
<td><strong>A-- 将得到 17</strong></td>
</tr>
</tbody>
</table>
<h3>关系运算符</h3>
<p><strong>关系运算(Relational Operators),用于判断条件,决定程序的流程。</strong></p>
<p><strong>下表列出了 C 语言支持的关系运算符。假设两个整型数为 operand1 = 11, operand2 = 2,则</strong></p>
<table>
<thead>
<tr>
<th><strong>关系运算符</strong></th>
<th><strong>说明</strong></th>
<th><strong>示例</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>==</strong></td>
<td><strong>判断两个操作数是否相等,若相等则值为1,反之值为0</strong></td>
<td><strong>operand1 == operand2 的值为 0</strong></td>
</tr>
<tr>
<td><strong>!=</strong></td>
<td><strong>判断两个操作数是否不相等,若不相等则值为1,反之值为0</strong></td>
<td><strong>operand1 != operand2 的值为 1</strong></td>
</tr>
<tr>
<td><strong>&gt;</strong></td>
<td><strong>判断第1个操作数是否大于第2个操作数,若大于则值为1,反之值为0</strong></td>
<td><strong>operand1 &gt; operand2 的值为 1</strong></td>
</tr>
<tr>
<td><strong>&lt;</strong></td>
<td><strong>判断第1个操作数是否小于第2个操作数,若小于则值为1,反之值为0</strong></td>
<td><strong>operand1 &lt; operand2 的值为 0</strong></td>
</tr>
<tr>
<td><strong>&gt;=</strong></td>
<td><strong>判断第1个操作数是否大于或等于第2个操作数,若大于或等于则值为1,反之值为0</strong></td>
<td><strong>operand1 &gt;= operand2 的值为 1</strong></td>
</tr>
<tr>
<td><strong>&lt;=</strong></td>
<td><strong>判断第1个操作数是否小于或等于第2个操作数,若小于或等于则值为1,反之值为0</strong></td>
<td><strong>operand1 &lt;= operand2 的值为 0</strong></td>
</tr>
</tbody>
</table>
<h3>逻辑运算符</h3>
<p><strong>下表列出了 C 语言支持的逻辑运算符。假设两个整型数为 operand1 = 1, operand2 = 0,则:</strong></p>
<table>
<thead>
<tr>
<th><strong>逻辑运算符</strong></th>
<th><strong>说明</strong></th>
<th><strong>示例</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>&amp;&amp;</strong></td>
<td><strong>如果两个操作数均为非0,则表达式的值为1,反之为0</strong></td>
<td><strong>operand1 &amp;&amp; operand2 的值为 0</strong></td>
</tr>
<tr>
<td><strong>丨丨</strong></td>
<td><strong>如果两个操作数至少有一个为非0,则表达式的值为1,反之为0</strong></td>
<td><strong>operand1丨丨operand2 的值为 1</strong></td>
</tr>
<tr>
<td><strong>!</strong></td>
<td><strong>如果操作数的值为非0,则表达式的值为0,反之亦反</strong></td>
<td><strong>!operand1 的值为 0</strong></td>
</tr>
</tbody>
</table>
<h3>赋值运算符</h3>
<p><strong>下表列出了 C 语言支持的赋值运算符:</strong></p>
<table>
<thead>
<tr>
<th><strong>赋值运算符</strong></th>
<th><strong>说明</strong></th>
<th><strong>示例</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>=</strong></td>
<td><strong>普通赋值运算符</strong></td>
<td><strong>val = 2</strong></td>
</tr>
<tr>
<td><strong>+=</strong></td>
<td><strong>加并赋值操作</strong></td>
<td><strong>val += 2 等价于 val = val + 2</strong></td>
</tr>
<tr>
<td><strong>-=</strong></td>
<td><strong>减并赋值操作</strong></td>
<td><strong>val -= 2 等价于 val = val - 2</strong></td>
</tr>
<tr>
<td><strong>*=</strong></td>
<td><strong>乘并赋值操作</strong></td>
<td><strong>val *= 2 等价于 val = val * 2</strong></td>
</tr>
<tr>
<td><strong>/=</strong></td>
<td><strong>除并赋值操作</strong></td>
<td><strong>val /= 2 等价于 val = val / 2</strong></td>
</tr>
<tr>
<td><strong>%=</strong></td>
<td><strong>取余并赋值操作</strong></td>
<td><strong>val %= 2 等价于 val = val % 2</strong></td>
</tr>
<tr>
<td><strong>&lt;&lt;=</strong></td>
<td><strong>左移并赋值操作</strong></td>
<td><strong>val &lt;&lt;= 1 等价于 val = val &lt;&lt; 1</strong></td>
</tr>
<tr>
<td><strong>&gt;&gt;=</strong></td>
<td><strong>右移并赋值操作</strong></td>
<td><strong>val &gt;&gt;= 1 等价于 val = val &gt;&gt; 1</strong></td>
</tr>
<tr>
<td><strong>&amp;=</strong></td>
<td><strong>按位与并赋值操作</strong></td>
<td><strong>val &amp;= 1 等价于 val = val &amp; 1</strong></td>
</tr>
<tr>
<td><strong>^=</strong></td>
<td><strong>按位异或并赋值操作</strong></td>
<td><strong>val ^= 1 等价于 val = val ^ 1</strong></td>
</tr>
<tr>
<td><strong>|=</strong></td>
<td><strong>按位或并赋值操作</strong></td>
<td><strong>val |= 1等价于 val = val | 1</strong></td>
</tr>
</tbody>
</table>
<p><strong>赋值运算符支持的是C语言的基本数据类型,包括char、int和double,字符串(字符数组)不能使用赋值运算符。</strong></p>
<h3>位运算符</h3>
<p>假设A=5(0000 0101),B=11(0000 1011)</p>
<table>
<thead>
<tr>
<th align="center"><strong>运算符</strong></th>
<th><strong>描述</strong></th>
<th><strong>运算法则</strong></th>
<th><strong>实例</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><code>&amp;</code></td>
<td><strong>如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中</strong></td>
<td><strong>同一为一,其它为零</strong></td>
<td><code>(A&amp;B)</code>得到 <code>00000001</code></td>
</tr>
<tr>
<td align="center">|</td>
<td><strong>如果存在任一操作数中,二进制 OR 运算符复制一位到结果中</strong></td>
<td><strong>有一为一,皆零为零</strong></td>
<td><code>(A|B)</code>得到 <code>00001111</code></td>
</tr>
<tr>
<td align="center"><code>^</code></td>
<td><strong>如果只存在于一个操作数中,二进制异或运算符复制一位到结果中</strong></td>
<td><strong>相同为零,不同为一</strong></td>
<td><code>(A^B)</code>得到 <code>00001110</code></td>
</tr>
<tr>
<td align="center"><code>~</code></td>
<td><strong>取反,二进制将每一位 0 变为 1,1 变为 0</strong></td>
<td><strong>零变一,一变零</strong></td>
<td><code>(~A)</code>得到 <code>11111101</code></td>
</tr>
<tr>
<td align="center"><code>&lt;&lt;</code></td>
<td><strong>二进制左移运算符,左操作数的值向左移动右操作数指定位数</strong></td>
<td><strong>向高位移动两位,低位补零</strong></td>
<td><code>(A&lt;&lt;2)</code>得到 <code>00010100</code></td>
</tr>
<tr>
<td align="center"><code>&gt;&gt;</code></td>
<td><strong>二进制右移运算符,左操作数的值向右移动右操作数指定位数</strong></td>
<td><strong>向低位移动两位,高位补零</strong></td>
<td><code>(A&gt;&gt;2)</code>得到 <code>00000001</code></td>
</tr>
</tbody>
</table>
<h3>其他运算符</h3>
<table>
<thead>
<tr>
<th align="center"><strong>运算符</strong></th>
<th><strong>描述</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><code>Condition? X : Y</code></td>
<td><strong>条件运算符,如果</strong> <code>Condition</code>为真,则值为 <code>X</code>,否则为 <code>Y</code></td>
</tr>
<tr>
<td align="center"><code>.</code>(点) 和 <code>-&gt;</code>(箭头)</td>
<td><strong>成员运算符,用于引用类、结构体和共用体成员</strong></td>
</tr>
<tr>
<td align="center"><code>&amp;</code></td>
<td><strong>取地址运算符,返回变量的存储地址</strong></td>
</tr>
<tr>
<td align="center"><code>*</code></td>
<td><strong>指针运算符,</strong><code>*</code>指向一个变量,如 <code>*a</code>将指向变量 <code>a</code></td>
</tr>
<tr>
<td align="center"><code>,</code></td>
<td><strong>逗号运算符会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值</strong></td>
</tr>
</tbody>
</table>

MagicBude 发表于 2025-1-27 20:52:29

<h1>六、I/O 输入输出</h1>
<h2>1. 什么是 GPIO</h2>
<p>GPIO(General Purpose I/O Ports)意思为通用输入 / 输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态 —— 是高电平或是低电平。</p>
<h3>问:什么是高低电平?</h3>
<p>高电平就是指接近于电源正极电压的电平,也叫逻辑 “1”;</p>
<p>低电平就是指接近于电源负极(地)电压的电平,也叫逻辑 “0”;</p>
<p>单片机输出高电平就是输出 VCC 电压,输出低电平就是输出 GND 的电压。</p>
<h2>2. 按键输入检测</h2>
<p><img src="data/attachment/forum/202501/27/205134kfpsvxv4jva2t2zj.png" alt="image-20250127201558306" /></p>
<p><strong>代码实现原理:程序直接读取按键的 IO 的电平即可,一般使用 “==” 即可。</strong></p>
<p><strong>机械按键按下或者松开有抖动,一般在 20ms 内。</strong> <strong>因此需要进行按键消抖,初学采用延时消抖,通过软件生成的延时函数来延时 20ms。</strong></p>
<pre><code class="language-c">if(按键是否按下)
{
   //延时20ms消去抖动
   if(按键是否按下)//按键再次确认按下
 {
       //执行按键功能
       while(按键是否松开);
 }
}
</code></pre>
<p><img src="data/attachment/forum/202501/27/205134op3h1n80ri5k39i7.png" alt="image-20250127203139799" /></p>
<p><strong>任务 1</strong>:按下 P32 按钮灯亮,松开 P32 按钮灯灭;</p>
<p><strong>任务 2</strong>:按下 P32 按钮灯灭,松开 P32 按钮灯亮;</p>
<p><strong>任务 3</strong>:按一下灯亮,按一下灯灭;</p>
<p><strong>代码如下</strong></p>
<pre><code class="language-c">#include &quot;ai8051u.h&quot;            //调用头文件
#include &quot;stc32_stc8_usb.h&quot;   //调用头文件
#include &quot;intrins.h&quot;            //d调用头文件

#define u8unsigned char       //8位无符号变量(0-255)
#define u16 unsigned int      //16位无符号变量(0-65535)

u8 state = 0;                   //初始状态

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;

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

    _nop_();
    _nop_();
    i = 119998UL;
    while (i) i--;
}


void main(void)
{
   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();                         //
     }

//      //任务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:按一下灯亮,按一下灯灭
      if( P32 == 0 )                              //判断P32按钮是否按下
      {
            Delay20ms();                            //延时20ms消抖
            if( P32 == 0 )
            {
                state = !state;                     //变量取反 0 1 0 1 0 1
                P00 = state;
                printf(&quot;state:%d\r\n&quot;,(int)state);
         
                while( P32 == 0 );                  //等待P32松开
         
            }
      }


    }
}
</code></pre>

MagicBude 发表于 2025-1-27 22:41:24

<h1>七、定时器中断</h1>
<h2>1. 定时器的介绍</h2>
<p><strong>问题</strong>:LED 三秒闪烁一下,这三秒按下按键但是没有反应了?这怎么办呢?</p>
<p><strong>答</strong>:因为 MCU 是单核的,同一时间只能执行一个任务,在没有特殊情况时不能被打断。所以这里就要引入一个特殊情况,即定时器中断。</p>
<p><strong>定时器作用</strong>:</p>
<ul>
<li><strong>(1) 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作。</strong></li>
<li><strong>(2) 替代长时间的 Delay,提高程序的运行效率和处理速度(可以打断主循环)。</strong></li>
</ul>
<h2>2. 定时器的应用</h2>
<p><strong>利用 ISP 软件直接生成定时函数!</strong></p>
<p><img src="data/attachment/forum/202501/27/224103hucc6562cccz71cz.png" alt="image-20250127223146733" /></p>
<h2>3. 函数的定义、声明、调用</h2>
<p><strong>函数定义</strong>:</p>
<pre><code class="language-c">返回值类型 函数名(入口参数)
{
   // 函数体
   // 函数执行的代码
   return 返回值;
}
</code></pre>
<ul>
<li><strong>定义包含返回值、函数名和入口参数,并定义了函数的具体功能。</strong></li>
<li><strong>函数的名称应当能够描述函数的功能,便于代码的阅读和理解。</strong></li>
<li><strong>函数名称应当使用有意义的英文单词或者组合的英文单词,避免使用特殊字符或数字。</strong></li>
<li><strong>函数名称不能与 C 语言的关键字同名。</strong></li>
</ul>
<p><strong>函数声明</strong>:</p>
<pre><code class="language-c">返回值类型 函数名(入口参数);
</code></pre>
<ul>
<li><strong>在头文件或者被调用之前使用,注意末尾要加分号。</strong></li>
</ul>
<p><strong>函数调用</strong>:</p>
<pre><code class="language-c">函数名(入口参数);
</code></pre>
<ul>
<li><strong>在需要调用的地方直接使用函数名,加上括号和分号。如果有入口参数,需要在括号内的多个参数之间用逗号隔开。</strong></li>
</ul>

MagicBude 发表于 2025-1-28 10:49:45

<h1>八、定时器周期性任务调度</h1>
<h2>1. 周期性任务介绍</h2>
<p><strong>任务 1</strong>:用一个定时器实现这个任务。LED1 实现 0.3 秒取反一次,LED2 实现 0.6 秒取反一次,LED3 0.9 秒取反一次。</p>
<ul>
<li>通过一个变量计数,假设这个变量 1ms 自加一次,加到 300 即为 300ms,加到 600 就是 600ms;计数到达后重新清 0。</li>
</ul>
<p><strong>任务 2</strong>:数组点亮 LED,实现流水灯。</p>
<ul>
<li>数组使用分为如下两步:
<ul>
<li>定义类型 名称 [长度] = { 数值 };</li>
<li>使用赋值:名称 [索引] = 数值。</li>
</ul>
</li>
<li>注意事项:LED 是 0 点亮,1 熄灭,数组长度需要把握好流水灯移动的时间。</li>
</ul>
<p><strong>任务 3</strong>:按键 1 按一下,LED 通过数组移动一下。</p>
<ul>
<li>注意事项:按键不能再通过 <code>while</code>判断是否按下,松开了可以通过按键按下计数。</li>
</ul>
<p><img src="data/attachment/forum/202501/28/104934bnpaar9v3rfnavzn.png" alt="image-20250128103459724" /></p>
<ul>
<li>检测到按键连续按下,按键计数变量 +1,只要松开一下,计数清 0,计数累积到 50ms 的时候判定为按下。</li>
</ul>
<h2>2. 文件的创建(.c 和.h)</h2>
<p>创建程序文件三步,把硬件需要的初始化弄一个 <code>config.c</code>。</p>
<ul>
<li>新建文件并保存。</li>
<li>添加到工程。</li>
<li>添加引用路径。</li>
</ul>
<p>一般一个 <code>.c</code>和一个 <code>.h</code>文件执行一个外设或者一个任务或功能。这样可以让代码看起来简洁明了。</p>
<p>新建 <code>xxx.c</code>和 <code>xxx.h</code>文件,代表一个功能块。</p>
<p><strong><code>xxx.h</code>格式</strong>:</p>
<pre><code class="language-C">#ifndef __XXX_H
#define __XXX_H

// 调用头文件
// 函数声明...

#endif
</code></pre>
<p><strong><code>xxx.c</code>格式</strong>:</p>
<pre><code class="language-c">#include “xxx.h”

// 函数定义
</code></pre>
<p>添加文件一定要记得引用路径和添加到工程里。</p>
<h2>3. 结构体数组的周期性任务调度</h2>
<p>LED1 0.3 秒闪一次,LED2 0.6 秒闪一次,LED3 0.9 秒闪一次。</p>
<ul>
<li>都有定时器 1ms 加的变量。</li>
<li>都有一个设定的计数目标。</li>
<li>都有需要执行的功能。</li>
<li>定时时间到了才能执行。</li>
</ul>
<pre><code class="language-c">typedef struct
{
    u8 Run;                  //任务状态:Run/Stop
    u16 TIMCount;            //定时计数器
    u16 TRITime;             //重载计数器
    void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;
</code></pre>
<pre><code class="language-C">static TASK_COMPONENTS Task_Comps[]=
{
//状态计数周期函数
    {0,      1,       1,   执行功能},      
    {0,   10,      10,   执行功能},   
};
</code></pre>
<p>参考试验箱历程 “27 - 通过定时器周期性调度任务综合例程,简单实用的任务调度系统,推荐”。</p>

MagicBude 发表于 2025-2-6 23:07:24

<h1>九、数码管</h1>
<h2>1.数码管介绍</h2>
<h3>数码管介绍——外观</h3>
<p><img src="data/attachment/forum/202502/06/230551t77m5xxw9mxwo9vg.png" alt="image-20250203205050288" /><img src="data/attachment/forum/202502/06/230551mef2efixfitf2xxe.png" alt="image-20250203205101764" /><img src="data/attachment/forum/202502/06/230551mpjvvsaaofoiqza7.png" alt="image-20250203205120403" /><img src="data/attachment/forum/202502/06/230552gajim4sajjs4j41l.png" alt="image-20250203205132804" /><img src="data/attachment/forum/202502/06/230552ks3ancmc1mssxtic.png" alt="image-20250203205144131" /></p>
<p><strong>数码管也叫LED数码管,内部是由多个发光二极管封装在一起组成,他们可以有很多种颜色,很多种外形,很多种样式,但是本质来说他们都是通过点亮内部的LED来显示的,只要面板做好了,理论可以显示任意的字符或者图案。</strong></p>
<p><strong>以第一张图这种最普通的数码管来说,一个“8”我们称之为1位数码管,两个“8”就是2位数码管,以此类推。</strong></p>
<p><strong>数码管显示内容:</strong></p>
<p><img src="data/attachment/forum/202502/06/230634cea8tiaeiiaq6l8t.png" alt="image.png" title="image.png" /></p>
<p><img src="data/attachment/forum/202502/06/230551aeu4cxb5exe0ucg9.png" alt="image-20250203205316064" /></p>
<h3>数码管介绍——类型</h3>
<p><img src="data/attachment/forum/202502/06/230555pnhglxiqrhg4g9w9.png" alt="image-20250203205524307" /></p>
<p><strong>按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管</strong></p>
<p><img src="data/attachment/forum/202502/06/230555wxtx4sf04pnf4hot.png" alt="image-20250203205639739" /></p>
<p><strong>“AS”代表单色,而“BS”代表双色</strong></p>
<h2>2.数码管显示原理</h2>
<p><img src="data/attachment/forum/202502/06/230556lk8h2hv9298883nk.png" alt="image-20250204115339208" /></p>
<p><img src="data/attachment/forum/202502/06/230556cjlatoazzatodkj9.png" alt="image-20250204115432832" /></p>
<p><img src="data/attachment/forum/202502/06/230556h993m1adm71e0r0m.png" alt="image-20250204115455088" /></p>
<h2>3.数码管静态显示</h2>
<pre><code class="language-c">/**************** 向HC595发送一个字节函数 ******************/
void Send_595(u8 dat)
{
   u8  i;
   for(i=0; i&lt;8; i++)
 {
       dat &lt;&lt;= 1;
       P_HC595_SER   = CY;
       P_HC595_SRCLK = 1;
       P_HC595_SRCLK = 0;
 }
}

/********************** 显示扫描函数 ************************/
void DisplayScan(void)
{
   Send_595(t_display]);   //输出段码
   Send_595(~T_COM);            //输出位码

   P_HC595_RCLK = 1;
   P_HC595_RCLK = 0;
   if(++display_index &gt;= 8)    display_index = 0;  //8位结束回0
}
</code></pre>
<p><strong>使用ISP软件自带工具快速生成数码管数组</strong></p>
<p><img src="data/attachment/forum/202502/06/230556m7g26qc277f7eeft.png" alt="image-20250204120611686" /></p>
<h2>4.数码管动态显示</h2>
<p><img src="data/attachment/forum/202502/06/230559kqbzpgcoeobo4hce.png" alt="image-20250206230159766" /></p>
<p><strong>具体的控制的流程如图所示,N表示有几个数码管!其中需要注意每个延时不能太短,我们这边程序就以1ms为准,且需要保证总共一个循环结束的时间不能大于20ms,因为人眼的视觉不容易分辨出50HZ以上的动态刷新。</strong></p>
<p><img src="data/attachment/forum/202502/06/230700h12lbxwluw1ub2qu.png" alt="image.png" title="image.png" /></p>
页: [1] 2
查看完整版本: 8051U学习打卡+笔记