WeDesign第2期:基于树莓派RP2040微控制器的设计体验 DIY:炫彩灯组 (时钟)
利用树莓派RP2040微控制器的设计的点亮WS2812 DIY:炫彩灯组 RGB灯显示时钟 总体功能是显示实时的时间,可以整点报时,还可以利用按键进行时间的设定。
标签
嵌入式系统
2040
meiyao
更新2023-06-30
1429

1.自我介绍:本人从事电子工程师多年,一直是以硬件为主工作,最两年才从事一些与软件有关的设计工作,基础不是特别的牢,软件水平不是特别流畅,所以才申请RP2040学习。

2.芯片介绍:

      RP2040芯片参数:

  • 双核 Arm Cortex-M0 + @ 133MHz 
  • 芯片内置 264KB SRAM 和 2MB 的板载闪存 
  • 通过专用 QSPI 总线支持最高 16MB 的片外闪存 
  • DMA 控制器  30 个 GPIO 引脚,其中 4 个可用作模拟输入 
  • 2 个 UART、2 个 SPI 控制器和 2 个 I2C 控制器  16 个 PWM 通道 
  • USB 1.1 主机和设备支持  8 个树莓派可编程 I/O(PIO)状态机,用于自定义外围设备支持  支持 UF2 的 USB 大容量存储启动模式,用于拖放式编程 。

3.芯片设计体验思路(含开发思路、扩展硬件、搜集素材的思路等)

   1、芯片设计思路主要是根据PCIO核心板相似,参照核心板的部分相关布局,包括相关BOOT、存储芯片、晶振布局都有一些类似。

   2、主要扩展硬件有GPIO8控制的WS2812显示时钟RGB灯,GPIO14脚控制蜂鸣器,SW1,SW2调节时间,有计划OLED显示等功能。

   3、素材主要是想引用核心板,小巧简单,排针随时可以插拔,方便。另一方面是想做一个只有自己看的懂的实时时钟,也是引用了网友的设计布局,主要原因是这个看的时候容易好理解,从上之下的可以很明理。

4、画原理图、PCB制板过程中遇到的问题,以及解决方法

   1、画原理图:

      画原理图时,找了好多相关的资料,不知道做哪一个功能的好,最后看到好多人都比较喜欢RGB最终才选择WS2812去实现一个时钟的功能,最终以RP2040官方原理图开始绘画原理图设计,在画官方原理图和WS2812灯这个过程中,想到时钟都有一个带整点报时,于时就增加了一个蜂鸣器。

  2、画PCB:

      在进行PCB时,一直都把PCIO核心板进行对比,核心板是四层,我画的时候尽量用双面去搞定,然后器件在一面就出现难题了,放不下,思来想去,决定把器件放到板子的另一面,最终还是完成了了PCB的工作。

以下是整个PCB背面布局。

FshHF0uXrD4gtDTNTm17MhOI4OVm

项目整体设计流程图:

Fm3xAIq51tGN0NoQD_s5ak8-8mB9

 

5、展示用RP2040芯片设计功能板与板功能介绍

图中1:主要是MCU RP2040的核心电路部分的供电电容器件,这些电容分别 有3.3V和1.9V电路,还包括R104,R107的5.1K电阻,是在TYPE C的CC1,CC2上的。

图中2:是用的WS2812,作为时钟的时显示。

图中3:是用来显示时间的分显示。

Ftqa6R-e-etr22PvlUFLSfIkxIM8

 

 

6、核心代码:

 

peak = 255
music_on = False
mymusic = None

led = neopixel_rp2040.neopixel(LEDS=pin_cfg.LED_COUNT, PIN=pin_cfg.ws2812)
# led = neopixel_rp2040.neopixel(LEDS=28, PIN=8)

# 将WS2812 LED灯根据时间指示分成三个数组  
hour_leds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]  
ten_min_leds = [13, 14, 15, 16, 17, 18]  
one_min_leds = [19, 20, 21, 22, 23, 24, 25, 26, 27, 28]


class OledTime():
    def __init__(self, oled):
        self.oled = oled
        self.oled.fill(0)
        self.wri = Writer(oled, freesans20)
    def show_tim(self, hour, minite, second):
        self.h=hour
        self.mi=minite
        self.s=second
    def draw1(self):

        self.wri.set_textpos(oled, 30, 20)
        self.wri.printstring(str(self.h))
        self.wri.set_textpos(oled, 30, 60)
        self.wri.printstring(str(self.mi))
        self.wri.set_textpos(oled, 30, 100)
        self.wri.printstring(str(self.s))
        
    def show_date(self, year, month, day):
        self.y = year
        self.m = month
        self.d = day
    def draw2(self):

        self.wri.set_textpos(oled, 10, 10)
        self.wri.printstring(str(self.y))
        self.wri.set_textpos(oled, 10, 70)
        self.wri.printstring(str(self.m))
        self.wri.set_textpos(oled, 10, 100)
        self.wri.printstring(str(self.d))

