dfjs 发表于 2024-10-28 22:02

嘉楠K230 AI开发板测评3--RTC、ADC、PWM、UART、Thread、看门狗、文件读写

<div style="text-align: center;"><strong>嘉楠科技CanMV 勘智(Kendryte)K230嵌入式AI开发板</strong><strong>--测评</strong><strong>3</strong></div>

<div style="text-align: right;"><strong>----基础实验篇</strong></div>

<ol>
        <li style="text-align: justify;"><strong>RTC(实时时钟)</strong><br />
        &nbsp;&nbsp;&nbsp;&nbsp;MicroPyrhon已经集成了内置时钟函数模块,位于machine的RTC模块中(https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc),实验的原理是读取RTC时钟数据。<br />
        &nbsp;&nbsp;&nbsp;&nbsp;首先构造RTC对象,rtc=machine.RTC(),设置RTC日期和时间,rtc.datetime(year,mon,<br />
        day,hour,min,sec,microsec),其中datetime有8个参数,按顺序分别为年、月、日、星期、时、分、秒、微妙,其中星期使用0-6表示星期一到星期日。同时rtc.datetime返回当前RTC时间元组。<br />
        &nbsp;&nbsp;&nbsp;&nbsp;通过代码首次上电如果检测到未设置时间先设置时间,然后周期打印获取的时间信息,代码流程图如图所示<br />
        &nbsp;&nbsp;&nbsp;&nbsp;<br />
        参考代码:
        <table border="1">
                <tbody>
                        <tr>
                                <td>&#39;&#39;&#39;<br />
                                实验名称:RTC实时时钟<br />
                                说明:实时时钟使用<br />
                                教程:wiki.01studio.cc<br />
                                &#39;&#39;&#39;<br />
                                # 导入相关模块<br />
                                from machine import RTC<br />
                                import time<br />
                                # 构建RTC对象<br />
                                rtc = RTC()<br />
                                # 首次上电设置RTC日期和时间。(2024, 1, 1, 0, 0, 0, 0, 0)按顺序分别表示(年,月,日,星期,时,分,秒,微妙),<br />
                                # 其中星期使用0-6表示星期一到星期日。<br />
                                if rtc.datetime() != 2024:<br />
                                rtc.datetime((2024, 1, 1, 0, 0, 0, 0, 0))<br />
                                while True:<br />
                                print(rtc.datetime()) #打印时间<br />
                                time.sleep(1) #延时1秒</td>
                        </tr>
                </tbody>
        </table>
        &nbsp;&nbsp;&nbsp;&nbsp; 实验结果如下图,运行代码,可以看到终端打印当前RTC时间信息,注:RTC时间是断电丢失的,想要RTC时间连续运行需要持续对开发板供电。<br />
        </li>
        <li><strong>ADC(电压测量)</strong><br />
        &nbsp;&nbsp;&nbsp;&nbsp; ADC(analog to digital conversion) 模拟数字转换,意思就是将模拟信号转化成数字信号,由于单片机只能识别二级制数字,所以外界模拟信号常常会通过ADC转换成其可以识别的数字信息,常见的应用就是将变化的电压转成数字信号实现对电压值测量。<br />
        &nbsp;&nbsp;&nbsp;&nbsp; K230内部包含一个ADC硬件模块,有6个通道,采样分辨率为12bit(0-4095),采样速率为1M。01Studio CanMV K230开发板引出0~3共4个通道。其中通道0、1量程为0-3.6V(原理图如下左图),通道2、3量程为0-1.8V,引脚定义如下右图。<br />
        <br />
        &nbsp;&nbsp;&nbsp;&nbsp; 首先构造函数对象adc=machine.ADC(channel),channel为0-3,接着adc.read_u16()获取ADC值,测量精度是12位,返回0-4095,adc.read_uv()获取ADC电压值,返回0-1.8,通道0、1要乘以2,对应0-3.6V,通道2、3返回值与实际电压值一一对应,代码编写流程如下:<br />
        <br />
        &nbsp;&nbsp;&nbsp; 参考代码如下:
        <table border="1">
                <tbody>
                        <tr>
                                <td>&#39;&#39;&#39;<br />
                                实验名称:ADC(电压测量)<br />
                                版本:v1.0<br />
                                作者:01Studio<br />
                                实验平台:01Studio CanMV K230<br />
                                说明:ADC共4个通道,其中通道0、1实际量程为0-3.6V,通道2、3量程为0-1.8V。<br />
                                (请勿超出测量量程, 可能导致主控芯片烧坏!)<br />
                                &#39;&#39;&#39;<br />
                                from machine import ADC<br />
                                import time<br />
                                &#39;&#39;&#39;<br />
                                构建ADC对象:<br />
                                ADC0(排针32引脚,量程0-3.6V), ADC1(排针36引脚,量程0-3.6V),<br />
                                ADC2(排针38引脚,量程0-1.8V), ADC3(排针40引脚,量程0-1.8V)。<br />
                                &#39;&#39;&#39;<br />
                                adc = ADC(0) #通道0<br />
                                while True:<br />
                                print(adc.read_u16()) # 获取ADC通道采样值<br />
                                # 获取ADC通道电压值,保留2为小数。通道0、1实际量程为0-3.6V,返回值x2。<br />
                                print(&#39;%.2f&#39;%(adc.read_uv()/1000000*2), &quot;V&quot;)<br />
                                time.sleep(1) #延时1秒</td>
                        </tr>
                </tbody>
        </table>
        &nbsp;&nbsp;&nbsp;&nbsp; 实验结果如下图,通过杜邦线将CanMV K230 ADC通道0引脚分别与和GND引脚和3.3V引脚短接分别测量,可以看到在一定误差范围内,结果正确。<br />
        </li>
        <li><strong>PWM(蜂鸣器)</strong><br />
        &nbsp;&nbsp;&nbsp; PWM(脉冲宽度调制)就是一个特定信号输出,主要用于输出不同频率、占空比(一个周期内高电平出现时间占总时间比例)的方波,以实现固定频率或平均电压输出,如下图占空比为75%的5V方波等效于3.75V,占空比为50%的5V方波等效于2.5V,占空比为20%的5V方波等效于1V。<br />
        <br />
        &nbsp;&nbsp;&nbsp; 蜂鸣器分为有源蜂鸣器与无源蜂鸣器,有源蜂鸣器只需要接上电源,蜂鸣器就能发声,断开电源就停止发声。而无源蜂鸣器,需要给指定的频率,才能发声,通过改变频率来改变蜂鸣器的发声音色。<br />
        &nbsp;&nbsp; 首先构造PWM函数对象,PWM对象位于machine模块下,pwm = machine.PWM(channel, freq, duty, enable=False),channel为通道编号,取值0-3,PWM0对应GPIO42,PWM1对应GPIO43,PWM2对应GPIO46,PWM3对应GPIO47,frep为PWM频率,duty为PWM占空比,enable为PWM输出使能。可以通过pwm.freq(),pwm.duty(),直接设置频率与占空比。无源蜂鸣器我们可以用特定频率的方波来驱动,方波的原理很简单,就是一定频率的高低电平转换,可以简单理解成占空比为50%的PWM输出。代码流程如下:<br />
        <br />
        &nbsp;&nbsp; 参考代码如下
        <table border="1">
                <tbody>
                        <tr>
                                <td>&#39;&#39;&#39;<br />
                                实验名称:PWM<br />
                                版本:v1.0<br />
                                作者:01Studio<br />
                                实验平台:01Studio CanMV K230<br />
                                说明:通过不同频率的PWM信号输出,驱动无源蜂鸣器发出不同频率的声音。<br />
                                &#39;&#39;&#39;<br />
                                from machine import Pin, PWM<br />
                                from machine import FPIOA<br />
                                import time<br />
                                #配置引脚42为PWM0功能<br />
                                #通道0:GPIO42,通道1:GPIO43,通道2:GPIO46,通道3:GPIO47,<br />
                                fpioa = FPIOA()<br />
                                fpioa.set_function(42,FPIOA.PWM0)<br />
                                #构建蜂鸣器PWM对象,通道0,频率为200Hz,占空比为50%,默认使能输出<br />
                                Beep = PWM(0,200, 50, enable=True) # 在同一语句下创建和配置PWM,占空比50%<br />
                                #蜂鸣器发出频率200Hz响声<br />
                                Beep.freq(200)<br />
                                time.sleep(1)<br />
                                #蜂鸣器发出频率400Hz响声<br />
                                Beep.freq(400)<br />
                                time.sleep(1)<br />
                                #蜂鸣器发出频率600Hz响声<br />
                                Beep.freq(600)<br />
                                time.sleep(1)<br />
                                #蜂鸣器发出频率800Hz响声<br />
                                Beep.freq(800)<br />
                                time.sleep(1)<br />
                                #蜂鸣器发出频率1000Hz响声<br />
                                Beep.freq(1000)<br />
                                time.sleep(1)<br />
                                #停止<br />
                                Beep.enable(False)</td>
                        </tr>
                </tbody>
        </table>
        &nbsp;&nbsp;&nbsp; 实验结果如下图,使用引脚GPIO42输出PWM波形,通过示波器测量PWM波形,在图一中,设置初始频率为200Hz,最终频率为800Hz;在图二中,设置默认频率为200Hz,初始占空比为50%,最终占空比为80%。<br />
        <br />
        </li>
        <li><strong>UART(串口通信)</strong><br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; K230内部包含五个UART硬件模块,其中UART0被小核终端占用,UART3被大核终端占用,剩余UART1,UART2,UART4。 01Studio CanMV K230开发板通过排针引出了UART1和UART2共2个UART供用户使用。<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先构造函数,machine.UART (id, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE ),id为串口编号,串口1(UART.UART1:TX1(GPIO3), RX1(GPIO4))和串口2(UART.UART2:TX2(GPIO11), RX2(GPIO12))可用,baudrate为波特率,常用的115200、9600,bits为数据位,默认8位,parity为奇偶校验位,默认None,stop为停止位,默认1。通过UART.read(num)和UART.write(buf)分别读取和写入缓冲数据,同时可通过UART.readline(num)整行读取。<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 需要使用一个USB转TTL工具,然后配合串口助手与K230通信,串口1的引脚与原理图如下图,IO3--TX1,IO4--RX1:<br />
        <br />
        &nbsp;&nbsp;&nbsp; 使用3.3V串口转TTL工具,接线示意图与实物图分别如下:<br />
        <br />
        <br />
        &nbsp;&nbsp;&nbsp;&nbsp; 先初始化串口,然后给串口发去一条信息,这样PC机的串口助手就会在接收区显示出来,然后进入循环,当检测到有数据可以接收时候就将数据接收并打印,并通过REPL打印显示。代码编写流程图如下:<br />
        <br />
        &nbsp;&nbsp;&nbsp;&nbsp; 参考代码如下:
        <table border="1">
                <tbody>
                        <tr>
                                <td>&#39;&#39;&#39;<br />
                                实验名称:UART(串口通信)<br />
                                作者:01Studio<br />
                                实验平台:01Studio CanMV K230<br />
                                说明:通过编程实现串口通信,跟电脑串口助手实现数据收发。<br />
                                &#39;&#39;&#39;<br />
                                #导入串口模块<br />
                                from machine import UART<br />
                                from machine import FPIOA<br />
                                import time<br />
                                fpioa = FPIOA()<br />
                                # UART1代码<br />
                                fpioa.set_function(3,FPIOA.UART1_TXD)<br />
                                fpioa.set_function(4,FPIOA.UART1_RXD)<br />
                                uart=UART(UART.UART1,115200) #设置串口号1和波特率<br />
                                &#39;&#39;&#39;<br />
                                # UART2代码<br />
                                fpioa.set_function(11,FPIOA.UART2_TXD)<br />
                                fpioa.set_function(12,FPIOA.UART2_RXD)<br />
                                uart=UART(UART.UART2,115200) #设置串口号2和波特率<br />
                                &#39;&#39;&#39;<br />
                                uart.write(&#39;Hello 01Studio!&#39;)#发送一条数据<br />
                                while True:<br />
                                text=uart.read(128) #接收128个字符<br />
                                if text != b&#39;&#39;:<br />
                                print(text) #通过REPL打印串口3接收的数据<br />
                                time.sleep(0.1) #100ms</td>
                        </tr>
                </tbody>
        </table>
        &nbsp;&nbsp;&nbsp; 实验结果如下图,将串口助手调为COM6,波特率为115200,可以看到串口成功输出(如左图),同时使用串口助手向K230发送一串字符&ldquo;http://www.cmsoft.cn&rdquo;,也可以看到K230的UART1正确输出(如右图)。<br />
        </li>
        <li><strong>Thread(线程)</strong><br />
        &nbsp;&nbsp;&nbsp;&nbsp; 当我们需要分时完成不同任务时候,线程编程就派上用场了,这有点像RTOS(实时操作系统),编程实现多线程同时运行任务。<br />
        &nbsp;&nbsp;&nbsp;&nbsp; CanMV K230的MicroPython固件已经集成了_thread线程模块。我们直接调用即可。该模块衍生于python3(https://docs.python.org/3.5/library/_thread.html#module-thread),属于低级线程,代码编写流程如下:<br />
        <br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 参考代码如下:
        <table border="1">
                <tbody>
                        <tr>
                                <td>&#39;&#39;&#39;<br />
                                实验名称:线程<br />
                                版本: v1.0<br />
                                作者:01Studio<br />
                                实验平台:01Studio CanMV K230<br />
                                说明:通过编程实现多线程。<br />
                                &#39;&#39;&#39;<br />
                                import _thread #导入线程模块<br />
                                import time<br />
                                #线程函数<br />
                                def func(name):<br />
                                while True:<br />
                                print(&quot;hello {}&quot;.format(name))<br />
                                time.sleep(1)<br />
                                _thread.start_new_thread(func,(&quot;1&quot;,)) #开启线程1,参数必须是元组<br />
                                _thread.start_new_thread(func,(&quot;2&quot;,)) #开启线程2,参数必须是元组<br />
                                while True:<br />
                                time.sleep(0.01) #防止CPU满跑</td>
                        </tr>
                </tbody>
        </table>
        &nbsp;&nbsp;&nbsp; 实验结果,运行代码,可以看到串口终端重复执行2个线程,如下图所示。<br />
        </li>
        <li><strong>看门狗</strong><br />
        &nbsp;&nbsp;&nbsp;&nbsp; 任何代码在运行过程中都可能出现崩溃的情况,这时候就可以加入看门狗代码。看门狗的用途是在应用程序崩溃并最终进入不可恢复状态时自动重新启动系统。一旦启动,就无法以任何方式停止或重新配置。启用后,应用程序必须定期&ldquo;喂食&rdquo;看门狗,以防止其过期并重置系统。<br />
        &nbsp;&nbsp;&nbsp;&nbsp; CanMV K230的MicroPython固件已经集成了看门狗WDT模块,我们直接调用即可。<br />
        &nbsp;&nbsp;&nbsp;&nbsp; 首先构造WDT对象,wdt=WDT(id,timeout)创建看门狗对象,id为看门狗编号,timeout为超时时间,wdt.feed()喂狗,需要在构建看门狗对象时指定的超时时间内执行该指令。代码编写流程如图所示:<br />
        <br />
        &nbsp;&nbsp;&nbsp;&nbsp; 参考代码如下:
        <table border="1">
                <tbody>
                        <tr>
                                <td>&#39;&#39;&#39;<br />
                                实验名称:看门狗<br />
                                版本: v1.0<br />
                                作者:01Studio<br />
                                实验平台:01Studio CanMV K230<br />
                                说明:看门狗测试。<br />
                                &#39;&#39;&#39;<br />
                                from machine import WDT #导入线程模块<br />
                                import time<br />
                                #构建看门狗对象。<br />
                                wdt = WDT(1,3) #看门狗编号1,超时时间3秒。<br />
                                #每隔1秒喂一次狗,执行3次。<br />
                                for i in range(3):<br />
                                time.sleep(1)<br />
                                print(i)<br />
                                wdt.feed() #喂狗<br />
                                #停止喂狗,系统会重启。<br />
                                while True:<br />
                                time.sleep(0.01) #防止CPU满跑</td>
                        </tr>
                </tbody>
        </table>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实验结果,运行代码,可以看到串口终端打印了3次信息后自动重启,断开了IDE连接。有了看门狗,当开发板死机时候就可以自动重启了。<br />
        </li>
        <li><strong>文件读写</strong></li>
</ol>

<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在嵌入式编程中我们经常会遇到需要将某些数据实现掉电保存功能,如传感器数据等。往往会用到EEPROM、flash等一些储存方式。而CanMV K230 MicroPython自带文件系统,我们 只&nbsp; 需要将数据直接用文件方式保存即可。</div>

<div>&nbsp;&nbsp;&nbsp;&nbsp; micropython的文件操作大部分指令兼容CPython。因此我们可以直接使用Python编程来实现文件读写。CanMV K230盘符对应的目录为/sdcard/路径下,代码编写流程如下所示:</div>

<div></div>

<div>&nbsp;&nbsp;&nbsp;&nbsp; 参考代码如下:</div>

<table border="1">
        <tbody>
                <tr>
                        <td>&#39;&#39;&#39;<br />
                        实验名称:文件读写<br />
                        版本: v1.0<br />
                        作者:01Studio<br />
                        实验平台:01Studio CanMV K230<br />
                        说明:文件读写,将字符&ldquo;01Studio&rdquo;写入文件后再读取出来。<br />
                        &#39;&#39;&#39;<br />
                        ###########<br />
                        ## 写文件<br />
                        ###########<br />
                        f = open(&#39;/sdcard/1.txt&#39;, &#39;w&#39;) #以写的方式打开一个文件,没有该文件就自动新建<br />
                        f.write(&#39;01Studio&#39;) #写入数据<br />
                        f.close() #每次操作完记得关闭文件<br />
                        ###########<br />
                        ## 读文件<br />
                        ###########<br />
                        f = open(&#39;/sdcard/1.txt&#39;, &#39;r&#39;) #以读方式打开一个文件<br />
                        text = f.read()<br />
                        print(text) #读取数据并在终端打印<br />
                        f.close() #每次操作完记得关闭文件</td>
                </tr>
        </tbody>
</table>

<div>&nbsp;&nbsp;&nbsp; 实验结果,运行代码,可以看到串口终端打印了文件内容。打开CanMV盘符,在sdcard目录下可以看到刚刚代码新建的1.txt文件,里面的内容就是我们写入的01Studio。除了txt,你可以写入任何后缀的文件,如json、csv或者无后缀的文件。</div>

<div></div>

<p>&nbsp;</p>

<p><!--importdoc--></p>

<p>&nbsp;</p>
页: [1]
查看完整版本: 嘉楠K230 AI开发板测评3--RTC、ADC、PWM、UART、Thread、看门狗、文件读写