zihegfkq 发表于 2025-1-3 23:27:33

Ai8051U学习心得=====已安排实验箱

<h1>第一集 序言</h1>
<p><strong>我学习单片机是从Arduino入门的,那个时候也只是随便玩玩点点灯之类的,总觉得这种封装过度的开发方式虽然简单,但是对自己的能力提升不大,后来上了微机原理的课程,课上使用的试验箱主控就是STC89C52,也学会了用汇编对着寄存器进行编程,老实说我挺喜欢这种编程方式的。后面也用过各种开发板,就一直想找一个芯片作为自己开发的主力芯片,我希望它能尽可能的简单,包含尽可能的多的外设,价格要便宜点的方便自己DIY。AI8051U这个芯片最吸引我的地方是支持usb且能移植操作系统,在我的印象中这需要很大的资源,有的32位的单片机都不支持,51的内核竟然支持,这让我对这颗芯片充满了兴趣。正好STC推出了这AI8051U的课程,能帮助我更深入的了解这颗芯片。</strong></p>
<p><strong>序言这一集视频主要展示了AI8051U单片机实现的几个效果,最让人感觉惊艳的是手写计算器,作者用了一个小型的神经网络,从这里可以看出这颗芯片具有强大的计算能力,期待后续的功能!</strong></p>

zihegfkq 发表于 2025-1-4 21:34:15

<h1>第二集 硬件工具及介绍</h1>
<p><strong>本集主要讲述了AI8051实验箱的组成部分以及开发环镜的配置。我依照自己的理解把这些内容写一写。</strong></p>
<h2>硬件部分</h2>
<p><strong>由于没有拿到试验箱,先照着说明书以及原理图说一说我的理解</strong></p>
<p><img src="data/attachment/forum/202501/04/213330nedg9eg9dodeg5m0.jpg" alt="" /></p>
<ul>
<li><strong>RTC电池,给芯片中的RTC部分供电,保证时间系统的正常运行</strong></li>
<li><strong>USB-TypeA,视频中介绍说是双A口用于程序的下载(特殊的线防止被实验室其他人拿走用你又找不到)</strong></li>
<li><strong>LCD对比度调节 ,一个100k的电位器,两端为5V,GND,在12864模块的VO引脚上</strong></li>
<li><strong>外部并行总线扩展32ksram,采用了一个IS62C256AL作为SRAM,同时使用了一个74hc573作为锁存器芯片,减少io的使用(也可能是P0.0-P0.7使用外部SRAM时时序上先在该引脚输出地址然后输出数据,目前没有深究)</strong></li>
<li><strong>QSPI/SPI FLASH,flash芯片可作程序和数据的存储</strong></li>
<li><strong>电源按键 复位按键</strong></li>
<li><strong>INT0,INT1按键,两个中断按键,可能是想用来做嵌套中断的实验 按下通过300R接地无上拉</strong></li>
<li><strong>T0,T1按键,定时/计数器的按键,以此作为计数器的输入按下通过300R接地无上拉</strong></li>
<li><strong>ADC按键 测量模拟输入,按键不同接入电路的电阻不同,我感觉使用一个电位器替代会好一点</strong></li>
<li><strong>矩阵键盘 2*4可用扫描法读取键盘的输入</strong></li>
<li><strong>红外发射,使用一个三极管控制红外发射二极管</strong></li>
<li><strong>红外接收,使用红外接收传感器接收信号</strong></li>
<li><strong>掉电检测电压调节,一个100K电位器</strong></li>
<li><strong>TFT彩屏,预留彩屏接口</strong></li>
<li><strong>8位数码管,两个四位的共阴数码管,使用两个串转并芯片74hc595,只需使用3个引脚控制</strong></li>
<li><strong>8路流水灯,P0口控制负极,正极通过三极管开关控制</strong></li>
<li><strong>oled显示屏接口</strong></li>
<li><strong>话筒录音,后接了一个三阶的巴特沃斯滤波器,没有处理过音频不懂,接了P1.2不知道是不是一个ADC接口</strong></li>
<li><strong>立体声输出,声音输出接口</strong></li>
<li><strong>示波器BNC输入,目前看不懂后续研究</strong></li>
<li><strong>tf卡座,支持tf卡可以移植文件系统</strong></li>
<li><strong>USB转双串口,STC主推芯片,说是可以替代CH340,期待</strong></li>
<li><strong>USB-TypeC,程序下载接口</strong></li>
<li><strong>USB LINK 1D,仿真器接口</strong></li>
</ul>
<p><strong>背面都是一些芯片不再介绍</strong></p>
<h2>软件环境配置</h2>
<p><strong>目前采用的是keil开发,安装软件去keil官网下载c251以及arm,安装教程网上很多,不再赘述。</strong></p>
<p><strong>这里要注意的是使用stcisp软件安装头文件和器件包,以及下载中断号软件(keil原生不支持这么多中断)。</strong></p>