oled_time = OledTime(oled)

def Ws2812Time(hour,minite,second):
        h_tmp = hour
        m_tmp = minite
        s_tmp = second
        tw_h  = h_tmp % 12 or 12  
        minute_tens = (m_tmp // 10) % 10  
        minute_ones = m_tmp % 10  

        led.set(COLOR=led.BLACK, BRIGHTNESS=0.03)

        led.set(LED_NUMBER=hour_leds[tw_h]-2, COLOR=led.MAGENTA, BRIGHTNESS=0.03)
        led.set(LED_NUMBER=ten_min_leds[minute_tens]-1, COLOR=led.CYAN, BRIGHTNESS=0.03)
        led.set(LED_NUMBER=one_min_leds[minute_ones]-1, COLOR=led.RED, BRIGHTNESS=0.03)


def music_toggle(on):
    global music_on, mymusic
    if music_on and not on:
        mymusic.stop()
        music_on = False
    elif not music_on and on:
        mymusic = music(song, tempo = 1)
        gc.collect()
        mymusic.beat = 200
        music_on = True
        
class AlarmTime:
    def __init__(self, oled):
        self.oled = oled
        self.s = 5
        self.ss = 0 # alarm absolute time 
        self.on = False
        self.wri = Writer(oled, freesans20)
        
    def render(self):
        if self.on and mymusic is not None:
            mymusic.tick()
    
    def update(self, s):
        if (s - 10 - self.ss) % 60 == 10:
            self.on = False
        
        if self.on and self.ss < s:
            music_toggle(True)
        elif not self.on:
            music_toggle(False)
            
    def draw(self):
        self.oled.fill(0)
        self.wri.set_textpos(oled, 10, 50)
        self.wri.printstring(str(self.s))
        self.wri.set_textpos(oled, 10, 70)
        self.wri.printstring(str('s'))
        self.wri.set_textpos(oled, 40, 10)
        self.wri.printstring(str('k2:Increase '))
        self.wri.set_textpos(oled, 25, 10)
        self.wri.printstring(str('k1:Confirm '))
        
alarm_time = AlarmTime(oled)

class StateMachine():
    SettingAlarmTime = 0
    ShowCurrentTime = 1
    
    def __init__(self, alarmTime):
        self.state = StateMachine.ShowCurrentTime
        self.old_state = self.state
        self.alarmTime = alarmTime
    
    def update(self, k1, k2, s):
        self.old_state = self.state
        
        if self.state == StateMachine.ShowCurrentTime:
            self.showCurrentTime(k1)
        elif self.state == StateMachine.SettingAlarmTime:
            self.settingAlarmTime(k1, k2, s)
        
        
    def showCurrentTime(self, k1):#未按k1显示时间

        if k1 == False:
            pass
        elif k1 == True:
            self.alarmTime.on = False
            self.state = StateMachine.SettingAlarmTime
    
    def settingAlarmTime(self, k1, k2, s):#按k1显示倒计时的时间
        if k1 == False:
            if k2:
                self.alarmTime.s = (self.alarmTime.s + 5) % 60
            pass
        if k1 == True:
            self.alarmTime.ss = (s + self.alarmTime.s + 1) % 60
            self.alarmTime.on = True
            self.state = StateMachine.ShowCurrentTime

fsm = StateMachine(alarm_time)

tick = 0

led.reset()
# led.set(BRIGHTNESS=0.01)
while True:
    oled.fill(0)
    dt_tuple = rtc.datetime()
    print(dt_tuple)

    year = dt_tuple[0]
    month = dt_tuple[1]
    day =dt_tuple[2]
    hour = dt_tuple[4] 
    minite = dt_tuple[5] 
    second = dt_tuple[6] 

    oled_time.show_date(year, month, day)
    oled_time.show_tim(hour, minite, second)
#     ws2812_time.show_time(hour, minite, second)
    alarm_time.update(second)

    k1_value = k1.value()
    k2_value = k2.value()
    fsm.update(k1_value, k2_value, second)

    if fsm.state == StateMachine.ShowCurrentTime:
        oled_time.draw2()
        oled_time.draw1()
    if fsm.state == StateMachine.SettingAlarmTime:
        alarm_time.draw()

    Ws2812Time(hour, minite, second)

    # rendering
    oled.show()

    alarm_time.render()
    
    tick = (tick + 1) % 65536
    sleep(0.04) # fps = 25

 

总结:

1.首先说一下RP2040的性能,个人感觉还是非常强大的,资源很丰富。

2.开发使用可选用Python或C/C++进行开发,方便快速开发,灵活易用。

附件下载
RP2040.kicad_pcb
PCB文件
RP2040.kicad_sch
原理图
main-clock(1).py
团队介绍
个人
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号