zihegfkq 发表于 2025-1-4 22:22:02

<h1>第三集 点亮第一颗LED灯</h1>
<p><strong>点灯是嵌入式开发的入门操作,我们首先来看一下led的硬件电路图,然后根据硬件电路图写出对应的控制代码。</strong></p>
<h2>LED硬件电路图</h2>
<p><img src="data/attachment/forum/202501/04/222114qs7r7orjs39u6v1o.jpg" alt="" /></p>
<p><strong>从led的原理图中可以看出,led的正极通过一个pnp三极管连接到vcc,当P4.0引脚为低电平时,Q2导通,此时P0的某一位置低时,对应的led灯便会亮起。</strong></p>
<h2>LED软件控制</h2>
<p><strong>可以看到led硬件部分的电路极其简单,我们只需控制P0口和P4口就可使led亮起,接下来我们看具体如何做来控制P0与P4口</strong></p>
<h3>创建工程</h3>
<p><strong>我们首先学习创建工程</strong></p>
<p><strong>选择芯片</strong></p>
<p><img src="data/attachment/forum/202501/04/222114flelttmi6dtittr6.jpg" alt="" /></p>
<p><strong>调整配置</strong></p>
<p><img src="data/attachment/forum/202501/04/222114ic9699d9t3alz6av.jpg" alt="" /></p>
<h3>代码编写</h3>
<p><strong>一般来说控制外设的流程:</strong></p>
<ul>
<li><strong>配置外设的寄存器</strong></li>
<li><strong>打开外设的时钟</strong></li>
<li><strong>控制外设</strong></li>
</ul>
<p><strong>AI8051U控制通用端口时,只有两个操作,配置端口的寄存器,向端口输入数据</strong></p>
<p><strong>stcisp提供了方便配置端口的工具,我们点亮led可以将端口配置为推挽输出,然后输出端口数据</strong></p>
<p><img src="data/attachment/forum/202501/04/222114kvvtd5ult65lamvz.jpg" alt="" /></p>
<p><strong>代码如下</strong></p>
<pre><code class="language-c">#include&quot;AI8051U.h&quot;//添加头文件,里面有寄存器定义

void main(){
    P0M0 = 0xff; P0M1 = 0x00; //配置P0口模式
    P4M0 = 0xff; P4M1 = 0x00; //配置P1口模式
    P40=0;//打开Q2管
    while(1){
      P0=0xaa;//控制P0口输出点亮led
    }
}
</code></pre>
<p><strong>没有板子只能编译一下看个热闹</strong></p>
<p><img src="data/attachment/forum/202501/04/222114qswyltgwqwqet3ye.jpg" alt="" /></p>

zihegfkq 发表于 2025-1-7 23:57:57

<h1>第四集 USB不断电下载</h1>
<p><strong>本节课主要学习的是USB不断电下载程序的移植,因为此前的下载都需要手动按下板子上的按钮才能进入下载模式,而在程序中添加这个功能就是不用按按钮而进入下载模式。</strong></p>
<ol>
<li><strong>原理</strong></li>
</ol>
<p><strong>猜测加了这段代码后,当usb口接收到数据时就会产生中断使板子进入下载模式</strong></p>
<ol start="2">
<li><strong>usb库的移植</strong></li>
</ol>
<p><strong>这一步操作就是复制usb库的lib文件与头文件到工程项目中</strong></p>
<ol start="3">
<li><strong>程序的编写</strong></li>
</ol>
<p><strong>重要的是代码的编写每一步做了什么及原因写在了注释里</strong></p>
<pre><code class="language-c">#include&quot;ai8051u.h&quot;
#include&quot;stc32_stc8_usb.h&quot;//引入usb库文件
//应该是库中使用到了这几个字符串,未定义编译时会报错
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = &quot;@STCISP#&quot;;
void main(){
        //使能XFR寄存器,usb配置相关寄存器再XFR
        P_SW2 |= 0x80;
        //配置各端口为准双向口
        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 初始化

        EA = 1;//开启中断,开启了中断usb接收到数据才会有反应

        while (DeviceState != DEVSTATE_CONFIGURED);   //等待USB设备配置完成

        while (1)
        {
            //轮询,当接收到数据就能下载程序
                        if (bUsbOutReady)
                        {
                                USB_SendData(UsbOutBuffer,OutNumber);   //发送缓冲区数据
                                usb_OUT_done();
                        }
                        //点亮LED
                        P40=0;
                        P02=0;
        }
}
</code></pre>
<ol start="4">
<li><strong>编译</strong></li>
</ol>
<p><strong>编译时注意屏蔽掉57号警告,否则编译时会警告函数定义了但未使用</strong></p>
<p><img src="data/attachment/forum/202501/07/235752yzz7bzx6s7gbw6x7.jpg" alt="" /></p>

zihegfkq 发表于 2025-1-8 00:15:18

<h1>第五集 c语言基础</h1>
<p><strong>本集讲解了printf的重定向问题,以及C语言的一些基础语法</strong></p>
<p><strong>printf重定向是很多单片机开发要考虑的问题,它使得printf打印的数据从串口发送出去,实现此功能大大方便了程序的调试工作,在开发过程中通过printf输出的信息进行程序调试,判断芯片是否正常工作。stc的厂家的usb封装比较好,只需把usb库中宏定义#define PRINTF_HID前的注释符号去掉就可以在程序中使用printf打印信息</strong></p>
<p><strong>c语言的基础语法部分在这里就不再赘述,都是很基础的入门内容。</strong></p>

zihegfkq 发表于 2025-1-9 23:30:52

<h1>第六集 I/O的输入输出</h1>
<p><strong>本集视频主要介绍了GPIO的输入输出特征,ai8050u的io模式,以及如何使用IO完成按键的读取操作。</strong></p>
<p><strong>我来对着数据手册看一下AI8051U的IO接口具体的情况</strong></p>
<h2>IO模式以及结构图</h2>
<p><strong>AI8051U的IO一共有四种模式分别是准双向口,推挽输出,高阻输入,开漏模式,我们由易到难进行介绍,在编写代码时对寄存器名称赋值是写入,即单片机对外输出,而使用寄存器名称是读取,即单片机读取外部的信号值。</strong></p>
<h3>高阻输入</h3>
<p><img src="data/attachment/forum/202501/09/233047stymltt2tfcltt46.jpg" alt="" /></p>
<p><strong>该模式下电流既不能输入也不能输出,从结构上来看该模式只能读取外部数据,而没有输入电流说明该模式不会有灌电流,从而不会吸收外界信号源的能量削弱信号源,比较适合作为ADC采集信号</strong></p>
<h3>推挽输出</h3>
<p><img src="data/attachment/forum/202501/09/233047eszrtsqs7iiz7tpo.jpg" alt="" /></p>
<p><strong>该模式下输入部分与高阻输入相同,输出部分则采用两个mos管互补输出,当端口写入0时,经反相器变高,下管导通,当端口写入1时,经反相器变低,上管导通。该模式下可以输出很大的电流,当需要强力输出时可以使用该模式</strong></p>
<h3>准双向口</h3>
<p><img src="data/attachment/forum/202501/09/233047n890n9kpjpm900jp.jpg" alt="" /></p>
<p><strong>这个模式我是第一次见到,感觉比较有意思,先看输出部分,输出0是逻辑比较简单,经一个反相器下管直接导通,而上管就比较有趣了,有三个管子漏极相连,当输出1的时候,极弱的管子肯定会导通,输出稳定高电平后,弱管也会导通,看一下强管什么导通,强管的栅极是一个或门的输出,只有当两管输入都为0的时候,强管才会导通,即当前或门输入处为0,2个时钟周期之前输入处为1,对应写入数据为从0到1跳变时强管会导通。一般情况下可用该模式。</strong></p>
<h3>开漏模式</h3>
<p><img src="data/attachment/forum/202501/09/233047vfi7unny4nyfzizt.jpg" alt="" /></p>
<p><strong>该模式对外写入1时,没有管子导通,等同于高阻输入。</strong></p>
<p><strong>当接入上拉电阻后,与准双向口类似。</strong></p>
<p><strong>值得一提的是每个端口可通过寄存器配置上拉电阻和下拉电阻而省去外部电阻。</strong></p>

zihegfkq 发表于 2025-1-10 00:22:39

<h1>第七课 定时器中断</h1>
<p><strong>本集课程讲述了如何使用定时器进行周期性的计时以及如何使用定时器中断,在这里就介绍一下中断,如何使用定时器以及分析一个定时器的工作模式</strong></p>
<h2>中断</h2>
<p><strong>由于cpu的结构设计使得它每次只能执行一件事,当很多事同时发生时,cpu也只能通过轮询的方式来处理每件事,但事实上每件事情重要的程度不一样,我们希望先执行重要的事情,而中断能很好的解决这个问题。中断就是当一件事发生后,可以通知cpu放下当前的事情转而执行重要的事情,当重要事情执行完成后再去返回去执行原来的事情</strong></p>
<p><strong>中断分为内部中断及外部中断,内部中断一般为单片机内部的外设如定时器串口等,外部中断一般是外部引脚引发的中断</strong></p>
<p><strong>中断具有优先级,高优先级的中断可以打破低优先级的中断</strong></p>
<p><strong>中断的执行是在每个始终周期检测中断标志位,当标志位置1时程序会跳转到对应的中断服务函数中去执行,执行完成程序再返回到主函数。</strong></p>
<h2>使用定时器</h2>
<p><strong>AI8051U的定时器可以通过isp下载工具生成对应的代码可以说非常方便</strong></p>
<p><strong>首先选择定时器计算器</strong></p>
<p><strong>然后设置对应的参数</strong></p>
<p><strong>复制生成的定时器初始化代码</strong></p>
<p><strong>将代码放到主程序中,并在main函数中调用定时器初始化函数</strong></p>
<p><strong>最后编写中断服务函数,在该函数中写出定时时间到了需要执行的操作</strong></p>

zhange 发表于 2025-1-10 07:08:41

其实课程里再加点硬件知识更好。。。。{:4_168:}{:4_168:}

zihegfkq 发表于 2025-1-12 22:59:20

<h1>第八集 定时器周期性调度任务</h1>
<p><strong>本集所讲述的周期性调度任务也就是每隔一定时间需要执行的任务,要实现该类任务基本思路是使用定时器,每隔一定的时间产生中断,在中断服务函数中对计时变量进行自增,在主函数的死循环中对该计时变量进行判断,当计时变量达到一定的值之后,执行任务,并将计时变量清除。</strong></p>
<p><strong>官方对这种周期性调度的任务进行了封装,我来介绍一下大体思路</strong></p>
<p><strong>对于周期性任务无非就两个要素:一个是周期是多少,另一个是执行的具体任务,对应程序中的某个功能函数,官方定义了一个任务组件的结构体</strong></p>
<pre><code class="language-c">typedef struct
{
        u8 Run;               //任务状态:Run/Stop
        u16 TIMCount;         //定时计数器
        u16 TRITime;          //重载计数器
        void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;   
</code></pre>
<p><strong>变量Run表示时间到了任务应该执行还是时间没到不应该执行</strong></p>
<p><strong>TIMCount为定时器中断中的计数器,用来看定时的时间有没有到</strong></p>
<p><strong>TRITime为重载计数器,在TIMCount清零后给其赋值让其重新开始计时</strong></p>
<p><strong>void (*TaskHook) (void)是一个函数指针,用以指定定时时间到后所执行的任务</strong></p>
<p><strong>官方定义了一个上述结构体的数组Task_Comps,用以存储一系列的周期性任务,我们来看看这些任务是如何调度的</strong></p>
<p><strong>官方定义了两个函数,一个用在中断服务函数中处理计时变量,另一个用在主函数中进行任务调度</strong></p>
<p><strong>首先看第一个函数</strong></p>
<pre><code class="language-c">void Task_Marks_Handler_Callback(void)
{
    u8 i;
    for(i=0; i&lt;Tasks_Max; i++)
    {
      if(Task_Comps.TIMCount)      /* If the time is not 0 */
      {
            Task_Comps.TIMCount--;   /* Time counter decrement */
            if(Task_Comps.TIMCount == 0) /* If time arrives */
            {
                /*Resume the timer value and try again */
                Task_Comps.TIMCount = Task_Comps.TRITime;
                Task_Comps.Run = 1;      /* The task can be run */
            }
      }
    }
}
</code></pre>
<p><strong>外层的for循环用以遍历每个任务,我认为外部的if判读多余,如果不是在数组初始化时给TIMCount赋值0,程序执行过程中它被减为0后马上重载了,内部的话就是一个定时器中断后计数器减一,减到0了重载计数器的值,同时让任务执行标志位置一。</strong></p>
<p><strong>第二个函数是主函数的任务调度</strong></p>
<pre><code class="language-c">void Task_Pro_Handler_Callback(void)
{
    u8 i;
    for(i=0; i&lt;Tasks_Max; i++)
    {
      if(Task_Comps.Run) /* If task can be run */
      {
            Task_Comps.Run = 0;      /* Flag clear 0 */
            Task_Comps.TaskHook();   /* Run task */
      }
    }
}
</code></pre>
<p><strong>同样外层的for循环用以遍历每个任务,然后检查任务执行标志位,如果标志位被置一就执行任务,并且将标志位清0,说明任务执行过了。</strong></p>
<p><strong>官方提供的模板可以说非常简洁,便于理解,非常不错。</strong></p>
页: [1]
查看完整版本: Ai8051U学习心得=====已安排实验箱